From 70cd688ac245a70a3146e2ac7374f24b0c3453ab Mon Sep 17 00:00:00 2001 From: AntsyLich <59261191+AntsyLich@users.noreply.github.com> Date: Sat, 4 May 2024 16:26:45 +0600 Subject: [PATCH] Trust extension by repo (#570) --- .../java/eu/kanade/domain/DomainModule.kt | 2 +- .../extension/interactor/TrustExtension.kt | 13 ++++---- .../tachiyomi/extension/ExtensionManager.kt | 2 +- .../util/ExtensionInstallReceiver.kt | 33 ++++++++++--------- .../extension/util/ExtensionLoader.kt | 7 ++-- .../browse/extension/ExtensionsScreenModel.kt | 5 ++- 6 files changed, 35 insertions(+), 27 deletions(-) diff --git a/app/src/main/java/eu/kanade/domain/DomainModule.kt b/app/src/main/java/eu/kanade/domain/DomainModule.kt index 48c183a92..4c769f703 100644 --- a/app/src/main/java/eu/kanade/domain/DomainModule.kt +++ b/app/src/main/java/eu/kanade/domain/DomainModule.kt @@ -179,7 +179,7 @@ class DomainModule : InjektModule { addFactory { ToggleLanguage(get()) } addFactory { ToggleSource(get()) } addFactory { ToggleSourcePin(get()) } - addFactory { TrustExtension(get()) } + addFactory { TrustExtension(get(), get()) } addSingletonFactory { ExtensionRepoRepositoryImpl(get()) } addFactory { ExtensionRepoService(get(), get()) } diff --git a/app/src/main/java/eu/kanade/domain/extension/interactor/TrustExtension.kt b/app/src/main/java/eu/kanade/domain/extension/interactor/TrustExtension.kt index c3daec5f8..b4259945d 100644 --- a/app/src/main/java/eu/kanade/domain/extension/interactor/TrustExtension.kt +++ b/app/src/main/java/eu/kanade/domain/extension/interactor/TrustExtension.kt @@ -3,15 +3,18 @@ package eu.kanade.domain.extension.interactor import android.content.pm.PackageInfo import androidx.core.content.pm.PackageInfoCompat import eu.kanade.domain.source.service.SourcePreferences +import mihon.domain.extensionrepo.repository.ExtensionRepoRepository import tachiyomi.core.common.preference.getAndSet class TrustExtension( + private val extensionRepoRepository: ExtensionRepoRepository, private val preferences: SourcePreferences, ) { - fun isTrusted(pkgInfo: PackageInfo, signatureHash: String): Boolean { - val key = "${pkgInfo.packageName}:${PackageInfoCompat.getLongVersionCode(pkgInfo)}:$signatureHash" - return key in preferences.trustedExtensions().get() + suspend fun isTrusted(pkgInfo: PackageInfo, fingerprints: List): Boolean { + val trustedFingerprints = extensionRepoRepository.getAll().map { it.signingKeyFingerprint }.toHashSet() + val key = "${pkgInfo.packageName}:${PackageInfoCompat.getLongVersionCode(pkgInfo)}:${fingerprints.last()}" + return trustedFingerprints.any { fingerprints.contains(it) } || key in preferences.trustedExtensions().get() } fun trust(pkgName: String, versionCode: Long, signatureHash: String) { @@ -19,9 +22,7 @@ class TrustExtension( // Remove previously trusted versions val removed = exts.filterNot { it.startsWith("$pkgName:") }.toMutableSet() - removed.also { - it += "$pkgName:$versionCode:$signatureHash" - } + removed.also { it += "$pkgName:$versionCode:$signatureHash" } } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/extension/ExtensionManager.kt b/app/src/main/java/eu/kanade/tachiyomi/extension/ExtensionManager.kt index 5c5e359c2..968263b5d 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/extension/ExtensionManager.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/extension/ExtensionManager.kt @@ -264,7 +264,7 @@ class ExtensionManager( * * @param extension the extension to trust */ - fun trust(extension: Extension.Untrusted) { + suspend fun trust(extension: Extension.Untrusted) { _untrustedExtensionsMapFlow.value[extension.pkgName] ?: return trustExtension.trust(extension.pkgName, extension.versionCode, extension.signatureHash) diff --git a/app/src/main/java/eu/kanade/tachiyomi/extension/util/ExtensionInstallReceiver.kt b/app/src/main/java/eu/kanade/tachiyomi/extension/util/ExtensionInstallReceiver.kt index be9a60a75..a0ccb23fb 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/extension/util/ExtensionInstallReceiver.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/extension/util/ExtensionInstallReceiver.kt @@ -9,6 +9,9 @@ import androidx.core.content.ContextCompat import eu.kanade.tachiyomi.BuildConfig import eu.kanade.tachiyomi.extension.model.Extension import eu.kanade.tachiyomi.extension.model.LoadResult +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.SupervisorJob +import kotlinx.coroutines.launch import logcat.LogPriority import tachiyomi.core.common.util.system.logcat @@ -20,16 +23,12 @@ import tachiyomi.core.common.util.system.logcat */ internal class ExtensionInstallReceiver(private val listener: Listener) : BroadcastReceiver() { - /** - * Registers this broadcast receiver - */ + val scope = CoroutineScope(SupervisorJob()) + fun register(context: Context) { ContextCompat.registerReceiver(context, this, filter, ContextCompat.RECEIVER_NOT_EXPORTED) } - /** - * Returns the intent filter this receiver should subscribe to. - */ private val filter = IntentFilter().apply { addAction(Intent.ACTION_PACKAGE_ADDED) addAction(Intent.ACTION_PACKAGE_REPLACED) @@ -51,17 +50,21 @@ internal class ExtensionInstallReceiver(private val listener: Listener) : Broadc Intent.ACTION_PACKAGE_ADDED, ACTION_EXTENSION_ADDED -> { if (isReplacing(intent)) return - when (val result = getExtensionFromIntent(context, intent)) { - is LoadResult.Success -> listener.onExtensionInstalled(result.extension) - is LoadResult.Untrusted -> listener.onExtensionUntrusted(result.extension) - else -> {} + scope.launch { + when (val result = getExtensionFromIntent(context, intent)) { + is LoadResult.Success -> listener.onExtensionInstalled(result.extension) + is LoadResult.Untrusted -> listener.onExtensionUntrusted(result.extension) + else -> {} + } } } Intent.ACTION_PACKAGE_REPLACED, ACTION_EXTENSION_REPLACED -> { - when (val result = getExtensionFromIntent(context, intent)) { - is LoadResult.Success -> listener.onExtensionUpdated(result.extension) - is LoadResult.Untrusted -> listener.onExtensionUntrusted(result.extension) - else -> {} + scope.launch { + when (val result = getExtensionFromIntent(context, intent)) { + is LoadResult.Success -> listener.onExtensionUpdated(result.extension) + is LoadResult.Untrusted -> listener.onExtensionUntrusted(result.extension) + else -> {} + } } } Intent.ACTION_PACKAGE_REMOVED, ACTION_EXTENSION_REMOVED -> { @@ -90,7 +93,7 @@ internal class ExtensionInstallReceiver(private val listener: Listener) : Broadc * @param context The application context. * @param intent The intent containing the package name of the extension. */ - private fun getExtensionFromIntent(context: Context, intent: Intent?): LoadResult { + private suspend fun getExtensionFromIntent(context: Context, intent: Intent?): LoadResult { val pkgName = getPackageNameFromIntent(intent) if (pkgName == null) { logcat(LogPriority.WARN) { "Package name not found" } diff --git a/app/src/main/java/eu/kanade/tachiyomi/extension/util/ExtensionLoader.kt b/app/src/main/java/eu/kanade/tachiyomi/extension/util/ExtensionLoader.kt index 0468c45e5..50ab94279 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/extension/util/ExtensionLoader.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/extension/util/ExtensionLoader.kt @@ -172,7 +172,7 @@ internal object ExtensionLoader { * Attempts to load an extension from the given package name. It checks if the extension * contains the required feature flag before trying to load it. */ - fun loadExtensionFromPkgName(context: Context, pkgName: String): LoadResult { + suspend fun loadExtensionFromPkgName(context: Context, pkgName: String): LoadResult { val extensionPackage = getExtensionInfoFromPkgName(context, pkgName) if (extensionPackage == null) { logcat(LogPriority.ERROR) { "Extension package is not found ($pkgName)" } @@ -223,7 +223,8 @@ internal object ExtensionLoader { * @param context The application context. * @param extensionInfo The extension to load. */ - private fun loadExtension(context: Context, extensionInfo: ExtensionInfo): LoadResult { + @Suppress("LongMethod", "CyclomaticComplexMethod", "ReturnCount") + private suspend fun loadExtension(context: Context, extensionInfo: ExtensionInfo): LoadResult { val pkgManager = context.packageManager val pkgInfo = extensionInfo.packageInfo val appInfo = pkgInfo.applicationInfo @@ -252,7 +253,7 @@ internal object ExtensionLoader { if (signatures.isNullOrEmpty()) { logcat(LogPriority.WARN) { "Package $pkgName isn't signed" } return LoadResult.Error - } else if (!trustExtension.isTrusted(pkgInfo, signatures.last())) { + } else if (!trustExtension.isTrusted(pkgInfo, signatures)) { val extension = Extension.Untrusted( extName, pkgName, diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/extension/ExtensionsScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/extension/ExtensionsScreenModel.kt index e71d65997..feb69c5ce 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/extension/ExtensionsScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/extension/ExtensionsScreenModel.kt @@ -27,6 +27,7 @@ import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onCompletion import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.update +import kotlinx.coroutines.launch import tachiyomi.core.common.util.lang.launchIO import tachiyomi.i18n.MR import uy.kohesive.injekt.Injekt @@ -196,7 +197,9 @@ class ExtensionsScreenModel( } fun trustExtension(extension: Extension.Untrusted) { - extensionManager.trust(extension) + screenModelScope.launch { + extensionManager.trust(extension) + } } @Immutable