mirror of
https://github.com/revanced/revanced-cli.git
synced 2024-08-25 16:51:45 +02:00
Merge branch 'dev'
# Conflicts: # CHANGELOG.md # gradle.properties
This commit is contained in:
commit
457c371fb9
@ -4,7 +4,7 @@
|
||||
<component name="FrameworkDetectionExcludesConfiguration">
|
||||
<file type="web" url="file://$PROJECT_DIR$" />
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="true" project-jdk-name="azul-1.8" project-jdk-type="JavaSDK">
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="azul-17" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/out" />
|
||||
</component>
|
||||
</project>
|
11
CHANGELOG.md
11
CHANGELOG.md
@ -1,15 +1,16 @@
|
||||
# [1.1.0](https://github.com/revanced/revanced-cli/compare/v1.0.1...v1.1.0) (2022-05-07)
|
||||
# [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
|
||||
|
||||
* ClassLoader not working with Java 9+ ([3a11e11](https://github.com/revanced/revanced-cli/commit/3a11e1135bd1e8958dd21247622d549440725ead))
|
||||
* leftover TODOs ([5b1139c](https://github.com/revanced/revanced-cli/commit/5b1139ce43df1f5c2c848a8209a9e618857031ce))
|
||||
* 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)
|
||||
|
||||
|
||||
### Features
|
||||
### Bug Fixes
|
||||
|
||||
* run `release.yml` workflow on branch `dev` ([9a64730](https://github.com/revanced/revanced-cli/commit/9a6473056b940c6df4860dd09c09d7ac61545f7d))
|
||||
* 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)
|
||||
|
||||
|
@ -22,17 +22,16 @@ repositories {
|
||||
}
|
||||
}
|
||||
|
||||
val patchesDependency = "app.revanced:revanced-patches:1.+"
|
||||
|
||||
dependencies {
|
||||
implementation(kotlin("stdlib"))
|
||||
implementation("app.revanced:revanced-patcher:+")
|
||||
implementation(patchesDependency)
|
||||
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 {
|
||||
@ -45,9 +44,6 @@ tasks {
|
||||
dependsOn(shadowJar)
|
||||
}
|
||||
shadowJar {
|
||||
dependencies {
|
||||
exclude(dependency(patchesDependency))
|
||||
}
|
||||
manifest {
|
||||
attributes("Main-Class" to "app.revanced.cli.MainKt")
|
||||
attributes("Implementation-Title" to project.name)
|
||||
|
@ -1,2 +1,2 @@
|
||||
kotlin.code.style = official
|
||||
version = 1.1.0
|
||||
version = 1.1.0-dev.3
|
||||
|
@ -1,7 +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
|
||||
|
||||
@ -33,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<File>()
|
||||
|
||||
@ -47,36 +54,44 @@ 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 PatchLoader.loadFromFile(patchBundle))
|
||||
println(
|
||||
"[available] ${
|
||||
it.javaClass.findAnnotationRecursively(
|
||||
Name::class.java
|
||||
)?.name ?: Name::class.java.name
|
||||
}"
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
val patcher = app.revanced.patcher.Patcher(
|
||||
inputFile,
|
||||
cacheDirectory,
|
||||
patchResources
|
||||
inputFile, cacheDirectory, patchResources
|
||||
)
|
||||
|
||||
if (signatureCheck) {
|
||||
patcher.addPatchesFiltered()
|
||||
Signature.checkSignatures(patcher)
|
||||
return
|
||||
}
|
||||
|
||||
val outputFile = File(outputPath)
|
||||
|
||||
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()
|
||||
}
|
||||
}
|
@ -1,9 +1,9 @@
|
||||
package app.revanced.cli
|
||||
|
||||
import app.revanced.patch.Patches
|
||||
import app.revanced.patcher.data.base.Data
|
||||
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
|
||||
|
||||
@ -11,15 +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 ((meta, result) in patcher.applyPatches {
|
||||
println("Applying $it.")
|
||||
}) {
|
||||
println("Applied ${meta.name}. The result was $result.")
|
||||
}
|
||||
patcher.applyPatchesPrint()
|
||||
|
||||
// write output file
|
||||
val outFile = File(MainCommand.outputPath)
|
||||
@ -34,7 +30,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,40 +44,10 @@ internal class Patcher {
|
||||
|
||||
// and sign the apk file
|
||||
Signer.signApk(outFile)
|
||||
|
||||
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<Patch<Data>>()
|
||||
Patches.load(bundle).forEach patch@{
|
||||
val patch = it()
|
||||
|
||||
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.")
|
||||
return@patch
|
||||
}
|
||||
|
||||
if (checkInclude && !MainCommand.includedPatches.contains(patch.metadata.shortName)) {
|
||||
return@patch
|
||||
}
|
||||
|
||||
println("Adding ${patch.metadata.name}.")
|
||||
includedPatches.add(patch)
|
||||
|
||||
}
|
||||
this.addPatches(includedPatches)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +0,0 @@
|
||||
package app.revanced.patch
|
||||
|
||||
import java.io.File
|
||||
import java.net.URLClassLoader
|
||||
|
||||
internal class PatchLoader {
|
||||
internal companion object {
|
||||
|
||||
}
|
||||
}
|
@ -1,26 +1,2 @@
|
||||
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<Data>> {
|
||||
val url = patchFile.toURI().toURL()
|
||||
val classLoader = URLClassLoader(arrayOf(url))
|
||||
return loadIndex(classLoader).patches
|
||||
}
|
||||
private fun loadIndex(classLoader: ClassLoader) = classLoader
|
||||
.loadClass(Index::class.java.canonicalName)
|
||||
.fields
|
||||
.first()
|
||||
.get(null) as Index
|
||||
}
|
||||
|
@ -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
|
||||
@ -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()
|
||||
}
|
||||
|
71
src/main/kotlin/app/revanced/utils/patcher/Patcher.kt
Normal file
71
src/main/kotlin/app/revanced/utils/patcher/Patcher.kt
Normal file
@ -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<Patch<Data>>()
|
||||
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)
|
||||
}
|
58
src/main/kotlin/app/revanced/utils/signature/Signature.kt
Normal file
58
src/main/kotlin/app/revanced/utils/signature/Signature.kt
Normal file
@ -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<String>()
|
||||
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}"
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user