UpdateWorker: Try to build and use tmp AuthData if required
Users can skip opening Aurora Store for a long time after setting it once. They expect the auto-updates to continue working without any intervention. However, authdata can get expired over time. Try to build temp authdata and use it to check for updates without saving it in such cases. Signed-off-by: Aayush Gupta <aayushgupta219@gmail.com>
This commit is contained in:
@@ -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])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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() }
|
||||
|
||||
|
||||
@@ -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<Update> {
|
||||
suspend fun checkUpdates(tmpAuthData: AuthData? = null): List<Update> {
|
||||
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<String, PackageInfo>? = null
|
||||
): List<App> {
|
||||
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 ->
|
||||
|
||||
@@ -79,7 +79,7 @@ class SplashFragment : BaseFragment<FragmentSplashBinding>() {
|
||||
attachActions()
|
||||
|
||||
// Show anonymous logins if we have dispenser URL
|
||||
if (!viewModel.dispenserURL.isNullOrBlank()) {
|
||||
if (!viewModel.authProvider.dispenserURL.isNullOrBlank()) {
|
||||
binding.btnAnonymous.visibility = View.VISIBLE
|
||||
}
|
||||
|
||||
|
||||
@@ -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<AuthState> = 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
|
||||
|
||||
Reference in New Issue
Block a user