Compare commits

..

21 Commits

Author SHA1 Message Date
semantic-release-bot
c8a5e97f0d chore(release): 1.1.2 [skip ci]
## [1.1.2](https://github.com/revanced/revanced-cli/compare/v1.1.1...v1.1.2) (2022-05-22)

### Bug Fixes

* delete `outputFile` after deploying ([329f8a3](329f8a383f))
2022-05-22 20:39:34 +00:00
oSumAtrIX
329f8a383f fix: delete outputFile after deploying 2022-05-22 22:38:27 +02:00
semantic-release-bot
fb1cd41521 chore(release): 1.1.1 [skip ci]
## [1.1.1](https://github.com/revanced/revanced-cli/compare/v1.1.0...v1.1.1) (2022-05-22)

### Bug Fixes

* breaking changes by `revanced-patcher` dependency ([51d2504](51d250491f))
* wrong use of dependency to `revanced-patches` ([351de6c](351de6cb90))
* wrong use of variable substitution / typo ([81d53b5](81d53b5518)), closes [revanced/revanced-cli#12](https://github.com/revanced/revanced-cli/issues/12)
2022-05-22 15:28:46 +00:00
oSumAtrIX
457c371fb9 Merge branch 'dev'
# Conflicts:
#	CHANGELOG.md
#	gradle.properties
2022-05-22 17:25:38 +02:00
oSumAtrIX
cd58fe5869 Merge pull request #16 from revanced/annotations
fix: support annotated patches
2022-05-22 17:15:56 +02:00
oSumAtrIX
f297f7d1ef add: signature checker and compatibility filters
Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
2022-05-22 17:10:43 +02:00
oSumAtrIX
51d250491f fix: breaking changes by revanced-patcher dependency
Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
2022-05-22 13:47:45 +02:00
semantic-release-bot
f90205b243 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](81d53b5518)), closes [revanced/revanced-cli#12](https://github.com/revanced/revanced-cli/issues/12)
2022-05-15 20:11:14 +00:00
oSumAtrIX
159a169c16 Merge pull request #13 from AzimsTech/dev
fix: wrong use of variable substitution / typo
2022-05-15 22:09:27 +02:00
Wan Muhammad Azims
81d53b5518 fix: wrong use of variable substitution / typo
[revanced/revanced-cli#12](https://github.com/revanced/revanced-cli/issues/12)
2022-05-16 03:45:20 +08:00
semantic-release-bot
aba7965df8 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](351de6cb90))
2022-05-07 21:16:55 +00:00
oSumAtrIX
351de6cb90 fix: wrong use of dependency to revanced-patches
Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
2022-05-07 23:15:31 +02:00
oSumAtrIX
52dacc16a0 chore: bump project JDK to JDK 17
Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
2022-05-07 21:37:24 +02:00
semantic-release-bot
a7493e5e43 chore(release): 1.1.0 [skip ci]
# [1.1.0](https://github.com/revanced/revanced-cli/compare/v1.0.1...v1.1.0) (2022-05-07)

### Bug Fixes

* ClassLoader not working with Java 9+ ([3a11e11](3a11e1135b))
* leftover TODOs ([5b1139c](5b1139ce43))

### Features

* run `release.yml` workflow on branch `dev` ([9a64730](9a6473056b))
2022-05-07 19:26:36 +00:00
oSumAtrIX
46c275feb5 Merge pull request #10 from revanced/dev
feat: support java version 9+
2022-05-07 21:25:28 +02:00
oSumAtrIX
4fe620e84b chore: bump java-version for action setup-java
Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
2022-05-07 21:21:44 +02:00
semantic-release-bot
7b1f10a8e9 chore(release): 1.1.0-dev.1 [skip ci]
# [1.1.0-dev.1](https://github.com/revanced/revanced-cli/compare/v1.0.1...v1.1.0-dev.1) (2022-05-07)

### Bug Fixes

* ClassLoader not working with Java 9+ ([3a11e11](3a11e1135b))
* leftover TODOs ([5b1139c](5b1139ce43))

### Features

* run `release.yml` workflow on branch `dev` ([9a64730](9a6473056b))
2022-05-07 19:20:22 +00:00
oSumAtrIX
9a6473056b feat: run release.yml workflow on branch dev
Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
2022-05-07 21:19:01 +02:00
oSumAtrIX
a108c92ade Merge pull request #9 from danthe1st/main
fix: ClassLoader not working with Java 9+
2022-05-07 21:15:02 +02:00
oSumAtrIX
5b1139ce43 fix: leftover TODOs
Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
2022-05-07 21:13:28 +02:00
danthe1st
3a11e1135b fix: ClassLoader not working with Java 9+ 2022-05-07 21:08:11 +02:00
14 changed files with 227 additions and 124 deletions

View File

@@ -3,9 +3,11 @@ on:
push:
branches:
- main
- dev
pull_request:
branches:
- main
- dev
jobs:
release:
name: Release
@@ -18,7 +20,7 @@ jobs:
- name: Setup JDK
uses: actions/setup-java@v2
with:
java-version: '8'
java-version: '17'
distribution: 'adopt'
cache: gradle
- name: Setup Node.js

2
.idea/misc.xml generated
View File

@@ -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>

View File

@@ -1,3 +1,46 @@
## [1.1.2](https://github.com/revanced/revanced-cli/compare/v1.1.1...v1.1.2) (2022-05-22)
### Bug Fixes
* delete `outputFile` after deploying ([329f8a3](https://github.com/revanced/revanced-cli/commit/329f8a383fe52f4c2a66075d893c6599d3550bee))
## [1.1.1](https://github.com/revanced/revanced-cli/compare/v1.1.0...v1.1.1) (2022-05-22)
### Bug Fixes
* breaking changes by `revanced-patcher` dependency ([51d2504](https://github.com/revanced/revanced-cli/commit/51d250491f390695aedc64e7ee71a9dcf99d695c))
* wrong use of dependency to `revanced-patches` ([351de6c](https://github.com/revanced/revanced-cli/commit/351de6cb90aa0f2ec93e8b8f6c10d7d312082079))
* 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.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)
### 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)
### 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))
### Features
* run `release.yml` workflow on branch `dev` ([9a64730](https://github.com/revanced/revanced-cli/commit/9a6473056b940c6df4860dd09c09d7ac61545f7d))
## [1.0.1](https://github.com/revanced/revanced-cli/compare/v1.0.0...v1.0.1) (2022-05-07)

View File

@@ -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)

View File

@@ -1,2 +1,2 @@
kotlin.code.style = official
version = 1.0.1
version = 1.1.2

View File

@@ -1,8 +1,11 @@
package app.revanced.cli
import app.revanced.patch.PatchLoader
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
@@ -34,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>()
@@ -48,37 +54,43 @@ internal object MainCommand : Runnable {
override fun run() {
if (listOnly) {
patchBundles.forEach {
PatchLoader.injectPatches(it)
Patches.loadPatches().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
)
Patcher.start(patcher)
if (clean) {
File(cacheDirectory).deleteRecursively()
if (signatureCheck) {
patcher.addPatchesFiltered()
Signature.checkSignatures(patcher)
return
}
val outputFile = File(outputPath)
var adb: Adb? = null
deploy?.let {
Adb(
outputFile,
patcher.packageName,
deploy!!
).deploy()
adb = Adb(
outputFile, patcher.packageName, deploy!!
)
}
Patcher.start(patcher)
if (clean) File(cacheDirectory).deleteRecursively()
adb?.deploy()
if (clean) outputFile.delete()
}
}
}

View File

@@ -1,10 +1,9 @@
package app.revanced.cli
import app.revanced.patch.PatchLoader
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
@@ -12,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)
@@ -35,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
@@ -49,43 +44,10 @@ internal class Patcher {
// and sign the apk file
Signer.signApk(outFile)
println("[done]")
}
private fun app.revanced.patcher.Patcher.addPatchesFiltered() {
// TODO: get package metadata (outside of this method) for apk file which needs to be patched
val packageName = this.packageName
val packageVersion = this.packageVersion
val checkInclude = MainCommand.includedPatches.isNotEmpty()
MainCommand.patchBundles.forEach { bundle ->
PatchLoader.injectPatches(bundle)
val includedPatches = mutableListOf<Patch<Data>>()
Patches.loadPatches().forEach patch@{
val patch = it()
// TODO: filter out incompatible patches with package metadata
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)
}
}
}
}

View File

@@ -1,25 +0,0 @@
package app.revanced.patch
import java.io.File
import java.net.URL
import java.net.URLClassLoader
internal class PatchLoader {
internal companion object {
internal fun injectPatches(file: File) {
// This function will fail on Java 9 and above.
try {
val url = file.toURI().toURL()
val classLoader = Thread.currentThread().contextClassLoader as URLClassLoader
val method = URLClassLoader::class.java.getDeclaredMethod("addURL", URL::class.java)
method.isAccessible = true
method.invoke(classLoader, url)
} catch (e: Exception) {
throw Exception(
"Failed to inject patches! The CLI does NOT work on Java 9 and above, please use Java 8!",
e // propagate exception
)
}
}
}
}

View File

@@ -1,15 +1,2 @@
package app.revanced.patch
import app.revanced.patches.Index
internal class Patches {
internal companion object {
// You may ask yourself, "why do this?".
// We do it like this, because we don't want the Index class
// to be loaded while the dependency hasn't been injected yet.
// You can see this as "controlled class loading".
// Whenever this class is loaded (because it is invoked), all the imports
// will be loaded too. We don't want to do this until we've injected the class.
internal fun loadPatches() = Index.patches
}
}

View File

@@ -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()
}

View File

@@ -12,10 +12,7 @@ internal class FileSystemUtils(
private var fileSystem: FileSystem
init {
fileSystem = FileSystems.newFileSystem(
file.toPath(),
null
)
fileSystem = FileSystems.newFileSystem(file.toPath(), null as ClassLoader?)
}
private fun deleteDirectory(dirPath: String) {

View 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)
}

View 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}"
}
}

View File

@@ -91,7 +91,7 @@ object Signer {
(keyStore.getKey(alias, PASSWORD) as PrivateKey)
)
val zip = FileSystems.newFileSystem(apkFile.toPath(), null)
val zip = FileSystems.newFileSystem(apkFile.toPath(), null as ClassLoader?)
val dig = MessageDigest.getInstance("SHA1")
val digests: MutableMap<String, String> = LinkedHashMap()