diff --git a/app/src/main/java/com/aurora/store/data/providers/AuthProvider.kt b/app/src/main/java/com/aurora/store/data/providers/AuthProvider.kt index bf7480d63..4e012b6ad 100644 --- a/app/src/main/java/com/aurora/store/data/providers/AuthProvider.kt +++ b/app/src/main/java/com/aurora/store/data/providers/AuthProvider.kt @@ -21,17 +21,25 @@ package com.aurora.store.data.providers import android.content.Context import com.aurora.Constants +import com.aurora.Constants.ACCOUNT_SIGNED_IN import com.aurora.gplayapi.data.models.AuthData +import com.aurora.gplayapi.helpers.AuthHelper import com.aurora.gplayapi.helpers.AuthValidator +import com.aurora.store.R import com.aurora.store.data.model.AccountType +import com.aurora.store.data.model.Auth import com.aurora.store.data.network.HttpClient import com.aurora.store.util.Log import com.aurora.store.util.Preferences import com.aurora.store.util.Preferences.PREFERENCE_AUTH_DATA +import com.aurora.store.util.Preferences.PREFERENCE_DISPENSER_URLS +import com.aurora.store.util.Preferences.PREFERENCE_VENDING_VERSION import com.google.gson.Gson import dagger.hilt.android.qualifiers.ApplicationContext import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext +import java.util.Locale +import java.util.Properties import javax.inject.Inject import javax.inject.Singleton @@ -41,6 +49,30 @@ class AuthProvider @Inject constructor( private val gson: Gson ) { + private val spoofProvider: SpoofProvider get() = SpoofProvider(context) + val properties: Properties + get() { + val currentProperties = if (spoofProvider.isDeviceSpoofEnabled()) { + spoofProvider.getSpoofDeviceProperties() + } else { + NativeDeviceInfoProvider(context).getNativeDeviceProperties() + } + setVendingVersion(currentProperties) + return currentProperties + } + val locale: Locale + get() = if (spoofProvider.isLocaleSpoofEnabled()) { + spoofProvider.getSpoofLocale() + } else { + Locale.getDefault() + } + + val dispenserURL: String? + get() { + val dispensers = Preferences.getStringSet(context, PREFERENCE_DISPENSER_URLS) + return if (dispensers.isNotEmpty()) dispensers.random() else null + } + val authData: AuthData? get() = getSavedAuthData() val isAnonymous: Boolean @@ -49,6 +81,23 @@ class AuthProvider @Inject constructor( return AccountType.valueOf(name) == AccountType.ANONYMOUS } + private val signedIn: Boolean + get() = Preferences.getBoolean(context, ACCOUNT_SIGNED_IN) + + /** + * Builds and returns AuthData based on signed-in account type + */ + suspend fun getTmpAuthData(): AuthData? { + return when { + !signedIn -> null + !isAnonymous -> buildGoogleAuthData() + else -> buildAnonymousAuthData() + } + } + + /** + * Checks whether saved AuthData is valid or not + */ suspend fun isSavedAuthDataValid(): Boolean { return withContext(Dispatchers.IO) { try { @@ -70,4 +119,59 @@ class AuthProvider @Inject constructor( null } } + + private suspend fun buildGoogleAuthData(): AuthData? { + return withContext(Dispatchers.IO) { + try { + val email = Preferences.getString(context, Constants.ACCOUNT_EMAIL_PLAIN) + val aasToken = Preferences.getString(context, Constants.ACCOUNT_AAS_PLAIN) + + return@withContext AuthHelper.build( + email = email, + token = aasToken, + tokenType = AuthHelper.Token.AAS, + properties = properties, + locale = locale + ) + } catch (exception: Exception) { + Log.e("Failed to generate Session", exception) + return@withContext null + } + } + } + + private suspend fun buildAnonymousAuthData(): AuthData? { + return withContext(Dispatchers.IO) { + try { + val playResponse = HttpClient + .getPreferredClient(context) + .getAuth(dispenserURL!!) + + val auth = gson.fromJson(String(playResponse.responseBytes), Auth::class.java) + return@withContext AuthHelper.build( + email = auth.email, + token = auth.auth, + tokenType = AuthHelper.Token.AUTH, + isAnonymous = true, + properties = properties, + locale = locale + ) + } catch (exception: Exception) { + Log.e("Failed to generate AuthData", exception) + return@withContext null + } + } + } + + private fun setVendingVersion(currentProperties: Properties) { + val vendingVersionIndex = Preferences.getInteger(context, PREFERENCE_VENDING_VERSION) + if (vendingVersionIndex > 0) { + val resources = context.resources + val versionCodes = resources.getStringArray(R.array.pref_vending_version_codes) + val versionStrings = resources.getStringArray(R.array.pref_vending_version) + + currentProperties.setProperty("Vending.version", versionCodes[vendingVersionIndex]) + currentProperties.setProperty("Vending.versionString", versionStrings[vendingVersionIndex]) + } + } } diff --git a/app/src/main/java/com/aurora/store/data/work/UpdateWorker.kt b/app/src/main/java/com/aurora/store/data/work/UpdateWorker.kt index d5c1327bc..4f7a359e3 100644 --- a/app/src/main/java/com/aurora/store/data/work/UpdateWorker.kt +++ b/app/src/main/java/com/aurora/store/data/work/UpdateWorker.kt @@ -121,13 +121,19 @@ class UpdateWorker @AssistedInject constructor( } withContext(Dispatchers.IO) { - if (!authProvider.isSavedAuthDataValid()) { + val authData = if (authProvider.isSavedAuthDataValid()) { + authProvider.authData + } else { + authProvider.getTmpAuthData() + } + + if (authData == null) { Log.i(TAG, "AuthData is not valid, retrying later!") return@withContext Result.retry() } try { - val updatesList = appUtil.checkUpdates() + val updatesList = appUtil.checkUpdates(authData) .filter { it.hasValidCert } .filterNot { it.isSelfUpdate() } diff --git a/app/src/main/java/com/aurora/store/util/AppUtil.kt b/app/src/main/java/com/aurora/store/util/AppUtil.kt index e24306a8a..48ef4da6a 100644 --- a/app/src/main/java/com/aurora/store/util/AppUtil.kt +++ b/app/src/main/java/com/aurora/store/util/AppUtil.kt @@ -6,6 +6,7 @@ import android.util.Log import androidx.core.content.pm.PackageInfoCompat import com.aurora.Constants import com.aurora.gplayapi.data.models.App +import com.aurora.gplayapi.data.models.AuthData import com.aurora.gplayapi.helpers.AppDetailsHelper import com.aurora.store.AuroraApp import com.aurora.store.BuildConfig @@ -43,17 +44,18 @@ class AppUtil @Inject constructor( .map { list -> if (!isExtendedUpdateEnabled) list.filter { it.hasValidCert } else list } .stateIn(AuroraApp.scope, SharingStarted.WhileSubscribed(), null) - suspend fun checkUpdates(): List { + suspend fun checkUpdates(tmpAuthData: AuthData? = null): List { Log.i(TAG, "Checking for updates") val packageInfoMap = PackageUtil.getPackageInfoMap(context) - val appUpdatesList = getFilteredInstalledApps(packageInfoMap).filter { - val packageInfo = packageInfoMap[it.packageName] - if (packageInfo != null) { - it.versionCode.toLong() > PackageInfoCompat.getLongVersionCode(packageInfo) - } else { - false - } - }.toMutableList() + val appUpdatesList = getFilteredInstalledApps(tmpAuthData, packageInfoMap) + .filter { + val packageInfo = packageInfoMap[it.packageName] + if (packageInfo != null) { + it.versionCode.toLong() > PackageInfoCompat.getLongVersionCode(packageInfo) + } else { + false + } + }.toMutableList() if (canSelfUpdate(context)) { getSelfUpdate(context, gson)?.let { appUpdatesList.add(it) } @@ -70,10 +72,11 @@ class AppUtil @Inject constructor( } suspend fun getFilteredInstalledApps( + tmpAuthData: AuthData? = null, packageInfoMap: MutableMap? = null ): List { return withContext(Dispatchers.IO) { - val appDetailsHelper = AppDetailsHelper(authProvider.authData!!) + val appDetailsHelper = AppDetailsHelper(tmpAuthData?: authProvider.authData!!) .using(HttpClient.getPreferredClient(context)) (packageInfoMap ?: PackageUtil.getPackageInfoMap(context)).keys.let { packages -> diff --git a/app/src/main/java/com/aurora/store/view/ui/splash/SplashFragment.kt b/app/src/main/java/com/aurora/store/view/ui/splash/SplashFragment.kt index 56cff652e..2678f00c0 100644 --- a/app/src/main/java/com/aurora/store/view/ui/splash/SplashFragment.kt +++ b/app/src/main/java/com/aurora/store/view/ui/splash/SplashFragment.kt @@ -79,7 +79,7 @@ class SplashFragment : BaseFragment() { attachActions() // Show anonymous logins if we have dispenser URL - if (!viewModel.dispenserURL.isNullOrBlank()) { + if (!viewModel.authProvider.dispenserURL.isNullOrBlank()) { binding.btnAnonymous.visibility = View.VISIBLE } diff --git a/app/src/main/java/com/aurora/store/viewmodel/auth/AuthViewModel.kt b/app/src/main/java/com/aurora/store/viewmodel/auth/AuthViewModel.kt index 30342380d..ed92a14d1 100644 --- a/app/src/main/java/com/aurora/store/viewmodel/auth/AuthViewModel.kt +++ b/app/src/main/java/com/aurora/store/viewmodel/auth/AuthViewModel.kt @@ -38,12 +38,9 @@ import com.aurora.store.data.model.AuthState import com.aurora.store.data.network.HttpClient import com.aurora.store.data.providers.AccountProvider import com.aurora.store.data.providers.AuthProvider -import com.aurora.store.data.providers.NativeDeviceInfoProvider -import com.aurora.store.data.providers.SpoofProvider import com.aurora.store.util.AC2DMTask import com.aurora.store.util.Preferences import com.aurora.store.util.Preferences.PREFERENCE_AUTH_DATA -import com.aurora.store.util.Preferences.PREFERENCE_DISPENSER_URLS import com.google.gson.Gson import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.qualifiers.ApplicationContext @@ -52,44 +49,18 @@ import kotlinx.coroutines.launch import kotlinx.coroutines.supervisorScope import java.net.ConnectException import java.net.UnknownHostException -import java.util.Locale -import java.util.Properties import javax.inject.Inject @HiltViewModel @SuppressLint("StaticFieldLeak") // false positive, see https://github.com/google/dagger/issues/3253 class AuthViewModel @Inject constructor( + val authProvider: AuthProvider, @ApplicationContext private val context: Context, - private val gson: Gson, - private val authProvider: AuthProvider + private val gson: Gson ) : ViewModel() { private val TAG = AuthViewModel::class.java.simpleName - private val spoofProvider: SpoofProvider get() = SpoofProvider(context) - val properties: Properties - get() { - val currentProperties = if (spoofProvider.isDeviceSpoofEnabled()) { - spoofProvider.getSpoofDeviceProperties() - } else { - NativeDeviceInfoProvider(context).getNativeDeviceProperties() - } - setVendingVersion(currentProperties) - return currentProperties - } - val locale: Locale - get() = if (spoofProvider.isLocaleSpoofEnabled()) { - spoofProvider.getSpoofLocale() - } else { - Locale.getDefault() - } - - val dispenserURL: String? - get() { - val dispensers = Preferences.getStringSet(context, PREFERENCE_DISPENSER_URLS) - return if (dispensers.isNotEmpty()) dispensers.random() else null - } - val liveData: MutableLiveData = MutableLiveData() fun observe() { @@ -112,8 +83,8 @@ class AuthViewModel @Inject constructor( email = email, token = aasToken, tokenType = AuthHelper.Token.AAS, - properties = properties, - locale = locale + properties = authProvider.properties, + locale = authProvider.locale ) verifyAndSaveAuth(authData, AccountType.GOOGLE) } catch (exception: Exception) { @@ -131,7 +102,7 @@ class AuthViewModel @Inject constructor( try { val playResponse = HttpClient .getPreferredClient(context) - .getAuth(dispenserURL!!) + .getAuth(authProvider.dispenserURL!!) if (playResponse.isSuccessful) { val tmpAuthData = gson.fromJson( @@ -144,8 +115,8 @@ class AuthViewModel @Inject constructor( token = tmpAuthData.auth, tokenType = AuthHelper.Token.AUTH, isAnonymous = true, - properties = properties, - locale = locale + properties = authProvider.properties, + locale = authProvider.locale ) verifyAndSaveAuth(authData, AccountType.ANONYMOUS) } else { @@ -245,18 +216,6 @@ class AuthViewModel @Inject constructor( } } - private fun setVendingVersion(currentProperties: Properties) { - val vendingVersionIndex = Preferences.getInteger(context, Preferences.PREFERENCE_VENDING_VERSION) - if (vendingVersionIndex > 0) { - val resources = context.resources - val versionCodes = resources.getStringArray(R.array.pref_vending_version_codes) - val versionStrings = resources.getStringArray(R.array.pref_vending_version) - - currentProperties.setProperty("Vending.version", versionCodes[vendingVersionIndex]) - currentProperties.setProperty("Vending.versionString", versionStrings[vendingVersionIndex]) - } - } - private fun configAuthPref(authData: AuthData, type: AccountType, signedIn: Boolean) { if (signedIn) { //Save Auth Data