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

Commit 5c73c6d0 authored by Hasib Prince's avatar Hasib Prince
Browse files

Merge branch '6607-skip_initial_login_validation' into 'main'

6607 skip initial login validation

See merge request !282
parents 91221af4 2099d3ca
Loading
Loading
Loading
Loading
Loading
+20 −1
Original line number Diff line number Diff line
@@ -56,6 +56,7 @@ import foundation.e.apps.utils.eventBus.EventBus
import foundation.e.apps.utils.exceptions.GPlayValidationException
import foundation.e.apps.utils.modules.CommonUtilsFunctions
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.launch
import timber.log.Timber
@@ -130,7 +131,10 @@ class MainActivity : AppCompatActivity() {
                    viewModel.gPlayAuthData = data as AuthData
                } else if (exception is GPlayValidationException) {
                    val email = otherPayload.toString()
                    viewModel.uploadFaultyTokenToEcloud(email, CommonUtilsFunctions.getAppBuildInfo())
                    viewModel.uploadFaultyTokenToEcloud(
                        email,
                        CommonUtilsFunctions.getAppBuildInfo()
                    )
                }
            }
        }
@@ -213,6 +217,8 @@ class MainActivity : AppCompatActivity() {
        viewModel.updateAppWarningList()

        lifecycleScope.launchWhenResumed {
            observeInvalidAuth()

            EventBus.events.filter { appEvent ->
                appEvent is AppEvent.SignatureMissMatchError
            }.collectLatest {
@@ -226,6 +232,19 @@ class MainActivity : AppCompatActivity() {
        }
    }

    private suspend fun observeInvalidAuth() {
        EventBus.events.filter { appEvent ->
            appEvent is AppEvent.InvalidAuthEvent
        }.distinctUntilChanged { old, new ->
            ((old.data is String) && (new.data is String) && old.data == new.data)
        }.collectLatest {
            val data = it.data as String
            if (data.isNotBlank()) {
                loginViewModel.markInvalidAuthObject(data)
            }
        }
    }

    private fun setupBottomNavItemSelectedListener(
        bottomNavigationView: BottomNavigationView,
        navHostFragment: NavHostFragment,
+16 −1
Original line number Diff line number Diff line
@@ -21,7 +21,12 @@ package foundation.e.apps.api.gplay.utils

import com.aurora.gplayapi.data.models.PlayResponse
import com.aurora.gplayapi.network.IHttpClient
import foundation.e.apps.login.AuthObject
import foundation.e.apps.utils.eventBus.AppEvent
import foundation.e.apps.utils.eventBus.EventBus
import foundation.e.apps.utils.modules.CommonUtilsFunctions
import kotlinx.coroutines.MainScope
import kotlinx.coroutines.launch
import okhttp3.Cache
import okhttp3.Headers.Companion.toHeaders
import okhttp3.HttpUrl
@@ -39,7 +44,7 @@ import java.net.UnknownHostException
import javax.inject.Inject

class GPlayHttpClient @Inject constructor(
    cache: Cache
    cache: Cache,
) : IHttpClient {

    private val POST = "POST"
@@ -178,6 +183,16 @@ class GPlayHttpClient @Inject constructor(
            isSuccessful = response.isSuccessful
            code = response.code

            Timber.d("$TAG: Url: ${response.request.url}\nStatus: $code")

            if (code == 401) {
                MainScope().launch {
                    EventBus.invokeEvent(
                        AppEvent.InvalidAuthEvent(AuthObject.GPlayAuth::class.java.simpleName)
                    )
                }
            }

            if (response.body != null) {
                responseBytes = response.body!!.bytes()
            }
+1 −0
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@ import foundation.e.apps.login.LoginSourceInterface
@InstallIn(SingletonComponent::class)
@Module
object LoginModule {

    @Provides
    fun providesLoginSources(
        gPlay: LoginSourceGPlay,
+17 −10
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@ import foundation.e.apps.login.api.GPlayApiFactory
import foundation.e.apps.login.api.GPlayLoginInterface
import foundation.e.apps.login.api.GoogleLoginApi
import foundation.e.apps.login.api.LoginApiRepository
import foundation.e.apps.utils.enums.ResultStatus
import foundation.e.apps.utils.enums.User
import foundation.e.apps.utils.exceptions.GPlayValidationException
import java.util.Locale
@@ -86,13 +87,19 @@ class LoginSourceGPlay @Inject constructor(
            }
            )

        // validate authData and save it if nothing is saved (first time use.)
        validateAuthData(authData).run {
            if (isSuccess() && savedAuth == null) {
                saveAuthData(authData)
            }
            return AuthObject.GPlayAuth(this, user)
        val formattedAuthData = formatAuthData(authData)
        formattedAuthData.locale = locale
        val result: ResultSupreme<AuthData?> = ResultSupreme.create(
            status = ResultStatus.OK,
            data = formattedAuthData
        )
        result.otherPayload = formattedAuthData.email

        if (savedAuth == null) {
            saveAuthData(formattedAuthData)
        }

        return AuthObject.GPlayAuth(result, user)
    }

    override suspend fun clearSavedAuth() {
@@ -139,7 +146,7 @@ class LoginSourceGPlay @Inject constructor(
     * Aurora OSS GPlay API complains of missing headers sometimes.
     * Converting [authData] to Json and back to [AuthData] fixed it.
     */
    private fun formattedAuthData(authData: AuthData): AuthData {
    private fun formatAuthData(authData: AuthData): AuthData {
        val localAuthDataJson = gson.toJson(authData)
        return gson.fromJson(localAuthDataJson, AuthData::class.java)
    }
@@ -149,7 +156,7 @@ class LoginSourceGPlay @Inject constructor(
     */
    private suspend fun getAuthData(): ResultSupreme<AuthData?> {
        return loginApiRepository.fetchAuthData("", "", locale).run {
            if (isSuccess()) ResultSupreme.Success(formattedAuthData(this.data!!))
            if (isSuccess()) ResultSupreme.Success(formatAuthData(this.data!!))
            else this
        }
    }
@@ -200,7 +207,7 @@ class LoginSourceGPlay @Inject constructor(
         */
        loginDataStore.saveAasToken(aasTokenFetched)
        return loginApiRepository.fetchAuthData(email, aasTokenFetched, locale).run {
            if (isSuccess()) ResultSupreme.Success(formattedAuthData(this.data!!))
            if (isSuccess()) ResultSupreme.Success(formatAuthData(this.data!!))
            else this
        }
    }
@@ -214,7 +221,7 @@ class LoginSourceGPlay @Inject constructor(
        authData: AuthData,
    ): ResultSupreme<AuthData?> {

        val formattedAuthData = formattedAuthData(authData)
        val formattedAuthData = formatAuthData(authData)
        formattedAuthData.locale = locale

        val validityResponse = loginApiRepository.login(formattedAuthData)
+64 −0
Original line number Diff line number Diff line
@@ -20,8 +20,13 @@ package foundation.e.apps.login
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.aurora.gplayapi.data.models.AuthData
import dagger.hilt.android.lifecycle.HiltViewModel
import foundation.e.apps.api.ResultSupreme
import foundation.e.apps.utils.enums.User
import foundation.e.apps.utils.exceptions.CleanApkException
import foundation.e.apps.utils.exceptions.GPlayValidationException
import foundation.e.apps.utils.parentFragment.LoadingViewModel
import kotlinx.coroutines.launch
import javax.inject.Inject

@@ -99,6 +104,65 @@ class LoginViewModel @Inject constructor(
        }
    }

    /**
     * Once an AuthObject is marked as invalid, it will be refreshed
     * automatically by LoadingViewModel.
     * If GPlay auth is invalid, [LoadingViewModel.onLoadData] has a retry block,
     * this block will clear existing GPlay AuthData and freshly start the login flow.
     */
    fun markInvalidAuthObject(authObjectName: String) {
        val authObjectsLocal = authObjects.value?.toMutableList()
        val invalidObject = authObjectsLocal?.find { it::class.java.simpleName == authObjectName }

        val replacedObject = when (invalidObject) {
            is AuthObject.GPlayAuth -> {
                createInvalidGplayAuth(invalidObject)
            }
            is AuthObject.CleanApk ->
                createInvalidCleanApkAuth(invalidObject)
            else -> null
        }

        authObjectsLocal?.apply {
            if (invalidObject != null && replacedObject != null) {
                remove(invalidObject)
                add(replacedObject)
            }
        }

        authObjects.postValue(authObjectsLocal)
    }

    private fun createInvalidCleanApkAuth(invalidObject: AuthObject.CleanApk) =
        AuthObject.CleanApk(
            ResultSupreme.Error(
                message = "Unauthorized",
                exception = CleanApkException(
                    isTimeout = false,
                    message = "Unauthorized",
                )
            ),
            invalidObject.user,
        )

    private fun createInvalidGplayAuth(invalidObject: AuthObject.GPlayAuth): AuthObject.GPlayAuth {
        val message = "Validating AuthData failed.\nNetwork code: 401"

        return AuthObject.GPlayAuth(
            ResultSupreme.Error<AuthData?>(
                message = message,
                exception = GPlayValidationException(
                    message,
                    invalidObject.user,
                    401,
                )
            ).apply {
                otherPayload = invalidObject.result.otherPayload
            },
            invalidObject.user,
        )
    }

    /**
     * Clears all saved data and logs out the user to the sign in screen.
     */
Loading