Loading data/src/main/java/foundation/e/apps/data/login/playstore/PlayStoreAuthenticator.kt +43 −102 Original line number Diff line number Diff line Loading @@ -23,7 +23,6 @@ import com.aurora.gplayapi.data.models.AuthData import dagger.hilt.android.qualifiers.ApplicationContext import foundation.e.apps.data.NetworkRetryPolicy import foundation.e.apps.data.ResultSupreme import foundation.e.apps.data.login.api.PlayStoreAuthValidator import foundation.e.apps.data.login.api.PlayStoreBootstrapCredentials import foundation.e.apps.data.login.api.PlayStoreLoginBootstrapper import foundation.e.apps.data.login.core.StoreActivationPolicy Loading @@ -37,7 +36,6 @@ import foundation.e.apps.domain.auth.AuthStore import foundation.e.apps.domain.auth.PersistedLoginIntent import foundation.e.apps.domain.auth.PlayStoreLoginMode import foundation.e.apps.domain.preferences.SessionRepository import foundation.e.apps.domain.source.SourceSelectionRepository import timber.log.Timber import java.util.Locale import javax.inject.Inject Loading Loading @@ -68,80 +66,6 @@ class PlayStoreAuthenticator @Inject constructor( private val playStoreStoredAuthPolicy: PlayStoreStoredAuthPolicy, ) : StoreAuthenticator, PlayStoreLoginBootstrapper { constructor( @ApplicationContext context: Context, sessionRepository: SessionRepository, playStoreAuthStore: PlayStoreAuthStore, sourceSelectionRepository: SourceSelectionRepository, authDataCache: AuthDataCache, googleLoginManager: GoogleLoginManager, microgLoginManager: MicrogLoginManager, anonymousLoginManager: AnonymousLoginManager, aasTokenConverter: OauthToAasTokenConverter, userProfileFetcher: UserProfileFetcher, successfulLoginNotifier: SuccessfulLoginNotifier, networkRetryPolicy: NetworkRetryPolicy, playStoreAuthValidator: PlayStoreAuthValidator, ) : this( context = context, sessionRepository = sessionRepository, playStoreAuthStore = playStoreAuthStore, storeActivationPolicy = StoreActivationPolicy( sessionRepository = sessionRepository, sourceSelectionRepository = sourceSelectionRepository, ), authDataCache = authDataCache, googleLoginManager = googleLoginManager, microgLoginManager = microgLoginManager, anonymousLoginManager = anonymousLoginManager, aasTokenConverter = aasTokenConverter, userProfileFetcher = userProfileFetcher, successfulLoginNotifier = successfulLoginNotifier, networkRetryPolicy = networkRetryPolicy, playStoreStoredAuthPolicy = PlayStoreStoredAuthPolicy( playStoreAuthStore = playStoreAuthStore, playStoreAuthValidator = playStoreAuthValidator, ), ) constructor( @ApplicationContext context: Context, sessionRepository: SessionRepository, playStoreAuthStore: PlayStoreAuthStore, sourceSelectionRepository: SourceSelectionRepository, authDataCache: AuthDataCache, googleLoginManager: GoogleLoginManager, microgLoginManager: MicrogLoginManager, anonymousLoginManager: AnonymousLoginManager, aasTokenConverter: OauthToAasTokenConverter, userProfileFetcher: UserProfileFetcher, successfulLoginNotifier: SuccessfulLoginNotifier, networkRetryPolicy: NetworkRetryPolicy, playStoreAuthValidator: PlayStoreAuthValidator, monotonicClockMs: () -> Long, ) : this( context = context, sessionRepository = sessionRepository, playStoreAuthStore = playStoreAuthStore, storeActivationPolicy = StoreActivationPolicy( sessionRepository = sessionRepository, sourceSelectionRepository = sourceSelectionRepository, ), authDataCache = authDataCache, googleLoginManager = googleLoginManager, microgLoginManager = microgLoginManager, anonymousLoginManager = anonymousLoginManager, aasTokenConverter = aasTokenConverter, userProfileFetcher = userProfileFetcher, successfulLoginNotifier = successfulLoginNotifier, networkRetryPolicy = networkRetryPolicy, playStoreStoredAuthPolicy = PlayStoreStoredAuthPolicy( playStoreAuthStore = playStoreAuthStore, playStoreAuthValidator = playStoreAuthValidator, monotonicClockMs = monotonicClockMs, ), ) override val storeType: AuthStore = AuthStore.PLAY_STORE private val locale: Locale get() = context.resources.configuration.locales[0] Loading Loading @@ -254,9 +178,9 @@ class PlayStoreAuthenticator @Inject constructor( val oauthToken = playStoreAuthStore.awaitOauthToken() val aasTokenResponse = aasTokenConverter.convert(email, oauthToken) return if (aasTokenResponse.isSuccess()) { loginWithAasTokenFromConversion(aasTokenResponse.data.orEmpty()) loginWithPersistedAasTokenFromConversion(aasTokenResponse.data.orEmpty()) } else { loginWithOauthToken(aasTokenResponse, oauthToken) loginWithPersistedOauthToken(aasTokenResponse, oauthToken) } } Loading @@ -268,15 +192,15 @@ class PlayStoreAuthenticator @Inject constructor( oauthToken = credentials.oauthToken, ) return if (aasTokenResponse.isSuccess()) { loginWithAasTokenFromConversion( loginWithExplicitAasTokenFromConversion( aasToken = aasTokenResponse.data.orEmpty(), email = credentials.email, ) } else { loginWithOauthToken( loginWithExplicitOauthToken( aasTokenResponse = aasTokenResponse, oauthToken = credentials.oauthToken, email = credentials.email, oauthToken = credentials.oauthToken, ) } } Loading @@ -302,19 +226,26 @@ class PlayStoreAuthenticator @Inject constructor( return formatLoginResult(sessionForGoogle().login()) } private suspend fun loginWithAasTokenFromConversion( private suspend fun loginWithPersistedAasTokenFromConversion( aasToken: String, email: String? = null, ): ResultSupreme<AuthData?> { if (aasToken.isBlank()) { return ResultSupreme.Error("Fetched AAS Token is blank") } return if (email == null) { playStoreAuthStore.saveAasToken(aasToken) loginWithAasToken() } else { formatLoginResult( return loginWithAasToken() } private suspend fun loginWithExplicitAasTokenFromConversion( aasToken: String, email: String, ): ResultSupreme<AuthData?> { if (aasToken.isBlank()) { return ResultSupreme.Error("Fetched AAS Token is blank") } return formatLoginResult( ResultSupreme.Success( googleLoginManager.login( email = email, Loading @@ -324,18 +255,28 @@ class PlayStoreAuthenticator @Inject constructor( ) ) } private suspend fun loginWithPersistedOauthToken( aasTokenResponse: ResultSupreme<String>, oauthToken: String, ): ResultSupreme<AuthData?> { val fallbackAuth = googleLoginManager.loginWithOauthToken(oauthToken) return replicateOauthFallback(aasTokenResponse, fallbackAuth) } private suspend fun loginWithOauthToken( private suspend fun loginWithExplicitOauthToken( aasTokenResponse: ResultSupreme<String>, email: String, oauthToken: String, email: String? = null, ): ResultSupreme<AuthData?> { val fallbackAuth = if (email == null) { googleLoginManager.loginWithOauthToken(oauthToken) } else { googleLoginManager.loginWithOauthToken(email, oauthToken) val fallbackAuth = googleLoginManager.loginWithOauthToken(email, oauthToken) return replicateOauthFallback(aasTokenResponse, fallbackAuth) } private fun replicateOauthFallback( aasTokenResponse: ResultSupreme<String>, fallbackAuth: AuthData?, ): ResultSupreme<AuthData?> { return if (fallbackAuth != null) { ResultSupreme.Success<AuthData?>(authDataCache.formatAuthData(fallbackAuth)) } else { Loading data/src/main/java/foundation/e/apps/data/login/repository/AuthenticatorRepository.kt +0 −33 Original line number Diff line number Diff line Loading @@ -20,7 +20,6 @@ package foundation.e.apps.data.login.repository import com.aurora.gplayapi.data.models.AuthData import foundation.e.apps.data.ResultSupreme import foundation.e.apps.data.login.api.PlayStoreAuthManager import foundation.e.apps.data.login.api.PlayStoreAuthValidator import foundation.e.apps.data.login.api.StoreAuthCoordinator import foundation.e.apps.data.login.core.StoreAuthResult import foundation.e.apps.data.login.core.StoreAuthenticator Loading Loading @@ -48,38 +47,6 @@ class AuthenticatorRepository @Inject constructor( ) : PlayStoreAuthManager, StoreAuthCoordinator { private val validatedAuthMutex = Mutex() constructor( authenticators: List<StoreAuthenticator>, sessionRepository: SessionRepository, playStoreAuthStore: PlayStoreAuthStore, playStoreAuthValidator: PlayStoreAuthValidator, ) : this( authenticators = authenticators, sessionRepository = sessionRepository, playStoreAuthStore = playStoreAuthStore, playStoreStoredAuthPolicy = PlayStoreStoredAuthPolicy( playStoreAuthStore = playStoreAuthStore, playStoreAuthValidator = playStoreAuthValidator, ), ) constructor( authenticators: List<StoreAuthenticator>, sessionRepository: SessionRepository, playStoreAuthStore: PlayStoreAuthStore, playStoreAuthValidator: PlayStoreAuthValidator, monotonicClockMs: () -> Long, ) : this( authenticators = authenticators, sessionRepository = sessionRepository, playStoreAuthStore = playStoreAuthStore, playStoreStoredAuthPolicy = PlayStoreStoredAuthPolicy( playStoreAuthStore = playStoreAuthStore, playStoreAuthValidator = playStoreAuthValidator, monotonicClockMs = monotonicClockMs, ), ) override suspend fun requireValidatedPlayStoreAuth(): AuthData { val result = getValidatedAuthData() val authData = result.data Loading data/src/test/java/foundation/e/apps/data/login/playstore/PlayStoreAuthenticatorTest.kt +81 −21 Original line number Diff line number Diff line Loading @@ -9,6 +9,7 @@ import foundation.e.apps.data.NetworkRetryPolicy import foundation.e.apps.data.ResultSupreme import foundation.e.apps.data.login.api.PlayStoreAuthValidationResult import foundation.e.apps.data.login.api.PlayStoreAuthValidator import foundation.e.apps.data.login.core.StoreActivationPolicy import foundation.e.apps.data.login.core.StoreAuthResult import foundation.e.apps.data.login.microg.MicrogLoginManager import foundation.e.apps.data.preference.PlayStoreAuthStore Loading Loading @@ -45,6 +46,46 @@ class PlayStoreAuthenticatorTest { private fun applicationContext(): Context = ApplicationProvider.getApplicationContext() private fun playStoreAuthenticator( context: Context = applicationContext(), sessionRepository: SessionRepository, playStoreAuthStore: PlayStoreAuthStore, sourceSelectionRepository: SourceSelectionRepository = sourceSelectionRepository(), authDataCache: AuthDataCache, googleLoginManager: GoogleLoginManager, microgLoginManager: MicrogLoginManager, anonymousLoginManager: AnonymousLoginManager, aasTokenConverter: OauthToAasTokenConverter, userProfileFetcher: UserProfileFetcher, successfulLoginNotifier: SuccessfulLoginNotifier, networkRetryPolicy: NetworkRetryPolicy, playStoreAuthValidator: PlayStoreAuthValidator, monotonicClockMs: (() -> Long)? = null, ): PlayStoreAuthenticator { return PlayStoreAuthenticator( context = context, sessionRepository = sessionRepository, playStoreAuthStore = playStoreAuthStore, storeActivationPolicy = StoreActivationPolicy( sessionRepository = sessionRepository, sourceSelectionRepository = sourceSelectionRepository, ), authDataCache = authDataCache, googleLoginManager = googleLoginManager, microgLoginManager = microgLoginManager, anonymousLoginManager = anonymousLoginManager, aasTokenConverter = aasTokenConverter, userProfileFetcher = userProfileFetcher, successfulLoginNotifier = successfulLoginNotifier, networkRetryPolicy = networkRetryPolicy, playStoreStoredAuthPolicy = createPlayStoreStoredAuthPolicy( playStoreAuthStore = playStoreAuthStore, playStoreAuthValidator = playStoreAuthValidator, monotonicClockMs = monotonicClockMs, ), ) } private fun sourceSelectionRepository( isPlayStoreSelected: Boolean = true, ): SourceSelectionRepository { Loading Loading @@ -78,7 +119,7 @@ class PlayStoreAuthenticatorTest { val aasTokenConverter = mockk<OauthToAasTokenConverter>() val userProfileFetcher = mockk<UserProfileFetcher>() val authenticator = PlayStoreAuthenticator( val authenticator = playStoreAuthenticator( context = context, sessionRepository = sessionRepository, playStoreAuthStore = sessionRepository, Loading Loading @@ -108,7 +149,7 @@ class PlayStoreAuthenticatorTest { @Test fun isStoreActive_awaitsPersistedLoginIntent() = runTest { val authenticator = PlayStoreAuthenticator( val authenticator = playStoreAuthenticator( context = applicationContext(), sessionRepository = FakeSessionRepository( initialLoginIntent = PersistedLoginIntent.NONE, Loading @@ -133,7 +174,7 @@ class PlayStoreAuthenticatorTest { @Test fun isStoreActive_allowsAnonymousPlayLoginWithoutPersistedAuthData() = runTest { val authenticator = PlayStoreAuthenticator( val authenticator = playStoreAuthenticator( context = applicationContext(), sessionRepository = FakeSessionRepository( initialLoginIntent = PersistedLoginIntent.PLAY_ANONYMOUS, Loading @@ -156,7 +197,7 @@ class PlayStoreAuthenticatorTest { @Test fun isStoreActive_returnsFalseWhenPlayStoreIsDeselected() = runTest { val authenticator = PlayStoreAuthenticator( val authenticator = playStoreAuthenticator( context = applicationContext(), sessionRepository = FakeSessionRepository( initialLoginIntent = PersistedLoginIntent.PLAY_ANONYMOUS, Loading @@ -179,7 +220,7 @@ class PlayStoreAuthenticatorTest { @Test fun isStoreActive_returnsFalseForNoGoogleUserEvenWhenPlayStoreIsSelected() = runTest { val authenticator = PlayStoreAuthenticator( val authenticator = playStoreAuthenticator( context = applicationContext(), sessionRepository = FakeSessionRepository( initialLoginIntent = PersistedLoginIntent.OPEN_SOURCE, Loading Loading @@ -209,7 +250,7 @@ class PlayStoreAuthenticatorTest { val authData = AuthData(email = "anon@example.com", isAnonymous = true) coEvery { anonymousLoginManager.login() } returns authData val authenticator = PlayStoreAuthenticator( val authenticator = playStoreAuthenticator( context = applicationContext(), sessionRepository = sessionRepository, playStoreAuthStore = mockk(relaxed = true), Loading Loading @@ -244,7 +285,7 @@ class PlayStoreAuthenticatorTest { val authData = AuthData(email = "google@example.com") coEvery { googleLoginManager.login() } returns authData val authenticator = PlayStoreAuthenticator( val authenticator = playStoreAuthenticator( context = applicationContext(), sessionRepository = sessionRepository, playStoreAuthStore = sessionRepository, Loading Loading @@ -279,7 +320,7 @@ class PlayStoreAuthenticatorTest { val authData = AuthData(email = "microg@example.com") coEvery { microgLoginManager.login() } returns authData val authenticator = PlayStoreAuthenticator( val authenticator = playStoreAuthenticator( context = applicationContext(), sessionRepository = sessionRepository, playStoreAuthStore = sessionRepository, Loading Loading @@ -319,7 +360,7 @@ class PlayStoreAuthenticatorTest { val authData = AuthData(email = "anon@example.com", isAnonymous = true) coEvery { anonymousLoginManager.login() } returns authData val authenticator = PlayStoreAuthenticator( val authenticator = playStoreAuthenticator( context = context, sessionRepository = sessionRepository, playStoreAuthStore = sessionRepository, Loading Loading @@ -363,7 +404,7 @@ class PlayStoreAuthenticatorTest { coEvery { anonymousLoginManager.login() } returns null val authenticator = PlayStoreAuthenticator( val authenticator = playStoreAuthenticator( context = context, sessionRepository = sessionRepository, playStoreAuthStore = sessionRepository, Loading Loading @@ -407,7 +448,7 @@ class PlayStoreAuthenticatorTest { coEvery { googleLoginManager.login() } returns authData coEvery { userProfileFetcher.fetch(authData) } returns profile val authenticator = PlayStoreAuthenticator( val authenticator = playStoreAuthenticator( context = context, sessionRepository = sessionRepository, playStoreAuthStore = sessionRepository, Loading Loading @@ -455,7 +496,7 @@ class PlayStoreAuthenticatorTest { coEvery { googleLoginManager.login() } returns authData coEvery { userProfileFetcher.fetch(any()) } returns null val authenticator = PlayStoreAuthenticator( val authenticator = playStoreAuthenticator( context = context, sessionRepository = sessionRepository, playStoreAuthStore = sessionRepository, Loading Loading @@ -497,7 +538,7 @@ class PlayStoreAuthenticatorTest { coEvery { googleLoginManager.login() } returns authData coEvery { userProfileFetcher.fetch(any()) } returns null val authenticator = PlayStoreAuthenticator( val authenticator = playStoreAuthenticator( context = context, sessionRepository = sessionRepository, playStoreAuthStore = sessionRepository, Loading Loading @@ -544,7 +585,7 @@ class PlayStoreAuthenticatorTest { coEvery { googleLoginManager.loginWithOauthToken("oauth-token") } returns authData coEvery { userProfileFetcher.fetch(any()) } returns null val authenticator = PlayStoreAuthenticator( val authenticator = playStoreAuthenticator( context = context, sessionRepository = sessionRepository, playStoreAuthStore = sessionRepository, Loading Loading @@ -588,7 +629,7 @@ class PlayStoreAuthenticatorTest { coEvery { microgLoginManager.login() } returns authData coEvery { userProfileFetcher.fetch(any()) } returns null val authenticator = PlayStoreAuthenticator( val authenticator = playStoreAuthenticator( context = context, sessionRepository = sessionRepository, playStoreAuthStore = sessionRepository, Loading Loading @@ -631,7 +672,7 @@ class PlayStoreAuthenticatorTest { coEvery { microgLoginManager.login() } returns authData coEvery { userProfileFetcher.fetch(any()) } returns null val authenticator = PlayStoreAuthenticator( val authenticator = playStoreAuthenticator( context = context, sessionRepository = sessionRepository, playStoreAuthStore = sessionRepository, Loading Loading @@ -666,7 +707,7 @@ class PlayStoreAuthenticatorTest { val anonymousLoginManager = mockk<AnonymousLoginManager>() val successfulLoginNotifier = FakeSuccessfulLoginNotifier() val authenticator = PlayStoreAuthenticator( val authenticator = playStoreAuthenticator( context = applicationContext(), sessionRepository = sessionRepository, playStoreAuthStore = sessionRepository, Loading Loading @@ -705,7 +746,7 @@ class PlayStoreAuthenticatorTest { val anonymousLoginManager = mockk<AnonymousLoginManager>() coEvery { anonymousLoginManager.login() } returns freshAuth val authenticator = PlayStoreAuthenticator( val authenticator = playStoreAuthenticator( context = context, sessionRepository = sessionRepository, playStoreAuthStore = sessionRepository, Loading Loading @@ -741,7 +782,7 @@ class PlayStoreAuthenticatorTest { ) val anonymousLoginManager = mockk<AnonymousLoginManager>() val authenticator = PlayStoreAuthenticator( val authenticator = playStoreAuthenticator( context = context, sessionRepository = sessionRepository, playStoreAuthStore = sessionRepository, Loading Loading @@ -789,7 +830,7 @@ class PlayStoreAuthenticatorTest { val validator = FakePlayStoreAuthValidator() var nowMs = 1_000L val authenticator = PlayStoreAuthenticator( val authenticator = playStoreAuthenticator( context = context, sessionRepository = sessionRepository, playStoreAuthStore = sessionRepository, Loading Loading @@ -833,7 +874,7 @@ class PlayStoreAuthenticatorTest { val validator = FakePlayStoreAuthValidator() var nowMs = 1_000L val authenticator = PlayStoreAuthenticator( val authenticator = playStoreAuthenticator( context = context, sessionRepository = sessionRepository, playStoreAuthStore = sessionRepository, Loading Loading @@ -939,6 +980,25 @@ class PlayStoreAuthenticatorTest { private fun alwaysValidAuthValidator(): PlayStoreAuthValidator = FakePlayStoreAuthValidator() private fun createPlayStoreStoredAuthPolicy( playStoreAuthStore: PlayStoreAuthStore, playStoreAuthValidator: PlayStoreAuthValidator, monotonicClockMs: (() -> Long)? = null, ): PlayStoreStoredAuthPolicy { return if (monotonicClockMs == null) { PlayStoreStoredAuthPolicy( playStoreAuthStore = playStoreAuthStore, playStoreAuthValidator = playStoreAuthValidator, ) } else { PlayStoreStoredAuthPolicy( playStoreAuthStore = playStoreAuthStore, playStoreAuthValidator = playStoreAuthValidator, monotonicClockMs = monotonicClockMs, ) } } private class FakePlayStoreAuthValidator( private val validateBlock: suspend (AuthData) -> PlayStoreAuthValidationResult = { PlayStoreAuthValidationResult.Valid Loading data/src/test/java/foundation/e/apps/data/login/repository/AuthenticatorRepositoryTest.kt +52 −14 File changed.Preview size limit exceeded, changes collapsed. Show changes Loading
data/src/main/java/foundation/e/apps/data/login/playstore/PlayStoreAuthenticator.kt +43 −102 Original line number Diff line number Diff line Loading @@ -23,7 +23,6 @@ import com.aurora.gplayapi.data.models.AuthData import dagger.hilt.android.qualifiers.ApplicationContext import foundation.e.apps.data.NetworkRetryPolicy import foundation.e.apps.data.ResultSupreme import foundation.e.apps.data.login.api.PlayStoreAuthValidator import foundation.e.apps.data.login.api.PlayStoreBootstrapCredentials import foundation.e.apps.data.login.api.PlayStoreLoginBootstrapper import foundation.e.apps.data.login.core.StoreActivationPolicy Loading @@ -37,7 +36,6 @@ import foundation.e.apps.domain.auth.AuthStore import foundation.e.apps.domain.auth.PersistedLoginIntent import foundation.e.apps.domain.auth.PlayStoreLoginMode import foundation.e.apps.domain.preferences.SessionRepository import foundation.e.apps.domain.source.SourceSelectionRepository import timber.log.Timber import java.util.Locale import javax.inject.Inject Loading Loading @@ -68,80 +66,6 @@ class PlayStoreAuthenticator @Inject constructor( private val playStoreStoredAuthPolicy: PlayStoreStoredAuthPolicy, ) : StoreAuthenticator, PlayStoreLoginBootstrapper { constructor( @ApplicationContext context: Context, sessionRepository: SessionRepository, playStoreAuthStore: PlayStoreAuthStore, sourceSelectionRepository: SourceSelectionRepository, authDataCache: AuthDataCache, googleLoginManager: GoogleLoginManager, microgLoginManager: MicrogLoginManager, anonymousLoginManager: AnonymousLoginManager, aasTokenConverter: OauthToAasTokenConverter, userProfileFetcher: UserProfileFetcher, successfulLoginNotifier: SuccessfulLoginNotifier, networkRetryPolicy: NetworkRetryPolicy, playStoreAuthValidator: PlayStoreAuthValidator, ) : this( context = context, sessionRepository = sessionRepository, playStoreAuthStore = playStoreAuthStore, storeActivationPolicy = StoreActivationPolicy( sessionRepository = sessionRepository, sourceSelectionRepository = sourceSelectionRepository, ), authDataCache = authDataCache, googleLoginManager = googleLoginManager, microgLoginManager = microgLoginManager, anonymousLoginManager = anonymousLoginManager, aasTokenConverter = aasTokenConverter, userProfileFetcher = userProfileFetcher, successfulLoginNotifier = successfulLoginNotifier, networkRetryPolicy = networkRetryPolicy, playStoreStoredAuthPolicy = PlayStoreStoredAuthPolicy( playStoreAuthStore = playStoreAuthStore, playStoreAuthValidator = playStoreAuthValidator, ), ) constructor( @ApplicationContext context: Context, sessionRepository: SessionRepository, playStoreAuthStore: PlayStoreAuthStore, sourceSelectionRepository: SourceSelectionRepository, authDataCache: AuthDataCache, googleLoginManager: GoogleLoginManager, microgLoginManager: MicrogLoginManager, anonymousLoginManager: AnonymousLoginManager, aasTokenConverter: OauthToAasTokenConverter, userProfileFetcher: UserProfileFetcher, successfulLoginNotifier: SuccessfulLoginNotifier, networkRetryPolicy: NetworkRetryPolicy, playStoreAuthValidator: PlayStoreAuthValidator, monotonicClockMs: () -> Long, ) : this( context = context, sessionRepository = sessionRepository, playStoreAuthStore = playStoreAuthStore, storeActivationPolicy = StoreActivationPolicy( sessionRepository = sessionRepository, sourceSelectionRepository = sourceSelectionRepository, ), authDataCache = authDataCache, googleLoginManager = googleLoginManager, microgLoginManager = microgLoginManager, anonymousLoginManager = anonymousLoginManager, aasTokenConverter = aasTokenConverter, userProfileFetcher = userProfileFetcher, successfulLoginNotifier = successfulLoginNotifier, networkRetryPolicy = networkRetryPolicy, playStoreStoredAuthPolicy = PlayStoreStoredAuthPolicy( playStoreAuthStore = playStoreAuthStore, playStoreAuthValidator = playStoreAuthValidator, monotonicClockMs = monotonicClockMs, ), ) override val storeType: AuthStore = AuthStore.PLAY_STORE private val locale: Locale get() = context.resources.configuration.locales[0] Loading Loading @@ -254,9 +178,9 @@ class PlayStoreAuthenticator @Inject constructor( val oauthToken = playStoreAuthStore.awaitOauthToken() val aasTokenResponse = aasTokenConverter.convert(email, oauthToken) return if (aasTokenResponse.isSuccess()) { loginWithAasTokenFromConversion(aasTokenResponse.data.orEmpty()) loginWithPersistedAasTokenFromConversion(aasTokenResponse.data.orEmpty()) } else { loginWithOauthToken(aasTokenResponse, oauthToken) loginWithPersistedOauthToken(aasTokenResponse, oauthToken) } } Loading @@ -268,15 +192,15 @@ class PlayStoreAuthenticator @Inject constructor( oauthToken = credentials.oauthToken, ) return if (aasTokenResponse.isSuccess()) { loginWithAasTokenFromConversion( loginWithExplicitAasTokenFromConversion( aasToken = aasTokenResponse.data.orEmpty(), email = credentials.email, ) } else { loginWithOauthToken( loginWithExplicitOauthToken( aasTokenResponse = aasTokenResponse, oauthToken = credentials.oauthToken, email = credentials.email, oauthToken = credentials.oauthToken, ) } } Loading @@ -302,19 +226,26 @@ class PlayStoreAuthenticator @Inject constructor( return formatLoginResult(sessionForGoogle().login()) } private suspend fun loginWithAasTokenFromConversion( private suspend fun loginWithPersistedAasTokenFromConversion( aasToken: String, email: String? = null, ): ResultSupreme<AuthData?> { if (aasToken.isBlank()) { return ResultSupreme.Error("Fetched AAS Token is blank") } return if (email == null) { playStoreAuthStore.saveAasToken(aasToken) loginWithAasToken() } else { formatLoginResult( return loginWithAasToken() } private suspend fun loginWithExplicitAasTokenFromConversion( aasToken: String, email: String, ): ResultSupreme<AuthData?> { if (aasToken.isBlank()) { return ResultSupreme.Error("Fetched AAS Token is blank") } return formatLoginResult( ResultSupreme.Success( googleLoginManager.login( email = email, Loading @@ -324,18 +255,28 @@ class PlayStoreAuthenticator @Inject constructor( ) ) } private suspend fun loginWithPersistedOauthToken( aasTokenResponse: ResultSupreme<String>, oauthToken: String, ): ResultSupreme<AuthData?> { val fallbackAuth = googleLoginManager.loginWithOauthToken(oauthToken) return replicateOauthFallback(aasTokenResponse, fallbackAuth) } private suspend fun loginWithOauthToken( private suspend fun loginWithExplicitOauthToken( aasTokenResponse: ResultSupreme<String>, email: String, oauthToken: String, email: String? = null, ): ResultSupreme<AuthData?> { val fallbackAuth = if (email == null) { googleLoginManager.loginWithOauthToken(oauthToken) } else { googleLoginManager.loginWithOauthToken(email, oauthToken) val fallbackAuth = googleLoginManager.loginWithOauthToken(email, oauthToken) return replicateOauthFallback(aasTokenResponse, fallbackAuth) } private fun replicateOauthFallback( aasTokenResponse: ResultSupreme<String>, fallbackAuth: AuthData?, ): ResultSupreme<AuthData?> { return if (fallbackAuth != null) { ResultSupreme.Success<AuthData?>(authDataCache.formatAuthData(fallbackAuth)) } else { Loading
data/src/main/java/foundation/e/apps/data/login/repository/AuthenticatorRepository.kt +0 −33 Original line number Diff line number Diff line Loading @@ -20,7 +20,6 @@ package foundation.e.apps.data.login.repository import com.aurora.gplayapi.data.models.AuthData import foundation.e.apps.data.ResultSupreme import foundation.e.apps.data.login.api.PlayStoreAuthManager import foundation.e.apps.data.login.api.PlayStoreAuthValidator import foundation.e.apps.data.login.api.StoreAuthCoordinator import foundation.e.apps.data.login.core.StoreAuthResult import foundation.e.apps.data.login.core.StoreAuthenticator Loading Loading @@ -48,38 +47,6 @@ class AuthenticatorRepository @Inject constructor( ) : PlayStoreAuthManager, StoreAuthCoordinator { private val validatedAuthMutex = Mutex() constructor( authenticators: List<StoreAuthenticator>, sessionRepository: SessionRepository, playStoreAuthStore: PlayStoreAuthStore, playStoreAuthValidator: PlayStoreAuthValidator, ) : this( authenticators = authenticators, sessionRepository = sessionRepository, playStoreAuthStore = playStoreAuthStore, playStoreStoredAuthPolicy = PlayStoreStoredAuthPolicy( playStoreAuthStore = playStoreAuthStore, playStoreAuthValidator = playStoreAuthValidator, ), ) constructor( authenticators: List<StoreAuthenticator>, sessionRepository: SessionRepository, playStoreAuthStore: PlayStoreAuthStore, playStoreAuthValidator: PlayStoreAuthValidator, monotonicClockMs: () -> Long, ) : this( authenticators = authenticators, sessionRepository = sessionRepository, playStoreAuthStore = playStoreAuthStore, playStoreStoredAuthPolicy = PlayStoreStoredAuthPolicy( playStoreAuthStore = playStoreAuthStore, playStoreAuthValidator = playStoreAuthValidator, monotonicClockMs = monotonicClockMs, ), ) override suspend fun requireValidatedPlayStoreAuth(): AuthData { val result = getValidatedAuthData() val authData = result.data Loading
data/src/test/java/foundation/e/apps/data/login/playstore/PlayStoreAuthenticatorTest.kt +81 −21 Original line number Diff line number Diff line Loading @@ -9,6 +9,7 @@ import foundation.e.apps.data.NetworkRetryPolicy import foundation.e.apps.data.ResultSupreme import foundation.e.apps.data.login.api.PlayStoreAuthValidationResult import foundation.e.apps.data.login.api.PlayStoreAuthValidator import foundation.e.apps.data.login.core.StoreActivationPolicy import foundation.e.apps.data.login.core.StoreAuthResult import foundation.e.apps.data.login.microg.MicrogLoginManager import foundation.e.apps.data.preference.PlayStoreAuthStore Loading Loading @@ -45,6 +46,46 @@ class PlayStoreAuthenticatorTest { private fun applicationContext(): Context = ApplicationProvider.getApplicationContext() private fun playStoreAuthenticator( context: Context = applicationContext(), sessionRepository: SessionRepository, playStoreAuthStore: PlayStoreAuthStore, sourceSelectionRepository: SourceSelectionRepository = sourceSelectionRepository(), authDataCache: AuthDataCache, googleLoginManager: GoogleLoginManager, microgLoginManager: MicrogLoginManager, anonymousLoginManager: AnonymousLoginManager, aasTokenConverter: OauthToAasTokenConverter, userProfileFetcher: UserProfileFetcher, successfulLoginNotifier: SuccessfulLoginNotifier, networkRetryPolicy: NetworkRetryPolicy, playStoreAuthValidator: PlayStoreAuthValidator, monotonicClockMs: (() -> Long)? = null, ): PlayStoreAuthenticator { return PlayStoreAuthenticator( context = context, sessionRepository = sessionRepository, playStoreAuthStore = playStoreAuthStore, storeActivationPolicy = StoreActivationPolicy( sessionRepository = sessionRepository, sourceSelectionRepository = sourceSelectionRepository, ), authDataCache = authDataCache, googleLoginManager = googleLoginManager, microgLoginManager = microgLoginManager, anonymousLoginManager = anonymousLoginManager, aasTokenConverter = aasTokenConverter, userProfileFetcher = userProfileFetcher, successfulLoginNotifier = successfulLoginNotifier, networkRetryPolicy = networkRetryPolicy, playStoreStoredAuthPolicy = createPlayStoreStoredAuthPolicy( playStoreAuthStore = playStoreAuthStore, playStoreAuthValidator = playStoreAuthValidator, monotonicClockMs = monotonicClockMs, ), ) } private fun sourceSelectionRepository( isPlayStoreSelected: Boolean = true, ): SourceSelectionRepository { Loading Loading @@ -78,7 +119,7 @@ class PlayStoreAuthenticatorTest { val aasTokenConverter = mockk<OauthToAasTokenConverter>() val userProfileFetcher = mockk<UserProfileFetcher>() val authenticator = PlayStoreAuthenticator( val authenticator = playStoreAuthenticator( context = context, sessionRepository = sessionRepository, playStoreAuthStore = sessionRepository, Loading Loading @@ -108,7 +149,7 @@ class PlayStoreAuthenticatorTest { @Test fun isStoreActive_awaitsPersistedLoginIntent() = runTest { val authenticator = PlayStoreAuthenticator( val authenticator = playStoreAuthenticator( context = applicationContext(), sessionRepository = FakeSessionRepository( initialLoginIntent = PersistedLoginIntent.NONE, Loading @@ -133,7 +174,7 @@ class PlayStoreAuthenticatorTest { @Test fun isStoreActive_allowsAnonymousPlayLoginWithoutPersistedAuthData() = runTest { val authenticator = PlayStoreAuthenticator( val authenticator = playStoreAuthenticator( context = applicationContext(), sessionRepository = FakeSessionRepository( initialLoginIntent = PersistedLoginIntent.PLAY_ANONYMOUS, Loading @@ -156,7 +197,7 @@ class PlayStoreAuthenticatorTest { @Test fun isStoreActive_returnsFalseWhenPlayStoreIsDeselected() = runTest { val authenticator = PlayStoreAuthenticator( val authenticator = playStoreAuthenticator( context = applicationContext(), sessionRepository = FakeSessionRepository( initialLoginIntent = PersistedLoginIntent.PLAY_ANONYMOUS, Loading @@ -179,7 +220,7 @@ class PlayStoreAuthenticatorTest { @Test fun isStoreActive_returnsFalseForNoGoogleUserEvenWhenPlayStoreIsSelected() = runTest { val authenticator = PlayStoreAuthenticator( val authenticator = playStoreAuthenticator( context = applicationContext(), sessionRepository = FakeSessionRepository( initialLoginIntent = PersistedLoginIntent.OPEN_SOURCE, Loading Loading @@ -209,7 +250,7 @@ class PlayStoreAuthenticatorTest { val authData = AuthData(email = "anon@example.com", isAnonymous = true) coEvery { anonymousLoginManager.login() } returns authData val authenticator = PlayStoreAuthenticator( val authenticator = playStoreAuthenticator( context = applicationContext(), sessionRepository = sessionRepository, playStoreAuthStore = mockk(relaxed = true), Loading Loading @@ -244,7 +285,7 @@ class PlayStoreAuthenticatorTest { val authData = AuthData(email = "google@example.com") coEvery { googleLoginManager.login() } returns authData val authenticator = PlayStoreAuthenticator( val authenticator = playStoreAuthenticator( context = applicationContext(), sessionRepository = sessionRepository, playStoreAuthStore = sessionRepository, Loading Loading @@ -279,7 +320,7 @@ class PlayStoreAuthenticatorTest { val authData = AuthData(email = "microg@example.com") coEvery { microgLoginManager.login() } returns authData val authenticator = PlayStoreAuthenticator( val authenticator = playStoreAuthenticator( context = applicationContext(), sessionRepository = sessionRepository, playStoreAuthStore = sessionRepository, Loading Loading @@ -319,7 +360,7 @@ class PlayStoreAuthenticatorTest { val authData = AuthData(email = "anon@example.com", isAnonymous = true) coEvery { anonymousLoginManager.login() } returns authData val authenticator = PlayStoreAuthenticator( val authenticator = playStoreAuthenticator( context = context, sessionRepository = sessionRepository, playStoreAuthStore = sessionRepository, Loading Loading @@ -363,7 +404,7 @@ class PlayStoreAuthenticatorTest { coEvery { anonymousLoginManager.login() } returns null val authenticator = PlayStoreAuthenticator( val authenticator = playStoreAuthenticator( context = context, sessionRepository = sessionRepository, playStoreAuthStore = sessionRepository, Loading Loading @@ -407,7 +448,7 @@ class PlayStoreAuthenticatorTest { coEvery { googleLoginManager.login() } returns authData coEvery { userProfileFetcher.fetch(authData) } returns profile val authenticator = PlayStoreAuthenticator( val authenticator = playStoreAuthenticator( context = context, sessionRepository = sessionRepository, playStoreAuthStore = sessionRepository, Loading Loading @@ -455,7 +496,7 @@ class PlayStoreAuthenticatorTest { coEvery { googleLoginManager.login() } returns authData coEvery { userProfileFetcher.fetch(any()) } returns null val authenticator = PlayStoreAuthenticator( val authenticator = playStoreAuthenticator( context = context, sessionRepository = sessionRepository, playStoreAuthStore = sessionRepository, Loading Loading @@ -497,7 +538,7 @@ class PlayStoreAuthenticatorTest { coEvery { googleLoginManager.login() } returns authData coEvery { userProfileFetcher.fetch(any()) } returns null val authenticator = PlayStoreAuthenticator( val authenticator = playStoreAuthenticator( context = context, sessionRepository = sessionRepository, playStoreAuthStore = sessionRepository, Loading Loading @@ -544,7 +585,7 @@ class PlayStoreAuthenticatorTest { coEvery { googleLoginManager.loginWithOauthToken("oauth-token") } returns authData coEvery { userProfileFetcher.fetch(any()) } returns null val authenticator = PlayStoreAuthenticator( val authenticator = playStoreAuthenticator( context = context, sessionRepository = sessionRepository, playStoreAuthStore = sessionRepository, Loading Loading @@ -588,7 +629,7 @@ class PlayStoreAuthenticatorTest { coEvery { microgLoginManager.login() } returns authData coEvery { userProfileFetcher.fetch(any()) } returns null val authenticator = PlayStoreAuthenticator( val authenticator = playStoreAuthenticator( context = context, sessionRepository = sessionRepository, playStoreAuthStore = sessionRepository, Loading Loading @@ -631,7 +672,7 @@ class PlayStoreAuthenticatorTest { coEvery { microgLoginManager.login() } returns authData coEvery { userProfileFetcher.fetch(any()) } returns null val authenticator = PlayStoreAuthenticator( val authenticator = playStoreAuthenticator( context = context, sessionRepository = sessionRepository, playStoreAuthStore = sessionRepository, Loading Loading @@ -666,7 +707,7 @@ class PlayStoreAuthenticatorTest { val anonymousLoginManager = mockk<AnonymousLoginManager>() val successfulLoginNotifier = FakeSuccessfulLoginNotifier() val authenticator = PlayStoreAuthenticator( val authenticator = playStoreAuthenticator( context = applicationContext(), sessionRepository = sessionRepository, playStoreAuthStore = sessionRepository, Loading Loading @@ -705,7 +746,7 @@ class PlayStoreAuthenticatorTest { val anonymousLoginManager = mockk<AnonymousLoginManager>() coEvery { anonymousLoginManager.login() } returns freshAuth val authenticator = PlayStoreAuthenticator( val authenticator = playStoreAuthenticator( context = context, sessionRepository = sessionRepository, playStoreAuthStore = sessionRepository, Loading Loading @@ -741,7 +782,7 @@ class PlayStoreAuthenticatorTest { ) val anonymousLoginManager = mockk<AnonymousLoginManager>() val authenticator = PlayStoreAuthenticator( val authenticator = playStoreAuthenticator( context = context, sessionRepository = sessionRepository, playStoreAuthStore = sessionRepository, Loading Loading @@ -789,7 +830,7 @@ class PlayStoreAuthenticatorTest { val validator = FakePlayStoreAuthValidator() var nowMs = 1_000L val authenticator = PlayStoreAuthenticator( val authenticator = playStoreAuthenticator( context = context, sessionRepository = sessionRepository, playStoreAuthStore = sessionRepository, Loading Loading @@ -833,7 +874,7 @@ class PlayStoreAuthenticatorTest { val validator = FakePlayStoreAuthValidator() var nowMs = 1_000L val authenticator = PlayStoreAuthenticator( val authenticator = playStoreAuthenticator( context = context, sessionRepository = sessionRepository, playStoreAuthStore = sessionRepository, Loading Loading @@ -939,6 +980,25 @@ class PlayStoreAuthenticatorTest { private fun alwaysValidAuthValidator(): PlayStoreAuthValidator = FakePlayStoreAuthValidator() private fun createPlayStoreStoredAuthPolicy( playStoreAuthStore: PlayStoreAuthStore, playStoreAuthValidator: PlayStoreAuthValidator, monotonicClockMs: (() -> Long)? = null, ): PlayStoreStoredAuthPolicy { return if (monotonicClockMs == null) { PlayStoreStoredAuthPolicy( playStoreAuthStore = playStoreAuthStore, playStoreAuthValidator = playStoreAuthValidator, ) } else { PlayStoreStoredAuthPolicy( playStoreAuthStore = playStoreAuthStore, playStoreAuthValidator = playStoreAuthValidator, monotonicClockMs = monotonicClockMs, ) } } private class FakePlayStoreAuthValidator( private val validateBlock: suspend (AuthData) -> PlayStoreAuthValidationResult = { PlayStoreAuthValidationResult.Valid Loading
data/src/test/java/foundation/e/apps/data/login/repository/AuthenticatorRepositoryTest.kt +52 −14 File changed.Preview size limit exceeded, changes collapsed. Show changes