|
40 | 40 | import android.widget.RelativeLayout; |
41 | 41 | import android.widget.TextView; |
42 | 42 |
|
| 43 | +import androidx.annotation.Nullable; |
43 | 44 | import androidx.annotation.StringRes; |
44 | 45 | import androidx.webkit.WebViewClientCompat; |
45 | 46 |
|
46 | 47 | import com.google.android.gms.R; |
| 48 | +import com.google.android.gms.droidguard.DroidGuardClient; |
| 49 | +import com.google.android.gms.tasks.Tasks; |
47 | 50 |
|
48 | 51 | import org.json.JSONArray; |
49 | 52 | import org.microg.gms.auth.AuthConstants; |
|
54 | 57 | import org.microg.gms.checkin.LastCheckinInfo; |
55 | 58 | import org.microg.gms.common.HttpFormClient; |
56 | 59 | import org.microg.gms.common.Utils; |
| 60 | +import org.microg.gms.droidguard.core.DroidGuardPreferences; |
57 | 61 | import org.microg.gms.people.PeopleManager; |
58 | 62 | import org.microg.gms.profile.Build; |
59 | 63 | import org.microg.gms.profile.ProfileManager; |
60 | 64 |
|
61 | 65 | import java.io.IOException; |
62 | 66 | import java.security.MessageDigest; |
| 67 | +import java.util.HashMap; |
63 | 68 | import java.util.Locale; |
| 69 | +import java.util.Map; |
| 70 | +import java.util.Random; |
| 71 | +import java.util.concurrent.TimeUnit; |
64 | 72 |
|
65 | 73 | import static android.accounts.AccountManager.PACKAGE_NAME_KEY_LEGACY_NOT_VISIBLE; |
66 | 74 | import static android.accounts.AccountManager.VISIBILITY_USER_MANAGED_VISIBLE; |
@@ -100,6 +108,9 @@ public class LoginActivity extends AssistantActivity { |
100 | 108 | private InputMethodManager inputMethodManager; |
101 | 109 | private ViewGroup authContent; |
102 | 110 | private int state = 0; |
| 111 | + private volatile boolean authDroidGuardResultLoaded = false; |
| 112 | + @Nullable |
| 113 | + private volatile String authDroidGuardResult; |
103 | 114 |
|
104 | 115 | @SuppressLint("AddJavascriptInterface") |
105 | 116 | @Override |
@@ -282,87 +293,95 @@ private void closeWeb(boolean programmaticAuth) { |
282 | 293 | } |
283 | 294 |
|
284 | 295 | private void retrieveRtToken(String oAuthToken) { |
285 | | - new AuthRequest().fromContext(this) |
286 | | - .appIsGms() |
287 | | - .callerIsGms() |
288 | | - .service("ac2dm") |
289 | | - .token(oAuthToken).isAccessToken() |
290 | | - .addAccount() |
291 | | - .getAccountId() |
292 | | - .droidguardResults(null /*TODO*/) |
293 | | - .getResponseAsync(new HttpFormClient.Callback<AuthResponse>() { |
294 | | - @Override |
295 | | - public void onResponse(AuthResponse response) { |
296 | | - Account account = new Account(response.email, accountType); |
297 | | - if (accountManager.addAccountExplicitly(account, response.token, null)) { |
298 | | - accountManager.setAuthToken(account, "SID", response.Sid); |
299 | | - accountManager.setAuthToken(account, "LSID", response.LSid); |
300 | | - accountManager.setUserData(account, "flags", "1"); |
301 | | - accountManager.setUserData(account, "services", response.services); |
302 | | - accountManager.setUserData(account, "oauthAccessToken", "1"); |
303 | | - accountManager.setUserData(account, "firstName", response.firstName); |
304 | | - accountManager.setUserData(account, "lastName", response.lastName); |
305 | | - if (!TextUtils.isEmpty(response.accountId)) |
306 | | - accountManager.setUserData(account, "GoogleUserId", response.accountId); |
307 | | - |
308 | | - retrieveGmsToken(account); |
309 | | - setResult(RESULT_OK); |
310 | | - } else { |
311 | | - Log.w(TAG, "Account NOT created!"); |
| 296 | + new Thread(() -> { |
| 297 | + String droidGuardResults = getAuthDroidGuardResultOrNullString(); |
| 298 | + Log.i(TAG, "droidGuardResults:" + droidGuardResults); |
| 299 | + new AuthRequest().fromContext(this) |
| 300 | + .appIsGms() |
| 301 | + .callerIsGms() |
| 302 | + .service("ac2dm") |
| 303 | + .token(oAuthToken).isAccessToken() |
| 304 | + .addAccount() |
| 305 | + .getAccountId() |
| 306 | + .droidguardResults(droidGuardResults) |
| 307 | + .getResponseAsync(new HttpFormClient.Callback<AuthResponse>() { |
| 308 | + @Override |
| 309 | + public void onResponse(AuthResponse response) { |
| 310 | + Account account = new Account(response.email, accountType); |
| 311 | + if (accountManager.addAccountExplicitly(account, response.token, null)) { |
| 312 | + accountManager.setAuthToken(account, "SID", response.Sid); |
| 313 | + accountManager.setAuthToken(account, "LSID", response.LSid); |
| 314 | + accountManager.setUserData(account, "flags", "1"); |
| 315 | + accountManager.setUserData(account, "services", response.services); |
| 316 | + accountManager.setUserData(account, "oauthAccessToken", "1"); |
| 317 | + accountManager.setUserData(account, "firstName", response.firstName); |
| 318 | + accountManager.setUserData(account, "lastName", response.lastName); |
| 319 | + if (!TextUtils.isEmpty(response.accountId)) |
| 320 | + accountManager.setUserData(account, "GoogleUserId", response.accountId); |
| 321 | + |
| 322 | + retrieveGmsToken(account); |
| 323 | + setResult(RESULT_OK); |
| 324 | + } else { |
| 325 | + Log.w(TAG, "Account NOT created!"); |
| 326 | + runOnUiThread(() -> { |
| 327 | + showError(R.string.auth_general_error_desc); |
| 328 | + setNextButtonText(android.R.string.ok); |
| 329 | + }); |
| 330 | + state = -2; |
| 331 | + } |
| 332 | + } |
| 333 | + |
| 334 | + @Override |
| 335 | + public void onException(Exception exception) { |
| 336 | + Log.w(TAG, "onException", exception); |
312 | 337 | runOnUiThread(() -> { |
313 | 338 | showError(R.string.auth_general_error_desc); |
314 | 339 | setNextButtonText(android.R.string.ok); |
315 | 340 | }); |
316 | 341 | state = -2; |
317 | 342 | } |
318 | | - } |
319 | | - |
320 | | - @Override |
321 | | - public void onException(Exception exception) { |
322 | | - Log.w(TAG, "onException", exception); |
323 | | - runOnUiThread(() -> { |
324 | | - showError(R.string.auth_general_error_desc); |
325 | | - setNextButtonText(android.R.string.ok); |
326 | | - }); |
327 | | - state = -2; |
328 | | - } |
329 | | - }); |
| 343 | + }); |
| 344 | + }).start(); |
330 | 345 | } |
331 | 346 |
|
332 | 347 | private void retrieveGmsToken(final Account account) { |
333 | 348 | final AuthManager authManager = new AuthManager(this, account.name, GMS_PACKAGE_NAME, "ac2dm"); |
334 | 349 | authManager.setPermitted(true); |
335 | | - new AuthRequest().fromContext(this) |
336 | | - .appIsGms() |
337 | | - .callerIsGms() |
338 | | - .service(authManager.getService()) |
339 | | - .email(account.name) |
340 | | - .token(AccountManager.get(this).getPassword(account)) |
341 | | - .systemPartition(true) |
342 | | - .hasPermission(true) |
343 | | - .addAccount() |
344 | | - .getAccountId() |
345 | | - .getResponseAsync(new HttpFormClient.Callback<AuthResponse>() { |
346 | | - @Override |
347 | | - public void onResponse(AuthResponse response) { |
348 | | - authManager.storeResponse(response); |
349 | | - String accountId = PeopleManager.loadUserInfo(LoginActivity.this, account); |
350 | | - if (!TextUtils.isEmpty(accountId)) |
351 | | - accountManager.setUserData(account, "GoogleUserId", accountId); |
352 | | - checkin(true); |
353 | | - finish(); |
354 | | - } |
355 | | - |
356 | | - @Override |
357 | | - public void onException(Exception exception) { |
358 | | - Log.w(TAG, "onException", exception); |
359 | | - runOnUiThread(() -> { |
360 | | - showError(R.string.auth_general_error_desc); |
361 | | - setNextButtonText(android.R.string.ok); |
362 | | - }); |
363 | | - state = -2; |
364 | | - } |
365 | | - }); |
| 350 | + new Thread(() -> { |
| 351 | + String droidGuardResults = getAuthDroidGuardResultOrNullString(); |
| 352 | + new AuthRequest().fromContext(this) |
| 353 | + .appIsGms() |
| 354 | + .callerIsGms() |
| 355 | + .service(authManager.getService()) |
| 356 | + .email(account.name) |
| 357 | + .token(AccountManager.get(this).getPassword(account)) |
| 358 | + .systemPartition(true) |
| 359 | + .hasPermission(true) |
| 360 | + .addAccount() |
| 361 | + .getAccountId() |
| 362 | + .droidguardResults(droidGuardResults) |
| 363 | + .getResponseAsync(new HttpFormClient.Callback<AuthResponse>() { |
| 364 | + @Override |
| 365 | + public void onResponse(AuthResponse response) { |
| 366 | + authManager.storeResponse(response); |
| 367 | + String accountId = PeopleManager.loadUserInfo(LoginActivity.this, account); |
| 368 | + if (!TextUtils.isEmpty(accountId)) |
| 369 | + accountManager.setUserData(account, "GoogleUserId", accountId); |
| 370 | + checkin(true); |
| 371 | + finish(); |
| 372 | + } |
| 373 | + |
| 374 | + @Override |
| 375 | + public void onException(Exception exception) { |
| 376 | + Log.w(TAG, "onException", exception); |
| 377 | + runOnUiThread(() -> { |
| 378 | + showError(R.string.auth_general_error_desc); |
| 379 | + setNextButtonText(android.R.string.ok); |
| 380 | + }); |
| 381 | + state = -2; |
| 382 | + } |
| 383 | + }); |
| 384 | + }).start(); |
366 | 385 | } |
367 | 386 |
|
368 | 387 | private boolean checkin(boolean force) { |
@@ -396,6 +415,53 @@ private static String buildUrl(String tmpl, Locale locale) { |
396 | 415 | .build().toString(); |
397 | 416 | } |
398 | 417 |
|
| 418 | + private String getAuthDroidGuardResultOrNullString() { |
| 419 | + String result = getAuthDroidGuardResult(); |
| 420 | + return result != null ? result : "null"; |
| 421 | + } |
| 422 | + |
| 423 | + @Nullable |
| 424 | + private synchronized String getAuthDroidGuardResult() { |
| 425 | + if (authDroidGuardResultLoaded) { |
| 426 | + return authDroidGuardResult; |
| 427 | + } |
| 428 | + |
| 429 | + authDroidGuardResultLoaded = true; |
| 430 | + if (!DroidGuardPreferences.isAvailable(this)) { |
| 431 | + return null; |
| 432 | + } |
| 433 | + |
| 434 | + Map<String, String> data = buildAuthDroidGuardData(); |
| 435 | + authDroidGuardResult = tryDroidGuardResult("auth", data); |
| 436 | + if (authDroidGuardResult == null) { |
| 437 | + authDroidGuardResult = tryDroidGuardResult("checkin", data); |
| 438 | + } |
| 439 | + return authDroidGuardResult; |
| 440 | + } |
| 441 | + |
| 442 | + @Nullable |
| 443 | + private String tryDroidGuardResult(String flow, Map<String, String> data) { |
| 444 | + try { |
| 445 | + return Tasks.await(DroidGuardClient.getResults(this, flow, data), 15, TimeUnit.SECONDS); |
| 446 | + } catch (Exception e) { |
| 447 | + Log.w(TAG, "DroidGuard auth flow failed: " + flow, e); |
| 448 | + return null; |
| 449 | + } |
| 450 | + } |
| 451 | + |
| 452 | + private Map<String, String> buildAuthDroidGuardData() { |
| 453 | + Map<String, String> data = new HashMap<>(); |
| 454 | + long androidId = LastCheckinInfo.read(this).getAndroidId(); |
| 455 | + if (androidId != 0 && androidId != -1) { |
| 456 | + data.put("dg_androidId", Long.toHexString(androidId)); |
| 457 | + } |
| 458 | + |
| 459 | + data.put("dg_gmsCoreVersion", Integer.toString(GMS_VERSION_CODE)); |
| 460 | + data.put("dg_sdkVersion", Integer.toString(Build.VERSION.SDK_INT)); |
| 461 | + data.put("dg_session", Long.toHexString(new Random().nextLong())); |
| 462 | + return data; |
| 463 | + } |
| 464 | + |
399 | 465 | private class JsBridge { |
400 | 466 |
|
401 | 467 | @JavascriptInterface |
|
0 commit comments