Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Unverified Commit b9b7c06c authored by DaVinci9196's avatar DaVinci9196 Committed by GitHub
Browse files

Auth: Handle invalid account (#2865)

parent 02c558c1
Loading
Loading
Loading
Loading
+49 −24
Original line number Diff line number Diff line
@@ -48,6 +48,7 @@ import androidx.webkit.WebViewClientCompat;
import com.google.android.gms.R;

import org.json.JSONArray;
import org.microg.gms.accountaction.AccountNotificationKt;
import org.microg.gms.auth.AuthConstants;
import org.microg.gms.auth.AuthManager;
import org.microg.gms.auth.AuthRequest;
@@ -85,10 +86,12 @@ public class LoginActivity extends AssistantActivity {
    public static final String EXTRA_TMPL = "tmpl";
    public static final String EXTRA_EMAIL = "email";
    public static final String EXTRA_TOKEN = "masterToken";
    public static final String EXTRA_RE_AUTH_ACCOUNT = "re_auth_account";
    public static final int STATUS_BAR_DISABLE_BACK = 0x00400000;

    private static final String TAG = "GmsAuthLoginBrowser";
    private static final String EMBEDDED_SETUP_URL = "https://accounts.google.com/EmbeddedSetup";
    private static final String EMBEDDED_RE_AUTH_URL = "https://accounts.google.com/embedded/reauth/v2/android";
    private static final String PROGRAMMATIC_AUTH_URL = "https://accounts.google.com/o/oauth2/programmatic_auth";
    private static final String GOOGLE_SUITE_URL = "https://accounts.google.com/signin/continue";
    private static final String MAGIC_USER_AGENT = " MinuteMaid";
@@ -106,6 +109,8 @@ public class LoginActivity extends AssistantActivity {
    private InputMethodManager inputMethodManager;
    private ViewGroup authContent;
    private int state = 0;
    private boolean isReAuth = false;
    private Account reAuthAccount;

    @SuppressLint("AddJavascriptInterface")
    @Override
@@ -148,6 +153,10 @@ public class LoginActivity extends AssistantActivity {
                response = (AccountAuthenticatorResponse) tempObject;
            }
        }
        if (getIntent().hasExtra(EXTRA_RE_AUTH_ACCOUNT)) {
            reAuthAccount = getIntent().getParcelableExtra(EXTRA_RE_AUTH_ACCOUNT);
            isReAuth = reAuthAccount != null;
        }
        if (getIntent().hasExtra(EXTRA_TOKEN)) {
            if (getIntent().hasExtra(EXTRA_EMAIL)) {
                AccountManager accountManager = AccountManager.get(this);
@@ -160,7 +169,7 @@ public class LoginActivity extends AssistantActivity {
            } else {
                retrieveRtToken(getIntent().getStringExtra(EXTRA_TOKEN));
            }
        } else if (android.os.Build.VERSION.SDK_INT < 21) {
        } else if (android.os.Build.VERSION.SDK_INT < 21 || isReAuth) {
            init();
        } else {
            setMessage(R.string.auth_before_connect);
@@ -320,6 +329,26 @@ public class LoginActivity extends AssistantActivity {
                    @Override
                    public void onResponse(AuthResponse response) {
                        Account account = new Account(response.email, accountType);
                        if (isReAuth && reAuthAccount != null && reAuthAccount.name.equals(account.name)) {
                            accountManager.removeAccount(account, future -> saveAccount(account, response), null);
                        } else {
                            saveAccount(account, response);
                        }
                    }

                    @Override
                    public void onException(Exception exception) {
                        Log.w(TAG, "onException", exception);
                        runOnUiThread(() -> {
                            showError(R.string.auth_general_error_desc);
                            setNextButtonText(android.R.string.ok);
                        });
                        state = -2;
                    }
                });
    }

    private void saveAccount(Account account, AuthResponse response) {
        if (accountManager.addAccountExplicitly(account, response.token, null)) {
            accountManager.setAuthToken(account, "SID", response.Sid);
            accountManager.setAuthToken(account, "LSID", response.LSid);
@@ -343,18 +372,10 @@ public class LoginActivity extends AssistantActivity {
        }
    }

                    @Override
                    public void onException(Exception exception) {
                        Log.w(TAG, "onException", exception);
                        runOnUiThread(() -> {
                            showError(R.string.auth_general_error_desc);
                            setNextButtonText(android.R.string.ok);
                        });
                        state = -2;
                    }
                });
    }
    private void returnSuccessResponse(Account account){
        if (isReAuth && reAuthAccount != null) {
            AccountNotificationKt.cancelAccountNotificationChannel(this, reAuthAccount);
        }
        if(response != null){
            Bundle bd = new Bundle();
            bd.putString(AccountManager.KEY_ACCOUNT_NAME,account.name);
@@ -426,16 +447,20 @@ public class LoginActivity extends AssistantActivity {
        return super.onKeyDown(keyCode, event);
    }

    private static String buildUrl(String tmpl, Locale locale) {
        return Uri.parse(EMBEDDED_SETUP_URL).buildUpon()
    private String buildUrl(String tmpl, Locale locale) {
        String uriString = isReAuth ? EMBEDDED_RE_AUTH_URL : EMBEDDED_SETUP_URL;
        Uri.Builder builder = Uri.parse(uriString).buildUpon()
                .appendQueryParameter("source", "android")
                .appendQueryParameter("xoauth_display_name", "Android Device")
                .appendQueryParameter("lang", locale.getLanguage())
                .appendQueryParameter("cc", locale.getCountry().toLowerCase(Locale.US))
                .appendQueryParameter("langCountry", locale.toString().toLowerCase(Locale.US))
                .appendQueryParameter("hl", locale.toString().replace("_", "-"))
                .appendQueryParameter("tmpl", tmpl)
                .build().toString();
                .appendQueryParameter("tmpl", tmpl);
        if (isReAuth && reAuthAccount != null) {
            builder.appendQueryParameter("Email", reAuthAccount.name);
        }
        return builder.build().toString();
    }

    private class JsBridge {
+37 −0
Original line number Diff line number Diff line
@@ -10,14 +10,47 @@ import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.os.Build
import android.util.Log
import androidx.annotation.RequiresApi
import androidx.core.app.ActivityCompat
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import com.google.android.gms.R
import org.microg.gms.auth.login.LoginActivity

private const val CHANNEL_ID = "AccountNotification"

@RequiresApi(21)
fun Context.sendAccountReAuthNotification(account: Account) {
    Log.d(TAG, "sendAccountReAuthNotification: account: ${account.name}")

    registerAccountNotificationChannel()

    val intent = Intent(this, LoginActivity::class.java).apply {
        putExtra(LoginActivity.EXTRA_RE_AUTH_ACCOUNT, account)
    }.let {
        PendingIntent.getActivity(
            this, account.hashCode(), it, PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_CANCEL_CURRENT
        )
    }

    val notification: Notification =
        NotificationCompat.Builder(this, CHANNEL_ID)
            .setSmallIcon(R.drawable.ic_manage_accounts)
            .setSound(null)
            .setContentTitle(getString(R.string.auth_action_reauth_notification_title))
            .setContentText(account.name)
            .setOnlyAlertOnce(true)
            .setContentIntent(intent)
            .setAutoCancel(true)
            .build()

    if (ActivityCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS) ==
        PackageManager.PERMISSION_GRANTED
    ) {
        NotificationManagerCompat.from(this).notify(account.hashCode(), notification)
    }
}

@RequiresApi(21)
fun Context.sendAccountActionNotification(account: Account, action: UserSatisfyRequirements) {
@@ -68,3 +101,7 @@ fun Context.registerAccountNotificationChannel() {
            .createNotificationChannel(channel)
    }
}

fun Context.cancelAccountNotificationChannel(account: Account) {
    NotificationManagerCompat.from(this).cancel(account.hashCode())
}
 No newline at end of file
+17 −3
Original line number Diff line number Diff line
@@ -2,9 +2,11 @@ package org.microg.gms.accountaction

import android.accounts.Account
import android.content.Context
import android.os.Build
import android.content.Intent
import android.os.Build.VERSION.SDK_INT
import android.util.Log
import kotlinx.coroutines.runBlocking
import org.microg.gms.auth.login.LoginActivity
import org.microg.gms.common.Constants
import org.microg.gms.cryptauth.isLockscreenConfigured
import org.microg.gms.cryptauth.sendDeviceScreenlockState
@@ -39,6 +41,8 @@ const val DEVICE_MANAGEMENT_ADMIN_PENDING_APPROVAL = "DeviceManagementAdminPendi
 */
const val BAD_AUTHENTICATION = "BadAuthentication"

const val SERVER_ERROR = "Error 500"

const val TAG = "GmsAccountErrorResolve"

/**
@@ -47,6 +51,8 @@ const val TAG = "GmsAccountErrorResolve"
 */
fun Context.resolveAuthErrorMessage(s: String): Resolution? = if (s.startsWith("Error=")) {
    resolveAuthErrorMessage(s.drop("Error=".length))
} else if (s.contains(SERVER_ERROR)) {
    Reauthenticate
} else when (s) {
    DEVICE_MANAGEMENT_SCREENLOCK_REQUIRED -> listOf(
        Requirement.ENABLE_CHECKIN,
@@ -123,13 +129,16 @@ fun <T> Resolution.initiateFromBackgroundBlocking(context: Context, account: Acc
        }
        is UserSatisfyRequirements -> {
            Log.w(TAG, "User intervention required! You need to ${actions.joinToString(", ")}.")
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            if (SDK_INT >= 21) {
                context.sendAccountActionNotification(account, this)
            }
            return null
        }
        Reauthenticate -> {
            Log.w(TAG, "Your account credentials have expired! Please remove the account, then sign in again.")
            if (SDK_INT >= 21) {
                context.sendAccountReAuthNotification(account)
            }
            return null
        }
    }
@@ -150,7 +159,7 @@ fun <T> Resolution.initiateFromForegroundBlocking(context: Context, account: Acc
        }
        is UserSatisfyRequirements -> {
            Log.w(TAG, "User intervention required! You need to ${actions.joinToString(", ")}.")
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            if (SDK_INT >= 21) {
                AccountActionActivity.createIntent(context, account, this).let {
                    context.startActivity(it)
                }
@@ -159,6 +168,11 @@ fun <T> Resolution.initiateFromForegroundBlocking(context: Context, account: Acc
        }
        Reauthenticate -> {
            Log.w(TAG, "Your account credentials have expired! Please remove the account, then sign in again.")
            Intent(context, LoginActivity::class.java).apply {
                putExtra(LoginActivity.EXTRA_RE_AUTH_ACCOUNT, account)
            }.let {
                context.startActivity(it)
            }
            return null
        }
    }
+1 −0
Original line number Diff line number Diff line
@@ -281,6 +281,7 @@ microG GmsCore 内置一套自由的 SafetyNet 实现,但是官方服务器要
    <string name="auth_action_notification_content">你的 Google 账户需要额外设置。</string>
    <string name="auth_action_activity_explanation">要能在这台设备上使用你的 Google 账户 %s 请完成下列步骤。</string>
    <string name="auth_action_step_enable_lockscreen_description">你的 Google 账户受工作场所或教育机构管理。你的管理员决定设备在可以访问账户数据前需要设置安全屏幕锁。\n\n请设置一个密码、PIN或手势屏幕锁。</string>
    <string name="auth_action_reauth_notification_title">需要执行账号相关操作</string>
    <string name="barcode_scanner_brand">由 microG 代表“%1$s”扫描</string>
    <string name="camera_permission_dialog_button">确定</string>
    <string name="camera_permission_dialog_message">microG 服务需要访问设备的摄像头,才能为%1$s扫描二维码。\n\n若要启用该权限,请在“设置”中向 microG 服务授予相机权限。</string>
+1 −0
Original line number Diff line number Diff line
@@ -43,6 +43,7 @@ This can take a couple of minutes."</string>
    <string name="auth_action_notification_title">Account action required</string>
    <string name="auth_action_notification_content">Your Google account needs additional setup.</string>

    <string name="auth_action_reauth_notification_title">Account action required</string>
    <string name="auth_action_activity_header">Finish setting up your Google account</string>
    <string name="auth_action_activity_explanation">Complete the following steps to be able to use your Google account %s on this device.</string>
    <string name="auth_action_step_enable_checkin">Enable device registration</string>