Skip to content

Commit cb03aa2

Browse files
committed
Introduce droid guard results into Google sign-in.
We first try to make a droid guard auth flow. If it fails, we try a droid guard checkin flow, if it fails, we fallback on the "null" value.
1 parent e19a998 commit cb03aa2

File tree

1 file changed

+128
-64
lines changed

1 file changed

+128
-64
lines changed

play-services-core/src/main/java/org/microg/gms/auth/login/LoginActivity.java

Lines changed: 128 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@
4747
import androidx.webkit.WebViewClientCompat;
4848

4949
import com.google.android.gms.R;
50+
import com.google.android.gms.droidguard.DroidGuardClient;
51+
import com.google.android.gms.tasks.Tasks;
5052

5153
import org.json.JSONArray;
5254
import org.microg.gms.accountaction.AccountNotificationKt;
@@ -60,13 +62,18 @@
6062
import org.microg.gms.common.Constants;
6163
import org.microg.gms.common.HttpFormClient;
6264
import org.microg.gms.common.Utils;
65+
import org.microg.gms.droidguard.core.DroidGuardPreferences;
6366
import org.microg.gms.people.PeopleManager;
6467
import org.microg.gms.profile.Build;
6568
import org.microg.gms.profile.ProfileManager;
6669

6770
import java.io.IOException;
6871
import java.security.MessageDigest;
72+
import java.util.HashMap;
6973
import java.util.Locale;
74+
import java.util.Map;
75+
import java.util.Random;
76+
import java.util.concurrent.TimeUnit;
7077

7178
import static android.accounts.AccountManager.PACKAGE_NAME_KEY_LEGACY_NOT_VISIBLE;
7279
import static android.accounts.AccountManager.VISIBILITY_USER_MANAGED_VISIBLE;
@@ -116,6 +123,9 @@ public class LoginActivity extends AssistantActivity {
116123
private int state = 0;
117124
private boolean isReAuth = false;
118125
private Account reAuthAccount;
126+
private volatile boolean authDroidGuardResultLoaded = false;
127+
@Nullable
128+
private volatile String authDroidGuardResult;
119129

120130
@SuppressLint("AddJavascriptInterface")
121131
@Override
@@ -346,35 +356,39 @@ private void closeWeb(boolean programmaticAuth) {
346356
}
347357

348358
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+
}
365379
}
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();
378392
}
379393

380394
private void saveAccount(Account account, AuthResponse response) {
@@ -420,43 +434,46 @@ private void returnSuccessResponse(Account account){
420434
private void retrieveGmsToken(final Account account) {
421435
final AuthManager authManager = new AuthManager(this, account.name, GMS_PACKAGE_NAME, "ac2dm");
422436
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;
443474
}
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();
460477
}
461478

462479
private void notifyGcmGroupUpdate(String accountName) {
@@ -501,6 +518,53 @@ private String buildUrl(String tmpl, Locale locale) {
501518
return builder.build().toString();
502519
}
503520

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+
504568
private class JsBridge {
505569

506570
@JavascriptInterface

0 commit comments

Comments
 (0)