Compare commits

...

25 Commits

Author SHA1 Message Date
semantic-release-bot
fca8a3f4c0 chore(release): 2.2.0-dev.1 [skip ci]
# [2.2.0-dev.1](https://github.com/ReVanced/revanced-library/compare/v2.1.0...v2.2.0-dev.1) (2024-03-09)

### Bug Fixes

* Make property private ([51109c4](51109c4768))
* Sign APKs using `apksig` ([f59ecbc](f59ecbccd1))

### Features

* Increase default expiration date of certificate ([f2bd3f5](f2bd3f5eee))
2024-03-09 03:31:10 +00:00
oSumAtrIX
f59ecbccd1 fix: Sign APKs using apksig
Previously, the signing extension from apkzlib was used incorrectly. The extension is meant to be added to a ZFile whereas on changes the extension would be used to sign. Instead the extension was added to a newly created ZFile, and without any changes, closed again, leading to no APK being signed. It turns out to be impractical to use the signing extension as we do not write an entire APK ZFile so that the signing extension can consider every file inside the ZFile, instead we just merge the patcher result to an existing ZFile. Instead use `apksig` after applying the patcher result to the ZFile which signs everything correctly.
2024-03-09 04:29:41 +01:00
oSumAtrIX
c92be32607 refactor: Simplify code 2024-03-09 03:25:11 +01:00
oSumAtrIX
51109c4768 fix: Make property private 2024-03-09 03:25:10 +01:00
oSumAtrIX
f2bd3f5eee feat: Increase default expiration date of certificate 2024-03-08 02:30:15 +01:00
oSumAtrIX
cc5ee29d14 build: Set target bytecode level to JVM 11 2024-03-04 19:16:09 +01:00
semantic-release-bot
c4bad9a653 chore(release): 2.1.0 [skip ci]
# [2.1.0](https://github.com/ReVanced/revanced-library/compare/v2.0.0...v2.1.0) (2024-03-04)

### Bug Fixes

* Use `BKS` instead of default signing provider to fix backwards compatibility ([41805fc](41805fcb0b))

### Features

* Mention APK file name when logging aligning ([244ebc2](244ebc2186))
2024-03-04 14:39:47 +00:00
oSumAtrIX
3f713cf76b chore: Merge branch dev to main (#32) 2024-03-04 15:38:10 +01:00
oSumAtrIX
dfe48a24bf ci: Update action 2024-03-04 15:37:06 +01:00
oSumAtrIX
132ad13670 build: Bump dependencies 2024-03-04 15:37:06 +01:00
semantic-release-bot
1670ceff9f chore(release): 2.1.0-dev.2 [skip ci]
# [2.1.0-dev.2](https://github.com/ReVanced/revanced-library/compare/v2.1.0-dev.1...v2.1.0-dev.2) (2024-03-04)

### Bug Fixes

* Use `BKS` instead of default signing provider to fix backwards compatibility ([41805fc](41805fcb0b))
2024-03-04 14:33:02 +00:00
oSumAtrIX
41805fcb0b fix: Use BKS instead of default signing provider to fix backwards compatibility 2024-03-04 15:31:26 +01:00
oSumAtrIX
0e9939f70d docs: Fix spelling mistakes 2024-02-26 04:37:58 +01:00
oSumAtrIX
f28a7ddeec docs: Fix broken links 2024-02-26 04:37:46 +01:00
oSumAtrIX
3e574e723c docs: Add readme 2024-02-25 04:01:25 +01:00
oSumAtrIX
a73ca721f3 chore: Rename issue templates 2024-02-25 03:37:52 +01:00
oSumAtrIX
393d74b7d9 ci: Rename workflow file 2024-02-25 03:14:02 +01:00
oSumAtrIX
51d6e9976c ci: Fix indentation in workflow 2024-02-24 01:14:44 +01:00
oSumAtrIX
24cecb1e57 docs: Format markdown code 2024-02-23 03:03:50 +01:00
oSumAtrIX
d4938c57e8 ci: Split release into a separate PR build workflow
Because the release workflow already runs on dev and main, it is not necessary to also trigger it for PRs.
2024-02-23 02:26:06 +01:00
semantic-release-bot
1526f98f53 chore(release): 2.1.0-dev.1 [skip ci]
# [2.1.0-dev.1](https://github.com/ReVanced/revanced-library/compare/v2.0.0...v2.1.0-dev.1) (2024-02-15)

### Features

* Mention APK file name when logging aligning ([244ebc2](244ebc2186))
2024-02-15 03:46:55 +00:00
oSumAtrIX
244ebc2186 feat: Mention APK file name when logging aligning 2024-02-15 02:54:31 +01:00
oSumAtrIX
486a7acff2 ci: Create a GitHub release with changelogs 2024-02-15 02:29:58 +01:00
semantic-release-bot
f0b8bc5438 chore(release): 2.0.0 [skip ci]
# [2.0.0](https://github.com/ReVanced/revanced-library/compare/v1.5.0...v2.0.0) (2024-02-15)

### Bug Fixes

* Map dependencies from `KClass` into `String` to fix serialization ([57e36ab](57e36ab5c1))
* Use the JVM name instead of the value from `KClass#toString` ([d18e436](d18e436de1))

### Features

* Use `apkzlib` instead of own implementations and bump ReVanced Patcher ([3aa6dc2](3aa6dc223a))

### BREAKING CHANGES

* This commit removes deprecated APIs and bumps ReVanced Patcher. Because of it's changes, `apkzlib` is now used instead of own implementations of `ZipFile`
2024-02-15 01:24:23 +00:00
oSumAtrIX
806f45c77f chore: Merge branch dev to main (#24) 2024-02-15 02:22:42 +01:00
16 changed files with 390 additions and 60 deletions

View File

@@ -0,0 +1,25 @@
name: Build pull request
on:
workflow_dispatch:
pull_request:
branches:
- dev
jobs:
release:
name: Build
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Cache Gradle
uses: burrunan/gradle-cache-action@v1
- name: Build
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: ./gradlew build --no-daemon

View File

@@ -6,10 +6,6 @@ on:
branches: branches:
- main - main
- dev - dev
pull_request:
branches:
- main
- dev
jobs: jobs:
release: release:

View File

@@ -11,7 +11,7 @@ jobs:
name: Dispatch event to documentation repository name: Dispatch event to documentation repository
if: github.ref == 'refs/heads/main' if: github.ref == 'refs/heads/main'
steps: steps:
- uses: peter-evans/repository-dispatch@v2 - uses: peter-evans/repository-dispatch@v3
with: with:
token: ${{ secrets.DOCUMENTATION_REPO_ACCESS_TOKEN }} token: ${{ secrets.DOCUMENTATION_REPO_ACCESS_TOKEN }}
repository: revanced/revanced-documentation repository: revanced/revanced-documentation

View File

@@ -32,6 +32,12 @@
backmergeBranches: [{"from": "main", "to": "dev"}], backmergeBranches: [{"from": "main", "to": "dev"}],
clearWorkspace: true clearWorkspace: true
} }
],
[
"@semantic-release/github",
{
successComment: false
}
] ]
] ]
} }

View File

@@ -1,3 +1,60 @@
# [2.2.0-dev.1](https://github.com/ReVanced/revanced-library/compare/v2.1.0...v2.2.0-dev.1) (2024-03-09)
### Bug Fixes
* Make property private ([51109c4](https://github.com/ReVanced/revanced-library/commit/51109c476837828535dcd395a5222d2fcf7fc22c))
* Sign APKs using `apksig` ([f59ecbc](https://github.com/ReVanced/revanced-library/commit/f59ecbccd14a08d87d4f18c3c0cc47a884088b99))
### Features
* Increase default expiration date of certificate ([f2bd3f5](https://github.com/ReVanced/revanced-library/commit/f2bd3f5eeee14ca32094be0d41c32b231a16bcc3))
# [2.1.0](https://github.com/ReVanced/revanced-library/compare/v2.0.0...v2.1.0) (2024-03-04)
### Bug Fixes
* Use `BKS` instead of default signing provider to fix backwards compatibility ([41805fc](https://github.com/ReVanced/revanced-library/commit/41805fcb0bdc778fe0870427a0a1caa6d4369cee))
### Features
* Mention APK file name when logging aligning ([244ebc2](https://github.com/ReVanced/revanced-library/commit/244ebc21868c07d1852857f6858c1a53a5561155))
# [2.1.0-dev.2](https://github.com/ReVanced/revanced-library/compare/v2.1.0-dev.1...v2.1.0-dev.2) (2024-03-04)
### Bug Fixes
* Use `BKS` instead of default signing provider to fix backwards compatibility ([41805fc](https://github.com/ReVanced/revanced-library/commit/41805fcb0bdc778fe0870427a0a1caa6d4369cee))
# [2.1.0-dev.1](https://github.com/ReVanced/revanced-library/compare/v2.0.0...v2.1.0-dev.1) (2024-02-15)
### Features
* Mention APK file name when logging aligning ([244ebc2](https://github.com/ReVanced/revanced-library/commit/244ebc21868c07d1852857f6858c1a53a5561155))
# [2.0.0](https://github.com/ReVanced/revanced-library/compare/v1.5.0...v2.0.0) (2024-02-15)
### Bug Fixes
* Map dependencies from `KClass` into `String` to fix serialization ([57e36ab](https://github.com/ReVanced/revanced-library/commit/57e36ab5c15a5fa7c50fb689ee43ad4eb9a4a515))
* Use the JVM name instead of the value from `KClass#toString` ([d18e436](https://github.com/ReVanced/revanced-library/commit/d18e436de1df14452ecaa7d827be5e6596ba8a2d))
### Features
* Use `apkzlib` instead of own implementations and bump ReVanced Patcher ([3aa6dc2](https://github.com/ReVanced/revanced-library/commit/3aa6dc223a9a1a2f735eda407917548ecbd366aa))
### BREAKING CHANGES
* This commit removes deprecated APIs and bumps ReVanced Patcher. Because of it's changes, `apkzlib` is now used instead of own implementations of `ZipFile`
# [2.0.0-dev.1](https://github.com/ReVanced/revanced-library/compare/v1.5.1-dev.2...v2.0.0-dev.1) (2024-02-14) # [2.0.0-dev.1](https://github.com/ReVanced/revanced-library/compare/v1.5.1-dev.2...v2.0.0-dev.1) (2024-02-14)

View File

@@ -65,13 +65,14 @@ This document describes how to contribute to ReVanced Library.
## 📖 Resources to help you get started ## 📖 Resources to help you get started
<!-- * The [documentation](/docs) explains how to use ReVanced Library --> <!-- * The [documentation](/docs) explains how to use ReVanced Library -->
* [Our backlog](https://github.com/orgs/ReVanced/projects/12) is where we keep track of what we're working on
* [Issues](https://github.com/ReVanced/revanced-cli/issues) are where we keep track of bugs and feature requests - [Our backlog](https://github.com/orgs/ReVanced/projects/12) is where we keep track of what we're working on
- [Issues](https://github.com/ReVanced/revanced-cli/issues) are where we keep track of bugs and feature requests
## 🙏 Submitting a feature request ## 🙏 Submitting a feature request
Features can be requested by opening an issue using the Features can be requested by opening an issue using the
[Feature request issue template](https://github.com/ReVanced/revanced-cli/issues/new?assignees=&labels=Feature+request&projects=&template=feature-request.yml&title=feat%3A+). [Feature request issue template](https://github.com/ReVanced/revanced-cli/issues/new?assignees=&labels=Feature+request&projects=&template=feature_request.yml&title=feat%3A+).
> [!NOTE] > [!NOTE]
> Requests can be accepted or rejected at the discretion of maintainers of ReVanced Library. > Requests can be accepted or rejected at the discretion of maintainers of ReVanced Library.
@@ -80,7 +81,7 @@ Features can be requested by opening an issue using the
## 🐞 Submitting a bug report ## 🐞 Submitting a bug report
If you encounter a bug while using ReVanced Library, open an issue using the If you encounter a bug while using ReVanced Library, open an issue using the
[Bug report issue template](https://github.com/ReVanced/revanced-cli/issues/new?assignees=&labels=Bug+report&projects=&template=bug-report.yml&title=bug%3A+). [Bug report issue template](https://github.com/ReVanced/revanced-cli/issues/new?assignees=&labels=Bug+report&projects=&template=bug_report.yml&title=bug%3A+).
## 📝 How to contribute ## 📝 How to contribute
@@ -88,11 +89,11 @@ If you encounter a bug while using ReVanced Library, open an issue using the
with the maintainers of ReVanced Library. This will help you determine whether your change is acceptable with the maintainers of ReVanced Library. This will help you determine whether your change is acceptable
and whether it is worth your time to implement it and whether it is worth your time to implement it
2. Development happens on the `dev` branch. Fork the repository and create your branch from `dev` 2. Development happens on the `dev` branch. Fork the repository and create your branch from `dev`
3. Commit your changes. 3. Commit your changes
4. Submit a pull request to the `dev` branch of the repository and reference issues 4. Submit a pull request to the `dev` branch of the repository and reference issues
that your pull request closes in the description of your pull request that your pull request closes in the description of your pull request
5. Our team will review your pull request and provide feedback. Once your pull request is approved, 5. Our team will review your pull request and provide feedback. Once your pull request is approved,
it will be merged into the `dev` branch and will be included in the next release of ReVanced Library it will be merged into the `dev` branch and will be included in the next release of ReVanced Library
❤️ Thank you for considering contributing to ReVanced Library, ❤️ Thank you for considering contributing to ReVanced Library,
ReVanced ReVanced

117
README.md Normal file
View File

@@ -0,0 +1,117 @@
<p align="center">
<picture>
<source
width="256px"
media="(prefers-color-scheme: dark)"
srcset="assets/revanced-headline/revanced-headline-vertical-dark.svg"
>
<img
width="256px"
src="assets/revanced-headline/revanced-headline-vertical-light.svg"
>
</picture>
<br>
<a href="https://revanced.app/">
<picture>
<source height="24px" media="(prefers-color-scheme: dark)" srcset="assets/revanced-logo/revanced-logo.svg" />
<img height="24px" src="assets/revanced-logo/revanced-logo.svg" />
</picture>
</a>&nbsp;&nbsp;&nbsp;
<a href="https://github.com/ReVanced">
<picture>
<source height="24px" media="(prefers-color-scheme: dark)" srcset="https://i.ibb.co/dMMmCrW/Git-Hub-Mark.png" />
<img height="24px" src="https://i.ibb.co/9wV3HGF/Git-Hub-Mark-Light.png" />
</picture>
</a>&nbsp;&nbsp;&nbsp;
<a href="http://revanced.app/discord">
<picture>
<source height="24px" media="(prefers-color-scheme: dark)" srcset="https://user-images.githubusercontent.com/13122796/178032563-d4e084b7-244e-4358-af50-26bde6dd4996.png" />
<img height="24px" src="https://user-images.githubusercontent.com/13122796/178032563-d4e084b7-244e-4358-af50-26bde6dd4996.png" />
</picture>
</a>&nbsp;&nbsp;&nbsp;
<a href="https://reddit.com/r/revancedapp">
<picture>
<source height="24px" media="(prefers-color-scheme: dark)" srcset="https://user-images.githubusercontent.com/13122796/178032351-9d9d5619-8ef7-470a-9eec-2744ece54553.png" />
<img height="24px" src="https://user-images.githubusercontent.com/13122796/178032351-9d9d5619-8ef7-470a-9eec-2744ece54553.png" />
</picture>
</a>&nbsp;&nbsp;&nbsp;
<a href="https://t.me/app_revanced">
<picture>
<source height="24px" media="(prefers-color-scheme: dark)" srcset="https://user-images.githubusercontent.com/13122796/178032213-faf25ab8-0bc3-4a94-a730-b524c96df124.png" />
<img height="24px" src="https://user-images.githubusercontent.com/13122796/178032213-faf25ab8-0bc3-4a94-a730-b524c96df124.png" />
</picture>
</a>&nbsp;&nbsp;&nbsp;
<a href="https://x.com/revancedapp">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://user-images.githubusercontent.com/93124920/270180600-7c1b38bf-889b-4d68-bd5e-b9d86f91421a.png">
<img height="24px" src="https://user-images.githubusercontent.com/93124920/270108715-d80743fa-b330-4809-b1e6-79fbdc60d09c.png" />
</picture>
</a>&nbsp;&nbsp;&nbsp;
<a href="https://www.youtube.com/@ReVanced">
<picture>
<source height="24px" media="(prefers-color-scheme: dark)" srcset="https://user-images.githubusercontent.com/13122796/178032714-c51c7492-0666-44ac-99c2-f003a695ab50.png" />
<img height="24px" src="https://user-images.githubusercontent.com/13122796/178032714-c51c7492-0666-44ac-99c2-f003a695ab50.png" />
</picture>
</a>
<br>
<br>
Continuing the legacy of Vanced
</p>
# 📚 ReVanced Library
![GitHub Workflow Status (with event)](https://img.shields.io/github/actions/workflow/status/ReVanced/revanced-library/release.yml)
![GPLv3 License](https://img.shields.io/badge/License-GPL%20v3-yellow.svg)
Library containing common utilities for ReVanced.
## ❓ About
ReVanced Library powers projects such as [ReVanced Manager](https://github.com/ReVanced/revanced-manager),
[ReVanced CLI](https://github.com/ReVanced/revanced-cli) with common utilities and functionalities
by providing shared code.
## 💪 Features
Some of the features the ReVanced Library provides are:
- 📝 **Signing APKs**: Read and write keystores, and sign APK files
- 🧩 **Common utility functions**: Various APIs for ReVanced patches such as JSON serialization,
reading and setting patch options, calculating the most common compatible version for a set of patches and more
- 💾 **Install and uninstall APKs**: Install and uninstall APK files via ADB or locally,
the Android package manager, or by mounting using root permissions
- 📦 **Repackage patched files to an APK**: Apply patched files from
[ReVanced Patcher](https://github.com/revanced/revanced-patcher) to an APK file, and align & sign the APK file automatically
## 🚀 How to get started
To use ReVanced Library in your project, follow these steps:
1. [Add the repository](https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-gradle-registry#using-a-published-package)
to your project
2. Add the dependency to your project:
```kt
dependencies {
implementation("app.revanced:revanced-library:{$version}")
}
```
## 📚 Everything else
### 📙 Contributing
Thank you for considering contributing to ReVanced Library.
You can find the contribution guidelines [here](CONTRIBUTING.md).
### 🛠️ Building
To build ReVanced Library,
you can follow the [ReVanced documentation](https://github.com/ReVanced/revanced-documentation).
## 📜 Licence
ReVanced Library is licensed under the GPLv3 license. Please see the [licence file](LICENSE) for more information.
[tl;dr](https://www.tldrlegal.com/license/gnu-general-public-license-v3-gpl-3) you may copy, distribute and modify ReVanced Library as long as you track changes/dates in source files.
Any modifications to ReVanced Library must also be made available under the GPL,
along with build & install instructions.

View File

@@ -1,6 +1,8 @@
public final class app/revanced/library/ApkSigner { public final class app/revanced/library/ApkSigner {
public static final field INSTANCE Lapp/revanced/library/ApkSigner; public static final field INSTANCE Lapp/revanced/library/ApkSigner;
public final fun newApkSigner (Lapp/revanced/library/ApkSigner$PrivateKeyCertificatePair;)Lapp/revanced/library/ApkSigner$Signer; public final fun newApkSigner (Lapp/revanced/library/ApkSigner$PrivateKeyCertificatePair;)Lapp/revanced/library/ApkSigner$Signer;
public final fun newApkSigner (Ljava/lang/String;Lapp/revanced/library/ApkSigner$PrivateKeyCertificatePair;)Lapp/revanced/library/ApkSigner$Signer;
public final fun newApkSigner (Ljava/lang/String;Ljava/security/KeyStore;Ljava/lang/String;Ljava/lang/String;)Lapp/revanced/library/ApkSigner$Signer;
public final fun newApkSigner (Ljava/security/KeyStore;Ljava/lang/String;Ljava/lang/String;)Lapp/revanced/library/ApkSigner$Signer; public final fun newApkSigner (Ljava/security/KeyStore;Ljava/lang/String;Ljava/lang/String;)Lapp/revanced/library/ApkSigner$Signer;
public final fun newKeyStore (Ljava/io/OutputStream;Ljava/lang/String;Ljava/util/Set;)V public final fun newKeyStore (Ljava/io/OutputStream;Ljava/lang/String;Ljava/util/Set;)V
public final fun newKeyStore (Ljava/util/Set;)Ljava/security/KeyStore; public final fun newKeyStore (Ljava/util/Set;)Ljava/security/KeyStore;
@@ -25,15 +27,16 @@ public final class app/revanced/library/ApkSigner$PrivateKeyCertificatePair {
} }
public final class app/revanced/library/ApkSigner$Signer { public final class app/revanced/library/ApkSigner$Signer {
public final fun getSigningExtension ()Lcom/android/tools/build/apkzlib/sign/SigningExtension;
public final fun signApk (Lcom/android/tools/build/apkzlib/zip/ZFile;)V public final fun signApk (Lcom/android/tools/build/apkzlib/zip/ZFile;)V
public final fun signApk (Ljava/io/File;)V public final fun signApk (Ljava/io/File;)V
public final fun signApk (Ljava/io/File;Ljava/io/File;)V
} }
public final class app/revanced/library/ApkUtils { public final class app/revanced/library/ApkUtils {
public static final field INSTANCE Lapp/revanced/library/ApkUtils; public static final field INSTANCE Lapp/revanced/library/ApkUtils;
public final fun applyTo (Lapp/revanced/patcher/PatcherResult;Ljava/io/File;)V public final fun applyTo (Lapp/revanced/patcher/PatcherResult;Ljava/io/File;)V
public final fun sign (Ljava/io/File;Lapp/revanced/library/ApkUtils$SigningOptions;)V public final fun sign (Ljava/io/File;Lapp/revanced/library/ApkUtils$SigningOptions;)V
public final fun sign (Ljava/io/File;Ljava/io/File;Lapp/revanced/library/ApkUtils$SigningOptions;)V
} }
public final class app/revanced/library/ApkUtils$SigningOptions { public final class app/revanced/library/ApkUtils$SigningOptions {

View File

@@ -1,3 +1,5 @@
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
plugins { plugins {
alias(libs.plugins.kotlin) alias(libs.plugins.kotlin)
alias(libs.plugins.binary.compatibility.validator) alias(libs.plugins.binary.compatibility.validator)
@@ -27,6 +29,7 @@ dependencies {
implementation(libs.jadb) // Fork with Shell v2 support. implementation(libs.jadb) // Fork with Shell v2 support.
implementation(libs.jackson.module.kotlin) implementation(libs.jackson.module.kotlin)
implementation(libs.apkzlib) implementation(libs.apkzlib)
implementation(libs.apksig)
implementation(libs.bcpkix.jdk15on) implementation(libs.bcpkix.jdk15on)
implementation(libs.guava) implementation(libs.guava)
@@ -43,10 +46,14 @@ tasks {
} }
} }
kotlin { jvmToolchain(11) } kotlin {
compilerOptions {
jvmTarget.set(JvmTarget.JVM_11)
}
}
java { java {
withSourcesJar() targetCompatibility = JavaVersion.VERSION_11
} }
publishing { publishing {

View File

@@ -1,4 +1,4 @@
org.gradle.parallel = true org.gradle.parallel = true
org.gradle.caching = true org.gradle.caching = true
kotlin.code.style = official kotlin.code.style = official
version = 2.0.0-dev.1 version = 2.2.0-dev.1

View File

@@ -4,9 +4,10 @@ jadb = "1.2.1"
kotlin = "1.9.22" kotlin = "1.9.22"
revanced-patcher = "19.3.1" revanced-patcher = "19.3.1"
binary-compatibility-validator = "0.14.0" binary-compatibility-validator = "0.14.0"
apkzlib = "8.2.2" apkzlib = "8.3.0"
bcpkix-jdk15on = "1.70" bcpkix-jdk15on = "1.70"
guava = "33.0.0-jre" guava = "33.0.0-jre"
apksig = "8.3.0"
[libraries] [libraries]
jackson-module-kotlin = { module = "com.fasterxml.jackson.module:jackson-module-kotlin", version.ref = "jackson-module-kotlin" } jackson-module-kotlin = { module = "com.fasterxml.jackson.module:jackson-module-kotlin", version.ref = "jackson-module-kotlin" }
@@ -17,6 +18,7 @@ revanced-patcher = { module = "app.revanced:revanced-patcher", version.ref = "re
apkzlib = { module = "com.android.tools.build:apkzlib", version.ref = "apkzlib" } apkzlib = { module = "com.android.tools.build:apkzlib", version.ref = "apkzlib" }
bcpkix-jdk15on = { module = "org.bouncycastle:bcpkix-jdk15on", version.ref = "bcpkix-jdk15on" } bcpkix-jdk15on = { module = "org.bouncycastle:bcpkix-jdk15on", version.ref = "bcpkix-jdk15on" }
guava = { module = "com.google.guava:guava", version.ref = "guava" } guava = { module = "com.google.guava:guava", version.ref = "guava" }
apksig = { module = "com.android.tools.build:apksig", version.ref = "apksig" }
[plugins] [plugins]
binary-compatibility-validator = { id = "org.jetbrains.kotlinx.binary-compatibility-validator", version.ref = "binary-compatibility-validator" } binary-compatibility-validator = { id = "org.jetbrains.kotlinx.binary-compatibility-validator", version.ref = "binary-compatibility-validator" }

View File

@@ -1,5 +1,6 @@
package app.revanced.library package app.revanced.library
import com.android.apksig.ApkSigner.SignerConfig
import com.android.tools.build.apkzlib.sign.SigningExtension import com.android.tools.build.apkzlib.sign.SigningExtension
import com.android.tools.build.apkzlib.sign.SigningOptions import com.android.tools.build.apkzlib.sign.SigningOptions
import com.android.tools.build.apkzlib.zip.ZFile import com.android.tools.build.apkzlib.zip.ZFile
@@ -7,6 +8,7 @@ import org.bouncycastle.asn1.x500.X500Name
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo
import org.bouncycastle.cert.X509v3CertificateBuilder import org.bouncycastle.cert.X509v3CertificateBuilder
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter
import org.bouncycastle.jce.provider.BouncyCastleProvider
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder
import java.io.File import java.io.File
import java.io.IOException import java.io.IOException
@@ -24,7 +26,13 @@ import kotlin.time.Duration.Companion.days
*/ */
@Suppress("MemberVisibilityCanBePrivate", "unused") @Suppress("MemberVisibilityCanBePrivate", "unused")
object ApkSigner { object ApkSigner {
private val logger = Logger.getLogger(Signer::class.java.name) private val logger = Logger.getLogger(ApkSigner::class.java.name)
init {
if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) {
Security.addProvider(BouncyCastleProvider())
}
}
/** /**
* Create a new [PrivateKeyCertificatePair]. * Create a new [PrivateKeyCertificatePair].
@@ -36,35 +44,28 @@ object ApkSigner {
*/ */
fun newPrivateKeyCertificatePair( fun newPrivateKeyCertificatePair(
commonName: String = "ReVanced", commonName: String = "ReVanced",
validUntil: Date = Date(System.currentTimeMillis() + 356.days.inWholeMilliseconds * 24), validUntil: Date = Date(System.currentTimeMillis() + (365.days * 8).inWholeMilliseconds * 24),
): PrivateKeyCertificatePair { ): PrivateKeyCertificatePair {
logger.fine("Creating certificate for $commonName") logger.fine("Creating certificate for $commonName")
// Generate a new key pair. // Generate a new key pair.
val keyPair = val keyPair = KeyPairGenerator.getInstance("RSA", BouncyCastleProvider.PROVIDER_NAME).apply {
KeyPairGenerator.getInstance("RSA").apply { initialize(4096)
initialize(4096) }.generateKeyPair()
}.generateKeyPair()
var serialNumber: BigInteger val contentSigner = JcaContentSignerBuilder("SHA256withRSA").build(keyPair.private)
do serialNumber = BigInteger.valueOf(SecureRandom().nextLong())
while (serialNumber < BigInteger.ZERO)
val name = X500Name("CN=$commonName") val name = X500Name("CN=$commonName")
val certificateHolder = X509v3CertificateBuilder(
// Create a new certificate. name,
val certificate = BigInteger.valueOf(SecureRandom().nextLong()),
JcaX509CertificateConverter().getCertificate( Date(System.currentTimeMillis()),
X509v3CertificateBuilder( validUntil,
name, Locale.ENGLISH,
serialNumber, name,
Date(System.currentTimeMillis()), SubjectPublicKeyInfo.getInstance(keyPair.public.encoded),
validUntil, ).build(contentSigner)
Locale.ENGLISH, val certificate = JcaX509CertificateConverter().getCertificate(certificateHolder)
name,
SubjectPublicKeyInfo.getInstance(keyPair.public.encoded),
).build(JcaContentSignerBuilder("SHA256withRSA").build(keyPair.private)),
)
return PrivateKeyCertificatePair(keyPair.private, certificate) return PrivateKeyCertificatePair(keyPair.private, certificate)
} }
@@ -117,7 +118,7 @@ object ApkSigner {
fun newKeyStore(entries: Set<KeyStoreEntry>): KeyStore { fun newKeyStore(entries: Set<KeyStoreEntry>): KeyStore {
logger.fine("Creating keystore") logger.fine("Creating keystore")
return KeyStore.getInstance(KeyStore.getDefaultType()).apply { return newKeyStoreInstance().apply {
load(null) load(null)
entries.forEach { entry -> entries.forEach { entry ->
@@ -132,6 +133,8 @@ object ApkSigner {
} }
} }
private fun newKeyStoreInstance() = KeyStore.getInstance("BKS", BouncyCastleProvider.PROVIDER_NAME)
/** /**
* Create a new keystore with a new keypair and saves it to the given [keyStoreOutputStream]. * Create a new keystore with a new keypair and saves it to the given [keyStoreOutputStream].
* *
@@ -164,7 +167,7 @@ object ApkSigner {
): KeyStore { ): KeyStore {
logger.fine("Reading keystore") logger.fine("Reading keystore")
return KeyStore.getInstance(KeyStore.getDefaultType()).apply { return newKeyStoreInstance().apply {
try { try {
load(keyStoreInputStream, keyStorePassword?.toCharArray()) load(keyStoreInputStream, keyStorePassword?.toCharArray())
} catch (exception: IOException) { } catch (exception: IOException) {
@@ -180,6 +183,7 @@ object ApkSigner {
/** /**
* Create a new [Signer]. * Create a new [Signer].
* *
* @param signer The name of the signer.
* @param privateKeyCertificatePair The private key and certificate pair to use for signing. * @param privateKeyCertificatePair The private key and certificate pair to use for signing.
* *
* @return The new [Signer]. * @return The new [Signer].
@@ -187,6 +191,38 @@ object ApkSigner {
* @see PrivateKeyCertificatePair * @see PrivateKeyCertificatePair
* @see Signer * @see Signer
*/ */
fun newApkSigner(
signer: String,
privateKeyCertificatePair: PrivateKeyCertificatePair,
) = Signer(
com.android.apksig.ApkSigner.Builder(
listOf(
SignerConfig.Builder(
signer,
privateKeyCertificatePair.privateKey,
listOf(privateKeyCertificatePair.certificate),
).build(),
),
),
)
/**
* Create a new [Signer].
*
* @param privateKeyCertificatePair The private key and certificate pair to use for signing.
*
* @return The new [Signer].
*
* @see PrivateKeyCertificatePair
* @see Signer
*/
@Suppress("DEPRECATION")
@Deprecated(
"This method will be removed in the future.",
ReplaceWith(
"newApkSigner(\"ReVanced\", privateKeyCertificatePair)",
),
)
fun newApkSigner(privateKeyCertificatePair: PrivateKeyCertificatePair) = fun newApkSigner(privateKeyCertificatePair: PrivateKeyCertificatePair) =
Signer( Signer(
SigningExtension( SigningExtension(
@@ -203,6 +239,7 @@ object ApkSigner {
/** /**
* Create a new [Signer]. * Create a new [Signer].
* *
* @param signer The name of the signer.
* @param keyStore The keystore to use for signing. * @param keyStore The keystore to use for signing.
* @param keyStoreEntryAlias The alias of the key store entry to use for signing. * @param keyStoreEntryAlias The alias of the key store entry to use for signing.
* @param keyStoreEntryPassword The password for recovering the signing key. * @param keyStoreEntryPassword The password for recovering the signing key.
@@ -213,10 +250,36 @@ object ApkSigner {
* @see Signer * @see Signer
*/ */
fun newApkSigner( fun newApkSigner(
signer: String,
keyStore: KeyStore, keyStore: KeyStore,
keyStoreEntryAlias: String, keyStoreEntryAlias: String,
keyStoreEntryPassword: String, keyStoreEntryPassword: String,
) = newApkSigner(readKeyCertificatePair(keyStore, keyStoreEntryAlias, keyStoreEntryPassword)) ) = newApkSigner(signer, readKeyCertificatePair(keyStore, keyStoreEntryAlias, keyStoreEntryPassword))
/**
* Create a new [Signer].
*
* @param keyStore The keystore to use for signing.
* @param keyStoreEntryAlias The alias of the key store entry to use for signing.
* @param keyStoreEntryPassword The password for recovering the signing key.
*
* @return The new [Signer].
*
* @see KeyStore
* @see Signer
*/
@Deprecated(
"This method will be removed in the future.",
ReplaceWith(
"newApkSigner(\"ReVanced\", readKeyCertificatePair(keyStore, keyStoreEntryAlias, keyStoreEntryPassword))",
"app.revanced.library.ApkSigner.newApkSigner",
),
)
fun newApkSigner(
keyStore: KeyStore,
keyStoreEntryAlias: String,
keyStoreEntryPassword: String,
) = newApkSigner("ReVanced", readKeyCertificatePair(keyStore, keyStoreEntryAlias, keyStoreEntryPassword))
/** /**
* An entry in a keystore. * An entry in a keystore.
@@ -244,23 +307,48 @@ object ApkSigner {
val certificate: X509Certificate, val certificate: X509Certificate,
) )
class Signer internal constructor(val signingExtension: SigningExtension) { class Signer {
private val signerBuilder: com.android.apksig.ApkSigner.Builder?
private val signingExtension: SigningExtension?
internal constructor(signerBuilder: com.android.apksig.ApkSigner.Builder) {
this.signerBuilder = signerBuilder
signingExtension = null
}
@Deprecated("This constructor will be removed in the future.")
internal constructor(signingExtension: SigningExtension) {
signerBuilder = null
this.signingExtension = signingExtension
}
/** /**
* Sign an APK file. * Sign an APK file.
* *
* @param apkFile The APK file to sign. * @param apkFile The APK file to sign.
*/ */
fun signApk(apkFile: File) = ZFile.openReadWrite(apkFile).use { signApk(it) } @Deprecated("This method will be removed in the future.")
fun signApk(apkFile: File) = ZFile.openReadWrite(apkFile).use {
@Suppress("DEPRECATION")
signApk(it)
}
/** /**
* Sign an APK file. * Sign an APK file.
* *
* @param apkZFile The APK [ZFile] to sign. * @param apkZFile The APK [ZFile] to sign.
*/ */
@Deprecated("This method will be removed in the future.")
fun signApk(apkZFile: ZFile) { fun signApk(apkZFile: ZFile) {
logger.info("Signing ${apkZFile.file.name}") logger.info("Signing ${apkZFile.file.name}")
signingExtension.register(apkZFile) signingExtension?.register(apkZFile)
}
fun signApk(inputApkFile: File, outputApkFile: File) {
logger.info("Signing APK")
signerBuilder?.setInputApk(inputApkFile)?.setOutputApk(outputApkFile)?.build()?.sign()
} }
} }
} }

View File

@@ -92,28 +92,38 @@ object ApkUtils {
} }
} }
/**
* Reads an existing or creates a new keystore.
*
* @param signingOptions The options to use for signing.
*/
private fun readOrNewKeyStore(signingOptions: SigningOptions) = if (signingOptions.keyStore.exists()) {
ApkSigner.readKeyStore(
signingOptions.keyStore.inputStream(),
signingOptions.keyStorePassword ?: "",
)
} else {
val entry = ApkSigner.KeyStoreEntry(signingOptions.alias, signingOptions.password)
// Create a new keystore with a new keypair and saves it.
ApkSigner.newKeyStore(setOf(entry)).apply {
store(
signingOptions.keyStore.outputStream(),
signingOptions.keyStorePassword?.toCharArray(),
)
}
}
/** /**
* Signs the apk file with the given options. * Signs the apk file with the given options.
* *
* @param signingOptions The options to use for signing. * @param signingOptions The options to use for signing.
*/ */
@Deprecated("Use sign(File, File, SigningOptions) instead.")
fun File.sign(signingOptions: SigningOptions) { fun File.sign(signingOptions: SigningOptions) {
// Get the keystore from the file or create a new one. val keyStore = readOrNewKeyStore(signingOptions)
val keyStore =
if (signingOptions.keyStore.exists()) {
ApkSigner.readKeyStore(signingOptions.keyStore.inputStream(), signingOptions.keyStorePassword ?: "")
} else {
val entries = setOf(ApkSigner.KeyStoreEntry(signingOptions.alias, signingOptions.password))
// Create a new keystore with a new keypair and saves it.
ApkSigner.newKeyStore(entries).apply {
store(
signingOptions.keyStore.outputStream(),
signingOptions.keyStorePassword?.toCharArray(),
)
}
}
@Suppress("DEPRECATION")
ApkSigner.newApkSigner( ApkSigner.newApkSigner(
keyStore, keyStore,
signingOptions.alias, signingOptions.alias,
@@ -121,6 +131,24 @@ object ApkUtils {
).signApk(this) ).signApk(this)
} }
/**
* Signs [inputApkFile] with the given options and saves the signed apk to [outputApkFile].
*
* @param inputApkFile The apk file to sign.
* @param outputApkFile The file to save the signed apk to.
* @param signingOptions The options to use for signing.
*/
fun sign(inputApkFile: File, outputApkFile: File, signingOptions: SigningOptions) {
val keyStore = readOrNewKeyStore(signingOptions)
ApkSigner.newApkSigner(
signingOptions.signer,
keyStore,
signingOptions.alias,
signingOptions.password,
).signApk(inputApkFile, outputApkFile)
}
/** /**
* Options for signing an apk. * Options for signing an apk.
* *