mirror of
https://github.com/ReVanced/revanced-library.git
synced 2026-01-17 16:33:56 +00:00
Compare commits
38 Commits
v2.0.0-dev
...
v2.3.0-dev
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
af0aba4a8e | ||
|
|
4c6a6360cf | ||
|
|
80e35270c4 | ||
|
|
13b6a846d7 | ||
|
|
2df3484b68 | ||
|
|
f2959b610a | ||
|
|
2a30845f61 | ||
|
|
1b4d87e563 | ||
|
|
7f7dfdd5b5 | ||
|
|
56773fa3d3 | ||
|
|
249372c31f | ||
|
|
e7bed8565e | ||
|
|
4a24e2e92d | ||
|
|
fca8a3f4c0 | ||
|
|
f59ecbccd1 | ||
|
|
c92be32607 | ||
|
|
51109c4768 | ||
|
|
f2bd3f5eee | ||
|
|
cc5ee29d14 | ||
|
|
c4bad9a653 | ||
|
|
3f713cf76b | ||
|
|
dfe48a24bf | ||
|
|
132ad13670 | ||
|
|
1670ceff9f | ||
|
|
41805fcb0b | ||
|
|
0e9939f70d | ||
|
|
f28a7ddeec | ||
|
|
3e574e723c | ||
|
|
a73ca721f3 | ||
|
|
393d74b7d9 | ||
|
|
51d6e9976c | ||
|
|
24cecb1e57 | ||
|
|
d4938c57e8 | ||
|
|
1526f98f53 | ||
|
|
244ebc2186 | ||
|
|
486a7acff2 | ||
|
|
f0b8bc5438 | ||
|
|
806f45c77f |
25
.github/workflows/build_pull_request.yml
vendored
Normal file
25
.github/workflows/build_pull_request.yml
vendored
Normal 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
|
||||||
4
.github/workflows/release.yml
vendored
4
.github/workflows/release.yml
vendored
@@ -6,10 +6,6 @@ on:
|
|||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
- dev
|
- dev
|
||||||
pull_request:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
- dev
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
release:
|
release:
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -32,6 +32,12 @@
|
|||||||
backmergeBranches: [{"from": "main", "to": "dev"}],
|
backmergeBranches: [{"from": "main", "to": "dev"}],
|
||||||
clearWorkspace: true
|
clearWorkspace: true
|
||||||
}
|
}
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"@semantic-release/github",
|
||||||
|
{
|
||||||
|
successComment: false
|
||||||
|
}
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
105
CHANGELOG.md
105
CHANGELOG.md
@@ -1,3 +1,108 @@
|
|||||||
|
# [2.3.0-dev.2](https://github.com/ReVanced/revanced-library/compare/v2.3.0-dev.1...v2.3.0-dev.2) (2024-03-14)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* Simplify signing utility API ([4c6a636](https://github.com/ReVanced/revanced-library/commit/4c6a6360cf83659d1f5c3a7c5710ac54426e9235))
|
||||||
|
|
||||||
|
# [2.3.0-dev.1](https://github.com/ReVanced/revanced-library/compare/v2.2.2-dev.1...v2.3.0-dev.1) (2024-03-13)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* Add utility function around key certificate pairs ([2df3484](https://github.com/ReVanced/revanced-library/commit/2df3484b68ed72338a52e76fb4b7ceb9c9c644ed))
|
||||||
|
|
||||||
|
## [2.2.2-dev.1](https://github.com/ReVanced/revanced-library/compare/v2.2.1...v2.2.2-dev.1) (2024-03-12)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* Support mounting even when Magisk is not installed ([2a30845](https://github.com/ReVanced/revanced-library/commit/2a30845f61d5f77ded7a72ee3d6ab55b4c512d52))
|
||||||
|
|
||||||
|
## [2.2.1](https://github.com/ReVanced/revanced-library/compare/v2.2.0...v2.2.1) (2024-03-09)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* Do not specify a provider to automatically select an available one ([249372c](https://github.com/ReVanced/revanced-library/commit/249372c31f7e7975fc9eacb5361bd07dbc5dfb92))
|
||||||
|
|
||||||
|
## [2.2.1-dev.1](https://github.com/ReVanced/revanced-library/compare/v2.2.0...v2.2.1-dev.1) (2024-03-09)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* Do not specify a provider to automatically select an available one ([249372c](https://github.com/ReVanced/revanced-library/commit/249372c31f7e7975fc9eacb5361bd07dbc5dfb92))
|
||||||
|
|
||||||
|
# [2.2.0](https://github.com/ReVanced/revanced-library/compare/v2.1.0...v2.2.0) (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.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)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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
117
README.md
Normal 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>
|
||||||
|
<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>
|
||||||
|
<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>
|
||||||
|
<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>
|
||||||
|
<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>
|
||||||
|
<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>
|
||||||
|
<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
|
||||||
|
|
||||||
|

|
||||||
|

|
||||||
|
|
||||||
|
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.
|
||||||
@@ -1,18 +1,19 @@
|
|||||||
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;
|
||||||
public final fun newPrivateKeyCertificatePair (Ljava/lang/String;Ljava/util/Date;)Lapp/revanced/library/ApkSigner$PrivateKeyCertificatePair;
|
public final fun newPrivateKeyCertificatePair (Ljava/lang/String;Ljava/util/Date;)Lapp/revanced/library/ApkSigner$PrivateKeyCertificatePair;
|
||||||
public static synthetic fun newPrivateKeyCertificatePair$default (Lapp/revanced/library/ApkSigner;Ljava/lang/String;Ljava/util/Date;ILjava/lang/Object;)Lapp/revanced/library/ApkSigner$PrivateKeyCertificatePair;
|
|
||||||
public final fun readKeyCertificatePair (Ljava/security/KeyStore;Ljava/lang/String;Ljava/lang/String;)Lapp/revanced/library/ApkSigner$PrivateKeyCertificatePair;
|
public final fun readKeyCertificatePair (Ljava/security/KeyStore;Ljava/lang/String;Ljava/lang/String;)Lapp/revanced/library/ApkSigner$PrivateKeyCertificatePair;
|
||||||
public final fun readKeyStore (Ljava/io/InputStream;Ljava/lang/String;)Ljava/security/KeyStore;
|
public final fun readKeyStore (Ljava/io/InputStream;Ljava/lang/String;)Ljava/security/KeyStore;
|
||||||
|
public final fun readPrivateKeyCertificatePair (Ljava/security/KeyStore;Ljava/lang/String;Ljava/lang/String;)Lapp/revanced/library/ApkSigner$PrivateKeyCertificatePair;
|
||||||
}
|
}
|
||||||
|
|
||||||
public final class app/revanced/library/ApkSigner$KeyStoreEntry {
|
public final class app/revanced/library/ApkSigner$KeyStoreEntry {
|
||||||
public fun <init> (Ljava/lang/String;Ljava/lang/String;Lapp/revanced/library/ApkSigner$PrivateKeyCertificatePair;)V
|
public fun <init> (Ljava/lang/String;Ljava/lang/String;Lapp/revanced/library/ApkSigner$PrivateKeyCertificatePair;)V
|
||||||
public synthetic fun <init> (Ljava/lang/String;Ljava/lang/String;Lapp/revanced/library/ApkSigner$PrivateKeyCertificatePair;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
|
|
||||||
public final fun getAlias ()Ljava/lang/String;
|
public final fun getAlias ()Ljava/lang/String;
|
||||||
public final fun getPassword ()Ljava/lang/String;
|
public final fun getPassword ()Ljava/lang/String;
|
||||||
public final fun getPrivateKeyCertificatePair ()Lapp/revanced/library/ApkSigner$PrivateKeyCertificatePair;
|
public final fun getPrivateKeyCertificatePair ()Lapp/revanced/library/ApkSigner$PrivateKeyCertificatePair;
|
||||||
@@ -25,15 +26,37 @@ 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 newPrivateKeyCertificatePair (Lapp/revanced/library/ApkUtils$PrivateKeyCertificatePairDetails;Lapp/revanced/library/ApkUtils$KeyStoreDetails;)Lapp/revanced/library/ApkSigner$PrivateKeyCertificatePair;
|
||||||
|
public final fun readPrivateKeyCertificatePairFromKeyStore (Lapp/revanced/library/ApkUtils$KeyStoreDetails;)Lapp/revanced/library/ApkSigner$PrivateKeyCertificatePair;
|
||||||
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 fun sign (Ljava/io/File;Ljava/io/File;Ljava/lang/String;Lapp/revanced/library/ApkSigner$PrivateKeyCertificatePair;)V
|
||||||
|
public final fun signApk (Ljava/io/File;Ljava/io/File;Ljava/lang/String;Lapp/revanced/library/ApkUtils$KeyStoreDetails;)V
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class app/revanced/library/ApkUtils$KeyStoreDetails {
|
||||||
|
public fun <init> (Ljava/io/File;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
|
||||||
|
public synthetic fun <init> (Ljava/io/File;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
|
||||||
|
public final fun getAlias ()Ljava/lang/String;
|
||||||
|
public final fun getKeyStore ()Ljava/io/File;
|
||||||
|
public final fun getKeyStorePassword ()Ljava/lang/String;
|
||||||
|
public final fun getPassword ()Ljava/lang/String;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class app/revanced/library/ApkUtils$PrivateKeyCertificatePairDetails {
|
||||||
|
public fun <init> ()V
|
||||||
|
public fun <init> (Ljava/lang/String;Ljava/util/Date;)V
|
||||||
|
public synthetic fun <init> (Ljava/lang/String;Ljava/util/Date;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
|
||||||
|
public final fun getCommonName ()Ljava/lang/String;
|
||||||
|
public final fun getValidUntil ()Ljava/util/Date;
|
||||||
}
|
}
|
||||||
|
|
||||||
public final class app/revanced/library/ApkUtils$SigningOptions {
|
public final class app/revanced/library/ApkUtils$SigningOptions {
|
||||||
|
|||||||
@@ -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,9 +46,15 @@ tasks {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
kotlin { jvmToolchain(11) }
|
kotlin {
|
||||||
|
compilerOptions {
|
||||||
|
jvmTarget.set(JvmTarget.JVM_11)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
java {
|
java {
|
||||||
|
targetCompatibility = JavaVersion.VERSION_11
|
||||||
|
|
||||||
withSourcesJar()
|
withSourcesJar()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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.3.0-dev.2
|
||||||
|
|||||||
@@ -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" }
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -17,54 +19,115 @@ import java.security.*
|
|||||||
import java.security.cert.X509Certificate
|
import java.security.cert.X509Certificate
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import java.util.logging.Logger
|
import java.util.logging.Logger
|
||||||
import kotlin.time.Duration.Companion.days
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utility class for reading or writing keystore files and entries as well as signing APK files.
|
* Utility class for reading or writing keystore files and entries as well as signing APK files.
|
||||||
*/
|
*/
|
||||||
@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())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun newKeyStoreInstance() = KeyStore.getInstance("BKS", BouncyCastleProvider.PROVIDER_NAME)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new [PrivateKeyCertificatePair].
|
* Create a new keystore with a new keypair.
|
||||||
|
*
|
||||||
|
* @param entries The entries to add to the keystore.
|
||||||
|
*
|
||||||
|
* @return The created keystore.
|
||||||
|
*
|
||||||
|
* @see KeyStoreEntry
|
||||||
|
* @see KeyStore
|
||||||
|
*/
|
||||||
|
fun newKeyStore(entries: Set<KeyStoreEntry>): KeyStore {
|
||||||
|
logger.fine("Creating keystore")
|
||||||
|
|
||||||
|
return newKeyStoreInstance().apply {
|
||||||
|
load(null)
|
||||||
|
|
||||||
|
entries.forEach { entry ->
|
||||||
|
// Add all entries to the keystore.
|
||||||
|
setKeyEntry(
|
||||||
|
entry.alias,
|
||||||
|
entry.privateKeyCertificatePair.privateKey,
|
||||||
|
entry.password.toCharArray(),
|
||||||
|
arrayOf(entry.privateKeyCertificatePair.certificate),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read a keystore from the given [keyStoreInputStream].
|
||||||
|
*
|
||||||
|
* @param keyStoreInputStream The stream to read the keystore from.
|
||||||
|
* @param keyStorePassword The password for the keystore.
|
||||||
|
*
|
||||||
|
* @return The keystore.
|
||||||
|
*
|
||||||
|
* @throws IllegalArgumentException If the keystore password is invalid.
|
||||||
|
*
|
||||||
|
* @see KeyStore
|
||||||
|
*/
|
||||||
|
fun readKeyStore(
|
||||||
|
keyStoreInputStream: InputStream,
|
||||||
|
keyStorePassword: String?,
|
||||||
|
): KeyStore {
|
||||||
|
logger.fine("Reading keystore")
|
||||||
|
|
||||||
|
return newKeyStoreInstance().apply {
|
||||||
|
try {
|
||||||
|
load(keyStoreInputStream, keyStorePassword?.toCharArray())
|
||||||
|
} catch (exception: IOException) {
|
||||||
|
if (exception.cause is UnrecoverableKeyException) {
|
||||||
|
throw IllegalArgumentException("Invalid keystore password")
|
||||||
|
} else {
|
||||||
|
throw exception
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new private key and certificate pair.
|
||||||
*
|
*
|
||||||
* @param commonName The common name of the certificate.
|
* @param commonName The common name of the certificate.
|
||||||
* @param validUntil The date until the certificate is valid.
|
* @param validUntil The date until which the certificate is valid.
|
||||||
*
|
*
|
||||||
* @return The created [PrivateKeyCertificatePair].
|
* @return The newly created private key and certificate pair.
|
||||||
|
*
|
||||||
|
* @see PrivateKeyCertificatePair
|
||||||
*/
|
*/
|
||||||
fun newPrivateKeyCertificatePair(
|
fun newPrivateKeyCertificatePair(
|
||||||
commonName: String = "ReVanced",
|
commonName: String,
|
||||||
validUntil: Date = Date(System.currentTimeMillis() + 356.days.inWholeMilliseconds * 24),
|
validUntil: Date,
|
||||||
): 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").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)
|
||||||
}
|
}
|
||||||
@@ -79,8 +142,11 @@ object ApkSigner {
|
|||||||
* @return The read [PrivateKeyCertificatePair].
|
* @return The read [PrivateKeyCertificatePair].
|
||||||
*
|
*
|
||||||
* @throws IllegalArgumentException If the keystore does not contain the given alias or the password is invalid.
|
* @throws IllegalArgumentException If the keystore does not contain the given alias or the password is invalid.
|
||||||
|
*
|
||||||
|
* @see PrivateKeyCertificatePair
|
||||||
|
* @see KeyStore
|
||||||
*/
|
*/
|
||||||
fun readKeyCertificatePair(
|
fun readPrivateKeyCertificatePair(
|
||||||
keyStore: KeyStore,
|
keyStore: KeyStore,
|
||||||
keyStoreEntryAlias: String,
|
keyStoreEntryAlias: String,
|
||||||
keyStoreEntryPassword: String,
|
keyStoreEntryPassword: String,
|
||||||
@@ -106,31 +172,48 @@ object ApkSigner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new keystore with a new keypair.
|
* Create a new [Signer].
|
||||||
*
|
*
|
||||||
* @param entries The entries to add to the keystore.
|
* @param signer The name of the signer.
|
||||||
|
* @param privateKeyCertificatePair The private key and certificate pair to use for signing.
|
||||||
*
|
*
|
||||||
* @return The created keystore.
|
* @return The new [Signer].
|
||||||
*
|
*
|
||||||
* @see KeyStoreEntry
|
* @see PrivateKeyCertificatePair
|
||||||
|
* @see Signer
|
||||||
*/
|
*/
|
||||||
fun newKeyStore(entries: Set<KeyStoreEntry>): KeyStore {
|
fun newApkSigner(
|
||||||
logger.fine("Creating keystore")
|
signer: String,
|
||||||
|
privateKeyCertificatePair: PrivateKeyCertificatePair,
|
||||||
|
) = Signer(
|
||||||
|
com.android.apksig.ApkSigner.Builder(
|
||||||
|
listOf(
|
||||||
|
SignerConfig.Builder(
|
||||||
|
signer,
|
||||||
|
privateKeyCertificatePair.privateKey,
|
||||||
|
listOf(privateKeyCertificatePair.certificate),
|
||||||
|
).build(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
return KeyStore.getInstance(KeyStore.getDefaultType()).apply {
|
/**
|
||||||
load(null)
|
* Read a [PrivateKeyCertificatePair] from a keystore entry.
|
||||||
|
*
|
||||||
entries.forEach { entry ->
|
* @param keyStore The keystore to read the entry from.
|
||||||
// Add all entries to the keystore.
|
* @param keyStoreEntryAlias The alias of the key store entry to read.
|
||||||
setKeyEntry(
|
* @param keyStoreEntryPassword The password for recovering the signing key.
|
||||||
entry.alias,
|
*
|
||||||
entry.privateKeyCertificatePair.privateKey,
|
* @return The read [PrivateKeyCertificatePair].
|
||||||
entry.password.toCharArray(),
|
*
|
||||||
arrayOf(entry.privateKeyCertificatePair.certificate),
|
* @throws IllegalArgumentException If the keystore does not contain the given alias or the password is invalid.
|
||||||
)
|
*/
|
||||||
}
|
@Deprecated("This method will be removed in the future.")
|
||||||
}
|
fun readKeyCertificatePair(
|
||||||
}
|
keyStore: KeyStore,
|
||||||
|
keyStoreEntryAlias: String,
|
||||||
|
keyStoreEntryPassword: String,
|
||||||
|
) = readPrivateKeyCertificatePair(keyStore, keyStoreEntryAlias, keyStoreEntryPassword)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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].
|
||||||
@@ -139,44 +222,16 @@ object ApkSigner {
|
|||||||
* @param keyStorePassword The password for the keystore.
|
* @param keyStorePassword The password for the keystore.
|
||||||
* @param entries The entries to add to the keystore.
|
* @param entries The entries to add to the keystore.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated("This method will be removed in the future.")
|
||||||
fun newKeyStore(
|
fun newKeyStore(
|
||||||
keyStoreOutputStream: OutputStream,
|
keyStoreOutputStream: OutputStream,
|
||||||
keyStorePassword: String,
|
keyStorePassword: String?,
|
||||||
entries: Set<KeyStoreEntry>,
|
entries: Set<KeyStoreEntry>,
|
||||||
) = newKeyStore(entries).store(
|
) = newKeyStore(entries).store(
|
||||||
keyStoreOutputStream,
|
keyStoreOutputStream,
|
||||||
keyStorePassword.toCharArray(),
|
keyStorePassword?.toCharArray(),
|
||||||
)
|
)
|
||||||
|
|
||||||
/**
|
|
||||||
* Read a keystore from the given [keyStoreInputStream].
|
|
||||||
*
|
|
||||||
* @param keyStoreInputStream The stream to read the keystore from.
|
|
||||||
* @param keyStorePassword The password for the keystore.
|
|
||||||
*
|
|
||||||
* @return The keystore.
|
|
||||||
*
|
|
||||||
* @throws IllegalArgumentException If the keystore password is invalid.
|
|
||||||
*/
|
|
||||||
fun readKeyStore(
|
|
||||||
keyStoreInputStream: InputStream,
|
|
||||||
keyStorePassword: String?,
|
|
||||||
): KeyStore {
|
|
||||||
logger.fine("Reading keystore")
|
|
||||||
|
|
||||||
return KeyStore.getInstance(KeyStore.getDefaultType()).apply {
|
|
||||||
try {
|
|
||||||
load(keyStoreInputStream, keyStorePassword?.toCharArray())
|
|
||||||
} catch (exception: IOException) {
|
|
||||||
if (exception.cause is UnrecoverableKeyException) {
|
|
||||||
throw IllegalArgumentException("Invalid keystore password")
|
|
||||||
} else {
|
|
||||||
throw exception
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new [Signer].
|
* Create a new [Signer].
|
||||||
*
|
*
|
||||||
@@ -187,6 +242,7 @@ object ApkSigner {
|
|||||||
* @see PrivateKeyCertificatePair
|
* @see PrivateKeyCertificatePair
|
||||||
* @see Signer
|
* @see Signer
|
||||||
*/
|
*/
|
||||||
|
@Deprecated("This method will be removed in the future.")
|
||||||
fun newApkSigner(privateKeyCertificatePair: PrivateKeyCertificatePair) =
|
fun newApkSigner(privateKeyCertificatePair: PrivateKeyCertificatePair) =
|
||||||
Signer(
|
Signer(
|
||||||
SigningExtension(
|
SigningExtension(
|
||||||
@@ -203,6 +259,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.
|
||||||
@@ -212,11 +269,32 @@ object ApkSigner {
|
|||||||
* @see KeyStore
|
* @see KeyStore
|
||||||
* @see Signer
|
* @see Signer
|
||||||
*/
|
*/
|
||||||
|
@Deprecated("This method will be removed in the future.")
|
||||||
|
fun newApkSigner(
|
||||||
|
signer: String,
|
||||||
|
keyStore: KeyStore,
|
||||||
|
keyStoreEntryAlias: String,
|
||||||
|
keyStoreEntryPassword: String,
|
||||||
|
) = 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.")
|
||||||
fun newApkSigner(
|
fun newApkSigner(
|
||||||
keyStore: KeyStore,
|
keyStore: KeyStore,
|
||||||
keyStoreEntryAlias: String,
|
keyStoreEntryAlias: String,
|
||||||
keyStoreEntryPassword: String,
|
keyStoreEntryPassword: String,
|
||||||
) = newApkSigner(readKeyCertificatePair(keyStore, keyStoreEntryAlias, keyStoreEntryPassword))
|
) = newApkSigner("ReVanced", readKeyCertificatePair(keyStore, keyStoreEntryAlias, keyStoreEntryPassword))
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An entry in a keystore.
|
* An entry in a keystore.
|
||||||
@@ -230,7 +308,7 @@ object ApkSigner {
|
|||||||
class KeyStoreEntry(
|
class KeyStoreEntry(
|
||||||
val alias: String,
|
val alias: String,
|
||||||
val password: String,
|
val password: String,
|
||||||
val privateKeyCertificatePair: PrivateKeyCertificatePair = newPrivateKeyCertificatePair(),
|
val privateKeyCertificatePair: PrivateKeyCertificatePair,
|
||||||
)
|
)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -244,23 +322,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
|
||||||
|
}
|
||||||
|
|
||||||
|
fun signApk(inputApkFile: File, outputApkFile: File) {
|
||||||
|
logger.info("Signing APK")
|
||||||
|
|
||||||
|
signerBuilder?.setInputApk(inputApkFile)?.setOutputApk(outputApkFile)?.build()?.sign()
|
||||||
|
}
|
||||||
|
|
||||||
|
@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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,15 @@
|
|||||||
package app.revanced.library
|
package app.revanced.library
|
||||||
|
|
||||||
|
import app.revanced.library.ApkSigner.newPrivateKeyCertificatePair
|
||||||
import app.revanced.patcher.PatcherResult
|
import app.revanced.patcher.PatcherResult
|
||||||
import com.android.tools.build.apkzlib.zip.AlignmentRules
|
import com.android.tools.build.apkzlib.zip.AlignmentRules
|
||||||
import com.android.tools.build.apkzlib.zip.StoredEntry
|
import com.android.tools.build.apkzlib.zip.StoredEntry
|
||||||
import com.android.tools.build.apkzlib.zip.ZFile
|
import com.android.tools.build.apkzlib.zip.ZFile
|
||||||
import com.android.tools.build.apkzlib.zip.ZFileOptions
|
import com.android.tools.build.apkzlib.zip.ZFileOptions
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
import java.util.*
|
||||||
import java.util.logging.Logger
|
import java.util.logging.Logger
|
||||||
|
import kotlin.time.Duration.Companion.days
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utility functions to work with APK files.
|
* Utility functions to work with APK files.
|
||||||
@@ -92,34 +95,145 @@ object ApkUtils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new private key and certificate pair and saves it to the keystore in [keyStoreDetails].
|
||||||
|
*
|
||||||
|
* @param privateKeyCertificatePairDetails The details for the private key and certificate pair.
|
||||||
|
* @param keyStoreDetails The details for the keystore.
|
||||||
|
*
|
||||||
|
* @return The newly created private key and certificate pair.
|
||||||
|
*/
|
||||||
|
@Deprecated("This method will be removed in the future.")
|
||||||
|
fun newPrivateKeyCertificatePair(
|
||||||
|
privateKeyCertificatePairDetails: PrivateKeyCertificatePairDetails,
|
||||||
|
keyStoreDetails: KeyStoreDetails,
|
||||||
|
) = newPrivateKeyCertificatePair(
|
||||||
|
privateKeyCertificatePairDetails.commonName,
|
||||||
|
privateKeyCertificatePairDetails.validUntil,
|
||||||
|
).also { privateKeyCertificatePair ->
|
||||||
|
ApkSigner.newKeyStore(
|
||||||
|
setOf(
|
||||||
|
ApkSigner.KeyStoreEntry(
|
||||||
|
keyStoreDetails.alias,
|
||||||
|
keyStoreDetails.password,
|
||||||
|
privateKeyCertificatePair,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
).store(
|
||||||
|
keyStoreDetails.keyStore.outputStream(),
|
||||||
|
keyStoreDetails.keyStorePassword?.toCharArray(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads the private key and certificate pair from an existing keystore.
|
||||||
|
*
|
||||||
|
* @param keyStoreDetails The details for the keystore.
|
||||||
|
*
|
||||||
|
* @return The private key and certificate pair.
|
||||||
|
*/
|
||||||
|
@Deprecated("This method will be removed in the future.")
|
||||||
|
fun readPrivateKeyCertificatePairFromKeyStore(
|
||||||
|
keyStoreDetails: KeyStoreDetails,
|
||||||
|
) = ApkSigner.readPrivateKeyCertificatePair(
|
||||||
|
ApkSigner.readKeyStore(
|
||||||
|
keyStoreDetails.keyStore.inputStream(),
|
||||||
|
keyStoreDetails.keyStorePassword,
|
||||||
|
),
|
||||||
|
keyStoreDetails.alias,
|
||||||
|
keyStoreDetails.password,
|
||||||
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Signs [inputApkFile] with the given options and saves the signed apk to [outputApkFile].
|
||||||
|
* If [KeyStoreDetails.keyStore] does not exist,
|
||||||
|
* a new private key and certificate pair will be created and saved to the keystore.
|
||||||
|
*
|
||||||
|
* @param inputApkFile The apk file to sign.
|
||||||
|
* @param outputApkFile The file to save the signed apk to.
|
||||||
|
* @param signer The name of the signer.
|
||||||
|
* @param keyStoreDetails The details for the keystore.
|
||||||
|
*/
|
||||||
|
fun signApk(
|
||||||
|
inputApkFile: File,
|
||||||
|
outputApkFile: File,
|
||||||
|
signer: String,
|
||||||
|
keyStoreDetails: KeyStoreDetails,
|
||||||
|
) = ApkSigner.newApkSigner(
|
||||||
|
signer,
|
||||||
|
if (keyStoreDetails.keyStore.exists()) {
|
||||||
|
readPrivateKeyCertificatePairFromKeyStore(keyStoreDetails)
|
||||||
|
} else {
|
||||||
|
newPrivateKeyCertificatePair(PrivateKeyCertificatePairDetails(), keyStoreDetails)
|
||||||
|
},
|
||||||
|
).signApk(inputApkFile, outputApkFile)
|
||||||
|
|
||||||
|
@Deprecated("This method will be removed in the future.")
|
||||||
|
private fun readOrNewPrivateKeyCertificatePair(
|
||||||
|
signingOptions: SigningOptions,
|
||||||
|
): ApkSigner.PrivateKeyCertificatePair {
|
||||||
|
val privateKeyCertificatePairDetails = PrivateKeyCertificatePairDetails(
|
||||||
|
signingOptions.alias,
|
||||||
|
PrivateKeyCertificatePairDetails().validUntil,
|
||||||
|
)
|
||||||
|
val keyStoreDetails = KeyStoreDetails(
|
||||||
|
signingOptions.keyStore,
|
||||||
|
signingOptions.keyStorePassword,
|
||||||
|
signingOptions.alias,
|
||||||
|
signingOptions.password,
|
||||||
|
)
|
||||||
|
|
||||||
|
return if (keyStoreDetails.keyStore.exists()) {
|
||||||
|
readPrivateKeyCertificatePairFromKeyStore(keyStoreDetails)
|
||||||
|
} else {
|
||||||
|
newPrivateKeyCertificatePair(privateKeyCertificatePairDetails, keyStoreDetails)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 signer The name of the signer.
|
||||||
|
* @param privateKeyCertificatePair The private key and certificate pair to use for signing.
|
||||||
|
*/
|
||||||
|
@Deprecated("This method will be removed in the future.")
|
||||||
|
fun sign(
|
||||||
|
inputApkFile: File,
|
||||||
|
outputApkFile: File,
|
||||||
|
signer: String,
|
||||||
|
privateKeyCertificatePair: ApkSigner.PrivateKeyCertificatePair,
|
||||||
|
) = ApkSigner.newApkSigner(
|
||||||
|
signer,
|
||||||
|
privateKeyCertificatePair,
|
||||||
|
).signApk(inputApkFile, outputApkFile)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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.
|
||||||
*/
|
*/
|
||||||
fun File.sign(signingOptions: SigningOptions) {
|
@Deprecated("This method will be removed in the future.")
|
||||||
// Get the keystore from the file or create a new one.
|
fun File.sign(signingOptions: SigningOptions) = ApkSigner.newApkSigner(
|
||||||
val keyStore =
|
signingOptions.signer,
|
||||||
if (signingOptions.keyStore.exists()) {
|
readOrNewPrivateKeyCertificatePair(signingOptions),
|
||||||
ApkSigner.readKeyStore(signingOptions.keyStore.inputStream(), signingOptions.keyStorePassword ?: "")
|
).signApk(this)
|
||||||
} 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 {
|
* Signs [inputApkFile] with the given options and saves the signed apk to [outputApkFile].
|
||||||
store(
|
*
|
||||||
signingOptions.keyStore.outputStream(),
|
* @param inputApkFile The apk file to sign.
|
||||||
signingOptions.keyStorePassword?.toCharArray(),
|
* @param outputApkFile The file to save the signed apk to.
|
||||||
)
|
* @param signingOptions The options to use for signing.
|
||||||
}
|
*/
|
||||||
}
|
@Deprecated("This method will be removed in the future.")
|
||||||
|
fun sign(inputApkFile: File, outputApkFile: File, signingOptions: SigningOptions) = sign(
|
||||||
ApkSigner.newApkSigner(
|
inputApkFile,
|
||||||
keyStore,
|
outputApkFile,
|
||||||
signingOptions.alias,
|
signingOptions.signer,
|
||||||
signingOptions.password,
|
readOrNewPrivateKeyCertificatePair(signingOptions),
|
||||||
).signApk(this)
|
)
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Options for signing an apk.
|
* Options for signing an apk.
|
||||||
@@ -130,6 +244,7 @@ object ApkUtils {
|
|||||||
* @param password The password for recovering the signing key.
|
* @param password The password for recovering the signing key.
|
||||||
* @param signer The name of the signer.
|
* @param signer The name of the signer.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated("This class will be removed in the future.")
|
||||||
class SigningOptions(
|
class SigningOptions(
|
||||||
val keyStore: File,
|
val keyStore: File,
|
||||||
val keyStorePassword: String?,
|
val keyStorePassword: String?,
|
||||||
@@ -137,4 +252,30 @@ object ApkUtils {
|
|||||||
val password: String = "",
|
val password: String = "",
|
||||||
val signer: String = "ReVanced",
|
val signer: String = "ReVanced",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Details for a keystore.
|
||||||
|
*
|
||||||
|
* @param keyStore The file to save the keystore to.
|
||||||
|
* @param keyStorePassword The password for the keystore.
|
||||||
|
* @param alias The alias of the key store entry to use for signing.
|
||||||
|
* @param password The password for recovering the signing key.
|
||||||
|
*/
|
||||||
|
class KeyStoreDetails(
|
||||||
|
val keyStore: File,
|
||||||
|
val keyStorePassword: String? = null,
|
||||||
|
val alias: String = "ReVanced Key",
|
||||||
|
val password: String = "",
|
||||||
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Details for a private key and certificate pair.
|
||||||
|
*
|
||||||
|
* @param commonName The common name for the certificate saved in the keystore.
|
||||||
|
* @param validUntil The date until which the certificate is valid.
|
||||||
|
*/
|
||||||
|
class PrivateKeyCertificatePairDetails(
|
||||||
|
val commonName: String = "ReVanced",
|
||||||
|
val validUntil: Date = Date(System.currentTimeMillis() + (365.days * 8).inWholeMilliseconds * 24),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,13 +29,17 @@ internal object Constants {
|
|||||||
internal val MOUNT_SCRIPT =
|
internal val MOUNT_SCRIPT =
|
||||||
"""
|
"""
|
||||||
#!/system/bin/sh
|
#!/system/bin/sh
|
||||||
MAGISKTMP="$( magisk --path )" || MAGISKTMP=/sbin
|
|
||||||
MIRROR="${'$'}MAGISKTMP/.magisk/mirror"
|
# Use Magisk mirror, if possible.
|
||||||
|
if command -v magisk &> /dev/null; then
|
||||||
|
MIRROR="${'$'}(magisk --path)/.magisk/mirror"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Wait for the system to boot.
|
||||||
until [ "$( getprop sys.boot_completed )" = 1 ]; do sleep 3; done
|
until [ "$( getprop sys.boot_completed )" = 1 ]; do sleep 3; done
|
||||||
until [ -d "/sdcard/Android" ]; do sleep 1; done
|
until [ -d "/sdcard/Android" ]; do sleep 1; done
|
||||||
|
|
||||||
# Unmount any existing mount as a safety measure
|
# Unmount any existing mount as a safety measure.
|
||||||
$UMOUNT
|
$UMOUNT
|
||||||
|
|
||||||
base_path="$PATCHED_APK_PATH"
|
base_path="$PATCHED_APK_PATH"
|
||||||
@@ -44,7 +48,7 @@ internal object Constants {
|
|||||||
chcon u:object_r:apk_data_file:s0 ${'$'}base_path
|
chcon u:object_r:apk_data_file:s0 ${'$'}base_path
|
||||||
mount -o bind ${'$'}MIRROR${'$'}base_path ${'$'}stock_path
|
mount -o bind ${'$'}MIRROR${'$'}base_path ${'$'}stock_path
|
||||||
|
|
||||||
# Kill the app to force it to restart the mounted APK in case it's already running
|
# Kill the app to force it to restart the mounted APK in case it's currently running.
|
||||||
$KILL
|
$KILL
|
||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user