Loading app/src/main/java/foundation/e/apps/data/updates/UpdatesManagerImpl.kt +60 −22 Original line number Diff line number Diff line Loading @@ -35,6 +35,8 @@ import foundation.e.apps.data.install.pkg.AppLoungePackageManager import foundation.e.apps.domain.model.install.Status import foundation.e.apps.domain.preferences.AppPreferencesRepository import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.async import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.withContext import timber.log.Timber import javax.inject.Inject Loading Loading @@ -311,33 +313,41 @@ class UpdatesManagerImpl @Inject constructor( private suspend fun getFDroidAppsAndSignatures( installedPackageNames: List<String>, cleanApkAppsByPackage: Map<String, Application?>, ): Map<String, String> { ): Map<String, String> = coroutineScope { val appsAndSignatures = hashMapOf<String, String>() for (packageName in installedPackageNames) { updateAppsWithPGPSignature(packageName, appsAndSignatures, cleanApkAppsByPackage) val candidates = installedPackageNames.map { packageName -> async { packageName to updateAppsWithPGPSignature(packageName, cleanApkAppsByPackage) } return appsAndSignatures } candidates.forEach { deferred -> val (packageName, signature) = deferred.await() if (signature != null) { appsAndSignatures[packageName] = signature } } return@coroutineScope appsAndSignatures } private suspend fun updateAppsWithPGPSignature( packageName: String, appsAndSignatures: HashMap<String, String>, cleanApkAppsByPackage: Map<String, Application?>, ) { ): String? { val cleanApkApplication = cleanApkAppsByPackage[packageName] val apps = when { cleanApkApplication != null -> listOf(cleanApkApplication) cleanApkAppsByPackage.containsKey(packageName) -> emptyList() else -> applicationRepository.getApplicationDetails(listOf(packageName), Source.OPEN_SOURCE).first } if (apps.isEmpty()) { return val app = apps.firstOrNull()?.takeIf { it.package_name.isNotBlank() } val signature = if (app == null) { null } else { val pgpSignature = getPgpSignature(app) pgpSignature } if (apps[0].package_name.isBlank()) { return } appsAndSignatures[packageName] = getPgpSignature(apps[0]) return signature } private suspend fun getPgpSignature(cleanApkApplication: Application): String { Loading Loading @@ -371,23 +381,51 @@ class UpdatesManagerImpl @Inject constructor( private suspend fun findPackagesMatchingFDroidSignatures( installedPackageNames: List<String>, cleanApkAppsByPackage: Map<String, Application?>, ): List<String> { ): List<String> = coroutineScope { val fDroidAppsAndSignatures = getFDroidAppsAndSignatures( installedPackageNames, cleanApkAppsByPackage, ) val fDroidUpdatablePackageNames = fDroidAppsAndSignatures.filter { if (it.value.isEmpty()) return@filter false val fDroidUpdatablePackageNames = mutableListOf<String>() val verificationTasks = fDroidAppsAndSignatures.mapNotNull { (packageName, signature) -> if (signature.isEmpty()) { return@mapNotNull null } // For each installed app also present on F-droid, check signature of base APK. val baseApkPath = appLoungePackageManager.getBaseApkPath(it.key) if (baseApkPath.isEmpty()) return@filter false async { verifyFdroidSignatureCandidate(packageName, signature) } } verificationTasks.forEach { deferred -> val (packageName, verified) = deferred.await() if (verified) { fDroidUpdatablePackageNames.add(packageName) } } ApkSignatureManager.verifyFdroidSignature(context, baseApkPath, it.value, it.key) }.map { it.key } return@coroutineScope fDroidUpdatablePackageNames } return fDroidUpdatablePackageNames private suspend fun verifyFdroidSignatureCandidate( packageName: String, signature: String, ): Pair<String, Boolean> { val baseApkPath = appLoungePackageManager.getBaseApkPath(packageName) if (baseApkPath.isEmpty()) { return Pair(packageName, false) } val verified = withContext(Dispatchers.IO) { ApkSignatureManager.verifyFdroidSignature( context, baseApkPath, signature, packageName, ) } return Pair(packageName, verified) } private suspend fun getCleanApkDetailsByPackage( Loading Loading
app/src/main/java/foundation/e/apps/data/updates/UpdatesManagerImpl.kt +60 −22 Original line number Diff line number Diff line Loading @@ -35,6 +35,8 @@ import foundation.e.apps.data.install.pkg.AppLoungePackageManager import foundation.e.apps.domain.model.install.Status import foundation.e.apps.domain.preferences.AppPreferencesRepository import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.async import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.withContext import timber.log.Timber import javax.inject.Inject Loading Loading @@ -311,33 +313,41 @@ class UpdatesManagerImpl @Inject constructor( private suspend fun getFDroidAppsAndSignatures( installedPackageNames: List<String>, cleanApkAppsByPackage: Map<String, Application?>, ): Map<String, String> { ): Map<String, String> = coroutineScope { val appsAndSignatures = hashMapOf<String, String>() for (packageName in installedPackageNames) { updateAppsWithPGPSignature(packageName, appsAndSignatures, cleanApkAppsByPackage) val candidates = installedPackageNames.map { packageName -> async { packageName to updateAppsWithPGPSignature(packageName, cleanApkAppsByPackage) } return appsAndSignatures } candidates.forEach { deferred -> val (packageName, signature) = deferred.await() if (signature != null) { appsAndSignatures[packageName] = signature } } return@coroutineScope appsAndSignatures } private suspend fun updateAppsWithPGPSignature( packageName: String, appsAndSignatures: HashMap<String, String>, cleanApkAppsByPackage: Map<String, Application?>, ) { ): String? { val cleanApkApplication = cleanApkAppsByPackage[packageName] val apps = when { cleanApkApplication != null -> listOf(cleanApkApplication) cleanApkAppsByPackage.containsKey(packageName) -> emptyList() else -> applicationRepository.getApplicationDetails(listOf(packageName), Source.OPEN_SOURCE).first } if (apps.isEmpty()) { return val app = apps.firstOrNull()?.takeIf { it.package_name.isNotBlank() } val signature = if (app == null) { null } else { val pgpSignature = getPgpSignature(app) pgpSignature } if (apps[0].package_name.isBlank()) { return } appsAndSignatures[packageName] = getPgpSignature(apps[0]) return signature } private suspend fun getPgpSignature(cleanApkApplication: Application): String { Loading Loading @@ -371,23 +381,51 @@ class UpdatesManagerImpl @Inject constructor( private suspend fun findPackagesMatchingFDroidSignatures( installedPackageNames: List<String>, cleanApkAppsByPackage: Map<String, Application?>, ): List<String> { ): List<String> = coroutineScope { val fDroidAppsAndSignatures = getFDroidAppsAndSignatures( installedPackageNames, cleanApkAppsByPackage, ) val fDroidUpdatablePackageNames = fDroidAppsAndSignatures.filter { if (it.value.isEmpty()) return@filter false val fDroidUpdatablePackageNames = mutableListOf<String>() val verificationTasks = fDroidAppsAndSignatures.mapNotNull { (packageName, signature) -> if (signature.isEmpty()) { return@mapNotNull null } // For each installed app also present on F-droid, check signature of base APK. val baseApkPath = appLoungePackageManager.getBaseApkPath(it.key) if (baseApkPath.isEmpty()) return@filter false async { verifyFdroidSignatureCandidate(packageName, signature) } } verificationTasks.forEach { deferred -> val (packageName, verified) = deferred.await() if (verified) { fDroidUpdatablePackageNames.add(packageName) } } ApkSignatureManager.verifyFdroidSignature(context, baseApkPath, it.value, it.key) }.map { it.key } return@coroutineScope fDroidUpdatablePackageNames } return fDroidUpdatablePackageNames private suspend fun verifyFdroidSignatureCandidate( packageName: String, signature: String, ): Pair<String, Boolean> { val baseApkPath = appLoungePackageManager.getBaseApkPath(packageName) if (baseApkPath.isEmpty()) { return Pair(packageName, false) } val verified = withContext(Dispatchers.IO) { ApkSignatureManager.verifyFdroidSignature( context, baseApkPath, signature, packageName, ) } return Pair(packageName, verified) } private suspend fun getCleanApkDetailsByPackage( Loading