Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,8 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
private final ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
protected LoginDialog loginDialog;

private static final String LOGIN_FLOW_LOG = "LoginFlowV2 |";

@VisibleForTesting
public AccountSetupBinding getAccountSetupBinding() {
return accountSetupBinding;
Expand All @@ -256,6 +258,7 @@ public AccountSetupBinding getAccountSetupBinding() {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log_OC.d(TAG, LOGIN_FLOW_LOG + " Lifecycle onCreate (recreated=" + (savedInstanceState != null) + ")");
loginDialog = new LoginDialog(this);
viewThemeUtils = viewThemeUtilsFactory.withPrimaryAsBackground();
viewThemeUtils.platform.colorStatusBar(this, getResources().getColor(R.color.primary));
Expand Down Expand Up @@ -407,7 +410,9 @@ private void deleteCookies() {
private String baseUrl;

private void poolLogin() {
Log_OC.d(TAG, LOGIN_FLOW_LOG + " Step 6: Polling started (interval=30s)");
loginFlowExecutorService.scheduleWithFixedDelay(() -> {
Log_OC.d(TAG, LOGIN_FLOW_LOG + " Poll tick (completed=" + isLoginProcessCompleted + ")");
if (!isLoginProcessCompleted) {
performLoginFlowV2();
}
Expand All @@ -430,9 +435,12 @@ private void anonymouslyPostLoginRequest(String url) {
return;
}
baseUrl = url;
Log_OC.d(TAG, LOGIN_FLOW_LOG + " Step 1: POST /login/v2 -> " + url);

singleThreadExecutor.execute(() -> {
String response = getResponseOfAnonymouslyPostLoginRequest();
Log_OC.d(TAG, LOGIN_FLOW_LOG + " Step 2: /login/v2 response received (empty="
+ TextUtils.isEmpty(response) + ")");
if (TextUtils.isEmpty(response)) {
DisplayUtils.showSnackMessage(AuthenticatorActivity.this, R.string.authenticator_activity_empty_response_message);
return;
Expand All @@ -450,6 +458,7 @@ private String extractLoginUrl(String response) {
try {
authObject = gson.fromJson(response, AuthObject.class);
if (authObject != null && !TextUtils.isEmpty(authObject.getLogin())) {
Log_OC.d(TAG, LOGIN_FLOW_LOG + " Step 3: login URL + poll token extracted");
return authObject.getLogin();
} else {
Log_OC.e(TAG, "AuthObject parsing failed or login empty, trying JSONObject fallback");
Expand Down Expand Up @@ -499,6 +508,7 @@ private void launchDefaultWebBrowser(String url) {
try {
int toolbarColor = ContextCompat.getColor(this, R.color.primary);
AuthTabIntent authTabIntent = new AuthTabIntent.Builder().setColorScheme(toolbarColor).build();
Log_OC.d(TAG, LOGIN_FLOW_LOG + " Step 5: launching browser via Auth Tab (scheme=" + loginScheme + ")");
authTabIntent.launch(authTabResultLauncher, uri, loginScheme);
return;
} catch (Exception e) {
Expand All @@ -509,13 +519,15 @@ private void launchDefaultWebBrowser(String url) {
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
PackageManager packageManager = getPackageManager();
if (intent.resolveActivity(packageManager) != null) {
Log_OC.d(TAG, LOGIN_FLOW_LOG + " Step 5 (fallback): launching external browser");
startActivity(intent);
return;
}
} catch (Exception e) {
Log_OC.e(TAG, "External browser launch failed: " + e);
}

Log_OC.d(TAG, LOGIN_FLOW_LOG + " Step 5 (failed): no web browser found");
DisplayUtils.showSnackMessage(this, R.string.authenticator_activity_no_web_browser_found);
}

Expand Down Expand Up @@ -549,25 +561,31 @@ private void performLoginFlowV2() {

PlainClient client = clientFactory.createPlainClient();
PostMethod post = new PostMethod(pollUrlAndToken.first, false, requestBody);
Log_OC.d(TAG, LOGIN_FLOW_LOG + " Step 7: Poll request -> " + pollUrlAndToken.first);
int status = post.execute(client);
String response = post.getResponseBodyAsString();

Log_OC.d(TAG, "performLoginFlowV2 status: " + status);
Log_OC.d(TAG, "performLoginFlowV2 response: " + response);

if (!response.isEmpty()) {
Log_OC.d(TAG, LOGIN_FLOW_LOG + " Step 8: non-empty poll response -> completeLoginFlow()");
runOnUiThread(() -> completeLoginFlow(response, status));
}
}

private void completeLoginFlow(String response, int status) {
Log_OC.d(TAG, LOGIN_FLOW_LOG + " Step 9: completeLoginFlow (status=" + status + ")");
try {
LoginUrlInfo loginUrlInfo = gson.fromJson(response, LoginUrlInfo.class);
if (loginUrlInfo == null) {
Log_OC.e(TAG, "cannot complete login flow loginUrl is null");
return;
}
isLoginProcessCompleted = loginUrlInfo.isValid(status);
Log_OC.d(TAG, LOGIN_FLOW_LOG + " Step 9: credentials received (valid=" + isLoginProcessCompleted
+ ", loginName=" + !TextUtils.isEmpty(loginUrlInfo.getLoginName())
+ ", appPassword=" + !TextUtils.isEmpty(loginUrlInfo.getAppPassword()) + ")");

if (accountSetupBinding != null) {
accountSetupBinding.hostUrlInput.setText("");
Expand All @@ -586,12 +604,16 @@ private void completeLoginFlow(String response, int status) {
checkOcServer();
loginFlowExecutorService.shutdown();
ProcessLifecycleOwner.get().getLifecycle().removeObserver(lifecycleEventObserver);
Log_OC.d(TAG, LOGIN_FLOW_LOG + " Step 9: polling stopped and lifecycle observer removed");
}

private final LifecycleEventObserver lifecycleEventObserver = ((lifecycleOwner, event) -> {
if (event == Lifecycle.Event.ON_START && authObject != null && !TextUtils.isEmpty(authObject.getPoll().getToken())) {
Log_OC.d(TAG, "Start poolLogin");
Log_OC.d(TAG, LOGIN_FLOW_LOG + " ProcessLifecycleOwner ON_START -> starting polling");
poolLogin();
} else if (event == Lifecycle.Event.ON_START) {
Log_OC.d(TAG, LOGIN_FLOW_LOG + " ProcessLifecycleOwner ON_START ignored (authObject="
+ (authObject != null) + ")");
}
});
// endregion
Expand Down Expand Up @@ -841,6 +863,7 @@ public void onRestoreInstanceState(@NonNull Bundle savedInstanceState) {
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
Log_OC.d(TAG, LOGIN_FLOW_LOG + " Lifecycle onNewIntent (browser return candidate)");
Log_OC.d(TAG, "onNewIntent()");

if (intent.getBooleanExtra(FirstRunActivity.EXTRA_EXIT, false)) {
Expand All @@ -860,6 +883,8 @@ protected void onNewIntent(Intent intent) {
finish();
return;
} else {
Log_OC.d(TAG, LOGIN_FLOW_LOG
+ " Browser returned via onNewIntent deep link (nc://) -> parsing credentials");
parseAndLoginFromWebView(data.toString());
}
}
Expand All @@ -871,6 +896,12 @@ protected void onNewIntent(Intent intent) {
}
}

@Override
protected void onStart() {
super.onStart();
Log_OC.d(TAG, LOGIN_FLOW_LOG + " Lifecycle onStart");
}

@SuppressFBWarnings("ANDROID_WEB_VIEW_JAVASCRIPT")
@SuppressLint("SetJavaScriptEnabled")
private void initSimpleSignupLogin() {
Expand Down Expand Up @@ -933,6 +964,7 @@ protected void onResume() {

@Override
protected void onPause() {
Log_OC.d(TAG, LOGIN_FLOW_LOG + " Lifecycle onPause");
if (mOperationsServiceBinder != null) {
mOperationsServiceBinder.removeOperationListener(this);
}
Expand All @@ -947,6 +979,7 @@ protected void onDestroy() {
mOperationsServiceBinder = null;
}

Log_OC.d(TAG, LOGIN_FLOW_LOG + " Lifecycle onDestroy (isFinishing=" + isFinishing() + ")");
Log_OC.d(TAG, "AuthenticatorActivity onDestroy called");
singleThreadExecutor.shutdown();
super.onDestroy();
Expand Down Expand Up @@ -1119,6 +1152,7 @@ private void onGetServerInfoFinish(RemoteOperationResult result) {

// region LoginInfoView
private void initLoginInfoView() {
Log_OC.d(TAG, LOGIN_FLOW_LOG + " Step 4: 'Waiting for browser' UI shown");
LinearLayout loginFlowLayout = accountSetupWebviewBinding.loginFlowV2.getRoot();
MaterialButton cancelButton = accountSetupWebviewBinding.loginFlowV2.cancelButton;
loginFlowLayout.setVisibility(View.VISIBLE);
Expand All @@ -1137,6 +1171,7 @@ private void initLoginInfoView() {
ViewCompat.requestApplyInsets(loginFlowLayout);

cancelButton.setOnClickListener(v -> {
Log_OC.d(TAG, LOGIN_FLOW_LOG + " Polling cancelled by user (cancel button)");
loginFlowExecutorService.shutdown();
ProcessLifecycleOwner.get().getLifecycle().removeObserver(lifecycleEventObserver);
recreate();
Expand Down Expand Up @@ -1564,7 +1599,8 @@ private void startQRScanner() {

private final ActivityResultLauncher<Intent> authTabResultLauncher = AuthTabIntent.registerActivityResultLauncher(
this,
result -> Log_OC.d(TAG, "Auth Tab result code: " + result.resultCode)
result -> Log_OC.d(TAG, LOGIN_FLOW_LOG + " Browser returned via Auth Tab (resultCode=" + result.resultCode
+ ", hasUri=" + (result.resultUri != null) + ")")
);

private final ActivityResultLauncher<Intent> qrScanResultLauncher = registerForActivityResult(
Expand Down
Loading