Compare commits

..

44 Commits

Author SHA1 Message Date
semantic-release-bot
d61ab058da chore(release): 2.17.0 [skip ci]
# [2.17.0](https://github.com/revanced/revanced-cli/compare/v2.16.1...v2.17.0) (2022-12-14)

### Bug Fixes

* invalid header when writing a `ZipFile` ([#169](https://github.com/revanced/revanced-cli/issues/169)) ([6e703eb](6e703eb8e8))

### Features

* improve missing compatibility annotation tracing log ([2c7eb72](2c7eb7274c))
* trace logs when compatibility annotation is missing ([#166](https://github.com/revanced/revanced-cli/issues/166)) ([c590bf5](c590bf559c))
2022-12-14 23:48:26 +00:00
oSumAtrIX
235c2742ec chore: merge branch dev to main (#173) 2022-12-15 00:39:03 +01:00
semantic-release-bot
8a964efd00 chore(release): 2.17.0-dev.3 [skip ci]
# [2.17.0-dev.3](https://github.com/revanced/revanced-cli/compare/v2.17.0-dev.2...v2.17.0-dev.3) (2022-12-14)

### Features

* improve missing compatibility annotation tracing log ([2c7eb72](2c7eb7274c))
2022-12-14 23:37:35 +00:00
oSumAtrIX
8114d1dca0 build: remove unnecessary step 2022-12-15 00:32:48 +01:00
oSumAtrIX
5a7cadd96d build: remove manifest attributes 2022-12-15 00:32:47 +01:00
oSumAtrIX
1c5983b803 build: minimize shadow jar 2022-12-15 00:32:47 +01:00
oSumAtrIX
2c7eb7274c feat: improve missing compatibility annotation tracing log 2022-12-15 00:32:47 +01:00
oSumAtrIX
512152fb66 ci: stash before rebasing 2022-12-15 00:32:47 +01:00
oSumAtrIX
8793b5fc65 chore: merge branch dev to main (#167) 2022-12-14 01:18:05 +01:00
semantic-release-bot
39c490d6b7 chore(release): 2.17.0-dev.2 [skip ci]
# [2.17.0-dev.2](https://github.com/revanced/revanced-cli/compare/v2.17.0-dev.1...v2.17.0-dev.2) (2022-12-14)

### Bug Fixes

* invalid header when writing a `ZipFile` ([#169](https://github.com/revanced/revanced-cli/issues/169)) ([6e703eb](6e703eb8e8))
2022-12-14 00:16:38 +00:00
oSumAtrIX
6e703eb8e8 fix: invalid header when writing a ZipFile (#169) 2022-12-14 01:14:00 +01:00
oSumAtrIX
c677eb9792 ci: back-merge releases back into dev branch 2022-12-14 01:13:45 +01:00
oSumAtrIX
75c8ea4639 chore: bump patcher dependency version 2022-12-14 01:13:00 +01:00
semantic-release-bot
b69dd52ca9 chore(release): 2.17.0-dev.1 [skip ci]
# [2.17.0-dev.1](https://github.com/revanced/revanced-cli/compare/v2.16.1...v2.17.0-dev.1) (2022-12-11)

### Features

* trace logs when compatibility annotation is missing ([#166](https://github.com/revanced/revanced-cli/issues/166)) ([c590bf5](c590bf559c))
2022-12-11 19:10:19 +00:00
oSumAtrIX
c590bf559c feat: trace logs when compatibility annotation is missing (#166) 2022-12-11 20:08:52 +01:00
oSumAtrIX
ec0b847419 chore: merge branch dev to main (#165) 2022-12-11 05:19:08 +01:00
oSumAtrIX
b3cf32e89d ci: open pull requests to merge dev to main (#164) 2022-12-11 05:16:51 +01:00
oSumAtrIX
8a1199ba9a ci: refactor release workflow 2022-12-11 05:14:23 +01:00
oSumAtrIX
25b45800a1 chore: bump patcher dependency version 2022-12-02 04:04:25 +01:00
oSumAtrIX
2fe3303a27 chore: bump patcher dependency version 2022-12-02 02:35:35 +01:00
semantic-release-bot
04339f0654 chore(release): 2.16.1 [skip ci]
## [2.16.1](https://github.com/revanced/revanced-cli/compare/v2.16.0...v2.16.1) (2022-11-22)
2022-11-22 23:37:24 +00:00
oSumAtrIX
456428a836 build: bump dependencies 2022-11-23 00:33:45 +01:00
oSumAtrIX
c9ae379c77 feat!: apply changes from ReVanced Patcher 2022-11-23 00:20:48 +01:00
semantic-release-bot
81d702949c chore(release): 2.16.0 [skip ci]
# [2.16.0](https://github.com/revanced/revanced-cli/compare/v2.15.1...v2.16.0) (2022-11-20)

### Features

* do not warn on incompatible packages ([39e377b](39e377bc48))
2022-11-20 01:50:38 +00:00
oSumAtrIX
39e377bc48 feat: do not warn on incompatible packages 2022-11-20 00:34:00 +01:00
oSumAtrIX
fce40421e9 chore: ignore file vcs.xml from version control [skip ci] 2022-11-19 19:56:46 +01:00
semantic-release-bot
cb554c8bdf chore(release): 2.15.1 [skip ci]
## [2.15.1](https://github.com/revanced/revanced-cli/compare/v2.15.0...v2.15.1) (2022-11-18)
2022-11-18 01:37:14 +00:00
oSumAtrIX
269c753dfa build: bump picocli dependency version 2022-11-18 02:34:28 +01:00
oSumAtrIX
6403e34712 build: bump patcher dependency version 2022-11-18 02:27:33 +01:00
Nico Mexis
f68e7697ff build: update workflow actions (#161) [skip ci] 2022-11-05 15:28:42 +01:00
semantic-release-bot
64b7e86252 chore(release): 2.15.0 [skip ci]
# [2.15.0](https://github.com/revanced/revanced-cli/compare/v2.14.0...v2.15.0) (2022-10-31)

### Bug Fixes

* **gitignore:** ignore `options.toml` ([#158](https://github.com/revanced/revanced-cli/issues/158)) ([7be9af0](7be9af0942))

### Features

* use `am` instead of `monkey` to launch the app ([#159](https://github.com/revanced/revanced-cli/issues/159)) ([6a35cf7](6a35cf7ea4))
2022-10-31 13:19:05 +00:00
OxrxL
7be9af0942 fix(gitignore): ignore options.toml (#158) 2022-10-31 14:16:00 +01:00
decipher
6a35cf7ea4 feat: use am instead of monkey to launch the app (#159) 2022-10-31 14:15:34 +01:00
SriBalaji
4914fd37bc build: update checkout actions to v3 [skip ci] (#155) 2022-10-13 17:35:24 +02:00
semantic-release-bot
38052b6ecf chore(release): 2.14.0 [skip ci]
# [2.14.0](https://github.com/revanced/revanced-cli/compare/v2.13.0...v2.14.0) (2022-10-05)

### Bug Fixes

* escape quotation mark in string ([6e21d81](6e21d81964))

### Features

* handle unmounting deleted files ([#148](https://github.com/revanced/revanced-cli/issues/148)) ([3a733e5](3a733e5137))
* unmount all occurrences in `/proc/mounts` ([#131](https://github.com/revanced/revanced-cli/issues/131)) ([4f4e1f9](4f4e1f9834))
2022-10-05 18:27:53 +00:00
oSumAtrIX
6e21d81964 fix: escape quotation mark in string 2022-10-05 20:26:15 +02:00
decipher
3a733e5137 feat: handle unmounting deleted files (#148) 2022-10-05 14:47:23 +02:00
decipher
4f4e1f9834 feat: unmount all occurrences in /proc/mounts (#131) 2022-10-05 14:20:41 +02:00
oSumAtrIX
e035d93d2c chore: migrate to new changes from the patcher 2022-10-05 04:12:46 +02:00
oSumAtrIX
839854d890 refactor: remove unused variable 2022-10-04 08:30:53 +02:00
semantic-release-bot
43c772c98d chore(release): 2.13.0 [skip ci]
# [2.13.0](https://github.com/revanced/revanced-cli/compare/v2.12.0...v2.13.0) (2022-10-01)

### Features

* check, if input file exists ([b6dff6d](b6dff6d832))
2022-10-01 03:21:30 +00:00
oSumAtrIX
b6dff6d832 feat: check, if input file exists 2022-10-01 05:19:42 +02:00
OxrxL
29b057dead chore: do not commit revanced-cache (#144) 2022-09-30 00:33:17 +02:00
oSumAtrIX
7df4a7e7da chore: bump patcher dependency version 2022-09-29 21:32:39 +02:00
20 changed files with 6418 additions and 147 deletions

24
.github/workflows/pull_request.yml vendored Normal file
View File

@@ -0,0 +1,24 @@
name: PR to main
on:
push:
branches:
- dev
workflow_dispatch:
env:
MESSAGE: merge branch \`${{ github.head_ref || github.ref_name }}\` to \`main\`
jobs:
pull-request:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Open pull request
uses: repo-sync/pull-request@v2
with:
destination_branch: 'main'
pr_title: 'chore: ${{ env.MESSAGE }}'
pr_body: 'This pull request will ${{ env.MESSAGE }}.'
pr_draft: true

View File

@@ -15,26 +15,23 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v2 uses: actions/checkout@v3
with: with:
fetch-depth: 0 fetch-depth: 0
- name: Setup JDK - name: Setup JDK
uses: actions/setup-java@v2 uses: actions/setup-java@v3
with: with:
java-version: '17' java-version: '17'
distribution: 'adopt' distribution: 'zulu'
cache: gradle cache: gradle
- name: Setup Node.js - name: Setup Node.js
uses: actions/setup-node@v2 uses: actions/setup-node@v3
with: with:
node-version: "lts/*" node-version: "latest"
- name: Build with Gradle cache: 'npm'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: ./gradlew build clean
- name: Setup semantic-release - name: Setup semantic-release
run: npm install -g semantic-release @semantic-release/git @semantic-release/changelog gradle-semantic-release-plugin -D run: npm install semantic-release @saithodev/semantic-release-backmerge @semantic-release/git @semantic-release/changelog gradle-semantic-release-plugin -D
- name: Release - name: Create release
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: npx semantic-release run: npx semantic-release

9
.gitignore vendored
View File

@@ -111,4 +111,11 @@ gradle-app.setting
.gradletasknamecache .gradletasknamecache
# # Work around https://youtrack.jetbrains.com/issue/IDEA-116898 # # Work around https://youtrack.jetbrains.com/issue/IDEA-116898
# gradle/wrapper/gradle-wrapper.properties # gradle/wrapper/gradle-wrapper.properties
# Dependency directories
node_modules/
# ReVanced CLI
revanced-cache/
options.toml

2
.idea/.gitignore generated vendored
View File

@@ -7,3 +7,5 @@
/dataSources/ /dataSources/
/dataSources.local.xml /dataSources.local.xml
/kotlinc.xml /kotlinc.xml
/vcs.xml
/codeStyles

4
.idea/misc.xml generated
View File

@@ -4,6 +4,10 @@
<component name="FrameworkDetectionExcludesConfiguration"> <component name="FrameworkDetectionExcludesConfiguration">
<file type="web" url="file://$PROJECT_DIR$" /> <file type="web" url="file://$PROJECT_DIR$" />
</component> </component>
<component name="PWA">
<option name="enabled" value="true" />
<option name="wasEnabledAtLeastOnce" value="true" />
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="azul-17" 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" /> <output url="file://$PROJECT_DIR$/out" />
</component> </component>

View File

@@ -33,6 +33,13 @@
} }
] ]
} }
],
[
"@saithodev/semantic-release-backmerge",
{
branches: [{from: "main", to: "dev"}],
clearWorkspace: true
}
] ]
] ]
} }

View File

@@ -1,3 +1,80 @@
# [2.17.0](https://github.com/revanced/revanced-cli/compare/v2.16.1...v2.17.0) (2022-12-14)
### Bug Fixes
* invalid header when writing a `ZipFile` ([#169](https://github.com/revanced/revanced-cli/issues/169)) ([6e703eb](https://github.com/revanced/revanced-cli/commit/6e703eb8e8d7da0e52266c4965f37bc8aafb409c))
### Features
* improve missing compatibility annotation tracing log ([2c7eb72](https://github.com/revanced/revanced-cli/commit/2c7eb7274c713dfbcb53c5f3b6a9205c751914fa))
* trace logs when compatibility annotation is missing ([#166](https://github.com/revanced/revanced-cli/issues/166)) ([c590bf5](https://github.com/revanced/revanced-cli/commit/c590bf559c4d2d2667c2af0c0da23d4706fcd4b7))
# [2.17.0-dev.3](https://github.com/revanced/revanced-cli/compare/v2.17.0-dev.2...v2.17.0-dev.3) (2022-12-14)
### Features
* improve missing compatibility annotation tracing log ([2c7eb72](https://github.com/revanced/revanced-cli/commit/2c7eb7274c713dfbcb53c5f3b6a9205c751914fa))
# [2.17.0-dev.2](https://github.com/revanced/revanced-cli/compare/v2.17.0-dev.1...v2.17.0-dev.2) (2022-12-14)
### Bug Fixes
* invalid header when writing a `ZipFile` ([#169](https://github.com/revanced/revanced-cli/issues/169)) ([6e703eb](https://github.com/revanced/revanced-cli/commit/6e703eb8e8d7da0e52266c4965f37bc8aafb409c))
# [2.17.0-dev.1](https://github.com/revanced/revanced-cli/compare/v2.16.1...v2.17.0-dev.1) (2022-12-11)
### Features
* trace logs when compatibility annotation is missing ([#166](https://github.com/revanced/revanced-cli/issues/166)) ([c590bf5](https://github.com/revanced/revanced-cli/commit/c590bf559c4d2d2667c2af0c0da23d4706fcd4b7))
## [2.16.1](https://github.com/revanced/revanced-cli/compare/v2.16.0...v2.16.1) (2022-11-22)
# [2.16.0](https://github.com/revanced/revanced-cli/compare/v2.15.1...v2.16.0) (2022-11-20)
### Features
* do not warn on incompatible packages ([39e377b](https://github.com/revanced/revanced-cli/commit/39e377bc485e2892422e9712d30e6ff665856ac1))
## [2.15.1](https://github.com/revanced/revanced-cli/compare/v2.15.0...v2.15.1) (2022-11-18)
# [2.15.0](https://github.com/revanced/revanced-cli/compare/v2.14.0...v2.15.0) (2022-10-31)
### Bug Fixes
* **gitignore:** ignore `options.toml` ([#158](https://github.com/revanced/revanced-cli/issues/158)) ([7be9af0](https://github.com/revanced/revanced-cli/commit/7be9af0942de2a834b9e57403d46263b65f1a422))
### Features
* use `am` instead of `monkey` to launch the app ([#159](https://github.com/revanced/revanced-cli/issues/159)) ([6a35cf7](https://github.com/revanced/revanced-cli/commit/6a35cf7ea46a4474120626ce03d28490cc96bf07))
# [2.14.0](https://github.com/revanced/revanced-cli/compare/v2.13.0...v2.14.0) (2022-10-05)
### Bug Fixes
* escape quotation mark in string ([6e21d81](https://github.com/revanced/revanced-cli/commit/6e21d81964e8160e06ffda7051dd484e4aaaa432))
### Features
* handle unmounting deleted files ([#148](https://github.com/revanced/revanced-cli/issues/148)) ([3a733e5](https://github.com/revanced/revanced-cli/commit/3a733e513717799ca0e32327e5b8be043680c556))
* unmount all occurrences in `/proc/mounts` ([#131](https://github.com/revanced/revanced-cli/issues/131)) ([4f4e1f9](https://github.com/revanced/revanced-cli/commit/4f4e1f9834bf28d9be2efd4fd7bae19951b85258))
# [2.13.0](https://github.com/revanced/revanced-cli/compare/v2.12.0...v2.13.0) (2022-10-01)
### Features
* check, if input file exists ([b6dff6d](https://github.com/revanced/revanced-cli/commit/b6dff6d832de4a513a6d86b0a59b2458eddd23c2))
# [2.12.0](https://github.com/revanced/revanced-cli/compare/v2.11.2...v2.12.0) (2022-09-26) # [2.12.0](https://github.com/revanced/revanced-cli/compare/v2.11.2...v2.12.0) (2022-09-26)

View File

@@ -25,8 +25,8 @@ repositories {
dependencies { dependencies {
implementation(kotlin("reflect")) implementation(kotlin("reflect"))
implementation("app.revanced:revanced-patcher:5.1.1") implementation("app.revanced:revanced-patcher:6.3.1")
implementation("info.picocli:picocli:4.6.3") implementation("info.picocli:picocli:4.7.0")
implementation("com.android.tools.build:apksig:7.2.1") implementation("com.android.tools.build:apksig:7.2.1")
implementation("com.github.revanced:jadb:master-SNAPSHOT") // updated fork implementation("com.github.revanced:jadb:master-SNAPSHOT") // updated fork
implementation("org.bouncycastle:bcpkix-jdk15on:1.70") implementation("org.bouncycastle:bcpkix-jdk15on:1.70")
@@ -40,9 +40,8 @@ tasks {
shadowJar { shadowJar {
manifest { manifest {
attributes("Main-Class" to "app.revanced.cli.main.MainKt") attributes("Main-Class" to "app.revanced.cli.main.MainKt")
attributes("Implementation-Title" to project.name)
attributes("Implementation-Version" to project.version)
} }
minimize()
} }
// Dummy task to fix the Gradle semantic-release plugin. // Dummy task to fix the Gradle semantic-release plugin.
// Remove this if you forked it to support building only. // Remove this if you forked it to support building only.

View File

@@ -1,2 +1,2 @@
kotlin.code.style = official kotlin.code.style = official
version = 2.12.0 version = 2.17.0

6107
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

8
package.json Normal file
View File

@@ -0,0 +1,8 @@
{
"devDependencies": {
"@semantic-release/changelog": "^6.0.2",
"@semantic-release/git": "^10.0.1",
"gradle-semantic-release-plugin": "^1.7.4",
"semantic-release": "^19.0.5"
}
}

View File

@@ -1,12 +1,37 @@
package app.revanced.cli.aligning package app.revanced.cli.aligning
import app.revanced.cli.command.MainCommand.logger import app.revanced.cli.command.MainCommand.logger
import app.revanced.patcher.PatcherResult
import app.revanced.utils.signing.align.ZipAligner import app.revanced.utils.signing.align.ZipAligner
import app.revanced.utils.signing.align.zip.ZipFile
import app.revanced.utils.signing.align.zip.structures.ZipEntry
import java.io.File import java.io.File
object Aligning { object Aligning {
fun align(inputFile: File, outputFile: File) { fun align(result: PatcherResult, inputFile: File, outputFile: File) {
logger.info("Aligning ${inputFile.name} to ${outputFile.name}") logger.info("Aligning ${inputFile.name} to ${outputFile.name}")
ZipAligner.align(inputFile, outputFile)
if (outputFile.exists()) outputFile.delete()
ZipFile(outputFile).use { file ->
result.dexFiles.forEach {
file.addEntryCompressData(
ZipEntry.createWithName(it.name),
it.stream.readBytes()
)
}
result.resourceFile?.let {
file.copyEntriesFromFileAligned(
ZipFile(it),
ZipAligner::getEntryAlignment
)
}
file.copyEntriesFromFileAligned(
ZipFile(inputFile),
ZipAligner::getEntryAlignment
)
}
} }
} }

View File

@@ -10,7 +10,7 @@ import app.revanced.patcher.PatcherOptions
import app.revanced.patcher.extensions.PatchExtensions.compatiblePackages import app.revanced.patcher.extensions.PatchExtensions.compatiblePackages
import app.revanced.patcher.extensions.PatchExtensions.description import app.revanced.patcher.extensions.PatchExtensions.description
import app.revanced.patcher.extensions.PatchExtensions.patchName import app.revanced.patcher.extensions.PatchExtensions.patchName
import app.revanced.patcher.util.patch.impl.JarPatchBundle import app.revanced.patcher.util.patch.PatchBundle
import app.revanced.utils.OptionsLoader import app.revanced.utils.OptionsLoader
import app.revanced.utils.adb.Adb import app.revanced.utils.adb.Adb
import picocli.CommandLine.* import picocli.CommandLine.*
@@ -131,14 +131,14 @@ internal object MainCommand : Runnable {
val outputFile = File(pArgs.outputPath) // the file to write to val outputFile = File(pArgs.outputPath) // the file to write to
val allPatches = args.patchArgs!!.patchBundles.flatMap { bundle -> val allPatches = args.patchArgs!!.patchBundles.flatMap { bundle ->
JarPatchBundle(bundle).loadPatches() PatchBundle.Jar(bundle).loadPatches()
} }
OptionsLoader.init(args.patchArgs!!.options, allPatches) OptionsLoader.init(args.patchArgs!!.options, allPatches)
val patcher = app.revanced.patcher.Patcher( val patcher = app.revanced.patcher.Patcher(
PatcherOptions( PatcherOptions(
args.inputFile, args.inputFile.also { if (!it.exists()) return logger.error("Input file ${args.inputFile} does not exist.") },
pArgs.cacheDirectory, pArgs.cacheDirectory,
pArgs.aaptPath, pArgs.aaptPath,
pArgs.cacheDirectory, pArgs.cacheDirectory,
@@ -148,19 +148,17 @@ internal object MainCommand : Runnable {
// prepare adb // prepare adb
val adb: Adb? = args.deploy?.let { val adb: Adb? = args.deploy?.let {
Adb(outputFile, patcher.data.packageMetadata.packageName, args.deploy!!, !pArgs.mount) Adb(outputFile, patcher.context.packageMetadata.packageName, args.deploy!!, !pArgs.mount)
} }
val patchedFile = File(pArgs.cacheDirectory).resolve("${outputFile.nameWithoutExtension}_raw.apk")
// start the patcher // start the patcher
Patcher.start(patcher, patchedFile, allPatches) val result = Patcher.start(patcher, allPatches)
val cacheDirectory = File(pArgs.cacheDirectory) val cacheDirectory = File(pArgs.cacheDirectory)
// align the file // align the file
val alignedFile = cacheDirectory.resolve("${outputFile.nameWithoutExtension}_aligned.apk") val alignedFile = cacheDirectory.resolve("${outputFile.nameWithoutExtension}_aligned.apk")
Aligning.align(patchedFile, alignedFile) Aligning.align(result, args.inputFile, alignedFile)
// sign the file // sign the file
val finalFile = if (!pArgs.mount) { val finalFile = if (!pArgs.mount) {
@@ -209,7 +207,7 @@ internal object MainCommand : Runnable {
val adb: Adb? = args.deploy?.let { val adb: Adb? = args.deploy?.let {
Adb( Adb(
File("placeholder_file"), File("placeholder_file"),
app.revanced.patcher.Patcher(PatcherOptions(args.inputFile, "")).data.packageMetadata.packageName, app.revanced.patcher.Patcher(PatcherOptions(args.inputFile, "")).context.packageMetadata.packageName,
args.deploy!!, args.deploy!!,
false false
) )
@@ -219,7 +217,8 @@ internal object MainCommand : Runnable {
private fun printListOfPatches() { private fun printListOfPatches() {
val logged = mutableListOf<String>() val logged = mutableListOf<String>()
for (patchBundlePath in args.patchArgs?.patchBundles!!) for (patch in JarPatchBundle(patchBundlePath).loadPatches()) { for (patchBundlePath in args.patchArgs?.patchBundles!!) for (patch in PatchBundle.Jar(patchBundlePath)
.loadPatches()) {
if (patch.patchName in logged) continue if (patch.patchName in logged) continue
for (compatiblePackage in patch.compatiblePackages!!) { for (compatiblePackage in patch.compatiblePackages!!) {
val packageEntryStr = buildString { val packageEntryStr = buildString {

View File

@@ -1,21 +1,17 @@
package app.revanced.cli.patcher package app.revanced.cli.patcher
import app.revanced.cli.command.MainCommand.args import app.revanced.patcher.PatcherResult
import app.revanced.cli.command.MainCommand.logger import app.revanced.patcher.data.Context
import app.revanced.patcher.data.Data
import app.revanced.patcher.patch.Patch import app.revanced.patcher.patch.Patch
import app.revanced.utils.filesystem.ZipFileSystemUtils
import app.revanced.utils.patcher.addPatchesFiltered import app.revanced.utils.patcher.addPatchesFiltered
import app.revanced.utils.patcher.applyPatchesVerbose import app.revanced.utils.patcher.applyPatchesVerbose
import app.revanced.utils.patcher.mergeFiles import app.revanced.utils.patcher.mergeFiles
import java.io.File
import java.nio.file.Files
internal object Patcher { internal object Patcher {
internal fun start(patcher: app.revanced.patcher.Patcher, output: File, allPatches: List<Class<out Patch<Data>>>) { internal fun start(
val inputFile = args.inputFile patcher: app.revanced.patcher.Patcher,
val args = args.patchArgs?.patchingArgs!! allPatches: List<Class<out Patch<Context>>>
): PatcherResult {
// merge files like necessary integrations // merge files like necessary integrations
patcher.mergeFiles() patcher.mergeFiles()
// add patches, but filter incompatible or excluded patches // add patches, but filter incompatible or excluded patches
@@ -23,28 +19,6 @@ internal object Patcher {
// apply patches // apply patches
patcher.applyPatchesVerbose() patcher.applyPatchesVerbose()
// write output file return patcher.save()
if (output.exists()) Files.delete(output.toPath())
inputFile.copyTo(output)
val result = patcher.save()
ZipFileSystemUtils(output).use { outputFileSystem ->
// replace all dex files
result.dexFiles.forEach {
logger.info("Writing dex file ${it.name}")
outputFileSystem.write(it.name, it.stream.readAllBytes())
}
result.resourceFile?.let {
logger.info("Writing resources...")
ZipFileSystemUtils(it).use { resourceFileSystem ->
val resourceFiles = resourceFileSystem.getFile(File.separator)
outputFileSystem.writePathRecursively(resourceFiles)
}
}
result.doNotCompress?.let { outputFileSystem.uncompress(*it.toTypedArray()) }
}
} }
} }

View File

@@ -2,7 +2,7 @@ package app.revanced.utils
import app.revanced.cli.command.MainCommand.logger import app.revanced.cli.command.MainCommand.logger
import app.revanced.patcher.Patcher import app.revanced.patcher.Patcher
import app.revanced.patcher.data.Data import app.revanced.patcher.data.Context
import app.revanced.patcher.extensions.PatchExtensions.options import app.revanced.patcher.extensions.PatchExtensions.options
import app.revanced.patcher.extensions.PatchExtensions.patchName import app.revanced.patcher.extensions.PatchExtensions.patchName
import app.revanced.patcher.patch.Patch import app.revanced.patcher.patch.Patch
@@ -12,7 +12,7 @@ import cc.ekblad.toml.serialization.from
import cc.ekblad.toml.tomlMapper import cc.ekblad.toml.tomlMapper
import java.io.File import java.io.File
private typealias PatchList = List<Class<out Patch<Data>>> private typealias PatchList = List<Class<out Patch<Context>>>
private typealias OptionsMap = MutableMap<String, MutableMap<String, Any>> private typealias OptionsMap = MutableMap<String, MutableMap<String, Any>>
object OptionsLoader { object OptionsLoader {

View File

@@ -9,7 +9,7 @@ internal object Constants {
internal const val COMMAND_PID_OF = "pidof -s" internal const val COMMAND_PID_OF = "pidof -s"
internal const val COMMAND_CREATE_DIR = "mkdir -p" internal const val COMMAND_CREATE_DIR = "mkdir -p"
internal const val COMMAND_LOGCAT = "logcat -c && logcat | grep AndroidRuntime" internal const val COMMAND_LOGCAT = "logcat -c && logcat | grep AndroidRuntime"
internal const val COMMAND_RESTART = "monkey -p $PLACEHOLDER 1 && kill ${'$'}($COMMAND_PID_OF $PLACEHOLDER)" internal const val COMMAND_RESTART = "pm resolve-activity --brief $PLACEHOLDER | tail -n 1 | xargs am start -n && kill ${'$'}($COMMAND_PID_OF $PLACEHOLDER)"
// default mount file name // default mount file name
private const val NAME_MOUNT_SCRIPT = "mount_revanced_$PLACEHOLDER.sh" private const val NAME_MOUNT_SCRIPT = "mount_revanced_$PLACEHOLDER.sh"
@@ -35,7 +35,7 @@ internal object Constants {
// unmount command // unmount command
internal const val COMMAND_UMOUNT = internal const val COMMAND_UMOUNT =
"stock_path=${'$'}( pm path $PLACEHOLDER | grep base | sed 's/package://g' ) && umount -l ${'$'}stock_path" "grep $PLACEHOLDER /proc/mounts | while read -r line; do echo ${'$'}line | cut -d \" \" -f 2 | sed 's/apk.*/apk/' | xargs -r umount -l; done"
// install mount script & set permissions // install mount script & set permissions
internal const val COMMAND_INSTALL_MOUNT = "mv $PATH_INIT_PUSH $PATH_MOUNT && $COMMAND_CHMOD_MOUNT $PATH_MOUNT" internal const val COMMAND_INSTALL_MOUNT = "mv $PATH_INIT_PUSH $PATH_MOUNT && $COMMAND_CHMOD_MOUNT $PATH_MOUNT"

View File

@@ -4,18 +4,17 @@ import app.revanced.cli.command.MainCommand
import app.revanced.cli.command.MainCommand.args import app.revanced.cli.command.MainCommand.args
import app.revanced.cli.command.MainCommand.logger import app.revanced.cli.command.MainCommand.logger
import app.revanced.patcher.Patcher import app.revanced.patcher.Patcher
import app.revanced.patcher.data.Data import app.revanced.patcher.data.Context
import app.revanced.patcher.extensions.PatchExtensions.compatiblePackages import app.revanced.patcher.extensions.PatchExtensions.compatiblePackages
import app.revanced.patcher.extensions.PatchExtensions.deprecated
import app.revanced.patcher.extensions.PatchExtensions.include import app.revanced.patcher.extensions.PatchExtensions.include
import app.revanced.patcher.extensions.PatchExtensions.patchName import app.revanced.patcher.extensions.PatchExtensions.patchName
import app.revanced.patcher.patch.Patch import app.revanced.patcher.patch.Patch
fun Patcher.addPatchesFiltered(allPatches: List<Class<out Patch<Data>>>) { fun Patcher.addPatchesFiltered(allPatches: List<Class<out Patch<Context>>>) {
val packageName = this.data.packageMetadata.packageName val packageName = this.context.packageMetadata.packageName
val packageVersion = this.data.packageMetadata.packageVersion val packageVersion = this.context.packageMetadata.packageVersion
val includedPatches = mutableListOf<Class<out Patch<Data>>>() val includedPatches = mutableListOf<Class<out Patch<Context>>>()
allPatches.forEach patchLoop@{ patch -> allPatches.forEach patchLoop@{ patch ->
val compatiblePackages = patch.compatiblePackages val compatiblePackages = patch.compatiblePackages
val patchName = patch.patchName val patchName = patch.patchName
@@ -32,16 +31,10 @@ fun Patcher.addPatchesFiltered(allPatches: List<Class<out Patch<Data>>>) {
return@patchLoop return@patchLoop
} }
patch.deprecated?.let { (reason, replacement) -> if (compatiblePackages == null) logger.trace("$prefix: No constraint on packages. Continuing.")
logger.warn("$prefix: deprecated: $reason")
if (replacement != null) logger.warn("Either use ${replacement.java.patchName} instead or include it manually")
return@patchLoop
}
if (compatiblePackages == null) logger.warn("$prefix: Missing compatibility annotation. Continuing.")
else { else {
if (!compatiblePackages.any { it.name == packageName }) { if (!compatiblePackages.any { it.name == packageName }) {
logger.warn("$prefix: incompatible with $packageName. This patch is only compatible with ${ logger.trace("$prefix: Incompatible with $packageName. This patch is only compatible with ${
compatiblePackages.joinToString( compatiblePackages.joinToString(
", " ", "
) { it.name } ) { it.name }
@@ -53,7 +46,7 @@ fun Patcher.addPatchesFiltered(allPatches: List<Class<out Patch<Data>>>) {
val compatibleWith = compatiblePackages.joinToString(";") { _package -> val compatibleWith = compatiblePackages.joinToString(";") { _package ->
"${_package.name}: ${_package.versions.joinToString(", ")}" "${_package.name}: ${_package.versions.joinToString(", ")}"
} }
logger.warn("$prefix: incompatible with version $packageVersion. This patch is only compatible with version $compatibleWith") logger.warn("$prefix: Incompatible with version $packageVersion. This patch is only compatible with version $compatibleWith")
return@patchLoop return@patchLoop
} }
} }
@@ -66,7 +59,7 @@ fun Patcher.addPatchesFiltered(allPatches: List<Class<out Patch<Data>>>) {
} }
fun Patcher.applyPatchesVerbose() { fun Patcher.applyPatchesVerbose() {
this.applyPatches().forEach { (patch, result) -> this.executePatches().forEach { (patch, result) ->
if (result.isSuccess) { if (result.isSuccess) {
logger.info("$patch succeeded") logger.info("$patch succeeded")
return@forEach return@forEach

View File

@@ -1,28 +1,11 @@
package app.revanced.utils.signing.align package app.revanced.utils.signing.align
import app.revanced.utils.signing.align.zip.ZipFile import app.revanced.utils.signing.align.zip.structures.ZipEntry
import java.io.File
internal object ZipAligner { internal object ZipAligner {
private const val DEFAULT_ALIGNMENT = 4 private const val DEFAULT_ALIGNMENT = 4
private const val LIBRARY_ALIGNMENT = 4096 private const val LIBRARY_ALIGNMENT = 4096
fun align(input: File, output: File) { fun getEntryAlignment(entry: ZipEntry): Int? =
val inputZip = ZipFile(input) if (entry.compression.toUInt() != 0u) null else if (entry.fileName.endsWith(".so")) LIBRARY_ALIGNMENT else DEFAULT_ALIGNMENT
val outputZip = ZipFile(output)
for (entry in inputZip.entries) {
val data = inputZip.getDataForEntry(entry)
if (entry.compression == 0.toUShort()) {
val alignment = if (entry.fileName.endsWith(".so")) LIBRARY_ALIGNMENT else DEFAULT_ALIGNMENT
outputZip.addEntryAligned(entry, data, alignment)
} else {
outputZip.addEntry(entry, data)
}
}
outputZip.finish()
}
} }

View File

@@ -2,15 +2,21 @@ package app.revanced.utils.signing.align.zip
import app.revanced.utils.signing.align.zip.structures.ZipEndRecord import app.revanced.utils.signing.align.zip.structures.ZipEndRecord
import app.revanced.utils.signing.align.zip.structures.ZipEntry import app.revanced.utils.signing.align.zip.structures.ZipEntry
import java.io.Closeable
import java.io.File import java.io.File
import java.io.RandomAccessFile import java.io.RandomAccessFile
import java.nio.ByteBuffer import java.nio.ByteBuffer
import java.nio.channels.FileChannel import java.nio.channels.FileChannel
import java.util.zip.CRC32
import java.util.zip.Deflater
class ZipFile(val file: File) { class ZipFile(file: File) : Closeable {
var entries: MutableList<ZipEntry> = mutableListOf() var entries: MutableList<ZipEntry> = mutableListOf()
private val filePointer: RandomAccessFile = RandomAccessFile(file, "rw") private val filePointer: RandomAccessFile = RandomAccessFile(file, "rw")
private var CDNeedsRewrite = false
private val compressionLevel = 5
init { init {
//if file isn't empty try to load entries //if file isn't empty try to load entries
@@ -53,23 +59,24 @@ class ZipFile(val file: File) {
return buildList(numberOfEntries) { return buildList(numberOfEntries) {
for (i in 1..numberOfEntries) { for (i in 1..numberOfEntries) {
add(ZipEntry.fromCDE(filePointer).also add(
{ ZipEntry.fromCDE(filePointer).also
//for some reason the local extra field can be different from the central one {
it.readLocalExtra( //for some reason the local extra field can be different from the central one
filePointer.channel.map( it.readLocalExtra(
FileChannel.MapMode.READ_ONLY, filePointer.channel.map(
it.localHeaderOffset.toLong() + 28, FileChannel.MapMode.READ_ONLY,
2 it.localHeaderOffset.toLong() + 28,
2
)
) )
) })
})
} }
} }
} }
private fun writeCDE() { private fun writeCD() {
val CDEStart = filePointer.channel.position().toUInt() val CDStart = filePointer.channel.position().toUInt()
entries.forEach { entries.forEach {
filePointer.channel.write(it.toCDE()) filePointer.channel.write(it.toCDE())
@@ -82,15 +89,17 @@ class ZipFile(val file: File) {
0u, 0u,
entriesCount, entriesCount,
entriesCount, entriesCount,
filePointer.channel.position().toUInt() - CDEStart, filePointer.channel.position().toUInt() - CDStart,
CDEStart, CDStart,
"" ""
) )
filePointer.channel.write(endRecord.toECD()) filePointer.channel.write(endRecord.toECD())
} }
fun addEntry(entry: ZipEntry, data: ByteBuffer) { private fun addEntry(entry: ZipEntry, data: ByteBuffer) {
CDNeedsRewrite = true
entry.localHeaderOffset = filePointer.channel.position().toUInt() entry.localHeaderOffset = filePointer.channel.position().toUInt()
filePointer.channel.write(entry.toLFH()) filePointer.channel.write(entry.toLFH())
@@ -99,17 +108,45 @@ class ZipFile(val file: File) {
entries.add(entry) entries.add(entry)
} }
fun addEntryAligned(entry: ZipEntry, data: ByteBuffer, alignment: Int) { fun addEntryCompressData(entry: ZipEntry, data: ByteArray) {
//calculate where data would end up val compressor = Deflater(compressionLevel, true)
val dataOffset = filePointer.filePointer + entry.LFHSize compressor.setInput(data)
compressor.finish()
val mod = dataOffset % alignment val uncompressedSize = data.size
val compressedData =
ByteArray(uncompressedSize) //i'm guessing compression won't make the data bigger
//wrong alignment val compressedDataLength = compressor.deflate(compressedData)
if (mod != 0L) { val compressedBuffer =
//add padding at end of extra field ByteBuffer.wrap(compressedData.take(compressedDataLength).toByteArray())
entry.localExtraField =
entry.localExtraField.copyOf((entry.localExtraField.size + (alignment - mod)).toInt()) compressor.end()
val crc = CRC32()
crc.update(data)
entry.compression = 8u //deflate compression
entry.uncompressedSize = uncompressedSize.toUInt()
entry.compressedSize = compressedDataLength.toUInt()
entry.crc32 = crc.value.toUInt()
addEntry(entry, compressedBuffer)
}
private fun addEntryCopyData(entry: ZipEntry, data: ByteBuffer, alignment: Int? = null) {
alignment?.let {
//calculate where data would end up
val dataOffset = filePointer.filePointer + entry.LFHSize
val mod = dataOffset % alignment
//wrong alignment
if (mod != 0L) {
//add padding at end of extra field
entry.localExtraField =
entry.localExtraField.copyOf((entry.localExtraField.size + (alignment - mod)).toInt())
}
} }
addEntry(entry, data) addEntry(entry, data)
@@ -123,8 +160,17 @@ class ZipFile(val file: File) {
) )
} }
fun finish() { fun copyEntriesFromFileAligned(file: ZipFile, entryAlignment: (entry: ZipEntry) -> Int?) {
writeCDE() for (entry in file.entries) {
if (entries.any { it.fileName == entry.fileName }) continue //don't add duplicates
val data = file.getDataForEntry(entry)
addEntryCopyData(entry, data, entryAlignment(entry))
}
}
override fun close() {
if (CDNeedsRewrite) writeCD()
filePointer.close() filePointer.close()
} }
} }

View File

@@ -1,10 +1,6 @@
package app.revanced.utils.signing.align.zip.structures package app.revanced.utils.signing.align.zip.structures
import app.revanced.utils.signing.align.zip.getUShort import app.revanced.utils.signing.align.zip.*
import app.revanced.utils.signing.align.zip.putUInt
import app.revanced.utils.signing.align.zip.putUShort
import app.revanced.utils.signing.align.zip.readUIntLE
import app.revanced.utils.signing.align.zip.readUShortLE
import java.io.DataInput import java.io.DataInput
import java.nio.ByteBuffer import java.nio.ByteBuffer
import java.nio.ByteOrder import java.nio.ByteOrder
@@ -13,12 +9,12 @@ data class ZipEntry(
val version: UShort, val version: UShort,
val versionNeeded: UShort, val versionNeeded: UShort,
val flags: UShort, val flags: UShort,
val compression: UShort, var compression: UShort,
val modificationTime: UShort, val modificationTime: UShort,
val modificationDate: UShort, val modificationDate: UShort,
val crc32: UInt, var crc32: UInt,
val compressedSize: UInt, var compressedSize: UInt,
val uncompressedSize: UInt, var uncompressedSize: UInt,
val diskNumber: UShort, val diskNumber: UShort,
val internalAttributes: UShort, val internalAttributes: UShort,
val externalAttributes: UInt, val externalAttributes: UInt,
@@ -26,7 +22,7 @@ data class ZipEntry(
val fileName: String, val fileName: String,
val extraField: ByteArray, val extraField: ByteArray,
val fileComment: String, val fileComment: String,
var localExtraField: ByteArray = ByteArray(0), //seperate for alignment var localExtraField: ByteArray = ByteArray(0), //separate for alignment
) { ) {
val LFHSize: Int val LFHSize: Int
get() = LFH_HEADER_SIZE + fileName.toByteArray(Charsets.UTF_8).size + localExtraField.size get() = LFH_HEADER_SIZE + fileName.toByteArray(Charsets.UTF_8).size + localExtraField.size
@@ -41,6 +37,27 @@ data class ZipEntry(
const val LFH_HEADER_SIZE = 30 const val LFH_HEADER_SIZE = 30
const val LFH_SIGNATURE = 0x04034b50u const val LFH_SIGNATURE = 0x04034b50u
fun createWithName(fileName: String): ZipEntry {
return ZipEntry(
0x1403u, //made by unix, version 20
0u,
0u,
0u,
0x0821u, //seems to be static time google uses, no idea
0x0221u, //same as above
0u,
0u,
0u,
0u,
0u,
0u,
0u,
fileName,
ByteArray(0),
""
)
}
fun fromCDE(input: DataInput): ZipEntry { fun fromCDE(input: DataInput): ZipEntry {
val signature = input.readUIntLE() val signature = input.readUIntLE()
@@ -59,7 +76,7 @@ data class ZipEntry(
val fileNameLength = input.readUShortLE() val fileNameLength = input.readUShortLE()
var fileName = "" var fileName = ""
val extraFieldLength = input.readUShortLE() val extraFieldLength = input.readUShortLE()
var extraField = ByteArray(extraFieldLength.toInt()) val extraField = ByteArray(extraFieldLength.toInt())
val fileCommentLength = input.readUShortLE() val fileCommentLength = input.readUShortLE()
var fileComment = "" var fileComment = ""
val diskNumber = input.readUShortLE() val diskNumber = input.readUShortLE()
@@ -67,7 +84,8 @@ data class ZipEntry(
val externalAttributes = input.readUIntLE() val externalAttributes = input.readUIntLE()
val localHeaderOffset = input.readUIntLE() val localHeaderOffset = input.readUIntLE()
val variableFieldsLength = fileNameLength.toInt() + extraFieldLength.toInt() + fileCommentLength.toInt() val variableFieldsLength =
fileNameLength.toInt() + extraFieldLength.toInt() + fileCommentLength.toInt()
if (variableFieldsLength > 0) { if (variableFieldsLength > 0) {
val fileNameBytes = ByteArray(fileNameLength.toInt()) val fileNameBytes = ByteArray(fileNameLength.toInt())
@@ -81,7 +99,8 @@ data class ZipEntry(
fileComment = fileCommentBytes.toString(Charsets.UTF_8) fileComment = fileCommentBytes.toString(Charsets.UTF_8)
} }
flags = (flags and 0b1000u.inv().toUShort()) //disable data descriptor flag as they are not used flags = (flags and 0b1000u.inv()
.toUShort()) //disable data descriptor flag as they are not used
return ZipEntry( return ZipEntry(
version, version,
@@ -138,8 +157,9 @@ data class ZipEntry(
val nameBytes = fileName.toByteArray(Charsets.UTF_8) val nameBytes = fileName.toByteArray(Charsets.UTF_8)
val commentBytes = fileComment.toByteArray(Charsets.UTF_8) val commentBytes = fileComment.toByteArray(Charsets.UTF_8)
val buffer = ByteBuffer.allocate(CDE_HEADER_SIZE + nameBytes.size + extraField.size + commentBytes.size) val buffer =
.also { it.order(ByteOrder.LITTLE_ENDIAN) } ByteBuffer.allocate(CDE_HEADER_SIZE + nameBytes.size + extraField.size + commentBytes.size)
.also { it.order(ByteOrder.LITTLE_ENDIAN) }
buffer.putUInt(CDE_SIGNATURE) buffer.putUInt(CDE_SIGNATURE)
buffer.putUShort(version) buffer.putUShort(version)
@@ -166,5 +186,4 @@ data class ZipEntry(
buffer.flip() buffer.flip()
return buffer return buffer
} }
} }