Skip to content

Commit 11e6666

Browse files
null2264AntsyLich
andcommitted
feat: Trust extension by repo
Co-authored-by: AntsyLich <[email protected]>
1 parent 2e2844a commit 11e6666

File tree

10 files changed

+70
-57
lines changed

10 files changed

+70
-57
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,11 @@
99
-->
1010
Please backup your data before updating to this version.
1111

12+
## Additions
13+
- Extensions now can be trusted by repo
14+
15+
## Changes
16+
- Extensions now required to have `repo.json`
17+
1218
## Other
1319
- Migrate to SQLDelight

app/src/main/java/dev/yokai/core/di/AppModule.kt

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import app.cash.sqldelight.driver.android.AndroidSqliteDriver
88
import dev.yokai.data.AndroidDatabaseHandler
99
import dev.yokai.data.DatabaseHandler
1010
import dev.yokai.domain.SplashState
11-
import dev.yokai.domain.extension.TrustExtension
11+
import dev.yokai.domain.extension.interactor.TrustExtension
1212
import dev.yokai.domain.storage.StorageManager
1313
import eu.kanade.tachiyomi.core.storage.AndroidStorageFolderProvider
1414
import eu.kanade.tachiyomi.data.cache.ChapterCache
@@ -124,8 +124,6 @@ class AppModule(val app: Application) : InjektModule {
124124

125125
addSingletonFactory { MangaShortcutManager() }
126126

127-
addSingletonFactory { TrustExtension() }
128-
129127
addSingletonFactory { AndroidStorageFolderProvider(app) }
130128
addSingletonFactory { StorageManager(app, get()) }
131129

app/src/main/java/dev/yokai/core/di/DomainModule.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package dev.yokai.core.di
22

33
import dev.yokai.domain.extension.repo.ExtensionRepoRepository
44
import dev.yokai.data.extension.repo.ExtensionRepoRepositoryImpl
5+
import dev.yokai.domain.extension.interactor.TrustExtension
56
import dev.yokai.domain.extension.repo.interactor.CreateExtensionRepo
67
import dev.yokai.domain.extension.repo.interactor.DeleteExtensionRepo
78
import dev.yokai.domain.extension.repo.interactor.GetExtensionRepo
@@ -23,5 +24,7 @@ class DomainModule : InjektModule {
2324
addFactory { GetExtensionRepoCount(get()) }
2425
addFactory { ReplaceExtensionRepo(get()) }
2526
addFactory { UpdateExtensionRepo(get(), get()) }
27+
28+
addFactory { TrustExtension(get(), get()) }
2629
}
2730
}

app/src/main/java/dev/yokai/domain/extension/TrustExtension.kt

Lines changed: 0 additions & 29 deletions
This file was deleted.
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package dev.yokai.domain.extension.interactor
2+
3+
import android.content.pm.PackageInfo
4+
import androidx.core.content.pm.PackageInfoCompat
5+
import dev.yokai.domain.extension.repo.ExtensionRepoRepository
6+
import dev.yokai.domain.source.SourcePreferences
7+
import eu.kanade.tachiyomi.core.preference.getAndSet
8+
import uy.kohesive.injekt.Injekt
9+
import uy.kohesive.injekt.api.get
10+
11+
class TrustExtension(
12+
private val extensionRepoRepository: ExtensionRepoRepository,
13+
private val sourcePreferences: SourcePreferences,
14+
) {
15+
suspend fun isTrusted(pkgInfo: PackageInfo, fingerprints: List<String>): Boolean {
16+
val trustedFingerprints = extensionRepoRepository.getAll().map { it.signingKeyFingerprint }.toHashSet()
17+
val key = "${pkgInfo.packageName}:${PackageInfoCompat.getLongVersionCode(pkgInfo)}:${fingerprints.last()}"
18+
return trustedFingerprints.any { fingerprints.contains(it) } || key in sourcePreferences.trustedExtensions().get()
19+
}
20+
21+
fun trust(pkgName: String, versionCode: Long, signatureHash: String) {
22+
sourcePreferences.trustedExtensions().getAndSet { exts ->
23+
val removed = exts.filterNot { it.startsWith("$pkgName:") }.toMutableSet()
24+
25+
removed.also { it += "$pkgName:$versionCode:$signatureHash" }
26+
}
27+
}
28+
29+
fun revokeAll() {
30+
sourcePreferences.trustedExtensions().delete()
31+
}
32+
}

app/src/main/java/eu/kanade/tachiyomi/extension/ExtensionManager.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import android.graphics.drawable.Drawable
55
import android.os.Build
66
import android.os.Parcelable
77
import dev.yokai.domain.base.BasePreferences
8-
import dev.yokai.domain.extension.TrustExtension
8+
import dev.yokai.domain.extension.interactor.TrustExtension
99
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
1010
import eu.kanade.tachiyomi.extension.api.ExtensionApi
1111
import eu.kanade.tachiyomi.extension.model.Extension
@@ -316,7 +316,7 @@ class ExtensionManager(
316316
* @param versionCode the version code of the extension
317317
* @param signatureHash the signature hash of the extension
318318
*/
319-
fun trust(pkgName: String, versionCode: Long, signatureHash: String) {
319+
suspend fun trust(pkgName: String, versionCode: Long, signatureHash: String) {
320320
val untrustedPkgName = untrustedExtensionsFlow.value.map { it.pkgName }.toSet()
321321
if (pkgName !in untrustedPkgName) return
322322

app/src/main/java/eu/kanade/tachiyomi/extension/util/ExtensionInstallReceiver.kt

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,14 @@ import eu.kanade.tachiyomi.BuildConfig
1010
import eu.kanade.tachiyomi.extension.model.Extension
1111
import eu.kanade.tachiyomi.extension.model.LoadResult
1212
import eu.kanade.tachiyomi.util.system.launchNow
13+
import kotlinx.coroutines.CoroutineScope
1314
import kotlinx.coroutines.CoroutineStart
1415
import kotlinx.coroutines.DelicateCoroutinesApi
1516
import kotlinx.coroutines.Dispatchers
1617
import kotlinx.coroutines.GlobalScope
18+
import kotlinx.coroutines.SupervisorJob
1719
import kotlinx.coroutines.async
20+
import kotlinx.coroutines.launch
1821

1922
/**
2023
* Broadcast receiver that listens for the system's packages installed, updated or removed, and only
@@ -25,6 +28,8 @@ import kotlinx.coroutines.async
2528
internal class ExtensionInstallReceiver(private val listener: Listener) :
2629
BroadcastReceiver() {
2730

31+
val scope = CoroutineScope(SupervisorJob())
32+
2833
/**
2934
* Registers this broadcast receiver
3035
*/
@@ -54,18 +59,18 @@ internal class ExtensionInstallReceiver(private val listener: Listener) :
5459

5560
when (intent.action) {
5661
Intent.ACTION_PACKAGE_ADDED, ACTION_EXTENSION_ADDED -> {
57-
if (!isReplacing(intent)) {
58-
launchNow {
59-
when (val result = getExtensionFromIntent(context, intent)) {
60-
is LoadResult.Success -> listener.onExtensionInstalled(result.extension)
61-
is LoadResult.Untrusted -> listener.onExtensionUntrusted(result.extension)
62-
else -> {}
63-
}
62+
if (isReplacing(intent)) return
63+
64+
scope.launch {
65+
when (val result = getExtensionFromIntent(context, intent)) {
66+
is LoadResult.Success -> listener.onExtensionInstalled(result.extension)
67+
is LoadResult.Untrusted -> listener.onExtensionUntrusted(result.extension)
68+
else -> {}
6469
}
6570
}
6671
}
6772
Intent.ACTION_PACKAGE_REPLACED, ACTION_EXTENSION_REPLACED -> {
68-
launchNow {
73+
scope.launch {
6974
when (val result = getExtensionFromIntent(context, intent)) {
7075
is LoadResult.Success -> listener.onExtensionUpdated(result.extension)
7176
is LoadResult.Untrusted -> listener.onExtensionUntrusted(result.extension)
@@ -74,11 +79,11 @@ internal class ExtensionInstallReceiver(private val listener: Listener) :
7479
}
7580
}
7681
Intent.ACTION_PACKAGE_REMOVED, ACTION_EXTENSION_REMOVED -> {
77-
if (!isReplacing(intent)) {
78-
val pkgName = getPackageNameFromIntent(intent)
79-
if (pkgName != null) {
80-
listener.onPackageUninstalled(pkgName)
81-
}
82+
if (isReplacing(intent)) return
83+
84+
val pkgName = getPackageNameFromIntent(intent)
85+
if (pkgName != null) {
86+
listener.onPackageUninstalled(pkgName)
8287
}
8388
}
8489
}

app/src/main/java/eu/kanade/tachiyomi/extension/util/ExtensionLoader.kt

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import android.content.pm.PackageManager
88
import android.os.Build
99
import androidx.core.content.pm.PackageInfoCompat
1010
import dalvik.system.PathClassLoader
11-
import dev.yokai.domain.extension.TrustExtension
11+
import dev.yokai.domain.extension.interactor.TrustExtension
1212
import eu.kanade.tachiyomi.BuildConfig
1313
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
1414
import eu.kanade.tachiyomi.extension.model.Extension
@@ -174,7 +174,7 @@ internal object ExtensionLoader {
174174
* Attempts to load an extension from the given package name. It checks if the extension
175175
* contains the required feature flag before trying to load it.
176176
*/
177-
fun loadExtensionFromPkgName(context: Context, pkgName: String): LoadResult {
177+
suspend fun loadExtensionFromPkgName(context: Context, pkgName: String): LoadResult {
178178
val extensionPackage = getExtensionInfoFromPkgName(context, pkgName)
179179
if (extensionPackage == null) {
180180
Timber.e("Extension package is not found ($pkgName)")
@@ -274,7 +274,7 @@ internal object ExtensionLoader {
274274
* @param context The application context.
275275
* @param extensionInfo The extension to load.
276276
*/
277-
private fun loadExtension(context: Context, extensionInfo: ExtensionInfo): LoadResult {
277+
private suspend fun loadExtension(context: Context, extensionInfo: ExtensionInfo): LoadResult {
278278
val pkgManager = context.packageManager
279279
val pkgInfo = extensionInfo.packageInfo
280280
val appInfo = pkgInfo.applicationInfo
@@ -302,7 +302,7 @@ internal object ExtensionLoader {
302302
if (signatures.isNullOrEmpty()) {
303303
Timber.w("Package $pkgName isn't signed")
304304
return LoadResult.Error
305-
} else if (!isTrusted(pkgInfo, signatures)) {
305+
} else if (!trustExtension.isTrusted(pkgInfo, signatures)) {
306306
val extension = Extension.Untrusted(
307307
extName,
308308
pkgName,
@@ -429,10 +429,6 @@ internal object ExtensionLoader {
429429
?.toList()
430430
}
431431

432-
private fun isTrusted(pkgInfo: PackageInfo, signatures: List<String>): Boolean {
433-
return trustExtension.isTrusted(pkgInfo, signatures.last())
434-
}
435-
436432
/**
437433
* On Android 13+ the ApplicationInfo generated by getPackageArchiveInfo doesn't
438434
* have sourceDir which breaks assets loading (used for getting icon here).

app/src/main/java/eu/kanade/tachiyomi/ui/extension/ExtensionBottomPresenter.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,8 @@ class ExtensionBottomPresenter : BaseMigrationPresenter<ExtensionBottomSheet>()
275275
}
276276

277277
fun trustExtension(pkgName: String, versionCode: Long, signatureHash: String) {
278-
extensionManager.trust(pkgName, versionCode, signatureHash)
278+
presenterScope.launch {
279+
extensionManager.trust(pkgName, versionCode, signatureHash)
280+
}
279281
}
280282
}

app/src/main/java/eu/kanade/tachiyomi/ui/setting/controllers/SettingsAdvancedController.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import com.google.firebase.crashlytics.ktx.crashlytics
1818
import com.google.firebase.ktx.Firebase
1919
import com.hippo.unifile.UniFile
2020
import dev.yokai.domain.base.BasePreferences.ExtensionInstaller
21-
import dev.yokai.domain.extension.TrustExtension
21+
import dev.yokai.domain.extension.interactor.TrustExtension
2222
import eu.kanade.tachiyomi.BuildConfig
2323
import eu.kanade.tachiyomi.R
2424
import eu.kanade.tachiyomi.data.cache.ChapterCache

0 commit comments

Comments
 (0)