From 906f39079dcd567b2d26df594b1967a10acb4a06 Mon Sep 17 00:00:00 2001 From: Davinci9196 Date: Mon, 17 Nov 2025 15:59:43 +0800 Subject: [PATCH 1/3] Auth: Fixed some login failure issues --- build.gradle | 1 + play-services-core/build.gradle | 2 + .../src/main/AndroidManifest.xml | 3 +- .../microg/gms/gcm/UnregisterReceiver.java | 50 -------------- .../identity/AuthorizationService.kt | 16 ++--- .../gms/auth/signin/AuthSignInService.kt | 13 ++-- .../auth/signin/SignInConfigurationService.kt | 36 +++++----- .../org/microg/gms/auth/signin/extensions.kt | 2 +- .../gms/common/PackageIntentOpWorker.kt | 68 +++++++++++++++++++ .../gms/common/PersistentTrustedReceiver.kt | 44 ++++++++++++ 10 files changed, 151 insertions(+), 84 deletions(-) delete mode 100644 play-services-core/src/main/java/org/microg/gms/gcm/UnregisterReceiver.java create mode 100644 play-services-core/src/main/kotlin/org/microg/gms/common/PackageIntentOpWorker.kt create mode 100644 play-services-core/src/main/kotlin/org/microg/gms/common/PersistentTrustedReceiver.kt diff --git a/build.gradle b/build.gradle index ae1cd09be2..c05a2b956f 100644 --- a/build.gradle +++ b/build.gradle @@ -24,6 +24,7 @@ buildscript { ext.preferenceVersion = '1.2.0' ext.recyclerviewVersion = '1.3.2' ext.webkitVersion = '1.10.0' + ext.workVersion = '2.7.0' ext.slf4jVersion = '1.7.36' ext.volleyVersion = '1.2.1' diff --git a/play-services-core/build.gradle b/play-services-core/build.gradle index 5648333872..8fc2896bbc 100644 --- a/play-services-core/build.gradle +++ b/play-services-core/build.gradle @@ -102,6 +102,8 @@ dependencies { implementation "androidx.lifecycle:lifecycle-service:$lifecycleVersion" implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlinVersion" + + implementation "androidx.work:work-runtime-ktx:$workVersion" } android { diff --git a/play-services-core/src/main/AndroidManifest.xml b/play-services-core/src/main/AndroidManifest.xml index 6f593efdf8..3ad889f6c8 100644 --- a/play-services-core/src/main/AndroidManifest.xml +++ b/play-services-core/src/main/AndroidManifest.xml @@ -412,8 +412,7 @@ + android:name="org.microg.gms.common.PersistentTrustedReceiver"> diff --git a/play-services-core/src/main/java/org/microg/gms/gcm/UnregisterReceiver.java b/play-services-core/src/main/java/org/microg/gms/gcm/UnregisterReceiver.java deleted file mode 100644 index bba2e414c4..0000000000 --- a/play-services-core/src/main/java/org/microg/gms/gcm/UnregisterReceiver.java +++ /dev/null @@ -1,50 +0,0 @@ -package org.microg.gms.gcm; - -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.util.Log; - -import java.util.List; - -import static android.content.Intent.ACTION_PACKAGE_REMOVED; -import static android.content.Intent.ACTION_PACKAGE_DATA_CLEARED; -import static android.content.Intent.ACTION_PACKAGE_FULLY_REMOVED; -import static android.content.Intent.EXTRA_DATA_REMOVED; -import static android.content.Intent.EXTRA_REPLACING; - -public class UnregisterReceiver extends BroadcastReceiver { - private static final String TAG = "GmsGcmUnregisterRcvr"; - - @Override - public void onReceive(final Context context, Intent intent) { - Log.d(TAG, "Package changed: " + intent); - if ((ACTION_PACKAGE_REMOVED.contains(intent.getAction()) && intent.getBooleanExtra(EXTRA_DATA_REMOVED, false) && - !intent.getBooleanExtra(EXTRA_REPLACING, false)) || - ACTION_PACKAGE_FULLY_REMOVED.contains(intent.getAction()) || - ACTION_PACKAGE_DATA_CLEARED.contains(intent.getAction())) { - final GcmDatabase database = new GcmDatabase(context); - final String packageName = intent.getData().getSchemeSpecificPart(); - Log.d(TAG, "Package removed or data cleared: " + packageName); - final GcmDatabase.App app = database.getApp(packageName); - if (app != null) { - new Thread(new Runnable() { - @Override - public void run() { - List registrations = database.getRegistrationsByApp(packageName); - boolean deletedAll = true; - for (GcmDatabase.Registration registration : registrations) { - deletedAll &= PushRegisterManager.unregister(context, registration.packageName, registration.signature, null, null).deleted != null; - } - if (deletedAll) { - database.removeApp(packageName); - } - database.close(); - } - }).start(); - } else { - database.close(); - } - } - } -} diff --git a/play-services-core/src/main/kotlin/org/microg/gms/auth/credentials/identity/AuthorizationService.kt b/play-services-core/src/main/kotlin/org/microg/gms/auth/credentials/identity/AuthorizationService.kt index 61e6618b8a..39121d7018 100644 --- a/play-services-core/src/main/kotlin/org/microg/gms/auth/credentials/identity/AuthorizationService.kt +++ b/play-services-core/src/main/kotlin/org/microg/gms/auth/credentials/identity/AuthorizationService.kt @@ -41,6 +41,7 @@ import org.microg.gms.auth.signin.scopeUris import org.microg.gms.common.Constants import org.microg.gms.common.GmsService import org.microg.gms.common.PackageUtils +import java.util.concurrent.atomic.AtomicInteger private const val TAG = "AuthorizationService" @@ -60,17 +61,16 @@ class AuthorizationService : BaseService(TAG, GmsService.AUTHORIZATION) { class AuthorizationServiceImpl(val context: Context, val packageName: String, override val lifecycle: Lifecycle) : IAuthorizationService.Stub(), LifecycleOwner { + companion object{ + private val nextRequestCode = AtomicInteger(0) + } + override fun authorize(callback: IAuthorizationCallback?, request: AuthorizationRequest?) { Log.d(TAG, "Method: authorize called, request:$request") lifecycleScope.launchWhenStarted { val account = request?.account ?: SignInConfigurationService.getDefaultAccount(context, packageName) - if (account == null) { - Log.d(TAG, "Method: authorize called, but account is null") - callback?.onAuthorized(Status.CANCELED, null) - return@launchWhenStarted - } val googleSignInOptions = GoogleSignInOptions.Builder().apply { - setAccountName(account.name) + account?.name?.let { setAccountName(it) } request?.requestedScopes?.forEach { requestScopes(it) } if (request?.idTokenRequested == true && request.serverClientId != null) requestIdToken(request.serverClientId) if (request?.serverAuthCodeRequested == true && request.serverClientId != null) requestServerAuthCode(request.serverClientId, request.forceCodeForRefreshToken) @@ -79,7 +79,7 @@ class AuthorizationServiceImpl(val context: Context, val packageName: String, ov `package` = Constants.GMS_PACKAGE_NAME putExtra("config", SignInConfiguration(packageName, googleSignInOptions)) } - val signInAccount = performSignIn(context, packageName, googleSignInOptions, account, false) + val signInAccount = account?.let { performSignIn(context, packageName, googleSignInOptions, account, false) } callback?.onAuthorized(Status.SUCCESS, AuthorizationResult( signInAccount?.serverAuthCode, @@ -87,7 +87,7 @@ class AuthorizationServiceImpl(val context: Context, val packageName: String, ov signInAccount?.idToken, signInAccount?.grantedScopes?.toList().orEmpty().map { it.scopeUri }, signInAccount, - PendingIntent.getActivity(context, account.hashCode(), intent, FLAG_UPDATE_CURRENT or FLAG_IMMUTABLE) + PendingIntent.getActivity(context, nextRequestCode.incrementAndGet(), intent, FLAG_UPDATE_CURRENT or FLAG_IMMUTABLE) ).also { Log.d(TAG, "authorize: result:$it") }) } } diff --git a/play-services-core/src/main/kotlin/org/microg/gms/auth/signin/AuthSignInService.kt b/play-services-core/src/main/kotlin/org/microg/gms/auth/signin/AuthSignInService.kt index c6e624c3b7..1f71749141 100644 --- a/play-services-core/src/main/kotlin/org/microg/gms/auth/signin/AuthSignInService.kt +++ b/play-services-core/src/main/kotlin/org/microg/gms/auth/signin/AuthSignInService.kt @@ -16,7 +16,6 @@ package org.microg.gms.auth.signin import android.accounts.Account -import android.accounts.AccountManager import android.content.Context import android.os.Bundle import android.os.Parcel @@ -39,7 +38,6 @@ import com.google.android.gms.common.internal.ConnectionInfo import com.google.android.gms.common.internal.GetServiceRequest import com.google.android.gms.common.internal.IGmsCallbacks import org.microg.gms.BaseService -import org.microg.gms.auth.AuthConstants import org.microg.gms.auth.AuthPrefs import org.microg.gms.common.GmsService import org.microg.gms.common.PackageUtils @@ -122,14 +120,15 @@ class AuthSignInServiceImpl( try { val account = account ?: options?.account ?: SignInConfigurationService.getDefaultAccount(context, packageName) if (account != null) { - val defaultOptions = SignInConfigurationService.getDefaultOptions(context, packageName) - Log.d(TAG, "$packageName:signOut defaultOptions:($defaultOptions)") - performSignOut(context, packageName, defaultOptions ?: options, account) + SignInConfigurationService.getAuthOptions(context, packageName)?.forEach { + Log.d(TAG, "$packageName:signOut authOption:($it)") + performSignOut(context, packageName, it, account) + } } if (options?.scopes?.any { it.scopeUri.contains(Scopes.GAMES) } == true) { GamesConfigurationService.setDefaultAccount(context, packageName, null) } - SignInConfigurationService.setDefaultSignInInfo(context, packageName, null, null) + SignInConfigurationService.setAuthInfo(context, packageName, null, null) runCatching { callbacks.onSignOut(Status.SUCCESS) } } catch (e: Exception) { Log.w(TAG, e) @@ -162,7 +161,7 @@ class AuthSignInServiceImpl( authManager.invalidateAuthToken(token) authManager.isPermitted = false } - SignInConfigurationService.setDefaultSignInInfo(context, packageName, account, options?.toJson()) + SignInConfigurationService.setAuthInfo(context, packageName, account, options?.toJson()) runCatching { callbacks.onRevokeAccess(Status.SUCCESS) } } catch (e: Exception) { Log.w(TAG, e) diff --git a/play-services-core/src/main/kotlin/org/microg/gms/auth/signin/SignInConfigurationService.kt b/play-services-core/src/main/kotlin/org/microg/gms/auth/signin/SignInConfigurationService.kt index 5cc24f7994..5a10836a08 100644 --- a/play-services-core/src/main/kotlin/org/microg/gms/auth/signin/SignInConfigurationService.kt +++ b/play-services-core/src/main/kotlin/org/microg/gms/auth/signin/SignInConfigurationService.kt @@ -54,7 +54,7 @@ class SignInConfigurationService : Service() { val packageName = msg.data?.getString(MSG_DATA_PACKAGE_NAME) val account = msg.data?.getParcelable(MSG_DATA_ACCOUNT) val googleSignInOptions = msg.data?.getString(MSG_DATA_SIGN_IN_OPTIONS) - packageName?.let { setDefaultSignInInfo(it, account, googleSignInOptions) } + packageName?.let { setAuthInfo(it, account, googleSignInOptions) } bundleOf( MSG_DATA_PACKAGE_NAME to packageName, MSG_DATA_ACCOUNT to account, @@ -64,10 +64,10 @@ class SignInConfigurationService : Service() { MSG_GET_DEFAULT_OPTIONS -> { val packageName = msg.data?.getString(MSG_DATA_PACKAGE_NAME) - val googleSignInOptions = packageName?.let { getDefaultOptions(it) } + val googleSignInOptions = packageName?.let { getAuthOptions(it) } bundleOf( MSG_DATA_PACKAGE_NAME to packageName, - MSG_DATA_SIGN_IN_OPTIONS to googleSignInOptions + MSG_DATA_SIGN_IN_OPTIONS to googleSignInOptions?.toTypedArray() ) } @@ -95,23 +95,27 @@ class SignInConfigurationService : Service() { return null } - private fun getDefaultOptions(packageName: String): String? { - val data = preferences.getString(DEFAULT_SIGN_IN_OPTIONS_PREFIX + getPackageNameSuffix(packageName), null) - if (data.isNullOrBlank()) return null + private fun getAuthOptions(packageName: String): Set? { + val data = preferences.getStringSet(DEFAULT_SIGN_IN_OPTIONS_PREFIX + getPackageNameSuffix(packageName), null) + if (data.isNullOrEmpty()) return null return data } - private fun setDefaultSignInInfo(packageName: String, account: Account?, optionsJson: String?) { + private fun setAuthInfo(packageName: String, account: Account?, optionsJson: String?) { val editor: SharedPreferences.Editor = preferences.edit() + val accountPrefix = DEFAULT_ACCOUNT_PREFIX + getPackageNameSuffix(packageName) + val optionsPrefix = DEFAULT_SIGN_IN_OPTIONS_PREFIX + getPackageNameSuffix(packageName) if (account == null || account.name == AuthConstants.DEFAULT_ACCOUNT) { - editor.remove(DEFAULT_ACCOUNT_PREFIX + getPackageNameSuffix(packageName)) + editor.remove(accountPrefix) + editor.remove(optionsPrefix) } else { - editor.putString(DEFAULT_ACCOUNT_PREFIX + getPackageNameSuffix(packageName), account.name) + editor.putString(accountPrefix, account.name) } - if (optionsJson == null) { - editor.remove(DEFAULT_SIGN_IN_OPTIONS_PREFIX + getPackageNameSuffix(packageName)) - } else { - editor.putString(DEFAULT_SIGN_IN_OPTIONS_PREFIX + getPackageNameSuffix(packageName), optionsJson) + if (optionsJson != null) { + val savedOptions = preferences.getStringSet(optionsPrefix, emptySet()) ?: emptySet() + val newSet = HashSet(savedOptions) + newSet.add(optionsJson) + editor.putStringSet(optionsPrefix, newSet) } editor.apply() } @@ -156,16 +160,16 @@ class SignInConfigurationService : Service() { }).data?.getParcelable(MSG_DATA_ACCOUNT) } - suspend fun getDefaultOptions(context: Context, packageName: String): GoogleSignInOptions? { + suspend fun getAuthOptions(context: Context, packageName: String): List? { return singleRequest(context, Message.obtain().apply { what = MSG_GET_DEFAULT_OPTIONS data = bundleOf( MSG_DATA_PACKAGE_NAME to packageName ) - }).data?.getString(MSG_DATA_SIGN_IN_OPTIONS)?.let { GoogleSignInOptions.fromJson(it) } + }).data?.getStringArray(MSG_DATA_SIGN_IN_OPTIONS)?.map { GoogleSignInOptions.fromJson(it) } } - suspend fun setDefaultSignInInfo(context: Context, packageName: String, account: Account?, optionsJson: String?) { + suspend fun setAuthInfo(context: Context, packageName: String, account: Account?, optionsJson: String?) { singleRequest(context, Message.obtain().apply { what = MSG_SET_DEFAULT_SIGN_IN_INFO data = bundleOf( diff --git a/play-services-core/src/main/kotlin/org/microg/gms/auth/signin/extensions.kt b/play-services-core/src/main/kotlin/org/microg/gms/auth/signin/extensions.kt index a3a2ae23a0..de90a9a230 100644 --- a/play-services-core/src/main/kotlin/org/microg/gms/auth/signin/extensions.kt +++ b/play-services-core/src/main/kotlin/org/microg/gms/auth/signin/extensions.kt @@ -169,7 +169,7 @@ suspend fun performSignIn(context: Context, packageName: String, options: Google if (options?.includeGame == true) { GamesConfigurationService.setDefaultAccount(context, packageName, account) } - SignInConfigurationService.setDefaultSignInInfo(context, packageName, account, options?.toJson()) + SignInConfigurationService.setAuthInfo(context, packageName, account, options?.toJson()) return GoogleSignInAccount( id, tokenId, diff --git a/play-services-core/src/main/kotlin/org/microg/gms/common/PackageIntentOpWorker.kt b/play-services-core/src/main/kotlin/org/microg/gms/common/PackageIntentOpWorker.kt new file mode 100644 index 0000000000..5dfb22cb29 --- /dev/null +++ b/play-services-core/src/main/kotlin/org/microg/gms/common/PackageIntentOpWorker.kt @@ -0,0 +1,68 @@ +/** + * SPDX-FileCopyrightText: 2025 microG Project Team + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.microg.gms.common + +import android.content.Context +import android.util.Log +import androidx.work.CoroutineWorker +import androidx.work.WorkerParameters +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext +import org.microg.gms.auth.signin.SignInConfigurationService +import org.microg.gms.auth.signin.performSignOut +import org.microg.gms.gcm.GcmDatabase +import org.microg.gms.gcm.PushRegisterManager + +class PackageIntentOpWorker( + val appContext: Context, + params: WorkerParameters +) : CoroutineWorker(appContext, params) { + + companion object { + private const val TAG = "PackageIntentOpWorker" + const val PACKAGE_NAME = "packageName" + } + + override suspend fun doWork(): Result { + val packageName = inputData.getString(PACKAGE_NAME) ?: return Result.failure() + Log.d(TAG, "doWork: $packageName clearing.") + + clearGcmData(packageName) + clearAuthInfo(packageName) + + Log.d(TAG, "doWork: $packageName cleared.") + return Result.success() + } + + private suspend fun clearGcmData(packageName: String) = withContext(Dispatchers.IO) { + val database = GcmDatabase(appContext) + val app = database.getApp(packageName) + if (app != null) { + val registrations = database.getRegistrationsByApp(packageName) + var deletedAll = true + for (registration in registrations) { + deletedAll = deletedAll and (PushRegisterManager.unregister(appContext, registration.packageName, registration.signature, null, null).deleted != null) + } + if (deletedAll) { + database.removeApp(packageName) + } + database.close() + } else { + database.close() + } + } + + private suspend fun clearAuthInfo(packageName: String) = withContext(Dispatchers.IO) { + val authOptions = SignInConfigurationService.getAuthOptions(appContext, packageName) + val authAccount = SignInConfigurationService.getDefaultAccount(appContext, packageName) + if (!authOptions.isNullOrEmpty() && authAccount != null) { + authOptions.forEach { + Log.d(TAG, "$packageName:clear authAccount: ${authAccount.name} authOption:($it)") + performSignOut(appContext, packageName, it, authAccount) + } + } + } +} \ No newline at end of file diff --git a/play-services-core/src/main/kotlin/org/microg/gms/common/PersistentTrustedReceiver.kt b/play-services-core/src/main/kotlin/org/microg/gms/common/PersistentTrustedReceiver.kt new file mode 100644 index 0000000000..62631912ba --- /dev/null +++ b/play-services-core/src/main/kotlin/org/microg/gms/common/PersistentTrustedReceiver.kt @@ -0,0 +1,44 @@ +/** + * SPDX-FileCopyrightText: 2025 microG Project Team + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.microg.gms.common + +import android.content.BroadcastReceiver +import android.content.Context +import android.content.Intent +import android.util.Log +import androidx.work.Data +import androidx.work.OneTimeWorkRequestBuilder +import androidx.work.WorkManager + +class PersistentTrustedReceiver : BroadcastReceiver() { + + companion object { + private const val TAG = "TrustedReceiver" + } + + override fun onReceive(context: Context, intent: Intent?) { + Log.d(TAG, "Package changed: $intent") + val action = intent?.action ?: return + val pkg = intent.data?.schemeSpecificPart ?: return + + if ((Intent.ACTION_PACKAGE_REMOVED.contains(action) + && intent.getBooleanExtra(Intent.EXTRA_DATA_REMOVED, false) + && !intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) + || Intent.ACTION_PACKAGE_FULLY_REMOVED.contains(action) + || Intent.ACTION_PACKAGE_DATA_CLEARED.contains(action) + ) { + Log.d(TAG, "Package removed or data cleared: $pkg") + val data = Data.Builder() + .putString(PackageIntentOpWorker.PACKAGE_NAME, pkg) + .build() + val request = OneTimeWorkRequestBuilder() + .setInputData(data) + .build() + WorkManager.getInstance(context).enqueue(request) + } + } + +} \ No newline at end of file From ad6a46fd4a06c0134d9091af976680bb26ee5afa Mon Sep 17 00:00:00 2001 From: Davinci9196 Date: Mon, 17 Nov 2025 17:11:59 +0800 Subject: [PATCH 2/3] Handling signOut --- .../identity/IdentitySignInService.kt | 24 ++++++++++++------- .../gms/auth/signin/AuthSignInService.kt | 2 +- .../auth/signin/SignInConfigurationService.kt | 4 ++-- .../gms/common/PackageIntentOpWorker.kt | 2 +- 4 files changed, 19 insertions(+), 13 deletions(-) diff --git a/play-services-core/src/main/kotlin/org/microg/gms/auth/credentials/identity/IdentitySignInService.kt b/play-services-core/src/main/kotlin/org/microg/gms/auth/credentials/identity/IdentitySignInService.kt index 41d46066d7..e112eb7de3 100644 --- a/play-services-core/src/main/kotlin/org/microg/gms/auth/credentials/identity/IdentitySignInService.kt +++ b/play-services-core/src/main/kotlin/org/microg/gms/auth/credentials/identity/IdentitySignInService.kt @@ -5,7 +5,6 @@ package org.microg.gms.auth.credentials.identity -import android.accounts.AccountManager import android.app.PendingIntent import android.content.Context import android.content.Intent @@ -14,6 +13,9 @@ import android.util.Base64 import android.util.Log import androidx.core.app.PendingIntentCompat import androidx.core.os.bundleOf +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.LifecycleOwner +import androidx.lifecycle.lifecycleScope import com.google.android.gms.auth.api.identity.BeginSignInRequest import com.google.android.gms.auth.api.identity.BeginSignInResult import com.google.android.gms.auth.api.identity.GetPhoneNumberHintIntentRequest @@ -34,16 +36,17 @@ import com.google.android.gms.fido.common.Transport import com.google.android.gms.fido.fido2.api.common.PublicKeyCredentialDescriptor import com.google.android.gms.fido.fido2.api.common.PublicKeyCredentialRequestOptions import com.google.android.gms.fido.fido2.api.common.UserVerificationRequirement +import kotlinx.coroutines.launch import org.json.JSONArray import org.json.JSONObject import org.microg.gms.BaseService -import org.microg.gms.auth.AuthConstants import org.microg.gms.auth.signin.ACTION_ASSISTED_SIGN_IN import org.microg.gms.auth.signin.BEGIN_SIGN_IN_REQUEST import org.microg.gms.auth.signin.GET_SIGN_IN_INTENT_REQUEST import org.microg.gms.auth.credentials.FEATURES import org.microg.gms.auth.signin.CLIENT_PACKAGE_NAME import org.microg.gms.auth.signin.GOOGLE_SIGN_IN_OPTIONS +import org.microg.gms.auth.signin.SignInConfigurationService import org.microg.gms.auth.signin.performSignOut import org.microg.gms.common.GmsService import org.microg.gms.fido.core.Database @@ -61,13 +64,13 @@ class IdentitySignInService : BaseService(TAG, GmsService.IDENTITY_SIGN_IN) { val connectionInfo = ConnectionInfo() connectionInfo.features = FEATURES callback.onPostInitCompleteWithConnectionInfo( - ConnectionResult.SUCCESS, IdentitySignInServiceImpl(this, request.packageName).asBinder(), connectionInfo + ConnectionResult.SUCCESS, IdentitySignInServiceImpl(this, request.packageName, lifecycle).asBinder(), connectionInfo ) } } -class IdentitySignInServiceImpl(private val context: Context, private val clientPackageName: String) : - ISignInService.Stub() { +class IdentitySignInServiceImpl(private val context: Context, private val clientPackageName: String, override val lifecycle: Lifecycle) : + ISignInService.Stub(), LifecycleOwner { private val requestMap = mutableMapOf() @@ -130,10 +133,13 @@ class IdentitySignInServiceImpl(private val context: Context, private val client override fun signOut(callback: IStatusCallback, requestTag: String) { Log.d(TAG, "method signOut called, requestTag=$requestTag") - if (requestMap.containsKey(requestTag)) { - val accounts = AccountManager.get(context).getAccountsByType(AuthConstants.DEFAULT_ACCOUNT_TYPE) - if (accounts.isNotEmpty()) { - accounts.forEach { performSignOut(context, clientPackageName, requestMap[requestTag], it) } + lifecycleScope.launch { + val signInAccount = SignInConfigurationService.getDefaultAccount(context, clientPackageName) + val authOptions = SignInConfigurationService.getAuthOptions(context, clientPackageName).plus(requestMap[requestTag]) + if (signInAccount != null && authOptions.isNotEmpty()) { + authOptions.forEach { + performSignOut(context, clientPackageName, it, signInAccount) + } } } callback.onResult(Status.SUCCESS) diff --git a/play-services-core/src/main/kotlin/org/microg/gms/auth/signin/AuthSignInService.kt b/play-services-core/src/main/kotlin/org/microg/gms/auth/signin/AuthSignInService.kt index 1f71749141..9c28971444 100644 --- a/play-services-core/src/main/kotlin/org/microg/gms/auth/signin/AuthSignInService.kt +++ b/play-services-core/src/main/kotlin/org/microg/gms/auth/signin/AuthSignInService.kt @@ -120,7 +120,7 @@ class AuthSignInServiceImpl( try { val account = account ?: options?.account ?: SignInConfigurationService.getDefaultAccount(context, packageName) if (account != null) { - SignInConfigurationService.getAuthOptions(context, packageName)?.forEach { + SignInConfigurationService.getAuthOptions(context, packageName).forEach { Log.d(TAG, "$packageName:signOut authOption:($it)") performSignOut(context, packageName, it, account) } diff --git a/play-services-core/src/main/kotlin/org/microg/gms/auth/signin/SignInConfigurationService.kt b/play-services-core/src/main/kotlin/org/microg/gms/auth/signin/SignInConfigurationService.kt index 5a10836a08..7bafef129a 100644 --- a/play-services-core/src/main/kotlin/org/microg/gms/auth/signin/SignInConfigurationService.kt +++ b/play-services-core/src/main/kotlin/org/microg/gms/auth/signin/SignInConfigurationService.kt @@ -160,13 +160,13 @@ class SignInConfigurationService : Service() { }).data?.getParcelable(MSG_DATA_ACCOUNT) } - suspend fun getAuthOptions(context: Context, packageName: String): List? { + suspend fun getAuthOptions(context: Context, packageName: String): Set { return singleRequest(context, Message.obtain().apply { what = MSG_GET_DEFAULT_OPTIONS data = bundleOf( MSG_DATA_PACKAGE_NAME to packageName ) - }).data?.getStringArray(MSG_DATA_SIGN_IN_OPTIONS)?.map { GoogleSignInOptions.fromJson(it) } + }).data?.getStringArray(MSG_DATA_SIGN_IN_OPTIONS)?.map { GoogleSignInOptions.fromJson(it) }?.toSet() ?: emptySet() } suspend fun setAuthInfo(context: Context, packageName: String, account: Account?, optionsJson: String?) { diff --git a/play-services-core/src/main/kotlin/org/microg/gms/common/PackageIntentOpWorker.kt b/play-services-core/src/main/kotlin/org/microg/gms/common/PackageIntentOpWorker.kt index 5dfb22cb29..221acca607 100644 --- a/play-services-core/src/main/kotlin/org/microg/gms/common/PackageIntentOpWorker.kt +++ b/play-services-core/src/main/kotlin/org/microg/gms/common/PackageIntentOpWorker.kt @@ -58,7 +58,7 @@ class PackageIntentOpWorker( private suspend fun clearAuthInfo(packageName: String) = withContext(Dispatchers.IO) { val authOptions = SignInConfigurationService.getAuthOptions(appContext, packageName) val authAccount = SignInConfigurationService.getDefaultAccount(appContext, packageName) - if (!authOptions.isNullOrEmpty() && authAccount != null) { + if (authOptions.isNotEmpty() && authAccount != null) { authOptions.forEach { Log.d(TAG, "$packageName:clear authAccount: ${authAccount.name} authOption:($it)") performSignOut(appContext, packageName, it, authAccount) From d6a63eba1f7049a424f2564ea8654071283f7002 Mon Sep 17 00:00:00 2001 From: Davinci9196 Date: Fri, 5 Dec 2025 11:08:56 +0800 Subject: [PATCH 3/3] Add missing methods to AuthorizationService and improve the login scenario. --- .../auth/api/identity/ClearTokenRequest.aidl | 8 ++ .../api/identity/RevokeAccessRequest.aidl | 8 ++ .../internal/IAuthorizationService.aidl | 5 ++ .../api/identity/RevokeAccessRequest.java | 9 ++ .../org/microg/gms/common/AccountUtils.kt | 50 +++++++++++ .../identity/AuthorizationService.kt | 86 ++++++++++++++++--- .../identity/IdentitySignInService.kt | 2 + .../gms/auth/signin/AssistedSignInFragment.kt | 38 +++++--- .../gms/auth/signin/AuthSignInActivity.kt | 2 +- .../gms/auth/signin/AuthSignInService.kt | 4 +- .../org/microg/gms/auth/signin/extensions.kt | 9 +- .../gms/common/PackageIntentOpWorker.kt | 2 + 12 files changed, 191 insertions(+), 32 deletions(-) create mode 100644 play-services-auth/src/main/aidl/com/google/android/gms/auth/api/identity/ClearTokenRequest.aidl create mode 100644 play-services-auth/src/main/aidl/com/google/android/gms/auth/api/identity/RevokeAccessRequest.aidl create mode 100644 play-services-base/core/src/main/kotlin/org/microg/gms/common/AccountUtils.kt diff --git a/play-services-auth/src/main/aidl/com/google/android/gms/auth/api/identity/ClearTokenRequest.aidl b/play-services-auth/src/main/aidl/com/google/android/gms/auth/api/identity/ClearTokenRequest.aidl new file mode 100644 index 0000000000..a2b736fb20 --- /dev/null +++ b/play-services-auth/src/main/aidl/com/google/android/gms/auth/api/identity/ClearTokenRequest.aidl @@ -0,0 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2025 microG Project Team + * SPDX-License-Identifier: Apache-2.0 + */ + +package com.google.android.gms.auth.api.identity; + +parcelable ClearTokenRequest; \ No newline at end of file diff --git a/play-services-auth/src/main/aidl/com/google/android/gms/auth/api/identity/RevokeAccessRequest.aidl b/play-services-auth/src/main/aidl/com/google/android/gms/auth/api/identity/RevokeAccessRequest.aidl new file mode 100644 index 0000000000..25526d9a51 --- /dev/null +++ b/play-services-auth/src/main/aidl/com/google/android/gms/auth/api/identity/RevokeAccessRequest.aidl @@ -0,0 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2025 microG Project Team + * SPDX-License-Identifier: Apache-2.0 + */ + +package com.google.android.gms.auth.api.identity; + +parcelable RevokeAccessRequest; \ No newline at end of file diff --git a/play-services-auth/src/main/aidl/com/google/android/gms/auth/api/identity/internal/IAuthorizationService.aidl b/play-services-auth/src/main/aidl/com/google/android/gms/auth/api/identity/internal/IAuthorizationService.aidl index db1fc73f2a..656f0c0f2d 100644 --- a/play-services-auth/src/main/aidl/com/google/android/gms/auth/api/identity/internal/IAuthorizationService.aidl +++ b/play-services-auth/src/main/aidl/com/google/android/gms/auth/api/identity/internal/IAuthorizationService.aidl @@ -9,8 +9,13 @@ import com.google.android.gms.auth.api.identity.internal.IAuthorizationCallback; import com.google.android.gms.auth.api.identity.internal.IVerifyWithGoogleCallback; import com.google.android.gms.auth.api.identity.AuthorizationRequest; import com.google.android.gms.auth.api.identity.VerifyWithGoogleRequest; +import com.google.android.gms.auth.api.identity.RevokeAccessRequest; +import com.google.android.gms.auth.api.identity.ClearTokenRequest; +import com.google.android.gms.common.api.internal.IStatusCallback; interface IAuthorizationService { void authorize(in IAuthorizationCallback callback, in AuthorizationRequest request) = 0; void verifyWithGoogle(in IVerifyWithGoogleCallback callback, in VerifyWithGoogleRequest request) = 1; + void revokeAccess(in IStatusCallback callback, in RevokeAccessRequest request) = 2; + void clearToken(in IStatusCallback callback, in ClearTokenRequest request) = 3; } \ No newline at end of file diff --git a/play-services-auth/src/main/java/com/google/android/gms/auth/api/identity/RevokeAccessRequest.java b/play-services-auth/src/main/java/com/google/android/gms/auth/api/identity/RevokeAccessRequest.java index 71c3140f9b..0019e5cf0a 100644 --- a/play-services-auth/src/main/java/com/google/android/gms/auth/api/identity/RevokeAccessRequest.java +++ b/play-services-auth/src/main/java/com/google/android/gms/auth/api/identity/RevokeAccessRequest.java @@ -143,4 +143,13 @@ public static abstract class Builder { public void writeToParcel(@NonNull Parcel parcel, int flags) { CREATOR.writeToParcel(this, parcel, flags); } + + @Override + public String toString() { + return "RevokeAccessRequest{" + + "scopes=" + scopes + + ", account=" + account + + ", sessionId='" + sessionId + '\'' + + '}'; + } } diff --git a/play-services-base/core/src/main/kotlin/org/microg/gms/common/AccountUtils.kt b/play-services-base/core/src/main/kotlin/org/microg/gms/common/AccountUtils.kt new file mode 100644 index 0000000000..e502e4b703 --- /dev/null +++ b/play-services-base/core/src/main/kotlin/org/microg/gms/common/AccountUtils.kt @@ -0,0 +1,50 @@ +/** + * SPDX-FileCopyrightText: 2025 microG Project Team + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.microg.gms.common + +import android.accounts.Account +import android.annotation.SuppressLint +import android.content.Context +import android.content.Context.MODE_PRIVATE +import androidx.core.content.edit +import org.microg.gms.auth.AuthConstants + +class AccountUtils(val context: Context) { + + private val prefs = context.getSharedPreferences("common.selected_account_prefs", MODE_PRIVATE) + + companion object { + private const val TYPE = "selected_account_type:" + @SuppressLint("StaticFieldLeak") + @Volatile + private var instance: AccountUtils? = null + fun get(context: Context): AccountUtils = instance ?: synchronized(this) { + instance ?: AccountUtils(context.applicationContext).also { instance = it } + } + } + + fun saveSelectedAccount(packageName: String, account: Account?) { + if (account != null) { + prefs.edit { + putString(packageName, account.name) + putString(TYPE.plus(packageName), account.type) + } + } + } + + fun getSelectedAccount(packageName: String): Account? { + val name = prefs.getString(packageName, null) ?: return null + val type = prefs.getString(TYPE.plus(packageName), AuthConstants.DEFAULT_ACCOUNT_TYPE) ?: return null + return Account(name, type) + } + + fun removeSelectedAccount(packageName: String) { + prefs.edit { + remove(packageName) + remove(TYPE.plus(packageName)) + } + } +} \ No newline at end of file diff --git a/play-services-core/src/main/kotlin/org/microg/gms/auth/credentials/identity/AuthorizationService.kt b/play-services-core/src/main/kotlin/org/microg/gms/auth/credentials/identity/AuthorizationService.kt index 39121d7018..cd5279ef24 100644 --- a/play-services-core/src/main/kotlin/org/microg/gms/auth/credentials/identity/AuthorizationService.kt +++ b/play-services-core/src/main/kotlin/org/microg/gms/auth/credentials/identity/AuthorizationService.kt @@ -5,6 +5,7 @@ package org.microg.gms.auth.credentials.identity +import android.accounts.AccountManager import android.app.PendingIntent import android.app.PendingIntent.FLAG_IMMUTABLE import android.app.PendingIntent.FLAG_UPDATE_CURRENT @@ -16,6 +17,8 @@ import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.lifecycleScope import com.google.android.gms.auth.api.identity.AuthorizationRequest import com.google.android.gms.auth.api.identity.AuthorizationResult +import com.google.android.gms.auth.api.identity.ClearTokenRequest +import com.google.android.gms.auth.api.identity.RevokeAccessRequest import com.google.android.gms.auth.api.identity.VerifyWithGoogleRequest import com.google.android.gms.auth.api.identity.VerifyWithGoogleResult import com.google.android.gms.auth.api.identity.internal.IAuthorizationCallback @@ -26,18 +29,22 @@ import com.google.android.gms.auth.api.signin.internal.SignInConfiguration import com.google.android.gms.common.ConnectionResult import com.google.android.gms.common.api.Scope import com.google.android.gms.common.api.Status +import com.google.android.gms.common.api.internal.IStatusCallback import com.google.android.gms.common.internal.ConnectionInfo import com.google.android.gms.common.internal.GetServiceRequest import com.google.android.gms.common.internal.IGmsCallbacks import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import org.microg.gms.BaseService +import org.microg.gms.auth.AuthConstants import org.microg.gms.auth.credentials.FEATURES import org.microg.gms.auth.signin.AuthSignInActivity import org.microg.gms.auth.signin.SignInConfigurationService +import org.microg.gms.auth.signin.getOAuthManager import org.microg.gms.auth.signin.getServerAuthTokenManager import org.microg.gms.auth.signin.performSignIn import org.microg.gms.auth.signin.scopeUris +import org.microg.gms.common.AccountUtils import org.microg.gms.common.Constants import org.microg.gms.common.GmsService import org.microg.gms.common.PackageUtils @@ -66,36 +73,62 @@ class AuthorizationServiceImpl(val context: Context, val packageName: String, ov } override fun authorize(callback: IAuthorizationCallback?, request: AuthorizationRequest?) { - Log.d(TAG, "Method: authorize called, request:$request") + Log.d(TAG, "Method: authorize called, packageName:$packageName request:$request") lifecycleScope.launchWhenStarted { - val account = request?.account ?: SignInConfigurationService.getDefaultAccount(context, packageName) + val requestAccount = request?.account + val account = requestAccount ?: AccountUtils.get(context).getSelectedAccount(packageName) val googleSignInOptions = GoogleSignInOptions.Builder().apply { - account?.name?.let { setAccountName(it) } request?.requestedScopes?.forEach { requestScopes(it) } - if (request?.idTokenRequested == true && request.serverClientId != null) requestIdToken(request.serverClientId) + if (request?.idTokenRequested == true && request.serverClientId != null) { + if (account?.name != requestAccount?.name) { + requestEmail().requestProfile() + } + requestIdToken(request.serverClientId) + } if (request?.serverAuthCodeRequested == true && request.serverClientId != null) requestServerAuthCode(request.serverClientId, request.forceCodeForRefreshToken) }.build() - val intent = Intent(context, AuthSignInActivity::class.java).apply { - `package` = Constants.GMS_PACKAGE_NAME - putExtra("config", SignInConfiguration(packageName, googleSignInOptions)) - } - val signInAccount = account?.let { performSignIn(context, packageName, googleSignInOptions, account, false) } - callback?.onAuthorized(Status.SUCCESS, + Log.d(TAG, "authorize: account: ${account?.name}") + val result = if (account != null) { + val (accessToken, signInAccount) = performSignIn(context, packageName, googleSignInOptions, account, false) + if (requestAccount != null) { + AccountUtils.get(context).saveSelectedAccount(packageName, requestAccount) + } AuthorizationResult( signInAccount?.serverAuthCode, - signInAccount?.idToken, + accessToken, signInAccount?.idToken, signInAccount?.grantedScopes?.toList().orEmpty().map { it.scopeUri }, signInAccount, + null + ) + } else { + val options = GoogleSignInOptions.Builder(googleSignInOptions).apply { + val defaultAccount = SignInConfigurationService.getDefaultAccount(context, packageName) + defaultAccount?.name?.let { setAccountName(it) } + }.build() + val intent = Intent(context, AuthSignInActivity::class.java).apply { + `package` = Constants.GMS_PACKAGE_NAME + putExtra("config", SignInConfiguration(packageName, options)) + } + AuthorizationResult( + null, + null, + null, + request?.requestedScopes.orEmpty().map { it.scopeUri }, + null, PendingIntent.getActivity(context, nextRequestCode.incrementAndGet(), intent, FLAG_UPDATE_CURRENT or FLAG_IMMUTABLE) - ).also { Log.d(TAG, "authorize: result:$it") }) + ) + } + runCatching { + callback?.onAuthorized(Status.SUCCESS, result.also { Log.d(TAG, "authorize: result:$it") }) + } } } override fun verifyWithGoogle(callback: IVerifyWithGoogleCallback?, request: VerifyWithGoogleRequest?) { Log.d(TAG, "unimplemented Method: verifyWithGoogle: request:$request") lifecycleScope.launchWhenStarted { - val account = SignInConfigurationService.getDefaultAccount(context, packageName) + val account = AccountUtils.get(context).getSelectedAccount(packageName) ?: SignInConfigurationService.getDefaultAccount(context, packageName) if (account == null) { Log.d(TAG, "Method: authorize called, but account is null") callback?.onVerifed(Status.CANCELED, null) @@ -119,4 +152,31 @@ class AuthorizationServiceImpl(val context: Context, val packageName: String, ov } } + override fun revokeAccess(callback: IStatusCallback?, request: RevokeAccessRequest?) { + Log.d(TAG, "Method: revokeAccess called, request:$request") + lifecycleScope.launchWhenStarted { + val authOptions = SignInConfigurationService.getAuthOptions(context, packageName) + val authAccount = request?.account + if (authOptions.isNotEmpty() && authAccount != null) { + val authManager = getOAuthManager(context, packageName, authOptions.first(), authAccount) + val token = authManager.peekAuthToken() + if (token != null) { + // todo "https://oauth2.googleapis.com/revoke" + authManager.invalidateAuthToken(token) + authManager.isPermitted = false + } + } + AccountUtils.get(context).removeSelectedAccount(packageName) + runCatching { callback?.onResult(Status.SUCCESS) } + } + } + + override fun clearToken(callback: IStatusCallback?, request: ClearTokenRequest?) { + Log.d(TAG, "Method: clearToken called, request:$request") + request?.token?.let { + AccountManager.get(context).invalidateAuthToken(AuthConstants.DEFAULT_ACCOUNT_TYPE, it) + } + runCatching { callback?.onResult(Status.SUCCESS) } + } + } \ No newline at end of file diff --git a/play-services-core/src/main/kotlin/org/microg/gms/auth/credentials/identity/IdentitySignInService.kt b/play-services-core/src/main/kotlin/org/microg/gms/auth/credentials/identity/IdentitySignInService.kt index e112eb7de3..07ad56b21a 100644 --- a/play-services-core/src/main/kotlin/org/microg/gms/auth/credentials/identity/IdentitySignInService.kt +++ b/play-services-core/src/main/kotlin/org/microg/gms/auth/credentials/identity/IdentitySignInService.kt @@ -48,6 +48,7 @@ import org.microg.gms.auth.signin.CLIENT_PACKAGE_NAME import org.microg.gms.auth.signin.GOOGLE_SIGN_IN_OPTIONS import org.microg.gms.auth.signin.SignInConfigurationService import org.microg.gms.auth.signin.performSignOut +import org.microg.gms.common.AccountUtils import org.microg.gms.common.GmsService import org.microg.gms.fido.core.Database import org.microg.gms.fido.core.ui.AuthenticatorActivity.Companion.KEY_OPTIONS @@ -141,6 +142,7 @@ class IdentitySignInServiceImpl(private val context: Context, private val client performSignOut(context, clientPackageName, it, signInAccount) } } + AccountUtils.get(context).removeSelectedAccount(clientPackageName) } callback.onResult(Status.SUCCESS) } diff --git a/play-services-core/src/main/kotlin/org/microg/gms/auth/signin/AssistedSignInFragment.kt b/play-services-core/src/main/kotlin/org/microg/gms/auth/signin/AssistedSignInFragment.kt index 75711452af..72ba905ce0 100644 --- a/play-services-core/src/main/kotlin/org/microg/gms/auth/signin/AssistedSignInFragment.kt +++ b/play-services-core/src/main/kotlin/org/microg/gms/auth/signin/AssistedSignInFragment.kt @@ -42,6 +42,7 @@ import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import org.microg.gms.auth.AuthConstants import org.microg.gms.auth.login.LoginActivity +import org.microg.gms.common.AccountUtils import org.microg.gms.people.PeopleManager import org.microg.gms.utils.getApplicationLabel @@ -75,6 +76,7 @@ class AssistedSignInFragment : BottomSheetDialogFragment() { private var container: FrameLayout? = null private var loginJob: Job? = null private var isSigningIn = false + private var signInBack = false private val authStatusList = arraySetOf>() private var lastChooseAccount: Account? = null @@ -91,14 +93,18 @@ class AssistedSignInFragment : BottomSheetDialogFragment() { fun initView() { accounts = accountManager.getAccountsByType(AuthConstants.DEFAULT_ACCOUNT_TYPE) lifecycleScope.launch { - if (accounts.isEmpty()) { - addGoogleAccount() - } else { - filterAccountsLogin({ - prepareMultiSignIn(it) - }, { accountName, permitted -> - autoSingleSignIn(accountName, permitted) - }) + runCatching { + if (accounts.isEmpty()) { + addGoogleAccount() + } else { + filterAccountsLogin({ + prepareMultiSignIn(it) + }, { accountName, permitted -> + autoSingleSignIn(accountName, permitted) + }) + } + }.onFailure { + errorResult() } } } @@ -292,8 +298,10 @@ class AssistedSignInFragment : BottomSheetDialogFragment() { } override fun onDismiss(dialog: DialogInterface) { - cancelLogin() - errorResult(Status.CANCELED) + if (!signInBack) { + cancelLogin() + errorResult(Status.CANCELED) + } super.onDismiss(dialog) } @@ -315,7 +323,7 @@ class AssistedSignInFragment : BottomSheetDialogFragment() { isSigningIn = true delay(3000) runCatching { - val googleSignInAccount = withContext(Dispatchers.IO) { + val (_, googleSignInAccount) = withContext(Dispatchers.IO) { performSignIn(requireContext(), clientPackageName, options, lastChooseAccount!!, true, beginSignInRequest.googleIdTokenRequestOptions.nonce) } loginResult(googleSignInAccount) @@ -345,8 +353,12 @@ class AssistedSignInFragment : BottomSheetDialogFragment() { private fun loginResult(googleSignInAccount: GoogleSignInAccount?) { if (activity != null && activity is AssistedSignInActivity) { - val assistedSignInActivity = activity as AssistedSignInActivity - assistedSignInActivity.loginResult(googleSignInAccount) + signInBack = true + runCatching { + val assistedSignInActivity = activity as AssistedSignInActivity + AccountUtils.get(requireContext()).saveSelectedAccount(clientPackageName, googleSignInAccount?.account) + assistedSignInActivity.loginResult(googleSignInAccount) + } } activity?.finish() } diff --git a/play-services-core/src/main/kotlin/org/microg/gms/auth/signin/AuthSignInActivity.kt b/play-services-core/src/main/kotlin/org/microg/gms/auth/signin/AuthSignInActivity.kt index 3f4a5f5bc7..dd7044d1dc 100644 --- a/play-services-core/src/main/kotlin/org/microg/gms/auth/signin/AuthSignInActivity.kt +++ b/play-services-core/src/main/kotlin/org/microg/gms/auth/signin/AuthSignInActivity.kt @@ -179,7 +179,7 @@ class AuthSignInActivity : AppCompatActivity() { } private suspend fun signIn(account: Account) { - val googleSignInAccount = performSignIn(this, config?.packageName!!, config?.options, account, true, idNonce) + val (_, googleSignInAccount) = performSignIn(this, config?.packageName!!, config?.options, account, true, idNonce) if (googleSignInAccount != null) { finishResult(CommonStatusCodes.SUCCESS, account = account, googleSignInAccount = googleSignInAccount) } else { diff --git a/play-services-core/src/main/kotlin/org/microg/gms/auth/signin/AuthSignInService.kt b/play-services-core/src/main/kotlin/org/microg/gms/auth/signin/AuthSignInService.kt index 9c28971444..956fb3fbf7 100644 --- a/play-services-core/src/main/kotlin/org/microg/gms/auth/signin/AuthSignInService.kt +++ b/play-services-core/src/main/kotlin/org/microg/gms/auth/signin/AuthSignInService.kt @@ -39,6 +39,7 @@ import com.google.android.gms.common.internal.GetServiceRequest import com.google.android.gms.common.internal.IGmsCallbacks import org.microg.gms.BaseService import org.microg.gms.auth.AuthPrefs +import org.microg.gms.common.AccountUtils import org.microg.gms.common.GmsService import org.microg.gms.common.PackageUtils import org.microg.gms.games.GAMES_PACKAGE_NAME @@ -95,7 +96,7 @@ class AuthSignInServiceImpl( Log.d(TAG, "silentSignIn: account -> ${account?.name}") if (account != null && options?.isForceCodeForRefreshToken != true) { if (getOAuthManager(context, packageName, options, account).isPermitted || AuthPrefs.isTrustGooglePermitted(context)) { - val googleSignInAccount = performSignIn(context, packageName, options, account) + val (_, googleSignInAccount) = performSignIn(context, packageName, options, account) if (googleSignInAccount != null) { sendResult(googleSignInAccount, Status(CommonStatusCodes.SUCCESS)) } else { @@ -128,6 +129,7 @@ class AuthSignInServiceImpl( if (options?.scopes?.any { it.scopeUri.contains(Scopes.GAMES) } == true) { GamesConfigurationService.setDefaultAccount(context, packageName, null) } + AccountUtils.get(context).removeSelectedAccount(packageName) SignInConfigurationService.setAuthInfo(context, packageName, null, null) runCatching { callbacks.onSignOut(Status.SUCCESS) } } catch (e: Exception) { diff --git a/play-services-core/src/main/kotlin/org/microg/gms/auth/signin/extensions.kt b/play-services-core/src/main/kotlin/org/microg/gms/auth/signin/extensions.kt index de90a9a230..76de77e71f 100644 --- a/play-services-core/src/main/kotlin/org/microg/gms/auth/signin/extensions.kt +++ b/play-services-core/src/main/kotlin/org/microg/gms/auth/signin/extensions.kt @@ -107,7 +107,7 @@ suspend fun checkAccountAuthStatus(context: Context, packageName: String, scopeL return withContext(Dispatchers.IO) { authManager.requestAuth(true) }.auth != null } -suspend fun performSignIn(context: Context, packageName: String, options: GoogleSignInOptions?, account: Account, permitted: Boolean = false, idNonce: String? = null): GoogleSignInAccount? { +suspend fun performSignIn(context: Context, packageName: String, options: GoogleSignInOptions?, account: Account, permitted: Boolean = false, idNonce: String? = null): Pair { val authManager = getOAuthManager(context, packageName, options, account) val authResponse = withContext(Dispatchers.IO) { if (options?.includeUnacceptableScope == true || !permitted) { @@ -119,9 +119,9 @@ suspend fun performSignIn(context: Context, packageName: String, options: Google var consentResult:String ?= null if ("remote_consent" == authResponse.issueAdvice && authResponse.resolutionDataBase64 != null){ consentResult = performConsentView(context, packageName, account, authResponse.resolutionDataBase64) - if (consentResult == null) return null + if (consentResult == null) return Pair(null, null) } else { - if (authResponse.auth == null) return null + if (authResponse.auth == null) return Pair(null, null) } Log.d(TAG, "id token requested: ${options?.isIdTokenRequested == true}, serverClientId = ${options?.serverClientId}, permitted = ${authManager.isPermitted}") val idTokenResponse = getIdTokenManager(context, packageName, options, account)?.let { @@ -170,7 +170,7 @@ suspend fun performSignIn(context: Context, packageName: String, options: Google GamesConfigurationService.setDefaultAccount(context, packageName, account) } SignInConfigurationService.setAuthInfo(context, packageName, account, options?.toJson()) - return GoogleSignInAccount( + val googleSignInAccount = GoogleSignInAccount( id, tokenId, account.name, @@ -183,6 +183,7 @@ suspend fun performSignIn(context: Context, packageName: String, options: Google givenName, familyName ) + return Pair(authResponse.auth, googleSignInAccount) } suspend fun performConsentView(context: Context, packageName: String, account: Account, dataBase64: String): String? { diff --git a/play-services-core/src/main/kotlin/org/microg/gms/common/PackageIntentOpWorker.kt b/play-services-core/src/main/kotlin/org/microg/gms/common/PackageIntentOpWorker.kt index 221acca607..56679a40bb 100644 --- a/play-services-core/src/main/kotlin/org/microg/gms/common/PackageIntentOpWorker.kt +++ b/play-services-core/src/main/kotlin/org/microg/gms/common/PackageIntentOpWorker.kt @@ -64,5 +64,7 @@ class PackageIntentOpWorker( performSignOut(appContext, packageName, it, authAccount) } } + SignInConfigurationService.setAuthInfo(appContext, packageName, null, null) + AccountUtils.get(appContext).removeSelectedAccount(packageName) } } \ No newline at end of file