Compare commits

...

23 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
17 changed files with 6342 additions and 120 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

@@ -22,19 +22,16 @@ jobs:
uses: actions/setup-java@v3
with:
java-version: '17'
distribution: 'temurin'
distribution: 'zulu'
cache: gradle
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: "lts/*"
- name: Build with Gradle
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: ./gradlew build clean
node-version: "latest"
cache: 'npm'
- name: Setup semantic-release
run: npm install -g semantic-release @semantic-release/git @semantic-release/changelog gradle-semantic-release-plugin -D
- name: Release
run: npm install semantic-release @saithodev/semantic-release-backmerge @semantic-release/git @semantic-release/changelog gradle-semantic-release-plugin -D
- name: Create release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: npx semantic-release

7
.gitignore vendored
View File

@@ -113,6 +113,9 @@ gradle-app.setting
# # Work around https://youtrack.jetbrains.com/issue/IDEA-116898
# gradle/wrapper/gradle-wrapper.properties
# Dependency directories
node_modules/
# ReVanced CLI
revanced-cache/
options.toml
.idea/vcs.xml
options.toml

2
.idea/.gitignore generated vendored
View File

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

View File

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

View File

@@ -1,3 +1,39 @@
# [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)

View File

@@ -25,7 +25,7 @@ repositories {
dependencies {
implementation(kotlin("reflect"))
implementation("app.revanced:revanced-patcher:6.0.2")
implementation("app.revanced:revanced-patcher:6.3.1")
implementation("info.picocli:picocli:4.7.0")
implementation("com.android.tools.build:apksig:7.2.1")
implementation("com.github.revanced:jadb:master-SNAPSHOT") // updated fork
@@ -40,9 +40,8 @@ tasks {
shadowJar {
manifest {
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.
// Remove this if you forked it to support building only.

View File

@@ -1,2 +1,2 @@
kotlin.code.style = official
version = 2.16.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
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.zip.ZipFile
import app.revanced.utils.signing.align.zip.structures.ZipEntry
import java.io.File
object Aligning {
fun align(inputFile: File, outputFile: File) {
fun align(result: PatcherResult, inputFile: File, outputFile: File) {
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

@@ -151,16 +151,14 @@ internal object MainCommand : Runnable {
Adb(outputFile, patcher.context.packageMetadata.packageName, args.deploy!!, !pArgs.mount)
}
val patchedFile = File(pArgs.cacheDirectory).resolve("${outputFile.nameWithoutExtension}_raw.apk")
// start the patcher
Patcher.start(patcher, patchedFile, allPatches)
val result = Patcher.start(patcher, allPatches)
val cacheDirectory = File(pArgs.cacheDirectory)
// align the file
val alignedFile = cacheDirectory.resolve("${outputFile.nameWithoutExtension}_aligned.apk")
Aligning.align(patchedFile, alignedFile)
Aligning.align(result, args.inputFile, alignedFile)
// sign the file
val finalFile = if (!pArgs.mount) {

View File

@@ -1,24 +1,17 @@
package app.revanced.cli.patcher
import app.revanced.cli.command.MainCommand.args
import app.revanced.cli.command.MainCommand.logger
import app.revanced.patcher.PatcherResult
import app.revanced.patcher.data.Context
import app.revanced.patcher.patch.Patch
import app.revanced.utils.filesystem.ZipFileSystemUtils
import app.revanced.utils.patcher.addPatchesFiltered
import app.revanced.utils.patcher.applyPatchesVerbose
import app.revanced.utils.patcher.mergeFiles
import java.io.File
import java.nio.file.Files
internal object Patcher {
internal fun start(
patcher: app.revanced.patcher.Patcher,
output: File,
allPatches: List<Class<out Patch<Context>>>
) {
val inputFile = args.inputFile
): PatcherResult {
// merge files like necessary integrations
patcher.mergeFiles()
// add patches, but filter incompatible or excluded patches
@@ -26,28 +19,6 @@ internal object Patcher {
// apply patches
patcher.applyPatchesVerbose()
// write output file
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()) }
}
return patcher.save()
}
}

View File

@@ -6,7 +6,6 @@ import app.revanced.cli.command.MainCommand.logger
import app.revanced.patcher.Patcher
import app.revanced.patcher.data.Context
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.patchName
import app.revanced.patcher.patch.Patch
@@ -32,13 +31,7 @@ fun Patcher.addPatchesFiltered(allPatches: List<Class<out Patch<Context>>>) {
return@patchLoop
}
patch.deprecated?.let { (reason, replacement) ->
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.")
if (compatiblePackages == null) logger.trace("$prefix: No constraint on packages. Continuing.")
else {
if (!compatiblePackages.any { it.name == packageName }) {
logger.trace("$prefix: Incompatible with $packageName. This patch is only compatible with ${

View File

@@ -1,28 +1,11 @@
package app.revanced.utils.signing.align
import app.revanced.utils.signing.align.zip.ZipFile
import java.io.File
import app.revanced.utils.signing.align.zip.structures.ZipEntry
internal object ZipAligner {
private const val DEFAULT_ALIGNMENT = 4
private const val LIBRARY_ALIGNMENT = 4096
fun align(input: File, output: File) {
val inputZip = ZipFile(input)
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()
}
fun getEntryAlignment(entry: ZipEntry): Int? =
if (entry.compression.toUInt() != 0u) null else if (entry.fileName.endsWith(".so")) LIBRARY_ALIGNMENT else DEFAULT_ALIGNMENT
}

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.ZipEntry
import java.io.Closeable
import java.io.File
import java.io.RandomAccessFile
import java.nio.ByteBuffer
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()
private val filePointer: RandomAccessFile = RandomAccessFile(file, "rw")
private var CDNeedsRewrite = false
private val compressionLevel = 5
init {
//if file isn't empty try to load entries
@@ -53,23 +59,24 @@ class ZipFile(val file: File) {
return buildList(numberOfEntries) {
for (i in 1..numberOfEntries) {
add(ZipEntry.fromCDE(filePointer).also
{
//for some reason the local extra field can be different from the central one
it.readLocalExtra(
filePointer.channel.map(
FileChannel.MapMode.READ_ONLY,
it.localHeaderOffset.toLong() + 28,
2
add(
ZipEntry.fromCDE(filePointer).also
{
//for some reason the local extra field can be different from the central one
it.readLocalExtra(
filePointer.channel.map(
FileChannel.MapMode.READ_ONLY,
it.localHeaderOffset.toLong() + 28,
2
)
)
)
})
})
}
}
}
private fun writeCDE() {
val CDEStart = filePointer.channel.position().toUInt()
private fun writeCD() {
val CDStart = filePointer.channel.position().toUInt()
entries.forEach {
filePointer.channel.write(it.toCDE())
@@ -82,15 +89,17 @@ class ZipFile(val file: File) {
0u,
entriesCount,
entriesCount,
filePointer.channel.position().toUInt() - CDEStart,
CDEStart,
filePointer.channel.position().toUInt() - CDStart,
CDStart,
""
)
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()
filePointer.channel.write(entry.toLFH())
@@ -99,17 +108,45 @@ class ZipFile(val file: File) {
entries.add(entry)
}
fun addEntryAligned(entry: ZipEntry, data: ByteBuffer, alignment: Int) {
//calculate where data would end up
val dataOffset = filePointer.filePointer + entry.LFHSize
fun addEntryCompressData(entry: ZipEntry, data: ByteArray) {
val compressor = Deflater(compressionLevel, true)
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
if (mod != 0L) {
//add padding at end of extra field
entry.localExtraField =
entry.localExtraField.copyOf((entry.localExtraField.size + (alignment - mod)).toInt())
val compressedDataLength = compressor.deflate(compressedData)
val compressedBuffer =
ByteBuffer.wrap(compressedData.take(compressedDataLength).toByteArray())
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)
@@ -123,8 +160,17 @@ class ZipFile(val file: File) {
)
}
fun finish() {
writeCDE()
fun copyEntriesFromFileAligned(file: ZipFile, entryAlignment: (entry: ZipEntry) -> Int?) {
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()
}
}
}

View File

@@ -9,12 +9,12 @@ data class ZipEntry(
val version: UShort,
val versionNeeded: UShort,
val flags: UShort,
val compression: UShort,
var compression: UShort,
val modificationTime: UShort,
val modificationDate: UShort,
val crc32: UInt,
val compressedSize: UInt,
val uncompressedSize: UInt,
var crc32: UInt,
var compressedSize: UInt,
var uncompressedSize: UInt,
val diskNumber: UShort,
val internalAttributes: UShort,
val externalAttributes: UInt,
@@ -22,7 +22,7 @@ data class ZipEntry(
val fileName: String,
val extraField: ByteArray,
val fileComment: String,
var localExtraField: ByteArray = ByteArray(0), //seperate for alignment
var localExtraField: ByteArray = ByteArray(0), //separate for alignment
) {
val LFHSize: Int
get() = LFH_HEADER_SIZE + fileName.toByteArray(Charsets.UTF_8).size + localExtraField.size
@@ -37,6 +37,27 @@ data class ZipEntry(
const val LFH_HEADER_SIZE = 30
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 {
val signature = input.readUIntLE()
@@ -55,7 +76,7 @@ data class ZipEntry(
val fileNameLength = input.readUShortLE()
var fileName = ""
val extraFieldLength = input.readUShortLE()
var extraField = ByteArray(extraFieldLength.toInt())
val extraField = ByteArray(extraFieldLength.toInt())
val fileCommentLength = input.readUShortLE()
var fileComment = ""
val diskNumber = input.readUShortLE()
@@ -63,7 +84,8 @@ data class ZipEntry(
val externalAttributes = 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) {
val fileNameBytes = ByteArray(fileNameLength.toInt())
@@ -77,7 +99,8 @@ data class ZipEntry(
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(
version,
@@ -134,8 +157,9 @@ data class ZipEntry(
val nameBytes = fileName.toByteArray(Charsets.UTF_8)
val commentBytes = fileComment.toByteArray(Charsets.UTF_8)
val buffer = ByteBuffer.allocate(CDE_HEADER_SIZE + nameBytes.size + extraField.size + commentBytes.size)
.also { it.order(ByteOrder.LITTLE_ENDIAN) }
val buffer =
ByteBuffer.allocate(CDE_HEADER_SIZE + nameBytes.size + extraField.size + commentBytes.size)
.also { it.order(ByteOrder.LITTLE_ENDIAN) }
buffer.putUInt(CDE_SIGNATURE)
buffer.putUShort(version)
@@ -162,5 +186,4 @@ data class ZipEntry(
buffer.flip()
return buffer
}
}
}