From 52dacc16a03bd54931d71e2c48882103959fe6f4 Mon Sep 17 00:00:00 2001 From: oSumAtrIX Date: Sat, 7 May 2022 21:37:24 +0200 Subject: [PATCH 1/7] chore: bump project JDK to JDK 17 Signed-off-by: oSumAtrIX --- .idea/misc.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.idea/misc.xml b/.idea/misc.xml index fd01dff..6a8d183 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -4,7 +4,7 @@ - + \ No newline at end of file From 351de6cb90aa0f2ec93e8b8f6c10d7d312082079 Mon Sep 17 00:00:00 2001 From: oSumAtrIX Date: Sat, 7 May 2022 23:15:31 +0200 Subject: [PATCH 2/7] fix: wrong use of dependency to `revanced-patches` Signed-off-by: oSumAtrIX --- build.gradle.kts | 6 ------ .../kotlin/app/revanced/patch/PatchLoader.kt | 10 ---------- src/main/kotlin/app/revanced/patch/Patches.kt | 20 +++++++++---------- 3 files changed, 10 insertions(+), 26 deletions(-) delete mode 100644 src/main/kotlin/app/revanced/patch/PatchLoader.kt diff --git a/build.gradle.kts b/build.gradle.kts index acc5960..78f6682 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -22,12 +22,9 @@ repositories { } } -val patchesDependency = "app.revanced:revanced-patches:1.+" - dependencies { implementation(kotlin("stdlib")) implementation("app.revanced:revanced-patcher:+") - implementation(patchesDependency) implementation("info.picocli:picocli:+") implementation("me.tongfei:progressbar:+") @@ -45,9 +42,6 @@ tasks { dependsOn(shadowJar) } shadowJar { - dependencies { - exclude(dependency(patchesDependency)) - } manifest { attributes("Main-Class" to "app.revanced.cli.MainKt") attributes("Implementation-Title" to project.name) diff --git a/src/main/kotlin/app/revanced/patch/PatchLoader.kt b/src/main/kotlin/app/revanced/patch/PatchLoader.kt deleted file mode 100644 index 088076f..0000000 --- a/src/main/kotlin/app/revanced/patch/PatchLoader.kt +++ /dev/null @@ -1,10 +0,0 @@ -package app.revanced.patch - -import java.io.File -import java.net.URLClassLoader - -internal class PatchLoader { - internal companion object { - - } -} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patch/Patches.kt b/src/main/kotlin/app/revanced/patch/Patches.kt index b302c90..4b24a81 100644 --- a/src/main/kotlin/app/revanced/patch/Patches.kt +++ b/src/main/kotlin/app/revanced/patch/Patches.kt @@ -2,25 +2,25 @@ package app.revanced.patch import app.revanced.patcher.data.base.Data import app.revanced.patcher.patch.base.Patch -import app.revanced.patches.Index import java.io.File import java.net.URLClassLoader internal object Patches { - /** * This method loads patches from a given patch file * @return the loaded patches represented as a list of functions returning instances of [Patch] */ - internal fun load(patchFile: File): List<() -> Patch> { - val url = patchFile.toURI().toURL() + internal fun load(patchesJar: File): List<() -> Patch> { + val url = patchesJar.toURI().toURL() val classLoader = URLClassLoader(arrayOf(url)) - return loadIndex(classLoader).patches + + val indexClass = classLoader.loadClass("app.revanced.patches.Index") + + val index = indexClass.declaredFields.last() + index.isAccessible = true + + @Suppress("UNCHECKED_CAST") + return index.get(null) as List<() -> Patch> } - private fun loadIndex(classLoader: ClassLoader) = classLoader - .loadClass(Index::class.java.canonicalName) - .fields - .first() - .get(null) as Index } From aba7965df8918e6936648637b776d1f0963eff9f Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Sat, 7 May 2022 21:16:55 +0000 Subject: [PATCH 3/7] chore(release): 1.1.0-dev.2 [skip ci] # [1.1.0-dev.2](https://github.com/revanced/revanced-cli/compare/v1.1.0-dev.1...v1.1.0-dev.2) (2022-05-07) ### Bug Fixes * wrong use of dependency to `revanced-patches` ([351de6c](https://github.com/revanced/revanced-cli/commit/351de6cb90aa0f2ec93e8b8f6c10d7d312082079)) --- CHANGELOG.md | 7 +++++++ gradle.properties | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4f5ebe0..91bc6bc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +# [1.1.0-dev.2](https://github.com/revanced/revanced-cli/compare/v1.1.0-dev.1...v1.1.0-dev.2) (2022-05-07) + + +### Bug Fixes + +* wrong use of dependency to `revanced-patches` ([351de6c](https://github.com/revanced/revanced-cli/commit/351de6cb90aa0f2ec93e8b8f6c10d7d312082079)) + # [1.1.0-dev.1](https://github.com/revanced/revanced-cli/compare/v1.0.1...v1.1.0-dev.1) (2022-05-07) diff --git a/gradle.properties b/gradle.properties index d755e8c..19d5c4a 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,2 +1,2 @@ kotlin.code.style = official -version = 1.1.0-dev.1 +version = 1.1.0-dev.2 From 81d53b5518454e479b7a8f2e9be934bee30702af Mon Sep 17 00:00:00 2001 From: Wan Muhammad Azims <4zims95@gmail.com> Date: Mon, 16 May 2022 03:45:20 +0800 Subject: [PATCH 4/7] fix: wrong use of variable substitution / typo [revanced/revanced-cli#12](https://github.com/revanced/revanced-cli/issues/12) --- src/main/kotlin/app/revanced/utils/adb/Constants.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/kotlin/app/revanced/utils/adb/Constants.kt b/src/main/kotlin/app/revanced/utils/adb/Constants.kt index 0710ef8..04b4ff3 100644 --- a/src/main/kotlin/app/revanced/utils/adb/Constants.kt +++ b/src/main/kotlin/app/revanced/utils/adb/Constants.kt @@ -42,7 +42,7 @@ internal object Constants { """ #!/system/bin/sh - stock_path=${'$'}{ pm path $PLACEHOLDER | grep base | sed 's/package://g' } + stock_path=${'$'}( pm path $PLACEHOLDER | grep base | sed 's/package://g' ) umount -l ${'$'}stock_path """.trimIndent() @@ -53,7 +53,7 @@ internal object Constants { while [ "${'$'}(getprop sys.boot_completed | tr -d '\r')" != "1" ]; do sleep 1; done base_path="$PATH_REVANCED_APP" - stock_path=${'$'}{ pm path $PLACEHOLDER | grep base | sed 's/package://g' } + stock_path=${'$'}( pm path $PLACEHOLDER | grep base | sed 's/package://g' ) mount -o bind ${'$'}base_path ${'$'}stock_path """.trimIndent() } From f90205b243979eb89d1ef4a0d3b0aa1f11967f7f Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Sun, 15 May 2022 20:11:14 +0000 Subject: [PATCH 5/7] chore(release): 1.1.0-dev.3 [skip ci] # [1.1.0-dev.3](https://github.com/revanced/revanced-cli/compare/v1.1.0-dev.2...v1.1.0-dev.3) (2022-05-15) ### Bug Fixes * wrong use of variable substitution / typo ([81d53b5](https://github.com/revanced/revanced-cli/commit/81d53b5518454e479b7a8f2e9be934bee30702af)), closes [revanced/revanced-cli#12](https://github.com/revanced/revanced-cli/issues/12) --- CHANGELOG.md | 7 +++++++ gradle.properties | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 91bc6bc..103a0af 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +# [1.1.0-dev.3](https://github.com/revanced/revanced-cli/compare/v1.1.0-dev.2...v1.1.0-dev.3) (2022-05-15) + + +### Bug Fixes + +* wrong use of variable substitution / typo ([81d53b5](https://github.com/revanced/revanced-cli/commit/81d53b5518454e479b7a8f2e9be934bee30702af)), closes [revanced/revanced-cli#12](https://github.com/revanced/revanced-cli/issues/12) + # [1.1.0-dev.2](https://github.com/revanced/revanced-cli/compare/v1.1.0-dev.1...v1.1.0-dev.2) (2022-05-07) diff --git a/gradle.properties b/gradle.properties index 19d5c4a..a7ce2f2 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,2 +1,2 @@ kotlin.code.style = official -version = 1.1.0-dev.2 +version = 1.1.0-dev.3 From 51d250491f390695aedc64e7ee71a9dcf99d695c Mon Sep 17 00:00:00 2001 From: oSumAtrIX Date: Thu, 19 May 2022 00:00:45 +0200 Subject: [PATCH 6/7] fix: breaking changes by `revanced-patcher` dependency Signed-off-by: oSumAtrIX --- build.gradle.kts | 4 +- .../kotlin/app/revanced/cli/MainCommand.kt | 40 +++++++++-------- src/main/kotlin/app/revanced/cli/Patcher.kt | 44 ++++++++++++------- src/main/kotlin/app/revanced/patch/Patches.kt | 31 ++++++++----- .../app/revanced/utils/adb/Constants.kt | 2 +- 5 files changed, 73 insertions(+), 48 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 78f6682..5294530 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -25,11 +25,13 @@ repositories { dependencies { implementation(kotlin("stdlib")) implementation("app.revanced:revanced-patcher:+") + implementation("app.revanced:revanced-patches:+") + implementation("info.picocli:picocli:+") - implementation("me.tongfei:progressbar:+") implementation("com.github.li-wjohnson:jadb:master-SNAPSHOT") // using a fork instead. implementation("org.bouncycastle:bcpkix-jdk15on:+") + implementation(kotlin("reflect")) } java { diff --git a/src/main/kotlin/app/revanced/cli/MainCommand.kt b/src/main/kotlin/app/revanced/cli/MainCommand.kt index 0bed6d2..13440dd 100644 --- a/src/main/kotlin/app/revanced/cli/MainCommand.kt +++ b/src/main/kotlin/app/revanced/cli/MainCommand.kt @@ -1,6 +1,8 @@ package app.revanced.cli import app.revanced.patch.Patches +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.extensions.findAnnotationRecursively import app.revanced.utils.adb.Adb import picocli.CommandLine.* import java.io.File @@ -47,36 +49,36 @@ internal object MainCommand : Runnable { override fun run() { if (listOnly) { - patchBundles.forEach { - Patches.load(it).forEach { - println(it().metadata) - } - } + for (patchBundle in patchBundles) for (it in Patches.load(patchBundle)) println( + "[available] ${ + it.javaClass.findAnnotationRecursively( + Name::class.java + )?.name ?: Name::class.java.name + }" + ) return } + val outputFile = File(outputPath) + val patcher = app.revanced.patcher.Patcher( - inputFile, - cacheDirectory, - patchResources + inputFile, cacheDirectory, patchResources ) + var adb: Adb? = null + deploy?.let { + adb = Adb( + outputFile, patcher.packageName, deploy!! + ) + } + Patcher.start(patcher) if (clean) { File(cacheDirectory).deleteRecursively() + outputFile.delete() } - val outputFile = File(outputPath) - - deploy?.let { - Adb( - outputFile, - patcher.packageName, - deploy!! - ).deploy() - } - - if (clean) outputFile.delete() + adb?.deploy() } } \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/cli/Patcher.kt b/src/main/kotlin/app/revanced/cli/Patcher.kt index c20d796..5459122 100644 --- a/src/main/kotlin/app/revanced/cli/Patcher.kt +++ b/src/main/kotlin/app/revanced/cli/Patcher.kt @@ -1,7 +1,10 @@ package app.revanced.cli import app.revanced.patch.Patches +import app.revanced.patcher.annotation.Compatibility +import app.revanced.patcher.annotation.Name import app.revanced.patcher.data.base.Data +import app.revanced.patcher.extensions.findAnnotationRecursively import app.revanced.patcher.patch.base.Patch import app.revanced.utils.filesystem.FileSystemUtils import app.revanced.utils.signing.Signer @@ -15,10 +18,8 @@ internal class Patcher { // add patches, but filter incompatible or excluded patches patcher.addPatchesFiltered() // apply patches - for ((meta, result) in patcher.applyPatches { - println("Applying $it.") - }) { - println("Applied ${meta.name}. The result was $result.") + for ((patch, result) in patcher.applyPatches()) { + println("[error: ${result.isFailure}] $patch") } // write output file @@ -34,7 +35,7 @@ internal class Patcher { } if (MainCommand.patchResources) { - for (file in File(MainCommand.cacheDirectory).resolve("build/").listFiles().first().listFiles()) { + for (file in File(MainCommand.cacheDirectory).resolve("build/").listFiles()?.first()?.listFiles()!!) { if (!file.isDirectory) { zipFileSystem.replaceFile(file.name, file.readBytes()) continue @@ -48,6 +49,8 @@ internal class Patcher { // and sign the apk file Signer.signApk(outFile) + + println("[done]") } private fun app.revanced.patcher.Patcher.addPatchesFiltered() { @@ -58,25 +61,34 @@ internal class Patcher { MainCommand.patchBundles.forEach { bundle -> val includedPatches = mutableListOf>() - Patches.load(bundle).forEach patch@{ - val patch = it() + Patches.load(bundle).forEach patch@{ it -> + val patch = it.getDeclaredConstructor().newInstance() val filterOutPatches = true - if (filterOutPatches && !patch.metadata.compatiblePackages.any { packageMetadata -> - packageMetadata.name == packageName && packageMetadata.versions.any { - it == packageVersion - } - }) { - println("Skipping ${patch.metadata.name} due to incompatibility with current package $packageName.") + val compatibilityAnnotation = patch.javaClass.findAnnotationRecursively(Compatibility::class.java) + + val patchName = + patch.javaClass.findAnnotationRecursively(Name::class.java)?.name ?: Name::class.java.name + + if (checkInclude && !MainCommand.includedPatches.contains(patchName)) { return@patch } - if (checkInclude && !MainCommand.includedPatches.contains(patch.metadata.shortName)) { - return@patch + if (filterOutPatches) { + if (compatibilityAnnotation == null || !(compatibilityAnnotation.compatiblePackages.any { packageMetadata -> + packageMetadata.name == packageName && packageMetadata.versions.any { + it == packageVersion + } + })) { + // TODO: misleading error message + println("[Skipped] $patchName: Incompatible with current package.") + return@patch + } } - println("Adding ${patch.metadata.name}.") + + println("[loaded] $patchName") includedPatches.add(patch) } diff --git a/src/main/kotlin/app/revanced/patch/Patches.kt b/src/main/kotlin/app/revanced/patch/Patches.kt index 4b24a81..8ed9f2c 100644 --- a/src/main/kotlin/app/revanced/patch/Patches.kt +++ b/src/main/kotlin/app/revanced/patch/Patches.kt @@ -1,26 +1,35 @@ package app.revanced.patch -import app.revanced.patcher.data.base.Data import app.revanced.patcher.patch.base.Patch import java.io.File import java.net.URLClassLoader +import java.util.jar.JarFile internal object Patches { /** - * This method loads patches from a given patch file - * @return the loaded patches represented as a list of functions returning instances of [Patch] + * This method loads patches from a given jar file containing [Patch]es + * @return the loaded patches represented as a list of [Patch] classes */ - internal fun load(patchesJar: File): List<() -> Patch> { - val url = patchesJar.toURI().toURL() - val classLoader = URLClassLoader(arrayOf(url)) + internal fun load(patchesJar: File) = buildList { + val jarFile = JarFile(patchesJar) + val classLoader = URLClassLoader(arrayOf(patchesJar.toURI().toURL())) - val indexClass = classLoader.loadClass("app.revanced.patches.Index") + val entries = jarFile.entries() + while (entries.hasMoreElements()) { + val entry = entries.nextElement() + if (!entry.name.endsWith(".class") || entry.name.contains("$")) continue - val index = indexClass.declaredFields.last() - index.isAccessible = true + val clazz = classLoader.loadClass(entry.realName.replace('/', '.').replace(".class", "")) - @Suppress("UNCHECKED_CAST") - return index.get(null) as List<() -> Patch> + if (!clazz.isAnnotationPresent(app.revanced.patcher.patch.annotations.Patch::class.java)) continue + + @Suppress("UNCHECKED_CAST") + val patch = clazz as Class> + + // TODO: include declared classes from patch + + this.add(patch) + } } } diff --git a/src/main/kotlin/app/revanced/utils/adb/Constants.kt b/src/main/kotlin/app/revanced/utils/adb/Constants.kt index 04b4ff3..1b27e3d 100644 --- a/src/main/kotlin/app/revanced/utils/adb/Constants.kt +++ b/src/main/kotlin/app/revanced/utils/adb/Constants.kt @@ -8,7 +8,7 @@ internal object Constants { private const val COMMAND_CHMOD_MOUNT = "chmod +x" internal const val COMMAND_PID_OF = "pidof -s" internal const val COMMAND_CREATE_DIR = "mkdir -p" - internal const val COMMAND_LOGCAT = "logcat -c && logcat --pid=$($COMMAND_PID_OF $PLACEHOLDER)" + internal const val COMMAND_LOGCAT = "logcat -c && logcat | grep AndroidRuntime" internal const val COMMAND_RESTART = "monkey -p $PLACEHOLDER 1 && kill ${'$'}($COMMAND_PID_OF $PLACEHOLDER)" // default mount file name From f297f7d1ef1e7871fb9e9138ffa0ae14a2d462cd Mon Sep 17 00:00:00 2001 From: oSumAtrIX Date: Sun, 22 May 2022 17:10:43 +0200 Subject: [PATCH 7/7] add: signature checker and compatibility filters Signed-off-by: oSumAtrIX --- .../kotlin/app/revanced/cli/MainCommand.kt | 33 ++++++--- src/main/kotlin/app/revanced/cli/Patcher.kt | 58 ++------------- src/main/kotlin/app/revanced/patch/Patches.kt | 33 --------- .../app/revanced/utils/patcher/Patcher.kt | 71 +++++++++++++++++++ .../app/revanced/utils/signature/Signature.kt | 58 +++++++++++++++ 5 files changed, 158 insertions(+), 95 deletions(-) create mode 100644 src/main/kotlin/app/revanced/utils/patcher/Patcher.kt create mode 100644 src/main/kotlin/app/revanced/utils/signature/Signature.kt diff --git a/src/main/kotlin/app/revanced/cli/MainCommand.kt b/src/main/kotlin/app/revanced/cli/MainCommand.kt index 13440dd..2236fad 100644 --- a/src/main/kotlin/app/revanced/cli/MainCommand.kt +++ b/src/main/kotlin/app/revanced/cli/MainCommand.kt @@ -1,9 +1,11 @@ package app.revanced.cli -import app.revanced.patch.Patches import app.revanced.patcher.annotation.Name import app.revanced.patcher.extensions.findAnnotationRecursively +import app.revanced.patcher.util.patch.PatchLoader import app.revanced.utils.adb.Adb +import app.revanced.utils.patcher.addPatchesFiltered +import app.revanced.utils.signature.Signature import picocli.CommandLine.* import java.io.File @@ -35,6 +37,9 @@ internal object MainCommand : Runnable { @Option(names = ["-l", "--list"], description = ["List patches only"]) internal var listOnly: Boolean = false + @Option(names = ["-s", "--signature-checker"], description = ["Check signatures of all patches"]) + internal var signatureCheck: Boolean = false + @Option(names = ["-m", "--merge"], description = ["One or more dex file containers to merge"]) internal var mergeFiles = listOf() @@ -49,22 +54,30 @@ internal object MainCommand : Runnable { override fun run() { if (listOnly) { - for (patchBundle in patchBundles) for (it in Patches.load(patchBundle)) println( - "[available] ${ - it.javaClass.findAnnotationRecursively( - Name::class.java - )?.name ?: Name::class.java.name - }" - ) + for (patchBundle in patchBundles) + for (it in PatchLoader.loadFromFile(patchBundle)) + println( + "[available] ${ + it.javaClass.findAnnotationRecursively( + Name::class.java + )?.name ?: Name::class.java.name + }" + ) return } - val outputFile = File(outputPath) - val patcher = app.revanced.patcher.Patcher( inputFile, cacheDirectory, patchResources ) + if (signatureCheck) { + patcher.addPatchesFiltered() + Signature.checkSignatures(patcher) + return + } + + val outputFile = File(outputPath) + var adb: Adb? = null deploy?.let { adb = Adb( diff --git a/src/main/kotlin/app/revanced/cli/Patcher.kt b/src/main/kotlin/app/revanced/cli/Patcher.kt index 5459122..0eac7b9 100644 --- a/src/main/kotlin/app/revanced/cli/Patcher.kt +++ b/src/main/kotlin/app/revanced/cli/Patcher.kt @@ -1,12 +1,9 @@ package app.revanced.cli -import app.revanced.patch.Patches -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Name -import app.revanced.patcher.data.base.Data -import app.revanced.patcher.extensions.findAnnotationRecursively -import app.revanced.patcher.patch.base.Patch import app.revanced.utils.filesystem.FileSystemUtils +import app.revanced.utils.patcher.addPatchesFiltered +import app.revanced.utils.patcher.applyPatchesPrint +import app.revanced.utils.patcher.mergeFiles import app.revanced.utils.signing.Signer import java.io.File @@ -14,13 +11,11 @@ internal class Patcher { internal companion object { internal fun start(patcher: app.revanced.patcher.Patcher) { // merge files like necessary integrations - patcher.addFiles(MainCommand.mergeFiles) + patcher.mergeFiles() // add patches, but filter incompatible or excluded patches - patcher.addPatchesFiltered() + patcher.addPatchesFiltered(includeFilter = MainCommand.includedPatches.isNotEmpty()) // apply patches - for ((patch, result) in patcher.applyPatches()) { - println("[error: ${result.isFailure}] $patch") - } + patcher.applyPatchesPrint() // write output file val outFile = File(MainCommand.outputPath) @@ -53,47 +48,6 @@ internal class Patcher { println("[done]") } - private fun app.revanced.patcher.Patcher.addPatchesFiltered() { - val packageName = this.packageName - val packageVersion = this.packageVersion - val checkInclude = MainCommand.includedPatches.isNotEmpty() - - MainCommand.patchBundles.forEach { bundle -> - val includedPatches = mutableListOf>() - Patches.load(bundle).forEach patch@{ it -> - val patch = it.getDeclaredConstructor().newInstance() - - val filterOutPatches = true - - val compatibilityAnnotation = patch.javaClass.findAnnotationRecursively(Compatibility::class.java) - - val patchName = - patch.javaClass.findAnnotationRecursively(Name::class.java)?.name ?: Name::class.java.name - - if (checkInclude && !MainCommand.includedPatches.contains(patchName)) { - return@patch - } - - if (filterOutPatches) { - if (compatibilityAnnotation == null || !(compatibilityAnnotation.compatiblePackages.any { packageMetadata -> - packageMetadata.name == packageName && packageMetadata.versions.any { - it == packageVersion - } - })) { - // TODO: misleading error message - println("[Skipped] $patchName: Incompatible with current package.") - return@patch - } - } - - - println("[loaded] $patchName") - includedPatches.add(patch) - - } - this.addPatches(includedPatches) - } - } } } diff --git a/src/main/kotlin/app/revanced/patch/Patches.kt b/src/main/kotlin/app/revanced/patch/Patches.kt index 8ed9f2c..add204a 100644 --- a/src/main/kotlin/app/revanced/patch/Patches.kt +++ b/src/main/kotlin/app/revanced/patch/Patches.kt @@ -1,35 +1,2 @@ package app.revanced.patch -import app.revanced.patcher.patch.base.Patch -import java.io.File -import java.net.URLClassLoader -import java.util.jar.JarFile - -internal object Patches { - - /** - * This method loads patches from a given jar file containing [Patch]es - * @return the loaded patches represented as a list of [Patch] classes - */ - internal fun load(patchesJar: File) = buildList { - val jarFile = JarFile(patchesJar) - val classLoader = URLClassLoader(arrayOf(patchesJar.toURI().toURL())) - - val entries = jarFile.entries() - while (entries.hasMoreElements()) { - val entry = entries.nextElement() - if (!entry.name.endsWith(".class") || entry.name.contains("$")) continue - - val clazz = classLoader.loadClass(entry.realName.replace('/', '.').replace(".class", "")) - - if (!clazz.isAnnotationPresent(app.revanced.patcher.patch.annotations.Patch::class.java)) continue - - @Suppress("UNCHECKED_CAST") - val patch = clazz as Class> - - // TODO: include declared classes from patch - - this.add(patch) - } - } -} diff --git a/src/main/kotlin/app/revanced/utils/patcher/Patcher.kt b/src/main/kotlin/app/revanced/utils/patcher/Patcher.kt new file mode 100644 index 0000000..fc2cf62 --- /dev/null +++ b/src/main/kotlin/app/revanced/utils/patcher/Patcher.kt @@ -0,0 +1,71 @@ +package app.revanced.utils.patcher + +import app.revanced.cli.MainCommand +import app.revanced.patcher.Patcher +import app.revanced.patcher.annotation.Compatibility +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.data.base.Data +import app.revanced.patcher.extensions.findAnnotationRecursively +import app.revanced.patcher.patch.base.Patch +import app.revanced.patcher.util.patch.PatchLoader + +fun Patcher.addPatchesFiltered( + packageCompatibilityFilter: Boolean = true, + packageVersionCompatibilityFilter: Boolean = true, + includeFilter: Boolean = false +) { + val packageName = this.packageName + val packageVersion = this.packageVersion + + MainCommand.patchBundles.forEach { bundle -> + val includedPatches = mutableListOf>() + PatchLoader.loadFromFile(bundle).forEach patch@{ p -> + val patch = p.getDeclaredConstructor().newInstance() + + val compatibilityAnnotation = patch.javaClass.findAnnotationRecursively(Compatibility::class.java) + + val patchName = patch.javaClass.findAnnotationRecursively(Name::class.java)?.name ?: Name::class.java.name + + val prefix = "[skipped] $patchName" + + if (includeFilter && !MainCommand.includedPatches.contains(patchName)) { + println(prefix) + return@patch + } + + if (packageVersionCompatibilityFilter || packageCompatibilityFilter) { + + if (compatibilityAnnotation == null) { + println("$prefix: Missing compatibility annotation.") + return@patch + } + + + for (compatiblePackage in compatibilityAnnotation.compatiblePackages) { + if (packageCompatibilityFilter && compatiblePackage.name != packageName) { + println("$prefix: Package name not matching ${compatiblePackage.name}.") + return@patch + } + + if (!packageVersionCompatibilityFilter || compatiblePackage.versions.any { it == packageVersion }) continue + println("$prefix: Unsupported version.") + return@patch + } + } + + includedPatches.add(patch) + println("[added] $patchName") + } + this.addPatches(includedPatches) + } +} + +fun Patcher.applyPatchesPrint() { + for ((patch, result) in this.applyPatches()) { + println("[${if (result.isFailure) "error" else "success"}] $patch") + } +} + +fun Patcher.mergeFiles() { + this.addFiles(MainCommand.mergeFiles) +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/utils/signature/Signature.kt b/src/main/kotlin/app/revanced/utils/signature/Signature.kt new file mode 100644 index 0000000..24afe9d --- /dev/null +++ b/src/main/kotlin/app/revanced/utils/signature/Signature.kt @@ -0,0 +1,58 @@ +package app.revanced.utils.signature + +import app.revanced.patcher.Patcher +import app.revanced.patcher.extensions.findAnnotationRecursively +import app.revanced.patcher.signature.implementation.method.annotation.FuzzyPatternScanMethod +import app.revanced.patcher.signature.implementation.method.annotation.MatchingMethod +import org.jf.dexlib2.iface.Method + +object Signature { + + fun checkSignatures(patcher: Patcher) { + val failed = mutableListOf() + for (signature in patcher.resolveSignatures()) { + val signatureClass = signature::class.java + val signatureName = + signatureClass.findAnnotationRecursively(app.revanced.patcher.annotation.Name::class.java)?.name + ?: signatureClass.name + if (!signature.resolved) { + failed.add(signatureName) + continue + } + + val method = signature.result!!.method + val matchingMethod = + signatureClass.findAnnotationRecursively(MatchingMethod::class.java) ?: MatchingMethod() + + println( + """ + [Signature] $signatureName + [Method] ${matchingMethod.definingClass}->${matchingMethod.name} + [Match] ${method.definingClass}->${method.toStr()} + """.trimIndent() + ) + + signatureClass.findAnnotationRecursively(FuzzyPatternScanMethod::class.java)?.let { + val warnings = signature.result!!.scanResult.warnings!! + println( + """ + [Warnings: ${warnings.count()}] + ${warnings.joinToString(separator = "\n") { warning -> "${warning.instructionIndex} / ${warning.patternIndex}: ${warning.wrongOpcode} (expected: ${warning.correctOpcode})" }} + """.trimIndent() + ) + } + } + + println( + """ + ${"=".repeat(50)} + [Failed signatures: ${failed.size}] + ${failed.joinToString(separator = "\n") { it }} + """.trimIndent() + ) + } + + private fun Method.toStr(): String { + return "${this.name}(${this.parameterTypes.joinToString("")})${this.returnType}" + } +} \ No newline at end of file