Skip to content

Commit fb87e81

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 ccb26ad commit fb87e81

File tree

1 file changed

+136
-70
lines changed

1 file changed

+136
-70
lines changed

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

Lines changed: 136 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,13 @@
4040
import android.widget.RelativeLayout;
4141
import android.widget.TextView;
4242

43+
import androidx.annotation.Nullable;
4344
import androidx.annotation.StringRes;
4445
import androidx.webkit.WebViewClientCompat;
4546

4647
import com.google.android.gms.R;
48+
import com.google.android.gms.droidguard.DroidGuardClient;
49+
import com.google.android.gms.tasks.Tasks;
4750

4851
import org.json.JSONArray;
4952
import org.microg.gms.auth.AuthConstants;
@@ -54,13 +57,18 @@
5457
import org.microg.gms.checkin.LastCheckinInfo;
5558
import org.microg.gms.common.HttpFormClient;
5659
import org.microg.gms.common.Utils;
60+
import org.microg.gms.droidguard.core.DroidGuardPreferences;
5761
import org.microg.gms.people.PeopleManager;
5862
import org.microg.gms.profile.Build;
5963
import org.microg.gms.profile.ProfileManager;
6064

6165
import java.io.IOException;
6266
import java.security.MessageDigest;
67+
import java.util.HashMap;
6368
import java.util.Locale;
69+
import java.util.Map;
70+
import java.util.Random;
71+
import java.util.concurrent.TimeUnit;
6472

6573
import static android.accounts.AccountManager.PACKAGE_NAME_KEY_LEGACY_NOT_VISIBLE;
6674
import static android.accounts.AccountManager.VISIBILITY_USER_MANAGED_VISIBLE;
@@ -100,6 +108,9 @@ public class LoginActivity extends AssistantActivity {
100108
private InputMethodManager inputMethodManager;
101109
private ViewGroup authContent;
102110
private int state = 0;
111+
private volatile boolean authDroidGuardResultLoaded = false;
112+
@Nullable
113+
private volatile String authDroidGuardResult;
103114

104115
@SuppressLint("AddJavascriptInterface")
105116
@Override
@@ -282,87 +293,95 @@ private void closeWeb(boolean programmaticAuth) {
282293
}
283294

284295
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);
312337
runOnUiThread(() -> {
313338
showError(R.string.auth_general_error_desc);
314339
setNextButtonText(android.R.string.ok);
315340
});
316341
state = -2;
317342
}
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();
330345
}
331346

332347
private void retrieveGmsToken(final Account account) {
333348
final AuthManager authManager = new AuthManager(this, account.name, GMS_PACKAGE_NAME, "ac2dm");
334349
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();
366385
}
367386

368387
private boolean checkin(boolean force) {
@@ -396,6 +415,53 @@ private static String buildUrl(String tmpl, Locale locale) {
396415
.build().toString();
397416
}
398417

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+
399465
private class JsBridge {
400466

401467
@JavascriptInterface

0 commit comments

Comments
 (0)