add support for installing external APK
This commit is contained in:
@@ -26,6 +26,7 @@ object MangaAPI {
|
||||
get("list", ExtensionController::list)
|
||||
|
||||
get("install/:pkgName", ExtensionController::install)
|
||||
post("install", ExtensionController::installFile)
|
||||
get("update/:pkgName", ExtensionController::update)
|
||||
get("uninstall/:pkgName", ExtensionController::uninstall)
|
||||
|
||||
|
||||
@@ -33,6 +33,19 @@ object ExtensionController {
|
||||
)
|
||||
}
|
||||
|
||||
/** install the uploaded apk file */
|
||||
fun installFile(ctx: Context) {
|
||||
|
||||
val uploadedFile = ctx.uploadedFile("file")!!
|
||||
println(uploadedFile.filename)
|
||||
|
||||
ctx.json(
|
||||
future {
|
||||
Extension.installExternalExtension(uploadedFile.content)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
/** update extension identified with "pkgName" */
|
||||
fun update(ctx: Context) {
|
||||
val pkgName = ctx.pathParam("pkgName")
|
||||
|
||||
@@ -17,6 +17,7 @@ import mu.KotlinLogging
|
||||
import okhttp3.Request
|
||||
import okio.buffer
|
||||
import okio.sink
|
||||
import okio.source
|
||||
import org.jetbrains.exposed.sql.deleteWhere
|
||||
import org.jetbrains.exposed.sql.insert
|
||||
import org.jetbrains.exposed.sql.select
|
||||
@@ -36,7 +37,6 @@ import suwayomi.tachidesk.manga.impl.util.PackageTools.dex2jar
|
||||
import suwayomi.tachidesk.manga.impl.util.PackageTools.getPackageInfo
|
||||
import suwayomi.tachidesk.manga.impl.util.PackageTools.getSignatureHash
|
||||
import suwayomi.tachidesk.manga.impl.util.PackageTools.loadExtensionSources
|
||||
import suwayomi.tachidesk.manga.impl.util.PackageTools.trustedSignatures
|
||||
import suwayomi.tachidesk.manga.impl.util.network.await
|
||||
import suwayomi.tachidesk.manga.impl.util.storage.CachedImageResponse.getCachedImageResponse
|
||||
import suwayomi.tachidesk.manga.model.table.ExtensionTable
|
||||
@@ -68,6 +68,22 @@ object Extension {
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun installExternalExtension(inputStream: InputStream): Int {
|
||||
return installAPK {
|
||||
val apkName = "apkToSave.apk"
|
||||
val savePath = "${applicationDirs.extensionsRoot}/$apkName"
|
||||
// download apk file
|
||||
val downloadedFile = File(savePath)
|
||||
downloadedFile.sink().buffer().use { sink ->
|
||||
inputStream.source().use { source ->
|
||||
sink.writeAll(source)
|
||||
sink.flush()
|
||||
}
|
||||
}
|
||||
savePath
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun installAPK(fetcher: suspend () -> String): Int {
|
||||
val apkFilePath = fetcher()
|
||||
val apkName = File(apkFilePath).name
|
||||
@@ -103,12 +119,12 @@ object Extension {
|
||||
|
||||
val signatureHash = getSignatureHash(packageInfo)
|
||||
|
||||
if (signatureHash == null) {
|
||||
throw Exception("Package $pkgName isn't signed")
|
||||
} else if (signatureHash !in trustedSignatures) {
|
||||
// TODO: allow trusting keys
|
||||
throw Exception("This apk is not a signed with the official tachiyomi signature")
|
||||
}
|
||||
// if (signatureHash == null) {
|
||||
// throw Exception("Package $pkgName isn't signed")
|
||||
// } else if (signatureHash !in trustedSignatures) {
|
||||
// // TODO: allow trusting keys
|
||||
// throw Exception("This apk is not a signed with the official tachiyomi signature")
|
||||
// }
|
||||
|
||||
val isNsfw = packageInfo.applicationInfo.metaData.getString(METADATA_NSFW) == "1"
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ object PackageTools {
|
||||
|
||||
private const val officialSignature = "7ce04da7773d41b489f4693a366c36bcd0a11fc39b547168553c285bd7348e23" // inorichi's key
|
||||
private const val unofficialSignature = "64feb21075ba97ebc9cc981243645b331595c111cef1b0d084236a0403b00581" // ArMor's key
|
||||
var trustedSignatures = mutableSetOf<String>() + officialSignature + unofficialSignature
|
||||
val trustedSignatures = mutableSetOf<String>() + officialSignature + unofficialSignature
|
||||
|
||||
/**
|
||||
* Convert dex to jar, a wrapper for the dex2jar library
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
package suwayomi.tachidesk.manga.impl.util.lang
|
||||
|
||||
fun List<String>.trimAll() = map { it.trim() }
|
||||
fun List<String>.trimAll() = map { it.trim() }
|
||||
|
||||
@@ -41,4 +41,4 @@ data class PagedMangaListDataClass(
|
||||
val hasNextPage: Boolean
|
||||
)
|
||||
|
||||
internal fun String?.toGenreList() = this?.split(",")?.trimAll().orEmpty()
|
||||
internal fun String?.toGenreList() = this?.split(",")?.trimAll().orEmpty()
|
||||
|
||||
Reference in New Issue
Block a user