Add OFFICIAL source & mine signature
This commit is contained in:
parent
81541ca67c
commit
6731edde87
7 changed files with 40 additions and 4 deletions
|
|
@ -6,8 +6,8 @@ import tachiyomi.core.preference.plusAssign
|
||||||
class CreateExtensionRepo(private val preferences: SourcePreferences) {
|
class CreateExtensionRepo(private val preferences: SourcePreferences) {
|
||||||
|
|
||||||
fun await(name: String): Result {
|
fun await(name: String): Result {
|
||||||
// Do not allow invalid formats
|
// Do not allow invalid formats & avoid adding duplicating official repo
|
||||||
if (!name.matches(repoRegex)) {
|
if (!name.matches(repoRegex) || name.startsWith(OFFICIAL_REPO_BASE_URL)) {
|
||||||
return Result.InvalidUrl
|
return Result.InvalidUrl
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -22,4 +22,5 @@ class CreateExtensionRepo(private val preferences: SourcePreferences) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const val OFFICIAL_REPO_BASE_URL = "https://raw.githubusercontent.com/cuong-tran/tachiyomi-extensions/repo"
|
||||||
private val repoRegex = """^https://.*/index\.min\.json$""".toRegex()
|
private val repoRegex = """^https://.*/index\.min\.json$""".toRegex()
|
||||||
|
|
|
||||||
|
|
@ -170,6 +170,11 @@ private fun ExtensionDetails(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// SY <--
|
// SY <--
|
||||||
|
if (extension.isUnofficial) {
|
||||||
|
item {
|
||||||
|
WarningBanner(MR.strings.unofficial_extension_message)
|
||||||
|
}
|
||||||
|
}
|
||||||
if (extension.isObsolete) {
|
if (extension.isObsolete) {
|
||||||
item {
|
item {
|
||||||
WarningBanner(MR.strings.obsolete_extension_message)
|
WarningBanner(MR.strings.obsolete_extension_message)
|
||||||
|
|
|
||||||
|
|
@ -354,6 +354,7 @@ private fun ExtensionItemContent(
|
||||||
|
|
||||||
val warning = when {
|
val warning = when {
|
||||||
extension is Extension.Untrusted -> MR.strings.ext_untrusted
|
extension is Extension.Untrusted -> MR.strings.ext_untrusted
|
||||||
|
extension is Extension.Installed && extension.isUnofficial -> MR.strings.ext_unofficial
|
||||||
extension is Extension.Installed && extension.isObsolete -> MR.strings.ext_obsolete
|
extension is Extension.Installed && extension.isObsolete -> MR.strings.ext_obsolete
|
||||||
// SY -->
|
// SY -->
|
||||||
extension is Extension.Installed && extension.isRedundant -> SYMR.strings.ext_redundant
|
extension is Extension.Installed && extension.isRedundant -> SYMR.strings.ext_redundant
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package eu.kanade.tachiyomi.extension.api
|
package eu.kanade.tachiyomi.extension.api
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import eu.kanade.domain.extension.interactor.OFFICIAL_REPO_BASE_URL
|
||||||
import eu.kanade.domain.source.service.SourcePreferences
|
import eu.kanade.domain.source.service.SourcePreferences
|
||||||
import eu.kanade.tachiyomi.extension.ExtensionManager
|
import eu.kanade.tachiyomi.extension.ExtensionManager
|
||||||
import eu.kanade.tachiyomi.extension.model.Extension
|
import eu.kanade.tachiyomi.extension.model.Extension
|
||||||
|
|
@ -36,7 +37,13 @@ internal class ExtensionApi {
|
||||||
|
|
||||||
suspend fun findExtensions(): List<Extension.Available> {
|
suspend fun findExtensions(): List<Extension.Available> {
|
||||||
return withIOContext {
|
return withIOContext {
|
||||||
sourcePreferences.extensionRepos().get().flatMap { getExtensions(it) }
|
// Combine built-in OFFICIAL repo's extensions list with repo's list
|
||||||
|
val extensions = buildList {
|
||||||
|
addAll(getExtensions(OFFICIAL_REPO_BASE_URL))
|
||||||
|
sourcePreferences.extensionRepos().get().map { addAll(getExtensions(it)) }
|
||||||
|
}
|
||||||
|
|
||||||
|
extensions
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ sealed class Extension {
|
||||||
val icon: Drawable?,
|
val icon: Drawable?,
|
||||||
val hasUpdate: Boolean = false,
|
val hasUpdate: Boolean = false,
|
||||||
val isObsolete: Boolean = false,
|
val isObsolete: Boolean = false,
|
||||||
|
val isUnofficial: Boolean = false,
|
||||||
val isShared: Boolean,
|
val isShared: Boolean,
|
||||||
val repoUrl: String? = null,
|
val repoUrl: String? = null,
|
||||||
// SY -->
|
// SY -->
|
||||||
|
|
|
||||||
|
|
@ -59,6 +59,9 @@ internal object ExtensionLoader {
|
||||||
PackageManager.GET_SIGNATURES or
|
PackageManager.GET_SIGNATURES or
|
||||||
(if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) PackageManager.GET_SIGNING_CERTIFICATES else 0)
|
(if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) PackageManager.GET_SIGNING_CERTIFICATES else 0)
|
||||||
|
|
||||||
|
// cuong-tran's key
|
||||||
|
private const val officialSignature = "cbec121aa82ebb02aaa73806992e0368a97d47b5451ed6524816d03084c45905"
|
||||||
|
|
||||||
private const val PRIVATE_EXTENSION_EXTENSION = "ext"
|
private const val PRIVATE_EXTENSION_EXTENSION = "ext"
|
||||||
|
|
||||||
private fun getPrivateExtensionDir(context: Context) = File(context.filesDir, "exts")
|
private fun getPrivateExtensionDir(context: Context) = File(context.filesDir, "exts")
|
||||||
|
|
@ -252,7 +255,8 @@ internal object ExtensionLoader {
|
||||||
if (signatures.isNullOrEmpty()) {
|
if (signatures.isNullOrEmpty()) {
|
||||||
logcat(LogPriority.WARN) { "Package $pkgName isn't signed" }
|
logcat(LogPriority.WARN) { "Package $pkgName isn't signed" }
|
||||||
return LoadResult.Error
|
return LoadResult.Error
|
||||||
} else if (!trustExtension.isTrusted(pkgInfo, signatures.last())) {
|
} else if (!isTrusted(pkgInfo, signatures.last())) {
|
||||||
|
// If not trusted then will load it as Untrusted extension to force use to Trust it
|
||||||
val extension = Extension.Untrusted(
|
val extension = Extension.Untrusted(
|
||||||
extName,
|
extName,
|
||||||
pkgName,
|
pkgName,
|
||||||
|
|
@ -320,6 +324,7 @@ internal object ExtensionLoader {
|
||||||
isNsfw = isNsfw,
|
isNsfw = isNsfw,
|
||||||
sources = sources,
|
sources = sources,
|
||||||
pkgFactory = appInfo.metaData.getString(METADATA_SOURCE_FACTORY),
|
pkgFactory = appInfo.metaData.getString(METADATA_SOURCE_FACTORY),
|
||||||
|
isUnofficial = !isOfficiallySigned(signatures),
|
||||||
icon = appInfo.loadIcon(pkgManager),
|
icon = appInfo.loadIcon(pkgManager),
|
||||||
isShared = extensionInfo.isShared,
|
isShared = extensionInfo.isShared,
|
||||||
)
|
)
|
||||||
|
|
@ -379,6 +384,20 @@ internal object ExtensionLoader {
|
||||||
?.toList()
|
?.toList()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun isTrusted(pkgInfo: PackageInfo, signatureHash: String): Boolean {
|
||||||
|
if (officialSignature == signatureHash) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return trustExtension.isTrusted(pkgInfo, signatureHash)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Showing UNOFFICIAL text on extension
|
||||||
|
*/
|
||||||
|
private fun isOfficiallySigned(signatures: List<String>): Boolean {
|
||||||
|
return signatures.all { it == officialSignature }
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* On Android 13+ the ApplicationInfo generated by getPackageArchiveInfo doesn't
|
* On Android 13+ the ApplicationInfo generated by getPackageArchiveInfo doesn't
|
||||||
* have sourceDir which breaks assets loading (used for getting icon here).
|
* have sourceDir which breaks assets loading (used for getting icon here).
|
||||||
|
|
|
||||||
|
|
@ -311,12 +311,14 @@
|
||||||
<string name="ext_installing">Installing</string>
|
<string name="ext_installing">Installing</string>
|
||||||
<string name="ext_installed">Installed</string>
|
<string name="ext_installed">Installed</string>
|
||||||
<string name="ext_trust">Trust</string>
|
<string name="ext_trust">Trust</string>
|
||||||
|
<string name="ext_unofficial">Unofficial</string>
|
||||||
<string name="ext_untrusted">Untrusted</string>
|
<string name="ext_untrusted">Untrusted</string>
|
||||||
<string name="ext_uninstall">Uninstall</string>
|
<string name="ext_uninstall">Uninstall</string>
|
||||||
<string name="ext_app_info">App info</string>
|
<string name="ext_app_info">App info</string>
|
||||||
<string name="untrusted_extension">Untrusted extension</string>
|
<string name="untrusted_extension">Untrusted extension</string>
|
||||||
<string name="untrusted_extension_message">Malicious extensions can read any stored login credentials or execute arbitrary code.\n\nBy trusting this extension, you accept these risks.</string>
|
<string name="untrusted_extension_message">Malicious extensions can read any stored login credentials or execute arbitrary code.\n\nBy trusting this extension, you accept these risks.</string>
|
||||||
<string name="obsolete_extension_message">This extension is no longer available. It may not function properly and can cause issues with the app. Uninstalling it is recommended.</string>
|
<string name="obsolete_extension_message">This extension is no longer available. It may not function properly and can cause issues with the app. Uninstalling it is recommended.</string>
|
||||||
|
<string name="unofficial_extension_message">This extension is not from the official repo.</string>
|
||||||
<string name="extension_api_error">Failed to fetch available extensions</string>
|
<string name="extension_api_error">Failed to fetch available extensions</string>
|
||||||
<string name="ext_info_version">Version</string>
|
<string name="ext_info_version">Version</string>
|
||||||
<string name="ext_info_language">Language</string>
|
<string name="ext_info_language">Language</string>
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue