|
47 | 47 | import androidx.webkit.WebViewClientCompat; |
48 | 48 |
|
49 | 49 | import com.google.android.gms.R; |
| 50 | +import com.google.android.gms.droidguard.DroidGuardClient; |
| 51 | +import com.google.android.gms.tasks.Tasks; |
50 | 52 |
|
51 | 53 | import org.json.JSONArray; |
52 | 54 | import org.microg.gms.accountaction.AccountNotificationKt; |
|
60 | 62 | import org.microg.gms.common.Constants; |
61 | 63 | import org.microg.gms.common.HttpFormClient; |
62 | 64 | import org.microg.gms.common.Utils; |
| 65 | +import org.microg.gms.droidguard.core.DroidGuardPreferences; |
63 | 66 | import org.microg.gms.people.PeopleManager; |
64 | 67 | import org.microg.gms.profile.Build; |
65 | 68 | import org.microg.gms.profile.ProfileManager; |
66 | 69 |
|
67 | 70 | import java.io.IOException; |
68 | 71 | import java.security.MessageDigest; |
| 72 | +import java.util.HashMap; |
69 | 73 | import java.util.Locale; |
| 74 | +import java.util.Map; |
| 75 | +import java.util.Random; |
| 76 | +import java.util.concurrent.TimeUnit; |
70 | 77 |
|
71 | 78 | import static android.accounts.AccountManager.PACKAGE_NAME_KEY_LEGACY_NOT_VISIBLE; |
72 | 79 | import static android.accounts.AccountManager.VISIBILITY_USER_MANAGED_VISIBLE; |
@@ -116,6 +123,9 @@ public class LoginActivity extends AssistantActivity { |
116 | 123 | private int state = 0; |
117 | 124 | private boolean isReAuth = false; |
118 | 125 | private Account reAuthAccount; |
| 126 | + private volatile boolean authDroidGuardResultLoaded = false; |
| 127 | + @Nullable |
| 128 | + private volatile String authDroidGuardResult; |
119 | 129 |
|
120 | 130 | @SuppressLint("AddJavascriptInterface") |
121 | 131 | @Override |
@@ -346,35 +356,39 @@ private void closeWeb(boolean programmaticAuth) { |
346 | 356 | } |
347 | 357 |
|
348 | 358 | private void retrieveRtToken(String oAuthToken) { |
349 | | - new AuthRequest().fromContext(this) |
350 | | - .appIsGms() |
351 | | - .callerIsGms() |
352 | | - .service("ac2dm") |
353 | | - .token(oAuthToken).isAccessToken() |
354 | | - .addAccount() |
355 | | - .getAccountId() |
356 | | - .droidguardResults("null" /*TODO*/) |
357 | | - .getResponseAsync(new HttpFormClient.Callback<AuthResponse>() { |
358 | | - @Override |
359 | | - public void onResponse(AuthResponse response) { |
360 | | - Account account = new Account(response.email, accountType); |
361 | | - if (isReAuth && reAuthAccount != null && reAuthAccount.name.equals(account.name)) { |
362 | | - accountManager.removeAccount(account, future -> saveAccount(account, response), null); |
363 | | - } else { |
364 | | - saveAccount(account, response); |
| 359 | + new Thread(() -> { |
| 360 | + String droidGuardResults = getAuthDroidGuardResultOrNullString(); |
| 361 | + Log.i(TAG, "droidGuardResults:" + droidGuardResults); |
| 362 | + new AuthRequest().fromContext(this) |
| 363 | + .appIsGms() |
| 364 | + .callerIsGms() |
| 365 | + .service("ac2dm") |
| 366 | + .token(oAuthToken).isAccessToken() |
| 367 | + .addAccount() |
| 368 | + .getAccountId() |
| 369 | + .droidguardResults(droidGuardResults) |
| 370 | + .getResponseAsync(new HttpFormClient.Callback<AuthResponse>() { |
| 371 | + @Override |
| 372 | + public void onResponse(AuthResponse response) { |
| 373 | + Account account = new Account(response.email, accountType); |
| 374 | + if (isReAuth && reAuthAccount != null && reAuthAccount.name.equals(account.name)) { |
| 375 | + accountManager.removeAccount(account, future -> saveAccount(account, response), null); |
| 376 | + } else { |
| 377 | + saveAccount(account, response); |
| 378 | + } |
365 | 379 | } |
366 | | - } |
367 | | - |
368 | | - @Override |
369 | | - public void onException(Exception exception) { |
370 | | - Log.w(TAG, "onException", exception); |
371 | | - runOnUiThread(() -> { |
372 | | - showError(R.string.auth_general_error_desc); |
373 | | - setNextButtonText(android.R.string.ok); |
374 | | - }); |
375 | | - state = -2; |
376 | | - } |
377 | | - }); |
| 380 | + |
| 381 | + @Override |
| 382 | + public void onException(Exception exception) { |
| 383 | + Log.w(TAG, "onException", exception); |
| 384 | + runOnUiThread(() -> { |
| 385 | + showError(R.string.auth_general_error_desc); |
| 386 | + setNextButtonText(android.R.string.ok); |
| 387 | + }); |
| 388 | + state = -2; |
| 389 | + } |
| 390 | + }); |
| 391 | + }).start(); |
378 | 392 | } |
379 | 393 |
|
380 | 394 | private void saveAccount(Account account, AuthResponse response) { |
@@ -420,43 +434,46 @@ private void returnSuccessResponse(Account account){ |
420 | 434 | private void retrieveGmsToken(final Account account) { |
421 | 435 | final AuthManager authManager = new AuthManager(this, account.name, GMS_PACKAGE_NAME, "ac2dm"); |
422 | 436 | authManager.setPermitted(true); |
423 | | - new AuthRequest().fromContext(this) |
424 | | - .appIsGms() |
425 | | - .callerIsGms() |
426 | | - .service(authManager.getService()) |
427 | | - .email(account.name) |
428 | | - .token(AccountManager.get(this).getPassword(account)) |
429 | | - .systemPartition(true) |
430 | | - .hasPermission(true) |
431 | | - .addAccount() |
432 | | - .getAccountId() |
433 | | - .droidguardResults("null") |
434 | | - .getResponseAsync(new HttpFormClient.Callback<AuthResponse>() { |
435 | | - @Override |
436 | | - public void onResponse(AuthResponse response) { |
437 | | - authManager.storeResponse(response); |
438 | | - String accountId = PeopleManager.loadUserInfo(LoginActivity.this, account); |
439 | | - if (!TextUtils.isEmpty(accountId)) |
440 | | - accountManager.setUserData(account, "GoogleUserId", accountId); |
441 | | - if (isAuthVisible(LoginActivity.this) && SDK_INT >= 26) { |
442 | | - accountManager.setAccountVisibility(account, PACKAGE_NAME_KEY_LEGACY_NOT_VISIBLE, VISIBILITY_USER_MANAGED_VISIBLE); |
| 437 | + new Thread(() -> { |
| 438 | + String droidGuardResults = getAuthDroidGuardResultOrNullString(); |
| 439 | + new AuthRequest().fromContext(this) |
| 440 | + .appIsGms() |
| 441 | + .callerIsGms() |
| 442 | + .service(authManager.getService()) |
| 443 | + .email(account.name) |
| 444 | + .token(AccountManager.get(this).getPassword(account)) |
| 445 | + .systemPartition(true) |
| 446 | + .hasPermission(true) |
| 447 | + .addAccount() |
| 448 | + .getAccountId() |
| 449 | + .droidguardResults(droidGuardResults) |
| 450 | + .getResponseAsync(new HttpFormClient.Callback<AuthResponse>() { |
| 451 | + @Override |
| 452 | + public void onResponse(AuthResponse response) { |
| 453 | + authManager.storeResponse(response); |
| 454 | + String accountId = PeopleManager.loadUserInfo(LoginActivity.this, account); |
| 455 | + if (!TextUtils.isEmpty(accountId)) |
| 456 | + accountManager.setUserData(account, "GoogleUserId", accountId); |
| 457 | + if (isAuthVisible(LoginActivity.this) && SDK_INT >= 26) { |
| 458 | + accountManager.setAccountVisibility(account, PACKAGE_NAME_KEY_LEGACY_NOT_VISIBLE, VISIBILITY_USER_MANAGED_VISIBLE); |
| 459 | + } |
| 460 | + checkin(true); |
| 461 | + returnSuccessResponse(account); |
| 462 | + notifyGcmGroupUpdate(account.name); |
| 463 | + if (SDK_INT >= 21) { finishAndRemoveTask(); } else finish(); |
| 464 | + } |
| 465 | + |
| 466 | + @Override |
| 467 | + public void onException(Exception exception) { |
| 468 | + Log.w(TAG, "onException", exception); |
| 469 | + runOnUiThread(() -> { |
| 470 | + showError(R.string.auth_general_error_desc); |
| 471 | + setNextButtonText(android.R.string.ok); |
| 472 | + }); |
| 473 | + state = -2; |
443 | 474 | } |
444 | | - checkin(true); |
445 | | - returnSuccessResponse(account); |
446 | | - notifyGcmGroupUpdate(account.name); |
447 | | - if (SDK_INT >= 21) { finishAndRemoveTask(); } else finish(); |
448 | | - } |
449 | | - |
450 | | - @Override |
451 | | - public void onException(Exception exception) { |
452 | | - Log.w(TAG, "onException", exception); |
453 | | - runOnUiThread(() -> { |
454 | | - showError(R.string.auth_general_error_desc); |
455 | | - setNextButtonText(android.R.string.ok); |
456 | | - }); |
457 | | - state = -2; |
458 | | - } |
459 | | - }); |
| 475 | + }); |
| 476 | + }).start(); |
460 | 477 | } |
461 | 478 |
|
462 | 479 | private void notifyGcmGroupUpdate(String accountName) { |
@@ -501,6 +518,53 @@ private String buildUrl(String tmpl, Locale locale) { |
501 | 518 | return builder.build().toString(); |
502 | 519 | } |
503 | 520 |
|
| 521 | + private String getAuthDroidGuardResultOrNullString() { |
| 522 | + String result = getAuthDroidGuardResult(); |
| 523 | + return result != null ? result : "null"; |
| 524 | + } |
| 525 | + |
| 526 | + @Nullable |
| 527 | + private synchronized String getAuthDroidGuardResult() { |
| 528 | + if (authDroidGuardResultLoaded) { |
| 529 | + return authDroidGuardResult; |
| 530 | + } |
| 531 | + |
| 532 | + authDroidGuardResultLoaded = true; |
| 533 | + if (!DroidGuardPreferences.isAvailable(this)) { |
| 534 | + return null; |
| 535 | + } |
| 536 | + |
| 537 | + Map<String, String> data = buildAuthDroidGuardData(); |
| 538 | + authDroidGuardResult = tryDroidGuardResult("auth", data); |
| 539 | + if (authDroidGuardResult == null) { |
| 540 | + authDroidGuardResult = tryDroidGuardResult("checkin", data); |
| 541 | + } |
| 542 | + return authDroidGuardResult; |
| 543 | + } |
| 544 | + |
| 545 | + @Nullable |
| 546 | + private String tryDroidGuardResult(String flow, Map<String, String> data) { |
| 547 | + try { |
| 548 | + return Tasks.await(DroidGuardClient.getResults(this, flow, data), 15, TimeUnit.SECONDS); |
| 549 | + } catch (Exception e) { |
| 550 | + Log.w(TAG, "DroidGuard auth flow failed: " + flow, e); |
| 551 | + return null; |
| 552 | + } |
| 553 | + } |
| 554 | + |
| 555 | + private Map<String, String> buildAuthDroidGuardData() { |
| 556 | + Map<String, String> data = new HashMap<>(); |
| 557 | + long androidId = LastCheckinInfo.read(this).getAndroidId(); |
| 558 | + if (androidId != 0 && androidId != -1) { |
| 559 | + data.put("dg_androidId", Long.toHexString(androidId)); |
| 560 | + } |
| 561 | + |
| 562 | + data.put("dg_gmsCoreVersion", Integer.toString(GMS_VERSION_CODE)); |
| 563 | + data.put("dg_sdkVersion", Integer.toString(Build.VERSION.SDK_INT)); |
| 564 | + data.put("dg_session", Long.toHexString(new Random().nextLong())); |
| 565 | + return data; |
| 566 | + } |
| 567 | + |
504 | 568 | private class JsBridge { |
505 | 569 |
|
506 | 570 | @JavascriptInterface |
|
0 commit comments