mirror of
https://github.com/ReVanced/revanced-library.git
synced 2026-01-11 13:56:17 +00:00
Compare commits
31 Commits
feat/netwo
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4065c87d5f | ||
|
|
be8d7bf643 | ||
|
|
2328902b6b | ||
|
|
7ec6504619 | ||
|
|
e7a98b5795 | ||
|
|
649f06b19d | ||
|
|
cace51700a | ||
|
|
91cefc8598 | ||
|
|
735c1e39cd | ||
|
|
84cc315541 | ||
|
|
4fe9304570 | ||
|
|
8bb41be8fc | ||
|
|
4b8ac026c3 | ||
|
|
557b6035f8 | ||
|
|
bfc5394b4e | ||
|
|
5b1cf1f190 | ||
|
|
dd5c37ddec | ||
|
|
9adccc04dd | ||
|
|
ed94d29461 | ||
|
|
efc72cdc55 | ||
|
|
737e272481 | ||
|
|
92ff93d6e6 | ||
|
|
d56126aa58 | ||
|
|
079776f241 | ||
|
|
7a554a85a8 | ||
|
|
b9bf3bc882 | ||
|
|
27b3359d66 | ||
|
|
893d22d793 | ||
|
|
7f5d6dad7b | ||
|
|
8aca650ebc | ||
|
|
db59d2cd0b |
5
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
5
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
@@ -70,7 +70,8 @@ body:
|
||||
|
||||
Before creating a new bug report, please keep the following in mind:
|
||||
|
||||
- **Do not submit a duplicate bug report**: You can review existing bug reports [here](https://github.com/ReVanced/revanced-library/labels/Bug%20report).
|
||||
- **Do not submit a duplicate bug report**: Search for existing bug reports [here](https://github.com/ReVanced/revanced-library/issues?q=label%3A%22Bug+report%22).
|
||||
- **Review the contribution guidelines**: Make sure your bug request adheres to it. You can find the guidelines [here](https://github.com/ReVanced/revanced-library/blob/main/CONTRIBUTING.md).
|
||||
- **Do not use the issue page for support**: If you need help or have questions, check out other platforms on [revanced.app](https://revanced.app).
|
||||
- type: textarea
|
||||
attributes:
|
||||
@@ -100,7 +101,7 @@ body:
|
||||
label: Acknowledgements
|
||||
description: Your bug report will be closed if you don't follow the checklist below.
|
||||
options:
|
||||
- label: This issue is not a duplicate of an existing bug report.
|
||||
- label: I have checked all open and closed bug reports and this is not a duplicate.
|
||||
required: true
|
||||
- label: I have chosen an appropriate title.
|
||||
required: true
|
||||
|
||||
6
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
6
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
@@ -70,8 +70,8 @@ body:
|
||||
|
||||
Before creating a new feature request, please keep the following in mind:
|
||||
|
||||
- **Do not submit a duplicate feature request**: You can review existing feature requests [here](https://github.com/ReVanced/revanced-library/labels/Feature%20request).
|
||||
- **Review the contribution guidelines**: Make sure your bug report adheres to it. You can find the guidelines [here](https://github.com/ReVanced/revanced-library/blob/main/CONTRIBUTING.md).
|
||||
- **Do not submit a duplicate feature request**: Search for existing feature requests [here](https://github.com/ReVanced/revanced-library/issues?q=label%3A%22Feature+request%22).
|
||||
- **Review the contribution guidelines**: Make sure your feature request adheres to it. You can find the guidelines [here](https://github.com/ReVanced/revanced-library/blob/main/CONTRIBUTING.md).
|
||||
- **Do not use the issue page for support**: If you need help or have questions, check out other platforms on [revanced.app](https://revanced.app).
|
||||
- type: textarea
|
||||
attributes:
|
||||
@@ -98,7 +98,7 @@ body:
|
||||
label: Acknowledgements
|
||||
description: Your feature request will be closed if you don't follow the checklist below.
|
||||
options:
|
||||
- label: This issue is not a duplicate of an existing feature request.
|
||||
- label: I have checked all open and closed feature requests and this is not a duplicate.
|
||||
required: true
|
||||
- label: I have chosen an appropriate title.
|
||||
required: true
|
||||
|
||||
7
.github/workflows/release.yml
vendored
7
.github/workflows/release.yml
vendored
@@ -10,6 +10,9 @@ on:
|
||||
jobs:
|
||||
release:
|
||||
name: Release
|
||||
permissions:
|
||||
contents: write
|
||||
packages: write
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
@@ -45,9 +48,9 @@ jobs:
|
||||
with:
|
||||
gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }}
|
||||
passphrase: ${{ secrets.GPG_PASSPHRASE }}
|
||||
fingerprint: ${{ env.GPG_FINGERPRINT }}
|
||||
fingerprint: ${{ vars.GPG_FINGERPRINT }}
|
||||
|
||||
- name: Release
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.REPOSITORY_PUSH_ACCESS }}
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: npm exec semantic-release
|
||||
|
||||
@@ -23,7 +23,8 @@
|
||||
"assets": [
|
||||
"CHANGELOG.md",
|
||||
"gradle.properties"
|
||||
]
|
||||
],
|
||||
"message": "chore: Release v${nextRelease.version} [skip ci]\n\n${nextRelease.notes}"
|
||||
}
|
||||
],
|
||||
[
|
||||
|
||||
97
CHANGELOG.md
97
CHANGELOG.md
@@ -1,3 +1,100 @@
|
||||
# [3.1.0](https://github.com/ReVanced/revanced-library/compare/v3.0.2...v3.1.0) (2024-11-27)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Detect if app is installed by fixing inversion ([649f06b](https://github.com/ReVanced/revanced-library/commit/649f06b19dd4d2a3f3216a0b3ea947b9fe0d475f))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* Warn when option could not be set because the option does not exist ([7ec6504](https://github.com/ReVanced/revanced-library/commit/7ec650461935faf2a8fbb667db3cf137157b70b5))
|
||||
|
||||
# [3.1.0-dev.1](https://github.com/ReVanced/revanced-library/compare/v3.0.3-dev.1...v3.1.0-dev.1) (2024-11-25)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* Warn when option could not be set because the option does not exist ([7ec6504](https://github.com/ReVanced/revanced-library/commit/7ec650461935faf2a8fbb667db3cf137157b70b5))
|
||||
|
||||
## [3.0.3-dev.1](https://github.com/ReVanced/revanced-library/compare/v3.0.2...v3.0.3-dev.1) (2024-11-11)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Detect if app is installed by fixing inversion ([649f06b](https://github.com/ReVanced/revanced-library/commit/649f06b19dd4d2a3f3216a0b3ea947b9fe0d475f))
|
||||
|
||||
## [3.0.2](https://github.com/ReVanced/revanced-library/compare/v3.0.1...v3.0.2) (2024-11-05)
|
||||
|
||||
## [3.0.2-dev.1](https://github.com/ReVanced/revanced-library/compare/v3.0.1...v3.0.2-dev.1) (2024-11-05)
|
||||
|
||||
## [3.0.1](https://github.com/ReVanced/revanced-library/compare/v3.0.0...v3.0.1) (2024-10-13)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Serialize compatible packages as a map instead of a set of pairs. ([737e272](https://github.com/ReVanced/revanced-library/commit/737e272481fe3b0b4c89233d139b5e657a0c1de4))
|
||||
|
||||
## [3.0.1-dev.3](https://github.com/ReVanced/revanced-library/compare/v3.0.1-dev.2...v3.0.1-dev.3) (2024-10-06)
|
||||
|
||||
## [3.0.1-dev.2](https://github.com/ReVanced/revanced-library/compare/v3.0.1-dev.1...v3.0.1-dev.2) (2024-10-01)
|
||||
|
||||
## [3.0.1-dev.1](https://github.com/ReVanced/revanced-library/compare/v3.0.0...v3.0.1-dev.1) (2024-08-16)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Serialize compatible packages as a map instead of a set of pairs. ([737e272](https://github.com/ReVanced/revanced-library/commit/737e272481fe3b0b4c89233d139b5e657a0c1de4))
|
||||
|
||||
# [3.0.0](https://github.com/ReVanced/revanced-library/compare/v2.3.0...v3.0.0) (2024-08-06)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Make functions internal which are supposed to be internal ([893d22d](https://github.com/ReVanced/revanced-library/commit/893d22d7938fa1c7544795635ed2ffacdd0cbf0d))
|
||||
|
||||
|
||||
### Build System
|
||||
|
||||
* Refactor to DSL to bump ReVanced Patcher ([7f5d6da](https://github.com/ReVanced/revanced-library/commit/7f5d6dad7ba73e2ee53010241ba3204d04860a22))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* Add local Android installer ([#25](https://github.com/ReVanced/revanced-library/issues/25)) ([43d655a](https://github.com/ReVanced/revanced-library/commit/43d655aea5d86288ae9916630e0f30de219d5cfb))
|
||||
* Remove deprecated functions ([b9bf3bc](https://github.com/ReVanced/revanced-library/commit/b9bf3bc88284c0381c7370c3606b662da2ef380d))
|
||||
|
||||
|
||||
### BREAKING CHANGES
|
||||
|
||||
* Some functions have been removed.
|
||||
* Some functions are not available anymore.
|
||||
* The signature of some functions has changed.
|
||||
|
||||
# [3.0.0-dev.1](https://github.com/ReVanced/revanced-library/compare/v2.4.0-dev.1...v3.0.0-dev.1) (2024-08-06)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Make functions internal which are supposed to be internal ([893d22d](https://github.com/ReVanced/revanced-library/commit/893d22d7938fa1c7544795635ed2ffacdd0cbf0d))
|
||||
|
||||
|
||||
### Build System
|
||||
|
||||
* Refactor to DSL to bump ReVanced Patcher ([7f5d6da](https://github.com/ReVanced/revanced-library/commit/7f5d6dad7ba73e2ee53010241ba3204d04860a22))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* Remove deprecated functions ([b9bf3bc](https://github.com/ReVanced/revanced-library/commit/b9bf3bc88284c0381c7370c3606b662da2ef380d))
|
||||
|
||||
|
||||
### BREAKING CHANGES
|
||||
|
||||
* Some functions have been removed.
|
||||
* Some functions are not available anymore.
|
||||
* The signature of some functions has changed.
|
||||
|
||||
# [2.4.0-dev.1](https://github.com/ReVanced/revanced-library/compare/v2.3.0...v2.4.0-dev.1) (2024-04-07)
|
||||
|
||||
|
||||
|
||||
@@ -1,13 +1,8 @@
|
||||
public final class app/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 (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 newKeyStore (Ljava/io/OutputStream;Ljava/lang/String;Ljava/util/Set;)V
|
||||
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 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 readPrivateKeyCertificatePair (Ljava/security/KeyStore;Ljava/lang/String;Ljava/lang/String;)Lapp/revanced/library/ApkSigner$PrivateKeyCertificatePair;
|
||||
}
|
||||
@@ -26,19 +21,12 @@ public final class app/revanced/library/ApkSigner$PrivateKeyCertificatePair {
|
||||
}
|
||||
|
||||
public final class app/revanced/library/ApkSigner$Signer {
|
||||
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;Ljava/io/File;)V
|
||||
}
|
||||
|
||||
public final class app/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 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;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
|
||||
}
|
||||
|
||||
@@ -59,80 +47,18 @@ public final class app/revanced/library/ApkUtils$PrivateKeyCertificatePairDetail
|
||||
public final fun getValidUntil ()Ljava/util/Date;
|
||||
}
|
||||
|
||||
public final class app/revanced/library/ApkUtils$SigningOptions {
|
||||
public fun <init> (Ljava/io/File;Ljava/lang/String;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;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 fun getSigner ()Ljava/lang/String;
|
||||
public final class app/revanced/library/OptionsKt {
|
||||
public static final fun setOptions (Ljava/util/Set;Ljava/util/Map;)V
|
||||
}
|
||||
|
||||
public final class app/revanced/library/Options {
|
||||
public static final field INSTANCE Lapp/revanced/library/Options;
|
||||
public final fun deserialize (Ljava/lang/String;)[Lapp/revanced/library/Options$Patch;
|
||||
public final fun serialize (Ljava/util/Set;Z)Ljava/lang/String;
|
||||
public static synthetic fun serialize$default (Lapp/revanced/library/Options;Ljava/util/Set;ZILjava/lang/Object;)Ljava/lang/String;
|
||||
public final fun setOptions (Ljava/util/Set;Ljava/io/File;)V
|
||||
public final fun setOptions (Ljava/util/Set;Ljava/lang/String;)V
|
||||
public final class app/revanced/library/PatchKt {
|
||||
public static final fun mostCommonCompatibleVersions (Ljava/util/Set;Ljava/util/Set;Z)Ljava/util/Map;
|
||||
public static synthetic fun mostCommonCompatibleVersions$default (Ljava/util/Set;Ljava/util/Set;ZILjava/lang/Object;)Ljava/util/Map;
|
||||
}
|
||||
|
||||
public final class app/revanced/library/Options$Patch {
|
||||
public final fun getOptions ()Ljava/util/List;
|
||||
public final fun getPatchName ()Ljava/lang/String;
|
||||
}
|
||||
|
||||
public final class app/revanced/library/Options$Patch$Option {
|
||||
public final fun getKey ()Ljava/lang/String;
|
||||
public final fun getValue ()Ljava/lang/Object;
|
||||
}
|
||||
|
||||
public final class app/revanced/library/PatchUtils {
|
||||
public static final field INSTANCE Lapp/revanced/library/PatchUtils;
|
||||
public final fun getMostCommonCompatibleVersions (Ljava/util/Set;Ljava/util/Set;Z)Ljava/util/Map;
|
||||
public static synthetic fun getMostCommonCompatibleVersions$default (Lapp/revanced/library/PatchUtils;Ljava/util/Set;Ljava/util/Set;ZILjava/lang/Object;)Ljava/util/Map;
|
||||
}
|
||||
|
||||
public final class app/revanced/library/PatchUtils$Json {
|
||||
public static final field INSTANCE Lapp/revanced/library/PatchUtils$Json;
|
||||
public final fun deserialize (Ljava/io/InputStream;Ljava/lang/Class;)Ljava/util/Set;
|
||||
public final fun serialize (Ljava/util/Set;Lkotlin/jvm/functions/Function1;ZLjava/io/OutputStream;)V
|
||||
public static synthetic fun serialize$default (Lapp/revanced/library/PatchUtils$Json;Ljava/util/Set;Lkotlin/jvm/functions/Function1;ZLjava/io/OutputStream;ILjava/lang/Object;)V
|
||||
}
|
||||
|
||||
public final class app/revanced/library/PatchUtils$Json$FullJsonPatch : app/revanced/library/PatchUtils$Json$JsonPatch {
|
||||
public static final field Companion Lapp/revanced/library/PatchUtils$Json$FullJsonPatch$Companion;
|
||||
public final fun getCompatiblePackages ()Ljava/util/Set;
|
||||
public final fun getDependencies ()Ljava/util/Set;
|
||||
public final fun getDescription ()Ljava/lang/String;
|
||||
public final fun getName ()Ljava/lang/String;
|
||||
public final fun getOptions ()Ljava/util/Map;
|
||||
public final fun getRequiresIntegrations ()Z
|
||||
public final fun getUse ()Z
|
||||
public final fun setRequiresIntegrations (Z)V
|
||||
}
|
||||
|
||||
public final class app/revanced/library/PatchUtils$Json$FullJsonPatch$Companion {
|
||||
public final fun fromPatch (Lapp/revanced/patcher/patch/Patch;)Lapp/revanced/library/PatchUtils$Json$FullJsonPatch;
|
||||
}
|
||||
|
||||
public final class app/revanced/library/PatchUtils$Json$FullJsonPatch$FullJsonPatchOption {
|
||||
public static final field Companion Lapp/revanced/library/PatchUtils$Json$FullJsonPatch$FullJsonPatchOption$Companion;
|
||||
public final fun getDefault ()Ljava/lang/Object;
|
||||
public final fun getDescription ()Ljava/lang/String;
|
||||
public final fun getKey ()Ljava/lang/String;
|
||||
public final fun getRequired ()Z
|
||||
public final fun getTitle ()Ljava/lang/String;
|
||||
public final fun getValueType ()Ljava/lang/String;
|
||||
public final fun getValues ()Ljava/util/Map;
|
||||
}
|
||||
|
||||
public final class app/revanced/library/PatchUtils$Json$FullJsonPatch$FullJsonPatchOption$Companion {
|
||||
public final fun fromPatchOption (Lapp/revanced/patcher/patch/options/PatchOption;)Lapp/revanced/library/PatchUtils$Json$FullJsonPatch$FullJsonPatchOption;
|
||||
}
|
||||
|
||||
public abstract interface class app/revanced/library/PatchUtils$Json$JsonPatch {
|
||||
public final class app/revanced/library/SerializationKt {
|
||||
public static final fun serializeTo (Ljava/util/Set;Ljava/io/OutputStream;Z)V
|
||||
public static synthetic fun serializeTo$default (Ljava/util/Set;Ljava/io/OutputStream;ZILjava/lang/Object;)V
|
||||
}
|
||||
|
||||
public final class app/revanced/library/Utils {
|
||||
@@ -140,52 +66,6 @@ public final class app/revanced/library/Utils {
|
||||
public final fun isAndroidEnvironment ()Z
|
||||
}
|
||||
|
||||
public abstract class app/revanced/library/adb/AdbManager {
|
||||
public static final field Companion Lapp/revanced/library/adb/AdbManager$Companion;
|
||||
public synthetic fun <init> (Ljava/lang/String;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
|
||||
protected abstract fun getInstaller ()Lapp/revanced/library/installation/installer/Installer;
|
||||
public fun install (Lapp/revanced/library/adb/AdbManager$Apk;)Lkotlin/jvm/functions/Function1;
|
||||
public fun uninstall (Ljava/lang/String;)Lkotlin/jvm/functions/Function1;
|
||||
}
|
||||
|
||||
public final class app/revanced/library/adb/AdbManager$Apk {
|
||||
public fun <init> (Ljava/io/File;Ljava/lang/String;)V
|
||||
public synthetic fun <init> (Ljava/io/File;Ljava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
|
||||
public final fun getFile ()Ljava/io/File;
|
||||
public final fun getPackageName ()Ljava/lang/String;
|
||||
}
|
||||
|
||||
public final class app/revanced/library/adb/AdbManager$Companion {
|
||||
public final fun getAdbManager (Ljava/lang/String;Z)Lapp/revanced/library/adb/AdbManager;
|
||||
public static synthetic fun getAdbManager$default (Lapp/revanced/library/adb/AdbManager$Companion;Ljava/lang/String;ZILjava/lang/Object;)Lapp/revanced/library/adb/AdbManager;
|
||||
}
|
||||
|
||||
public final class app/revanced/library/adb/AdbManager$DeviceNotFoundException : java/lang/Exception {
|
||||
public fun <init> ()V
|
||||
}
|
||||
|
||||
public final class app/revanced/library/adb/AdbManager$FailedToFindInstalledPackageException : java/lang/Exception {
|
||||
}
|
||||
|
||||
public final class app/revanced/library/adb/AdbManager$PackageNameRequiredException : java/lang/Exception {
|
||||
}
|
||||
|
||||
public final class app/revanced/library/adb/AdbManager$RootAdbManager : app/revanced/library/adb/AdbManager {
|
||||
public static final field Utils Lapp/revanced/library/adb/AdbManager$RootAdbManager$Utils;
|
||||
public synthetic fun getInstaller ()Lapp/revanced/library/installation/installer/Installer;
|
||||
public fun install (Lapp/revanced/library/adb/AdbManager$Apk;)Lkotlin/jvm/functions/Function1;
|
||||
public fun uninstall (Ljava/lang/String;)Lkotlin/jvm/functions/Function1;
|
||||
}
|
||||
|
||||
public final class app/revanced/library/adb/AdbManager$RootAdbManager$Utils {
|
||||
}
|
||||
|
||||
public final class app/revanced/library/adb/AdbManager$UserAdbManager : app/revanced/library/adb/AdbManager {
|
||||
public synthetic fun getInstaller ()Lapp/revanced/library/installation/installer/Installer;
|
||||
public fun install (Lapp/revanced/library/adb/AdbManager$Apk;)Lkotlin/jvm/functions/Function1;
|
||||
public fun uninstall (Ljava/lang/String;)Lkotlin/jvm/functions/Function1;
|
||||
}
|
||||
|
||||
public final class app/revanced/library/installation/command/AdbShellCommandRunner : app/revanced/library/installation/command/ShellCommandRunner {
|
||||
}
|
||||
|
||||
@@ -249,12 +129,16 @@ public final class app/revanced/library/installation/installer/AdbInstallerResul
|
||||
public static final field INSTANCE Lapp/revanced/library/installation/installer/AdbInstallerResult$Success;
|
||||
}
|
||||
|
||||
public final class app/revanced/library/installation/installer/AdbMountInstaller : app/revanced/library/installation/installer/MountInstaller {
|
||||
public final class app/revanced/library/installation/installer/AdbRootInstaller : app/revanced/library/installation/installer/RootInstaller {
|
||||
public fun <init> ()V
|
||||
public fun <init> (Ljava/lang/String;)V
|
||||
public synthetic fun <init> (Ljava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
|
||||
}
|
||||
|
||||
public final class app/revanced/library/installation/installer/DeviceNotFoundException : java/lang/Exception {
|
||||
public fun <init> ()V
|
||||
}
|
||||
|
||||
public class app/revanced/library/installation/installer/Installation {
|
||||
public final fun getApkFilePath ()Ljava/lang/String;
|
||||
}
|
||||
@@ -297,18 +181,18 @@ public final class app/revanced/library/installation/installer/LocalInstallerSer
|
||||
public fun onStartCommand (Landroid/content/Intent;II)I
|
||||
}
|
||||
|
||||
public final class app/revanced/library/installation/installer/LocalMountInstaller : app/revanced/library/installation/installer/MountInstaller, java/io/Closeable {
|
||||
public final class app/revanced/library/installation/installer/LocalRootInstaller : app/revanced/library/installation/installer/RootInstaller, java/io/Closeable {
|
||||
public fun <init> (Landroid/content/Context;Lkotlin/jvm/functions/Function1;)V
|
||||
public synthetic fun <init> (Landroid/content/Context;Lkotlin/jvm/functions/Function1;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
|
||||
public fun close ()V
|
||||
}
|
||||
|
||||
public final class app/revanced/library/installation/installer/MountInstallation : app/revanced/library/installation/installer/Installation {
|
||||
public final class app/revanced/library/installation/installer/RootInstallation : app/revanced/library/installation/installer/Installation {
|
||||
public final fun getInstalledApkFilePath ()Ljava/lang/String;
|
||||
public final fun getMounted ()Z
|
||||
}
|
||||
|
||||
public abstract class app/revanced/library/installation/installer/MountInstaller : app/revanced/library/installation/installer/Installer {
|
||||
public abstract class app/revanced/library/installation/installer/RootInstaller : app/revanced/library/installation/installer/Installer {
|
||||
public fun getInstallation (Ljava/lang/String;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
||||
protected final fun getShellCommandRunner ()Lapp/revanced/library/installation/command/ShellCommandRunner;
|
||||
public fun install (Lapp/revanced/library/installation/installer/Installer$Apk;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
||||
@@ -318,12 +202,12 @@ public abstract class app/revanced/library/installation/installer/MountInstaller
|
||||
protected final fun write (Ljava/lang/String;Ljava/lang/String;)V
|
||||
}
|
||||
|
||||
public final class app/revanced/library/installation/installer/MountInstallerResult : java/lang/Enum {
|
||||
public static final field FAILURE Lapp/revanced/library/installation/installer/MountInstallerResult;
|
||||
public static final field SUCCESS Lapp/revanced/library/installation/installer/MountInstallerResult;
|
||||
public final class app/revanced/library/installation/installer/RootInstallerResult : java/lang/Enum {
|
||||
public static final field FAILURE Lapp/revanced/library/installation/installer/RootInstallerResult;
|
||||
public static final field SUCCESS Lapp/revanced/library/installation/installer/RootInstallerResult;
|
||||
public static fun getEntries ()Lkotlin/enums/EnumEntries;
|
||||
public static fun valueOf (Ljava/lang/String;)Lapp/revanced/library/installation/installer/MountInstallerResult;
|
||||
public static fun values ()[Lapp/revanced/library/installation/installer/MountInstallerResult;
|
||||
public static fun valueOf (Ljava/lang/String;)Lapp/revanced/library/installation/installer/RootInstallerResult;
|
||||
public static fun values ()[Lapp/revanced/library/installation/installer/RootInstallerResult;
|
||||
}
|
||||
|
||||
public final class app/revanced/library/logging/Logger {
|
||||
167
api/jvm/revanced-library.api
Normal file
167
api/jvm/revanced-library.api
Normal file
@@ -0,0 +1,167 @@
|
||||
public final class app/revanced/library/ApkSigner {
|
||||
public static final field INSTANCE Lapp/revanced/library/ApkSigner;
|
||||
public final fun newApkSigner (Ljava/lang/String;Lapp/revanced/library/ApkSigner$PrivateKeyCertificatePair;)Lapp/revanced/library/ApkSigner$Signer;
|
||||
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 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 fun <init> (Ljava/lang/String;Ljava/lang/String;Lapp/revanced/library/ApkSigner$PrivateKeyCertificatePair;)V
|
||||
public final fun getAlias ()Ljava/lang/String;
|
||||
public final fun getPassword ()Ljava/lang/String;
|
||||
public final fun getPrivateKeyCertificatePair ()Lapp/revanced/library/ApkSigner$PrivateKeyCertificatePair;
|
||||
}
|
||||
|
||||
public final class app/revanced/library/ApkSigner$PrivateKeyCertificatePair {
|
||||
public fun <init> (Ljava/security/PrivateKey;Ljava/security/cert/X509Certificate;)V
|
||||
public final fun getCertificate ()Ljava/security/cert/X509Certificate;
|
||||
public final fun getPrivateKey ()Ljava/security/PrivateKey;
|
||||
}
|
||||
|
||||
public final class app/revanced/library/ApkSigner$Signer {
|
||||
public final fun signApk (Ljava/io/File;Ljava/io/File;)V
|
||||
}
|
||||
|
||||
public final class app/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 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/OptionsKt {
|
||||
public static final fun setOptions (Ljava/util/Set;Ljava/util/Map;)V
|
||||
}
|
||||
|
||||
public final class app/revanced/library/PatchKt {
|
||||
public static final fun mostCommonCompatibleVersions (Ljava/util/Set;Ljava/util/Set;Z)Ljava/util/Map;
|
||||
public static synthetic fun mostCommonCompatibleVersions$default (Ljava/util/Set;Ljava/util/Set;ZILjava/lang/Object;)Ljava/util/Map;
|
||||
}
|
||||
|
||||
public final class app/revanced/library/SerializationKt {
|
||||
public static final fun serializeTo (Ljava/util/Set;Ljava/io/OutputStream;Z)V
|
||||
public static synthetic fun serializeTo$default (Ljava/util/Set;Ljava/io/OutputStream;ZILjava/lang/Object;)V
|
||||
}
|
||||
|
||||
public final class app/revanced/library/Utils {
|
||||
public static final field INSTANCE Lapp/revanced/library/Utils;
|
||||
public final fun isAndroidEnvironment ()Z
|
||||
}
|
||||
|
||||
public final class app/revanced/library/installation/command/AdbShellCommandRunner : app/revanced/library/installation/command/ShellCommandRunner {
|
||||
}
|
||||
|
||||
public abstract interface class app/revanced/library/installation/command/RunResult {
|
||||
public abstract fun getError ()Ljava/lang/String;
|
||||
public abstract fun getExitCode ()I
|
||||
public abstract fun getOutput ()Ljava/lang/String;
|
||||
public abstract fun waitFor ()V
|
||||
}
|
||||
|
||||
public final class app/revanced/library/installation/command/RunResult$DefaultImpls {
|
||||
public static fun waitFor (Lapp/revanced/library/installation/command/RunResult;)V
|
||||
}
|
||||
|
||||
public abstract class app/revanced/library/installation/command/ShellCommandRunner {
|
||||
protected final fun getLogger ()Ljava/util/logging/Logger;
|
||||
protected abstract fun runCommand (Ljava/lang/String;)Lapp/revanced/library/installation/command/RunResult;
|
||||
}
|
||||
|
||||
public final class app/revanced/library/installation/installer/AdbInstaller : app/revanced/library/installation/installer/Installer {
|
||||
public fun <init> ()V
|
||||
public fun <init> (Ljava/lang/String;)V
|
||||
public synthetic fun <init> (Ljava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
|
||||
public fun getInstallation (Ljava/lang/String;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
||||
public fun install (Lapp/revanced/library/installation/installer/Installer$Apk;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
||||
public fun uninstall (Ljava/lang/String;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
||||
}
|
||||
|
||||
public abstract interface class app/revanced/library/installation/installer/AdbInstallerResult {
|
||||
}
|
||||
|
||||
public final class app/revanced/library/installation/installer/AdbInstallerResult$Failure : app/revanced/library/installation/installer/AdbInstallerResult {
|
||||
public final fun getException ()Ljava/lang/Exception;
|
||||
}
|
||||
|
||||
public final class app/revanced/library/installation/installer/AdbInstallerResult$Success : app/revanced/library/installation/installer/AdbInstallerResult {
|
||||
public static final field INSTANCE Lapp/revanced/library/installation/installer/AdbInstallerResult$Success;
|
||||
}
|
||||
|
||||
public final class app/revanced/library/installation/installer/AdbRootInstaller : app/revanced/library/installation/installer/RootInstaller {
|
||||
public fun <init> ()V
|
||||
public fun <init> (Ljava/lang/String;)V
|
||||
public synthetic fun <init> (Ljava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
|
||||
}
|
||||
|
||||
public final class app/revanced/library/installation/installer/DeviceNotFoundException : java/lang/Exception {
|
||||
public fun <init> ()V
|
||||
}
|
||||
|
||||
public class app/revanced/library/installation/installer/Installation {
|
||||
public final fun getApkFilePath ()Ljava/lang/String;
|
||||
}
|
||||
|
||||
public abstract class app/revanced/library/installation/installer/Installer {
|
||||
public abstract fun getInstallation (Ljava/lang/String;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
||||
protected final fun getLogger ()Ljava/util/logging/Logger;
|
||||
public abstract fun install (Lapp/revanced/library/installation/installer/Installer$Apk;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
||||
public abstract fun uninstall (Ljava/lang/String;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
||||
}
|
||||
|
||||
public final class app/revanced/library/installation/installer/Installer$Apk {
|
||||
public fun <init> (Ljava/io/File;Ljava/lang/String;)V
|
||||
public synthetic fun <init> (Ljava/io/File;Ljava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
|
||||
public final fun getFile ()Ljava/io/File;
|
||||
public final fun getPackageName ()Ljava/lang/String;
|
||||
}
|
||||
|
||||
public final class app/revanced/library/installation/installer/RootInstallation : app/revanced/library/installation/installer/Installation {
|
||||
public final fun getInstalledApkFilePath ()Ljava/lang/String;
|
||||
public final fun getMounted ()Z
|
||||
}
|
||||
|
||||
public abstract class app/revanced/library/installation/installer/RootInstaller : app/revanced/library/installation/installer/Installer {
|
||||
public fun getInstallation (Ljava/lang/String;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
||||
protected final fun getShellCommandRunner ()Lapp/revanced/library/installation/command/ShellCommandRunner;
|
||||
public fun install (Lapp/revanced/library/installation/installer/Installer$Apk;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
||||
protected final fun invoke (Ljava/lang/String;)Lapp/revanced/library/installation/command/RunResult;
|
||||
protected final fun move (Ljava/io/File;Ljava/lang/String;)V
|
||||
public fun uninstall (Ljava/lang/String;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
||||
protected final fun write (Ljava/lang/String;Ljava/lang/String;)V
|
||||
}
|
||||
|
||||
public final class app/revanced/library/installation/installer/RootInstallerResult : java/lang/Enum {
|
||||
public static final field FAILURE Lapp/revanced/library/installation/installer/RootInstallerResult;
|
||||
public static final field SUCCESS Lapp/revanced/library/installation/installer/RootInstallerResult;
|
||||
public static fun getEntries ()Lkotlin/enums/EnumEntries;
|
||||
public static fun valueOf (Ljava/lang/String;)Lapp/revanced/library/installation/installer/RootInstallerResult;
|
||||
public static fun values ()[Lapp/revanced/library/installation/installer/RootInstallerResult;
|
||||
}
|
||||
|
||||
public final class app/revanced/library/logging/Logger {
|
||||
public static final field INSTANCE Lapp/revanced/library/logging/Logger;
|
||||
public final fun addHandler (Lkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function0;)V
|
||||
public final fun removeAllHandlers ()V
|
||||
public final fun setDefault ()V
|
||||
public final fun setFormat (Ljava/lang/String;)V
|
||||
public static synthetic fun setFormat$default (Lapp/revanced/library/logging/Logger;Ljava/lang/String;ILjava/lang/Object;)V
|
||||
}
|
||||
|
||||
143
build.gradle.kts
143
build.gradle.kts
@@ -1,30 +1,141 @@
|
||||
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
||||
|
||||
plugins {
|
||||
alias(libs.plugins.kotlin.jvm) apply false
|
||||
alias(libs.plugins.kotlin.multiplatform) apply false
|
||||
alias(libs.plugins.kotlin.serialization) apply false
|
||||
alias(libs.plugins.android.library) apply false
|
||||
alias(libs.plugins.binary.compatibility.validator) apply false
|
||||
alias(libs.plugins.ktor) apply false
|
||||
alias(libs.plugins.android.library)
|
||||
alias(libs.plugins.binary.compatibility.validator)
|
||||
alias(libs.plugins.kotlin.multiplatform)
|
||||
alias(libs.plugins.kotlin.serialization)
|
||||
`maven-publish`
|
||||
signing
|
||||
}
|
||||
|
||||
group = "app.revanced"
|
||||
|
||||
subprojects {
|
||||
// Because access to the project is necessary to authenticate with GitHub,
|
||||
// the following block must be placed in the root build.gradle.kts file
|
||||
// instead of the settings.gradle.kts file inside the dependencyResolutionManagement block.
|
||||
// Because access to the project is necessary to authenticate with GitHub,
|
||||
// the following block must be placed in the root build.gradle.kts file
|
||||
// instead of the settings.gradle.kts file inside the dependencyResolutionManagement block.
|
||||
repositories {
|
||||
mavenCentral()
|
||||
mavenLocal()
|
||||
google()
|
||||
maven {
|
||||
// A repository must be specified for some reason. "registry" is a dummy.
|
||||
url = uri("https://maven.pkg.github.com/revanced/registry")
|
||||
credentials {
|
||||
username = project.findProperty("gpr.user") as String? ?: System.getenv("GITHUB_ACTOR")
|
||||
password = project.findProperty("gpr.key") as String? ?: System.getenv("GITHUB_TOKEN")
|
||||
}
|
||||
}
|
||||
maven { url = uri("https://jitpack.io") }
|
||||
}
|
||||
|
||||
kotlin {
|
||||
jvm {
|
||||
compilerOptions {
|
||||
jvmTarget = JvmTarget.JVM_11
|
||||
}
|
||||
}
|
||||
|
||||
androidTarget {
|
||||
compilerOptions {
|
||||
jvmTarget = JvmTarget.JVM_11
|
||||
}
|
||||
|
||||
publishLibraryVariants("release")
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
androidMain.dependencies {
|
||||
implementation(libs.core.ktx)
|
||||
implementation(libs.libsu.nio)
|
||||
implementation(libs.libsu.service)
|
||||
}
|
||||
|
||||
commonMain.dependencies {
|
||||
implementation(libs.apksig)
|
||||
implementation(libs.apkzlib)
|
||||
implementation(libs.bcpkix.jdk18on)
|
||||
implementation(libs.guava)
|
||||
implementation(libs.jadb)
|
||||
implementation(libs.kotlin.reflect)
|
||||
implementation(libs.kotlinx.serialization.json)
|
||||
implementation(libs.revanced.patcher)
|
||||
}
|
||||
|
||||
commonTest.dependencies {
|
||||
implementation(libs.kotlin.test.junit)
|
||||
implementation(libs.revanced.patcher)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "app.revanced.library"
|
||||
compileSdk = 34
|
||||
defaultConfig {
|
||||
minSdk = 26
|
||||
}
|
||||
|
||||
buildFeatures {
|
||||
aidl = true
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility = JavaVersion.VERSION_11
|
||||
targetCompatibility = JavaVersion.VERSION_11
|
||||
}
|
||||
}
|
||||
|
||||
java {
|
||||
targetCompatibility = JavaVersion.VERSION_11
|
||||
}
|
||||
|
||||
publishing {
|
||||
repositories {
|
||||
mavenCentral()
|
||||
mavenLocal()
|
||||
google()
|
||||
maven {
|
||||
// A repository must be specified for some reason. "registry" is a dummy.
|
||||
url = uri("https://maven.pkg.github.com/revanced/registry")
|
||||
name = "GitHubPackages"
|
||||
url = uri("https://maven.pkg.github.com/revanced/revanced-library")
|
||||
credentials {
|
||||
username = project.findProperty("gpr.user") as String? ?: System.getenv("GITHUB_ACTOR")
|
||||
password = project.findProperty("gpr.key") as String? ?: System.getenv("GITHUB_TOKEN")
|
||||
}
|
||||
}
|
||||
maven { url = uri("https://jitpack.io") }
|
||||
}
|
||||
|
||||
// KMP plugin creates a publication already, so just configure the POM.
|
||||
publications.all {
|
||||
if (this !is MavenPublication) return@all
|
||||
|
||||
pom {
|
||||
name = "ReVanced Library"
|
||||
description = "Library containing common utilities for ReVanced"
|
||||
url = "https://revanced.app"
|
||||
|
||||
licenses {
|
||||
license {
|
||||
name = "GNU General Public License v3.0"
|
||||
url = "https://www.gnu.org/licenses/gpl-3.0.en.html"
|
||||
}
|
||||
}
|
||||
|
||||
developers {
|
||||
developer {
|
||||
id = "ReVanced"
|
||||
name = "ReVanced"
|
||||
email = "contact@revanced.app"
|
||||
}
|
||||
}
|
||||
|
||||
scm {
|
||||
connection = "scm:git:git://github.com/revanced/revanced-library.git"
|
||||
developerConnection = "scm:git:git@github.com:revanced/revanced-library.git"
|
||||
url = "https://github.com/revanced/revanced-library"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
signing {
|
||||
useGpgCmd()
|
||||
sign(publishing.publications)
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
version = 2.4.0-dev.1
|
||||
version = 3.1.0
|
||||
#Gradle
|
||||
org.gradle.jvmargs = -Xmx2048M -Dfile.encoding=UTF-8 -Dkotlin.daemon.jvm.options="-Xmx2048M"
|
||||
org.gradle.caching = true
|
||||
|
||||
@@ -1,54 +1,35 @@
|
||||
[versions]
|
||||
jackson-module-kotlin = "2.15.0"
|
||||
android = "8.5.2"
|
||||
bcpkix-jdk18on = "1.77"
|
||||
binary-compatibility-validator = "0.15.1"
|
||||
core-ktx = "1.15.0"
|
||||
guava = "33.2.1-jre"
|
||||
jadb = "1.2.1"
|
||||
kotlin = "1.9.22"
|
||||
ktor-client = "2.3.10"
|
||||
ktor-server-test-host = "2.3.9"
|
||||
revanced-patcher = "19.3.1"
|
||||
binary-compatibility-validator = "0.14.0"
|
||||
android = "8.3.2"
|
||||
bcpkix-jdk15on = "1.70"
|
||||
guava = "33.0.0-jre"
|
||||
kotlin = "2.0.20"
|
||||
kotlinx-coroutines = "1.8.1"
|
||||
kotlinx-serialization = "1.7.1"
|
||||
libsu = "5.2.2"
|
||||
core-ktx = "1.12.0"
|
||||
ktor = "2.3.9"
|
||||
koin = "3.5.3"
|
||||
logback = "1.4.14"
|
||||
revanced-patcher = "21.0.0"
|
||||
|
||||
[libraries]
|
||||
jackson-module-kotlin = { module = "com.fasterxml.jackson.module:jackson-module-kotlin", version.ref = "jackson-module-kotlin" }
|
||||
jadb = { module = "app.revanced:jadb", version.ref = "jadb" }
|
||||
kotlin-reflect = { module = "org.jetbrains.kotlin:kotlin-reflect", version.ref = "kotlin" }
|
||||
kotlin-test-junit = { module = "org.jetbrains.kotlin:kotlin-test-junit", version.ref = "kotlin" }
|
||||
revanced-patcher = { module = "app.revanced:revanced-patcher", version.ref = "revanced-patcher" }
|
||||
apkzlib = { module = "com.android.tools.build:apkzlib", version.ref = "android" }
|
||||
apksig = { module = "com.android.tools.build:apksig", version.ref = "android" }
|
||||
bcpkix-jdk15on = { module = "org.bouncycastle:bcpkix-jdk15on", version.ref = "bcpkix-jdk15on" }
|
||||
bcpkix-jdk18on = { module = "org.bouncycastle:bcpkix-jdk18on", version.ref = "bcpkix-jdk18on" }
|
||||
core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "core-ktx" }
|
||||
guava = { module = "com.google.guava:guava", version.ref = "guava" }
|
||||
jadb = { module = "app.revanced:jadb", version.ref = "jadb" } # Fork with Shell v2 support.
|
||||
kotlin-reflect = { module = "org.jetbrains.kotlin:kotlin-reflect", version.ref = "kotlin" }
|
||||
kotlin-test-junit = { module = "org.jetbrains.kotlin:kotlin-test-junit", version.ref = "kotlin" }
|
||||
kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlinx-coroutines" }
|
||||
kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlinx-serialization" }
|
||||
libsu-core = { module = "com.github.topjohnwu.libsu:core", version.ref = "libsu" }
|
||||
libsu-nio = { module = "com.github.topjohnwu.libsu:nio", version.ref = "libsu" }
|
||||
libsu-service = { module = "com.github.topjohnwu.libsu:service", version.ref = "libsu" }
|
||||
core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "core-ktx" }
|
||||
logback-classic = { module = "ch.qos.logback:logback-classic", version.ref = "logback" }
|
||||
ktor-client-core = { module = "io.ktor:ktor-client-core", version.ref = "ktor-client" }
|
||||
ktor-client-cio = { module = "io.ktor:ktor-client-cio", version.ref = "ktor-client" }
|
||||
ktor-server-conditional-headers = { module = "io.ktor:ktor-server-conditional-headers" }
|
||||
ktor-server-core = { module = "io.ktor:ktor-server-core" }
|
||||
ktor-server-content-negotiation = { module = "io.ktor:ktor-server-content-negotiation" }
|
||||
ktor-server-auth = { module = "io.ktor:ktor-server-auth" }
|
||||
ktor-server-auth-jwt = { module = "io.ktor:ktor-server-auth-jwt" }
|
||||
ktor-server-cors = { module = "io.ktor:ktor-server-cors" }
|
||||
ktor-server-caching-headers = { module = "io.ktor:ktor-server-caching-headers" }
|
||||
ktor-server-host-common = { module = "io.ktor:ktor-server-host-common" }
|
||||
ktor-server-netty = { module = "io.ktor:ktor-server-netty" }
|
||||
ktor-server-websockets = { module = "io.ktor:ktor-server-websockets" }
|
||||
ktor-serialization-kotlinx-json = { module = "io.ktor:ktor-serialization-kotlinx-json" }
|
||||
koin-ktor = { module = "io.insert-koin:koin-ktor", version.ref = "koin" }
|
||||
revanced-patcher = { module = "app.revanced:revanced-patcher", version.ref = "revanced-patcher" }
|
||||
|
||||
[plugins]
|
||||
ktor = { id = "io.ktor.plugin", version.ref = "ktor" }
|
||||
binary-compatibility-validator = { id = "org.jetbrains.kotlinx.binary-compatibility-validator", version.ref = "binary-compatibility-validator" }
|
||||
android-library = { id = "com.android.library", version.ref = "android" }
|
||||
kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
|
||||
binary-compatibility-validator = { id = "org.jetbrains.kotlinx.binary-compatibility-validator", version.ref = "binary-compatibility-validator" }
|
||||
kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
|
||||
kotlin-multiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" }
|
||||
kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" }
|
||||
|
||||
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Binary file not shown.
8
gradle/wrapper/gradle-wrapper.properties
vendored
8
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -1,6 +1,8 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip
|
||||
distributionSha256Sum=9631d53cf3e74bfa726893aee1f8994fee4e060c401335946dba2156f440f24c
|
||||
distributionSha256Sum=d725d707bfabd4dfdc958c624003b3c80accc03f7037b5122c4b1d0ef15cecab
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dist
|
||||
zipStorePath=wrapper/dists
|
||||
|
||||
297
gradlew
vendored
297
gradlew
vendored
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env sh
|
||||
#!/bin/sh
|
||||
|
||||
#
|
||||
# Copyright 2015 the original author or authors.
|
||||
# Copyright © 2015-2021 the original authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
@@ -15,69 +15,104 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
##############################################################################
|
||||
##
|
||||
## Gradle start up script for UN*X
|
||||
##
|
||||
#
|
||||
# Gradle start up script for POSIX generated by Gradle.
|
||||
#
|
||||
# Important for running:
|
||||
#
|
||||
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
|
||||
# noncompliant, but you have some other compliant shell such as ksh or
|
||||
# bash, then to run this script, type that shell name before the whole
|
||||
# command line, like:
|
||||
#
|
||||
# ksh Gradle
|
||||
#
|
||||
# Busybox and similar reduced shells will NOT work, because this script
|
||||
# requires all of these POSIX shell features:
|
||||
# * functions;
|
||||
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
|
||||
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
|
||||
# * compound commands having a testable exit status, especially «case»;
|
||||
# * various built-in commands including «command», «set», and «ulimit».
|
||||
#
|
||||
# Important for patching:
|
||||
#
|
||||
# (2) This script targets any POSIX shell, so it avoids extensions provided
|
||||
# by Bash, Ksh, etc; in particular arrays are avoided.
|
||||
#
|
||||
# The "traditional" practice of packing multiple parameters into a
|
||||
# space-separated string is a well documented source of bugs and security
|
||||
# problems, so this is (mostly) avoided, by progressively accumulating
|
||||
# options in "$@", and eventually passing that to Java.
|
||||
#
|
||||
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
|
||||
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
|
||||
# see the in-line comments for details.
|
||||
#
|
||||
# There are tweaks for specific operating systems such as AIX, CygWin,
|
||||
# Darwin, MinGW, and NonStop.
|
||||
#
|
||||
# (3) This script is generated from the Groovy template
|
||||
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# within the Gradle project.
|
||||
#
|
||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
|
||||
# Resolve links: $0 may be a link
|
||||
PRG="$0"
|
||||
# Need this for relative symlinks.
|
||||
while [ -h "$PRG" ] ; do
|
||||
ls=`ls -ld "$PRG"`
|
||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||
if expr "$link" : '/.*' > /dev/null; then
|
||||
PRG="$link"
|
||||
else
|
||||
PRG=`dirname "$PRG"`"/$link"
|
||||
fi
|
||||
app_path=$0
|
||||
|
||||
# Need this for daisy-chained symlinks.
|
||||
while
|
||||
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
|
||||
[ -h "$app_path" ]
|
||||
do
|
||||
ls=$( ls -ld "$app_path" )
|
||||
link=${ls#*' -> '}
|
||||
case $link in #(
|
||||
/*) app_path=$link ;; #(
|
||||
*) app_path=$APP_HOME$link ;;
|
||||
esac
|
||||
done
|
||||
SAVED="`pwd`"
|
||||
cd "`dirname \"$PRG\"`/" >/dev/null
|
||||
APP_HOME="`pwd -P`"
|
||||
cd "$SAVED" >/dev/null
|
||||
|
||||
APP_NAME="Gradle"
|
||||
APP_BASE_NAME=`basename "$0"`
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
# This is normally unused
|
||||
# shellcheck disable=SC2034
|
||||
APP_BASE_NAME=${0##*/}
|
||||
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
|
||||
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s
|
||||
' "$PWD" ) || exit
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD="maximum"
|
||||
MAX_FD=maximum
|
||||
|
||||
warn () {
|
||||
echo "$*"
|
||||
}
|
||||
} >&2
|
||||
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
}
|
||||
} >&2
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
nonstop=false
|
||||
case "`uname`" in
|
||||
CYGWIN* )
|
||||
cygwin=true
|
||||
;;
|
||||
Darwin* )
|
||||
darwin=true
|
||||
;;
|
||||
MINGW* )
|
||||
msys=true
|
||||
;;
|
||||
NONSTOP* )
|
||||
nonstop=true
|
||||
;;
|
||||
case "$( uname )" in #(
|
||||
CYGWIN* ) cygwin=true ;; #(
|
||||
Darwin* ) darwin=true ;; #(
|
||||
MSYS* | MINGW* ) msys=true ;; #(
|
||||
NONSTOP* ) nonstop=true ;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
@@ -87,9 +122,9 @@ CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||
JAVACMD=$JAVA_HOME/jre/sh/java
|
||||
else
|
||||
JAVACMD="$JAVA_HOME/bin/java"
|
||||
JAVACMD=$JAVA_HOME/bin/java
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
@@ -98,88 +133,120 @@ Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD="java"
|
||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
JAVACMD=java
|
||||
if ! command -v java >/dev/null 2>&1
|
||||
then
|
||||
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
|
||||
MAX_FD_LIMIT=`ulimit -H -n`
|
||||
if [ $? -eq 0 ] ; then
|
||||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
||||
MAX_FD="$MAX_FD_LIMIT"
|
||||
fi
|
||||
ulimit -n $MAX_FD
|
||||
if [ $? -ne 0 ] ; then
|
||||
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
||||
fi
|
||||
else
|
||||
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
||||
fi
|
||||
fi
|
||||
|
||||
# For Darwin, add options to specify how the application appears in the dock
|
||||
if $darwin; then
|
||||
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
||||
fi
|
||||
|
||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
|
||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||
|
||||
JAVACMD=`cygpath --unix "$JAVACMD"`
|
||||
|
||||
# We build the pattern for arguments to be converted via cygpath
|
||||
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
||||
SEP=""
|
||||
for dir in $ROOTDIRSRAW ; do
|
||||
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
||||
SEP="|"
|
||||
done
|
||||
OURCYGPATTERN="(^($ROOTDIRS))"
|
||||
# Add a user-defined pattern to the cygpath arguments
|
||||
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
||||
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
||||
fi
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
i=0
|
||||
for arg in "$@" ; do
|
||||
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
||||
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
||||
|
||||
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
||||
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
||||
else
|
||||
eval `echo args$i`="\"$arg\""
|
||||
fi
|
||||
i=`expr $i + 1`
|
||||
done
|
||||
case $i in
|
||||
0) set -- ;;
|
||||
1) set -- "$args0" ;;
|
||||
2) set -- "$args0" "$args1" ;;
|
||||
3) set -- "$args0" "$args1" "$args2" ;;
|
||||
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
||||
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
||||
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
||||
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
||||
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
||||
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
||||
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||
case $MAX_FD in #(
|
||||
max*)
|
||||
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC2039,SC3045
|
||||
MAX_FD=$( ulimit -H -n ) ||
|
||||
warn "Could not query maximum file descriptor limit"
|
||||
esac
|
||||
case $MAX_FD in #(
|
||||
'' | soft) :;; #(
|
||||
*)
|
||||
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC2039,SC3045
|
||||
ulimit -n "$MAX_FD" ||
|
||||
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||
esac
|
||||
fi
|
||||
|
||||
# Escape application args
|
||||
save () {
|
||||
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
|
||||
echo " "
|
||||
}
|
||||
APP_ARGS=`save "$@"`
|
||||
# Collect all arguments for the java command, stacking in reverse order:
|
||||
# * args from the command line
|
||||
# * the main class name
|
||||
# * -classpath
|
||||
# * -D...appname settings
|
||||
# * --module-path (only if needed)
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
|
||||
|
||||
# Collect all arguments for the java command, following the shell quoting and substitution rules
|
||||
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
|
||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||
if "$cygwin" || "$msys" ; then
|
||||
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
||||
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
|
||||
|
||||
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
||||
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
for arg do
|
||||
if
|
||||
case $arg in #(
|
||||
-*) false ;; # don't mess with options #(
|
||||
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
|
||||
[ -e "$t" ] ;; #(
|
||||
*) false ;;
|
||||
esac
|
||||
then
|
||||
arg=$( cygpath --path --ignore --mixed "$arg" )
|
||||
fi
|
||||
# Roll the args list around exactly as many times as the number of
|
||||
# args, so each arg winds up back in the position where it started, but
|
||||
# possibly modified.
|
||||
#
|
||||
# NB: a `for` loop captures its iteration list before it begins, so
|
||||
# changing the positional parameters here affects neither the number of
|
||||
# iterations, nor the values presented in `arg`.
|
||||
shift # remove old arg
|
||||
set -- "$@" "$arg" # push replacement arg
|
||||
done
|
||||
fi
|
||||
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Collect all arguments for the java command:
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
||||
# and any embedded shellness will be escaped.
|
||||
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
|
||||
# treated as '${Hostname}' itself on the command line.
|
||||
|
||||
set -- \
|
||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||
-classpath "$CLASSPATH" \
|
||||
org.gradle.wrapper.GradleWrapperMain \
|
||||
"$@"
|
||||
|
||||
# Stop when "xargs" is not available.
|
||||
if ! command -v xargs >/dev/null 2>&1
|
||||
then
|
||||
die "xargs is not available"
|
||||
fi
|
||||
|
||||
# Use "xargs" to parse quoted args.
|
||||
#
|
||||
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
|
||||
#
|
||||
# In Bash we could simply go:
|
||||
#
|
||||
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
|
||||
# set -- "${ARGS[@]}" "$@"
|
||||
#
|
||||
# but POSIX shell has neither arrays nor command substitution, so instead we
|
||||
# post-process each arg (as a line of input to sed) to backslash-escape any
|
||||
# character that might be a shell metacharacter, then use eval to reverse
|
||||
# that process (while maintaining the separation between arguments), and wrap
|
||||
# the whole thing up as a single "set" statement.
|
||||
#
|
||||
# This will of course break if any of these variables contains a newline or
|
||||
# an unmatched quote.
|
||||
#
|
||||
|
||||
eval "set -- $(
|
||||
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
|
||||
xargs -n1 |
|
||||
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
|
||||
tr '\n' ' '
|
||||
)" '"$@"'
|
||||
|
||||
exec "$JAVACMD" "$@"
|
||||
|
||||
37
gradlew.bat
vendored
37
gradlew.bat
vendored
@@ -13,8 +13,10 @@
|
||||
@rem See the License for the specific language governing permissions and
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
@rem SPDX-License-Identifier: Apache-2.0
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%" == "" @echo off
|
||||
@if "%DEBUG%"=="" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@@ -25,7 +27,8 @@
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%" == "" set DIRNAME=.
|
||||
if "%DIRNAME%"=="" set DIRNAME=.
|
||||
@rem This is normally unused
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@@ -40,13 +43,13 @@ if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if "%ERRORLEVEL%" == "0" goto execute
|
||||
if %ERRORLEVEL% equ 0 goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
echo. 1>&2
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
|
||||
echo. 1>&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||
echo location of your Java installation. 1>&2
|
||||
|
||||
goto fail
|
||||
|
||||
@@ -56,11 +59,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
echo. 1>&2
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
|
||||
echo. 1>&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||
echo location of your Java installation. 1>&2
|
||||
|
||||
goto fail
|
||||
|
||||
@@ -75,13 +78,15 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||
if %ERRORLEVEL% equ 0 goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||
exit /b 1
|
||||
set EXIT_CODE=%ERRORLEVEL%
|
||||
if %EXIT_CODE% equ 0 set EXIT_CODE=1
|
||||
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
|
||||
exit /b %EXIT_CODE%
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
@@ -1,143 +0,0 @@
|
||||
public final class app/revanced/library/networking/Server {
|
||||
public final fun start ()Lio/ktor/server/engine/ApplicationEngine;
|
||||
public final fun stop ()V
|
||||
}
|
||||
|
||||
public final class app/revanced/library/networking/Server$DependenciesConfiguration {
|
||||
public fun <init> (Lapp/revanced/library/networking/configuration/repository/StorageRepository;Lapp/revanced/library/networking/configuration/repository/PatchSetRepository;Lapp/revanced/library/networking/configuration/repository/AppRepository;Lapp/revanced/library/networking/configuration/repository/InstallerRepository;)V
|
||||
}
|
||||
|
||||
public final class app/revanced/library/networking/Server$SecurityConfiguration {
|
||||
public fun <init> (Ljava/lang/String;Ljava/lang/String;)V
|
||||
}
|
||||
|
||||
public final class app/revanced/library/networking/Server$SerializersConfiguration {
|
||||
public fun <init> ()V
|
||||
public fun <init> (Ljava/util/Map;)V
|
||||
public synthetic fun <init> (Ljava/util/Map;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
|
||||
}
|
||||
|
||||
public final class app/revanced/library/networking/ServerBuilder {
|
||||
public fun <init> ()V
|
||||
public final fun configureDependencies (Lkotlin/jvm/functions/Function1;)Lapp/revanced/library/networking/ServerBuilder;
|
||||
public final fun configureSecurity (Ljava/lang/String;Ljava/lang/String;)Lapp/revanced/library/networking/ServerBuilder;
|
||||
public final fun configureSerializers (Lkotlin/jvm/functions/Function1;)Lapp/revanced/library/networking/ServerBuilder;
|
||||
}
|
||||
|
||||
public final class app/revanced/library/networking/ServerBuilder$DependenciesConfigurationBuilder {
|
||||
public final fun build ()Lapp/revanced/library/networking/Server$DependenciesConfiguration;
|
||||
public final fun configureAppRepository (Lapp/revanced/library/networking/configuration/repository/AppRepository;)Lapp/revanced/library/networking/ServerBuilder$DependenciesConfigurationBuilder;
|
||||
public final fun configureInstallerRepository (Lapp/revanced/library/networking/configuration/repository/InstallerRepository;)Lapp/revanced/library/networking/ServerBuilder$DependenciesConfigurationBuilder;
|
||||
public final fun configurePatchSetRepository (Lapp/revanced/library/networking/configuration/repository/PatchSetRepository;)Lapp/revanced/library/networking/ServerBuilder$DependenciesConfigurationBuilder;
|
||||
public final fun configureStorageRepository (Lapp/revanced/library/networking/configuration/repository/StorageRepository;)Lapp/revanced/library/networking/ServerBuilder$DependenciesConfigurationBuilder;
|
||||
}
|
||||
|
||||
public final class app/revanced/library/networking/ServerBuilder$SerializersConfigurationBuilder {
|
||||
public final fun build ()Lapp/revanced/library/networking/Server$SerializersConfiguration;
|
||||
public final fun configurePatchOptionSerializers ([Lkotlin/Pair;)V
|
||||
}
|
||||
|
||||
public final class app/revanced/library/networking/ServerKt {
|
||||
public static final fun main ()V
|
||||
public static synthetic fun main ([Ljava/lang/String;)V
|
||||
public static final fun server (Ljava/lang/String;ILio/ktor/server/engine/ApplicationEngineFactory;Lkotlin/jvm/functions/Function1;)Lapp/revanced/library/networking/Server;
|
||||
public static synthetic fun server$default (Ljava/lang/String;ILio/ktor/server/engine/ApplicationEngineFactory;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lapp/revanced/library/networking/Server;
|
||||
}
|
||||
|
||||
public final class app/revanced/library/networking/configuration/SerializationKt {
|
||||
public static final fun configureSerialization (Lio/ktor/server/application/Application;Lapp/revanced/library/networking/Server$SerializersConfiguration;)V
|
||||
}
|
||||
|
||||
public abstract class app/revanced/library/networking/configuration/repository/AppRepository {
|
||||
public fun <init> ()V
|
||||
}
|
||||
|
||||
public abstract class app/revanced/library/networking/configuration/repository/InstallerRepository {
|
||||
public fun <init> ()V
|
||||
}
|
||||
|
||||
public abstract class app/revanced/library/networking/configuration/repository/PatchSetRepository {
|
||||
public fun <init> (Lapp/revanced/library/networking/configuration/repository/StorageRepository;)V
|
||||
}
|
||||
|
||||
public abstract class app/revanced/library/networking/configuration/repository/StorageRepository {
|
||||
public fun <init> (Ljava/io/File;Ljava/io/File;Ljava/io/File;Ljava/io/File;)V
|
||||
public synthetic fun <init> (Ljava/io/File;Ljava/io/File;Ljava/io/File;Ljava/io/File;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
|
||||
public final fun getAaptBinaryPath ()Ljava/io/File;
|
||||
public final fun getKeystoreFilePath ()Ljava/io/File;
|
||||
public final fun getOutputFilePath ()Ljava/io/File;
|
||||
public final fun getTemporaryFilesPath ()Ljava/io/File;
|
||||
}
|
||||
|
||||
public class app/revanced/library/networking/models/App {
|
||||
public static final field Companion Lapp/revanced/library/networking/models/App$Companion;
|
||||
public synthetic fun <init> (ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;Lkotlinx/serialization/internal/SerializationConstructorMarker;)V
|
||||
public fun <init> (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
|
||||
public static final synthetic fun write$Self (Lapp/revanced/library/networking/models/App;Lkotlinx/serialization/encoding/CompositeEncoder;Lkotlinx/serialization/descriptors/SerialDescriptor;)V
|
||||
}
|
||||
|
||||
public final class app/revanced/library/networking/models/App$$serializer : kotlinx/serialization/internal/GeneratedSerializer {
|
||||
public static final field INSTANCE Lapp/revanced/library/networking/models/App$$serializer;
|
||||
public fun childSerializers ()[Lkotlinx/serialization/KSerializer;
|
||||
public fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Lapp/revanced/library/networking/models/App;
|
||||
public synthetic fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Object;
|
||||
public fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor;
|
||||
public fun serialize (Lkotlinx/serialization/encoding/Encoder;Lapp/revanced/library/networking/models/App;)V
|
||||
public synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V
|
||||
public fun typeParametersSerializers ()[Lkotlinx/serialization/KSerializer;
|
||||
}
|
||||
|
||||
public final class app/revanced/library/networking/models/App$Companion {
|
||||
public final fun serializer ()Lkotlinx/serialization/KSerializer;
|
||||
}
|
||||
|
||||
public final class app/revanced/library/networking/models/Patch {
|
||||
public static final field Companion Lapp/revanced/library/networking/models/Patch$Companion;
|
||||
}
|
||||
|
||||
public final class app/revanced/library/networking/models/Patch$$serializer : kotlinx/serialization/internal/GeneratedSerializer {
|
||||
public static final field INSTANCE Lapp/revanced/library/networking/models/Patch$$serializer;
|
||||
public fun childSerializers ()[Lkotlinx/serialization/KSerializer;
|
||||
public fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Lapp/revanced/library/networking/models/Patch;
|
||||
public synthetic fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Object;
|
||||
public fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor;
|
||||
public fun serialize (Lkotlinx/serialization/encoding/Encoder;Lapp/revanced/library/networking/models/Patch;)V
|
||||
public synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V
|
||||
public fun typeParametersSerializers ()[Lkotlinx/serialization/KSerializer;
|
||||
}
|
||||
|
||||
public final class app/revanced/library/networking/models/Patch$Companion {
|
||||
public final fun serializer ()Lkotlinx/serialization/KSerializer;
|
||||
}
|
||||
|
||||
public final class app/revanced/library/networking/models/Patch$KeyValuePatchOption {
|
||||
public fun <init> (Ljava/lang/String;Ljava/lang/Object;Ljava/lang/String;)V
|
||||
public final fun getKey ()Ljava/lang/String;
|
||||
public final fun getValue ()Ljava/lang/Object;
|
||||
public final fun getValueType ()Ljava/lang/String;
|
||||
}
|
||||
|
||||
public final class app/revanced/library/networking/models/Patch$PatchOption {
|
||||
public static final field Companion Lapp/revanced/library/networking/models/Patch$PatchOption$Companion;
|
||||
}
|
||||
|
||||
public final class app/revanced/library/networking/models/Patch$PatchOption$$serializer : kotlinx/serialization/internal/GeneratedSerializer {
|
||||
public synthetic fun <init> (Lkotlinx/serialization/KSerializer;)V
|
||||
public fun childSerializers ()[Lkotlinx/serialization/KSerializer;
|
||||
public fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Lapp/revanced/library/networking/models/Patch$PatchOption;
|
||||
public synthetic fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Object;
|
||||
public fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor;
|
||||
public fun serialize (Lkotlinx/serialization/encoding/Encoder;Lapp/revanced/library/networking/models/Patch$PatchOption;)V
|
||||
public synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V
|
||||
public fun typeParametersSerializers ()[Lkotlinx/serialization/KSerializer;
|
||||
}
|
||||
|
||||
public final class app/revanced/library/networking/models/Patch$PatchOption$Companion {
|
||||
public final fun serializer (Lkotlinx/serialization/KSerializer;)Lkotlinx/serialization/KSerializer;
|
||||
}
|
||||
|
||||
public final class app/revanced/library/networking/models/PatchBundle {
|
||||
public final fun getPatchBundleFile ()Ljava/io/File;
|
||||
public final fun getPatchBundleIntegrationsFile ()Ljava/io/File;
|
||||
}
|
||||
|
||||
@@ -1,97 +0,0 @@
|
||||
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
||||
|
||||
plugins {
|
||||
alias(libs.plugins.kotlin.jvm)
|
||||
alias(libs.plugins.kotlin.serialization)
|
||||
alias(libs.plugins.binary.compatibility.validator)
|
||||
alias(libs.plugins.ktor)
|
||||
`maven-publish`
|
||||
signing
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(project(":library"))
|
||||
implementation(libs.revanced.patcher)
|
||||
implementation(libs.ktor.client.core)
|
||||
implementation(libs.ktor.client.cio)
|
||||
implementation(libs.ktor.server.core)
|
||||
implementation(libs.ktor.server.content.negotiation)
|
||||
implementation(libs.ktor.server.auth)
|
||||
implementation(libs.ktor.server.auth.jwt)
|
||||
implementation(libs.ktor.server.cors)
|
||||
implementation(libs.ktor.server.caching.headers)
|
||||
implementation(libs.ktor.server.host.common)
|
||||
implementation(libs.ktor.server.netty)
|
||||
implementation(libs.ktor.server.conditional.headers)
|
||||
implementation(libs.ktor.server.websockets)
|
||||
implementation(libs.ktor.serialization.kotlinx.json)
|
||||
implementation(libs.koin.ktor)
|
||||
implementation(libs.logback.classic)
|
||||
}
|
||||
|
||||
tasks {
|
||||
processResources {
|
||||
expand("projectVersion" to project.version)
|
||||
}
|
||||
}
|
||||
|
||||
kotlin {
|
||||
compilerOptions {
|
||||
jvmTarget.set(JvmTarget.JVM_11)
|
||||
}
|
||||
}
|
||||
|
||||
java {
|
||||
targetCompatibility = JavaVersion.VERSION_11
|
||||
}
|
||||
|
||||
publishing {
|
||||
repositories {
|
||||
maven {
|
||||
name = "GitHubPackages"
|
||||
url = uri("https://maven.pkg.github.com/revanced/revanced-library")
|
||||
credentials {
|
||||
username = System.getenv("GITHUB_ACTOR")
|
||||
password = System.getenv("GITHUB_TOKEN")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
publications {
|
||||
create<MavenPublication>("revanced-library-networking-publication") {
|
||||
version = project.version.toString()
|
||||
|
||||
pom {
|
||||
name = "ReVanced Networking Library"
|
||||
description = "Library to interface to common utilities for ReVanced over a network."
|
||||
url = "https://revanced.app"
|
||||
|
||||
licenses {
|
||||
license {
|
||||
name = "GNU General Public License v3.0"
|
||||
url = "https://www.gnu.org/licenses/gpl-3.0.en.html"
|
||||
}
|
||||
}
|
||||
|
||||
developers {
|
||||
developer {
|
||||
id = "ReVanced"
|
||||
name = "ReVanced"
|
||||
email = "contact@revanced.app"
|
||||
}
|
||||
}
|
||||
|
||||
scm {
|
||||
connection = "scm:git:git://github.com/revanced/revanced-library.git"
|
||||
developerConnection = "scm:git:git@github.com:revanced/revanced-library.git"
|
||||
url = "https://github.com/revanced/revanced-library"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
signing {
|
||||
useGpgCmd()
|
||||
sign(publishing.publications["revanced-library-networking-publication"])
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
package app.revanced.library.networking
|
||||
|
||||
import io.ktor.server.application.*
|
||||
import io.ktor.util.pipeline.*
|
||||
|
||||
internal val PipelineContext<*, ApplicationCall>.parameters get() = call.parameters
|
||||
@@ -1,281 +0,0 @@
|
||||
@file:Suppress("unused")
|
||||
|
||||
package app.revanced.library.networking
|
||||
|
||||
import app.revanced.library.installation.installer.AdbInstaller
|
||||
import app.revanced.library.networking.configuration.configureDependencies
|
||||
import app.revanced.library.networking.configuration.configureHTTP
|
||||
import app.revanced.library.networking.configuration.configureSecurity
|
||||
import app.revanced.library.networking.configuration.configureSerialization
|
||||
import app.revanced.library.networking.configuration.repository.AppRepository
|
||||
import app.revanced.library.networking.configuration.repository.InstallerRepository
|
||||
import app.revanced.library.networking.configuration.repository.PatchSetRepository
|
||||
import app.revanced.library.networking.configuration.repository.StorageRepository
|
||||
import app.revanced.library.networking.configuration.routing.configureRouting
|
||||
import app.revanced.library.networking.models.App
|
||||
import app.revanced.library.networking.models.PatchBundle
|
||||
import app.revanced.patcher.PatchBundleLoader
|
||||
import app.revanced.patcher.PatchSet
|
||||
import app.revanced.patcher.patch.options.PatchOption
|
||||
import io.ktor.server.engine.*
|
||||
import io.ktor.server.netty.*
|
||||
import java.io.File
|
||||
import java.time.LocalDateTime
|
||||
import kotlin.reflect.KType
|
||||
import kotlin.reflect.typeOf
|
||||
|
||||
/**
|
||||
* A server.
|
||||
*
|
||||
* @param host The host.
|
||||
* @param port The port.
|
||||
* @param engineFactory The engine factory.
|
||||
* @param securityConfiguration The security configuration.
|
||||
* @param dependenciesConfiguration The dependencies configuration.
|
||||
* @param serializersConfiguration The serializers configuration.
|
||||
*/
|
||||
class Server internal constructor(
|
||||
host: String,
|
||||
port: Int,
|
||||
engineFactory: ApplicationEngineFactory<*, *>,
|
||||
securityConfiguration: SecurityConfiguration,
|
||||
dependenciesConfiguration: DependenciesConfiguration,
|
||||
serializersConfiguration: SerializersConfiguration,
|
||||
) {
|
||||
private val applicationEngine = embeddedServer(engineFactory, port, host) {
|
||||
configureHTTP(allowedHost = host)
|
||||
configureSecurity(securityConfiguration)
|
||||
configureDependencies(dependenciesConfiguration)
|
||||
configureSerialization(serializersConfiguration)
|
||||
configureRouting()
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the server and blocks the current thread.
|
||||
*/
|
||||
fun start() = applicationEngine.start(wait = true)
|
||||
|
||||
/**
|
||||
* Stops the server.
|
||||
*/
|
||||
fun stop() = applicationEngine.stop()
|
||||
|
||||
/**
|
||||
* The security configuration.
|
||||
*
|
||||
* @property username The username.
|
||||
* @property password The password.
|
||||
*/
|
||||
class SecurityConfiguration(
|
||||
internal val username: String,
|
||||
internal val password: String,
|
||||
)
|
||||
|
||||
/**
|
||||
* The dependencies configuration.
|
||||
*
|
||||
* @property storageRepository The storage repository.
|
||||
* @property patchSetRepository The patch set repository.
|
||||
* @property appRepository The app repository.
|
||||
* @property installerRepository The installer repository.
|
||||
*/
|
||||
class DependenciesConfiguration(
|
||||
internal val storageRepository: StorageRepository,
|
||||
internal val patchSetRepository: PatchSetRepository,
|
||||
internal val appRepository: AppRepository,
|
||||
internal val installerRepository: InstallerRepository,
|
||||
)
|
||||
|
||||
/**
|
||||
* The serializers configuration.
|
||||
*
|
||||
* @property patchOptionValueTypes A map of [PatchOption.valueType] to [KType] to add serializers for patch options
|
||||
* additional to the default ones.
|
||||
*/
|
||||
class SerializersConfiguration(
|
||||
internal val patchOptionValueTypes: Map<String, KType> = emptyMap(),
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* A server builder.
|
||||
*
|
||||
* @property host The host.
|
||||
* @property port The port.
|
||||
* @property engineFactory The engine factory.
|
||||
* @property securityConfiguration The security configuration.
|
||||
* @property dependenciesConfiguration The dependencies configuration.
|
||||
*/
|
||||
class ServerBuilder internal constructor(
|
||||
private val host: String = "localhost",
|
||||
private val port: Int = 8080,
|
||||
private val engineFactory: ApplicationEngineFactory<*, *> = Netty,
|
||||
) {
|
||||
private lateinit var securityConfiguration: Server.SecurityConfiguration
|
||||
private lateinit var dependenciesConfiguration: Server.DependenciesConfiguration
|
||||
private var serializersConfiguration = Server.SerializersConfiguration()
|
||||
|
||||
/**
|
||||
* Configures the security.
|
||||
*
|
||||
* @param basicUsername The basic username.
|
||||
* @param basicPassword The basic password.
|
||||
*
|
||||
* @return The server builder.
|
||||
*/
|
||||
fun configureSecurity(
|
||||
basicUsername: String,
|
||||
basicPassword: String,
|
||||
) = apply {
|
||||
securityConfiguration = Server.SecurityConfiguration(
|
||||
username = basicUsername,
|
||||
password = basicPassword,
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the dependencies.
|
||||
*
|
||||
* @param block The block to configure the dependencies.
|
||||
*
|
||||
* @return The server builder.
|
||||
*/
|
||||
fun configureDependencies(block: DependenciesConfigurationBuilder.() -> Unit) = apply {
|
||||
dependenciesConfiguration = DependenciesConfigurationBuilder().apply(block).build()
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the serializers.
|
||||
*
|
||||
* @param block The block to configure the serializers.
|
||||
*
|
||||
* @return The server builder.
|
||||
*/
|
||||
fun configureSerializers(block: SerializersConfigurationBuilder.() -> Unit) = apply {
|
||||
serializersConfiguration = SerializersConfigurationBuilder().apply(block).build()
|
||||
}
|
||||
|
||||
class DependenciesConfigurationBuilder internal constructor() {
|
||||
private lateinit var storageRepository: StorageRepository
|
||||
private lateinit var patchSetRepository: PatchSetRepository
|
||||
private lateinit var appRepository: AppRepository
|
||||
private lateinit var installerRepository: InstallerRepository
|
||||
|
||||
fun configureStorageRepository(storageRepository: StorageRepository) = apply {
|
||||
this.storageRepository = storageRepository
|
||||
}
|
||||
|
||||
fun configurePatchSetRepository(patchSetRepository: PatchSetRepository) = apply {
|
||||
this.patchSetRepository = patchSetRepository
|
||||
}
|
||||
|
||||
fun configureAppRepository(appRepository: AppRepository) = apply {
|
||||
this.appRepository = appRepository
|
||||
}
|
||||
|
||||
fun configureInstallerRepository(installerRepository: InstallerRepository) = apply {
|
||||
this.installerRepository = installerRepository
|
||||
}
|
||||
|
||||
fun build() = Server.DependenciesConfiguration(
|
||||
storageRepository,
|
||||
patchSetRepository,
|
||||
appRepository,
|
||||
installerRepository,
|
||||
)
|
||||
}
|
||||
|
||||
class SerializersConfigurationBuilder internal constructor() {
|
||||
private lateinit var patchOptionValueTypes: Map<String, KType>
|
||||
|
||||
fun configurePatchOptionSerializers(vararg pairs: Pair<String, KType>) {
|
||||
this.patchOptionValueTypes = mapOf(*pairs)
|
||||
}
|
||||
|
||||
fun build() = Server.SerializersConfiguration(patchOptionValueTypes)
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the server.
|
||||
*
|
||||
* @return The server.
|
||||
*/
|
||||
internal fun build() = Server(
|
||||
host,
|
||||
port,
|
||||
engineFactory,
|
||||
securityConfiguration,
|
||||
dependenciesConfiguration,
|
||||
serializersConfiguration,
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a server.
|
||||
*
|
||||
* @param host The host.
|
||||
* @param port The port.
|
||||
* @param engineFactory The engine factory.
|
||||
* @param block The block to build the server.
|
||||
*
|
||||
* @return The server.
|
||||
*/
|
||||
fun server(
|
||||
host: String = "localhost",
|
||||
port: Int = 8080,
|
||||
engineFactory: ApplicationEngineFactory<*, *> = Netty,
|
||||
block: ServerBuilder.() -> Unit = {},
|
||||
) = ServerBuilder(host, port, engineFactory).apply(block).build()
|
||||
|
||||
fun main() {
|
||||
server {
|
||||
configureSecurity("username", "password")
|
||||
|
||||
val storageRepository = object : StorageRepository(
|
||||
temporaryFilesPath = File("temp"),
|
||||
keystoreFilePath = File("keystore.jks"),
|
||||
) {
|
||||
override fun readPatchBundles() = setOf(
|
||||
PatchBundle(
|
||||
"ReVanced Patches",
|
||||
File("D:\\ReVanced\\revanced-patches\\build\\libs\\revanced-patches-4.7.0-dev.2.jar"),
|
||||
),
|
||||
)
|
||||
|
||||
override fun writePatchBundles(patchBundles: Set<PatchBundle>) {
|
||||
// TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun newPatchBundle(patchBundleName: String, withIntegrations: Boolean): PatchBundle {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
}
|
||||
|
||||
val patchSetRepository = object : PatchSetRepository(storageRepository) {
|
||||
override fun readPatchSet(patchBundles: Set<PatchBundle>): PatchSet {
|
||||
return PatchBundleLoader.Jar(*patchBundles.map { it.patchBundleFile }.toTypedArray())
|
||||
}
|
||||
}
|
||||
|
||||
val appRepository = object : AppRepository() {
|
||||
override fun readInstalledApps() = emptySet<App>()
|
||||
}
|
||||
|
||||
val installerRepository = object : InstallerRepository() {
|
||||
override val installer = AdbInstaller("127.0.0.1:58526")
|
||||
}
|
||||
|
||||
configureDependencies {
|
||||
configureStorageRepository(storageRepository)
|
||||
configurePatchSetRepository(patchSetRepository)
|
||||
configureAppRepository(appRepository)
|
||||
configureInstallerRepository(installerRepository)
|
||||
}
|
||||
|
||||
configureSerializers {
|
||||
configurePatchOptionSerializers(
|
||||
"LocalDateTime" to typeOf<PatchOption<LocalDateTime>>(),
|
||||
)
|
||||
}
|
||||
}.start()
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
package app.revanced.library.networking.configuration
|
||||
|
||||
import app.revanced.library.networking.Server
|
||||
import app.revanced.library.networking.services.HttpClientService
|
||||
import app.revanced.library.networking.services.PatchBundleService
|
||||
import app.revanced.library.networking.services.PatcherService
|
||||
import io.ktor.server.application.*
|
||||
import org.koin.core.module.dsl.singleOf
|
||||
import org.koin.dsl.module
|
||||
import org.koin.ktor.plugin.Koin
|
||||
|
||||
/**
|
||||
* Configure the dependencies for the application.
|
||||
*
|
||||
* @param dependenciesConfiguration The dependencies configuration.
|
||||
*/
|
||||
internal fun Application.configureDependencies(
|
||||
dependenciesConfiguration: Server.DependenciesConfiguration,
|
||||
) {
|
||||
val globalModule = module {
|
||||
single { dependenciesConfiguration.storageRepository }
|
||||
single { dependenciesConfiguration.patchSetRepository }
|
||||
single { dependenciesConfiguration.appRepository }
|
||||
single { dependenciesConfiguration.installerRepository }
|
||||
}
|
||||
|
||||
val patchBundleModule = module {
|
||||
single { HttpClientService() }
|
||||
singleOf(::PatchBundleService)
|
||||
}
|
||||
|
||||
val patcherModule = module {
|
||||
singleOf(::PatcherService)
|
||||
}
|
||||
|
||||
install(Koin) {
|
||||
modules(
|
||||
globalModule,
|
||||
patchBundleModule,
|
||||
patcherModule,
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
package app.revanced.library.networking.configuration
|
||||
|
||||
import io.ktor.http.*
|
||||
import io.ktor.http.content.*
|
||||
import io.ktor.server.application.*
|
||||
import io.ktor.server.plugins.cachingheaders.*
|
||||
import io.ktor.server.plugins.conditionalheaders.*
|
||||
import io.ktor.server.plugins.cors.routing.*
|
||||
import io.ktor.server.websocket.*
|
||||
import kotlin.time.Duration.Companion.minutes
|
||||
|
||||
/**
|
||||
* Configures HTTP for the application.
|
||||
*
|
||||
* @param allowedHost The allowed host for the application.
|
||||
*/
|
||||
internal fun Application.configureHTTP(
|
||||
allowedHost: String,
|
||||
) {
|
||||
install(ConditionalHeaders)
|
||||
install(CORS) {
|
||||
allowMethod(HttpMethod.Options)
|
||||
allowMethod(HttpMethod.Put)
|
||||
allowMethod(HttpMethod.Delete)
|
||||
allowMethod(HttpMethod.Patch)
|
||||
allowHeader(HttpHeaders.Authorization)
|
||||
allowHost(allowedHost)
|
||||
}
|
||||
install(WebSockets)
|
||||
install(CachingHeaders) {
|
||||
options { _, _ -> CachingOptions(CacheControl.MaxAge(maxAgeSeconds = 5.minutes.inWholeSeconds.toInt())) }
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
package app.revanced.library.networking.configuration
|
||||
|
||||
import app.revanced.library.networking.Server
|
||||
import io.ktor.server.application.*
|
||||
import io.ktor.server.auth.*
|
||||
|
||||
/**
|
||||
* Configures the security for the application.
|
||||
*
|
||||
* @param securityConfiguration The security configuration.
|
||||
*/
|
||||
internal fun Application.configureSecurity(
|
||||
securityConfiguration: Server.SecurityConfiguration,
|
||||
) {
|
||||
install(Authentication) {
|
||||
basic {
|
||||
validate { credentials ->
|
||||
if (credentials.name == securityConfiguration.username &&
|
||||
credentials.password == securityConfiguration.password
|
||||
) {
|
||||
UserIdPrincipal(credentials.name)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,92 +0,0 @@
|
||||
package app.revanced.library.networking.configuration
|
||||
|
||||
import app.revanced.library.networking.Server
|
||||
import app.revanced.library.networking.models.Patch
|
||||
import app.revanced.patcher.patch.options.PatchOption
|
||||
import io.ktor.serialization.kotlinx.json.*
|
||||
import io.ktor.server.application.*
|
||||
import io.ktor.server.plugins.contentnegotiation.*
|
||||
import kotlinx.serialization.KSerializer
|
||||
import kotlinx.serialization.builtins.SetSerializer
|
||||
import kotlinx.serialization.encoding.Decoder
|
||||
import kotlinx.serialization.encoding.Encoder
|
||||
import kotlinx.serialization.encoding.decodeStructure
|
||||
import kotlinx.serialization.json.Json
|
||||
import kotlinx.serialization.modules.SerializersModule
|
||||
import kotlinx.serialization.modules.SerializersModuleBuilder
|
||||
import kotlinx.serialization.modules.contextual
|
||||
import kotlinx.serialization.serializer
|
||||
import java.io.Serializable
|
||||
import kotlin.reflect.KType
|
||||
import kotlin.reflect.typeOf
|
||||
|
||||
/**
|
||||
* Configures the serialization for the application.
|
||||
*
|
||||
* @param serializersConfiguration The serializers configuration.
|
||||
*/
|
||||
fun Application.configureSerialization(serializersConfiguration: Server.SerializersConfiguration) {
|
||||
install(ContentNegotiation) {
|
||||
json(
|
||||
Json {
|
||||
serializersModule = SerializersModule {
|
||||
configurePatchOptionSerializers(serializersConfiguration.patchOptionValueTypes)
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the patch option serializers.
|
||||
*
|
||||
* @param patchOptionValueTypes A map of [PatchOption.valueType] to [KType] to add serializers for patch options
|
||||
* additional to the default ones.
|
||||
*/
|
||||
private fun SerializersModuleBuilder.configurePatchOptionSerializers(patchOptionValueTypes: Map<String, KType>) {
|
||||
val knownPatchOptionValueTypes = mapOf(
|
||||
"String" to typeOf<Patch.PatchOption<String>>(),
|
||||
"Int" to typeOf<Patch.PatchOption<Int>>(),
|
||||
"Boolean" to typeOf<Patch.PatchOption<Boolean>>(),
|
||||
"Long" to typeOf<Patch.PatchOption<Long>>(),
|
||||
"Float" to typeOf<Patch.PatchOption<Float>>(),
|
||||
"StringArray" to typeOf<Patch.PatchOption<Array<String>>>(),
|
||||
"IntArray" to typeOf<Patch.PatchOption<IntArray>>(),
|
||||
"BooleanArray" to typeOf<Patch.PatchOption<BooleanArray>>(),
|
||||
"LongArray" to typeOf<Patch.PatchOption<LongArray>>(),
|
||||
"FloatArray" to typeOf<Patch.PatchOption<FloatArray>>(),
|
||||
) + patchOptionValueTypes
|
||||
|
||||
/**
|
||||
* Gets the [KType] for a patch option value type.
|
||||
*
|
||||
* @param valueType The value type of the patch option.
|
||||
*
|
||||
* @return The [KType] for the patch option value type.
|
||||
*/
|
||||
fun patchOptionTypeOf(valueType: String) = knownPatchOptionValueTypes[valueType]
|
||||
?: error("Unknown patch option value type: $valueType")
|
||||
|
||||
/**
|
||||
* Serializer for [Patch.PatchOption].
|
||||
* Uses the [Patch.PatchOption.valueType] to determine the serializer for the generic type.
|
||||
*/
|
||||
val patchOptionSerializer = object : KSerializer<Patch.PatchOption<*>> {
|
||||
override val descriptor = serializer(typeOf<Patch.PatchOption<Serializable>>()).descriptor
|
||||
|
||||
override fun serialize(encoder: Encoder, value: Patch.PatchOption<*>) = serializer(
|
||||
patchOptionTypeOf(value.valueType),
|
||||
).serialize(encoder, value)
|
||||
|
||||
override fun deserialize(decoder: Decoder) = serializer(
|
||||
patchOptionTypeOf(
|
||||
decoder.decodeStructure(descriptor) {
|
||||
decodeStringElement(descriptor, descriptor.getElementIndex("valueType"))
|
||||
},
|
||||
),
|
||||
).deserialize(decoder) as Patch.PatchOption<*>
|
||||
}
|
||||
|
||||
contextual(patchOptionSerializer)
|
||||
contextual(SetSerializer(patchOptionSerializer))
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
package app.revanced.library.networking.configuration.repository
|
||||
|
||||
import app.revanced.library.networking.models.App
|
||||
|
||||
/**
|
||||
* A repository for apps and installers.
|
||||
*/
|
||||
abstract class AppRepository {
|
||||
/**
|
||||
* The set of [App] installed.
|
||||
*/
|
||||
internal lateinit var installedApps: Set<App>
|
||||
private set
|
||||
|
||||
init {
|
||||
readAndSetInstalledApps()
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a set of [App] from a storage.
|
||||
*
|
||||
* @return The set of [App] read.
|
||||
*/
|
||||
internal abstract fun readInstalledApps(): Set<App>
|
||||
|
||||
/**
|
||||
* Read a set of [App] using [readInstalledApps] and set [installedApps] to it.
|
||||
*/
|
||||
internal fun readAndSetInstalledApps() {
|
||||
this.installedApps = readInstalledApps()
|
||||
}
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
package app.revanced.library.networking.configuration.repository
|
||||
|
||||
import app.revanced.library.installation.installer.Installer
|
||||
import app.revanced.library.installation.installer.MountInstaller
|
||||
import app.revanced.library.networking.models.App
|
||||
|
||||
abstract class InstallerRepository {
|
||||
/**
|
||||
* The installer to use for installing and uninstalling [App]s.
|
||||
*/
|
||||
internal abstract val installer: Installer<*, *>
|
||||
|
||||
/**
|
||||
* The root installer to use for mounting and unmounting [App]s.
|
||||
*/
|
||||
internal open val mountInstaller: MountInstaller? = null
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
@file:Suppress("unused", "MemberVisibilityCanBePrivate")
|
||||
|
||||
package app.revanced.library.networking.configuration.repository
|
||||
|
||||
import app.revanced.library.networking.models.PatchBundle
|
||||
import app.revanced.patcher.PatchBundleLoader
|
||||
import app.revanced.patcher.PatchSet
|
||||
import app.revanced.patcher.patch.Patch
|
||||
|
||||
/**
|
||||
* A repository for patches from a set of [PatchBundle]s.
|
||||
*
|
||||
* @param storageRepository The [StorageRepository] to read the [PatchBundle]s from.
|
||||
*/
|
||||
abstract class PatchSetRepository(
|
||||
private val storageRepository: StorageRepository,
|
||||
) {
|
||||
/**
|
||||
* The set of [Patch]es loaded from [StorageRepository.patchBundles].
|
||||
*/
|
||||
internal lateinit var patchSet: PatchSet
|
||||
private set
|
||||
|
||||
init {
|
||||
readAndSetPatchSet()
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a [PatchSet] from a set of [patchBundles] using a [PatchBundleLoader].
|
||||
*
|
||||
* @param patchBundles The set of [PatchBundle]s to read the [PatchSet] from.
|
||||
*/
|
||||
internal abstract fun readPatchSet(patchBundles: Set<PatchBundle>): PatchSet
|
||||
|
||||
/**
|
||||
* Read a [PatchSet] from patch bundles from [storageRepository] using [readPatchSet] and set [patchSet] to it.
|
||||
*/
|
||||
internal fun readAndSetPatchSet() {
|
||||
this.patchSet = readPatchSet(storageRepository.patchBundles.values.toSet())
|
||||
}
|
||||
}
|
||||
@@ -1,93 +0,0 @@
|
||||
package app.revanced.library.networking.configuration.repository
|
||||
|
||||
import app.revanced.library.networking.models.PatchBundle
|
||||
import app.revanced.patcher.Patcher
|
||||
import java.io.File
|
||||
|
||||
/**
|
||||
* A repository for storage.
|
||||
*
|
||||
* @param temporaryFilesPath The path to the temporary files for [Patcher].
|
||||
* @param outputFilePath The path to the output file to save patched APKs to.
|
||||
* @param keystoreFilePath The path to the keystore file to sign patched APKs with.
|
||||
* @param aaptBinaryPath The path to the aapt binary to use by [Patcher].
|
||||
*/
|
||||
abstract class StorageRepository(
|
||||
val temporaryFilesPath: File,
|
||||
val outputFilePath: File = File(temporaryFilesPath, "output.apk"),
|
||||
val keystoreFilePath: File,
|
||||
val aaptBinaryPath: File? = null,
|
||||
) {
|
||||
/**
|
||||
* The stored [PatchBundle]s mapped by their name.
|
||||
*/
|
||||
internal lateinit var patchBundles: MutableMap<String, PatchBundle>
|
||||
private set
|
||||
|
||||
/**
|
||||
* The path to save the patched, but unsigned APK to.
|
||||
*/
|
||||
internal val unsignedApkFilePath = File(temporaryFilesPath, "unsigned.apk")
|
||||
|
||||
init {
|
||||
readAndSetPatchBundles()
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a set of [patchBundles] from a storage.
|
||||
*
|
||||
* @return The set of [PatchBundle] read.
|
||||
*/
|
||||
internal abstract fun readPatchBundles(): Set<PatchBundle>
|
||||
|
||||
/**
|
||||
* Write a set of [patchBundles] to a storage.
|
||||
*
|
||||
* @param patchBundles The set of patch bundles to write.
|
||||
*/
|
||||
internal abstract fun writePatchBundles(patchBundles: Set<PatchBundle>)
|
||||
|
||||
/**
|
||||
* Create a new [PatchBundle] in a storage to write to.
|
||||
*
|
||||
* @param patchBundleName The name of the patch bundle.
|
||||
* @param withIntegrations Whether the patch bundle also has integrations.
|
||||
*
|
||||
* @return The new [PatchBundle] created.
|
||||
*/
|
||||
internal abstract fun newPatchBundle(patchBundleName: String, withIntegrations: Boolean): PatchBundle
|
||||
|
||||
/**
|
||||
* Read the set of [patchBundles] stored and set it to [patchBundles].
|
||||
*/
|
||||
internal fun readAndSetPatchBundles() {
|
||||
patchBundles = readPatchBundles().associateBy { it.name }.toMutableMap()
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a [patchBundle] to the map of the stored [patchBundles] and write the set to a storage using [writePatchBundles].
|
||||
*
|
||||
* @param patchBundle The patch bundle to add.
|
||||
*/
|
||||
internal fun addPersistentlyPatchBundle(patchBundle: PatchBundle) {
|
||||
patchBundles[patchBundle.name] = patchBundle
|
||||
writePatchBundles(patchBundles.values.toSet())
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a path bundle from the map of [patchBundles] stored and write the set to a storage using [writePatchBundles].
|
||||
*
|
||||
* @param patchBundleName The name of the patch bundle to remove.
|
||||
*/
|
||||
internal fun removePersistentlyPatchBundle(patchBundleName: String) {
|
||||
patchBundles.remove(patchBundleName)
|
||||
writePatchBundles(patchBundles.values.toSet())
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the temporary files.
|
||||
*/
|
||||
internal fun deleteTemporaryFiles() {
|
||||
temporaryFilesPath.deleteRecursively()
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
package app.revanced.library.networking.configuration.routing
|
||||
|
||||
import app.revanced.library.networking.configuration.routing.routes.configurePatchBundlesRoute
|
||||
import app.revanced.library.networking.configuration.routing.routes.configurePatcherRoute
|
||||
import app.revanced.library.networking.configuration.routing.routes.configurePingRoute
|
||||
import app.revanced.library.networking.configuration.routing.routes.configureRootRoute
|
||||
import io.ktor.server.application.*
|
||||
import io.ktor.server.auth.*
|
||||
import io.ktor.server.routing.*
|
||||
|
||||
/**
|
||||
* Configures the routing for the application.
|
||||
*/
|
||||
internal fun Application.configureRouting() {
|
||||
routing {
|
||||
authenticate {
|
||||
configureRootRoute()
|
||||
configurePingRoute()
|
||||
configurePatchBundlesRoute()
|
||||
configurePatcherRoute()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
package app.revanced.library.networking.configuration.routing.routes
|
||||
|
||||
import app.revanced.library.networking.parameters
|
||||
import app.revanced.library.networking.services.PatchBundleService
|
||||
import io.ktor.server.application.*
|
||||
import io.ktor.server.response.*
|
||||
import io.ktor.server.routing.*
|
||||
import io.ktor.server.routing.get
|
||||
import io.ktor.server.util.*
|
||||
import org.koin.ktor.ext.get
|
||||
|
||||
/**
|
||||
* Route to handle all patch bundle related requests such as creating, reading, updating and deleting patch bundles.
|
||||
*/
|
||||
internal fun Route.configurePatchBundlesRoute() {
|
||||
val patchBundleService = get<PatchBundleService>()
|
||||
|
||||
route("/patch-bundles") {
|
||||
get {
|
||||
call.respond(patchBundleService.patchBundleNames)
|
||||
}
|
||||
|
||||
post("/add") {
|
||||
val patchBundleName: String by parameters
|
||||
val patchBundleFilePath = parameters["patchBundleFilePath"]
|
||||
|
||||
if (patchBundleFilePath != null) {
|
||||
val patchBundleIntegrationsFilePath = parameters["patchBundleIntegrationsFilePath"]
|
||||
|
||||
patchBundleService.addPersistentlyLocalPatchBundle(
|
||||
patchBundleName,
|
||||
patchBundleFilePath,
|
||||
patchBundleIntegrationsFilePath,
|
||||
)
|
||||
} else {
|
||||
val patchBundleDownloadLink: String by parameters
|
||||
val patchBundleIntegrationsDownloadLink = parameters["patchBundleIntegrationsDownloadLink"]
|
||||
|
||||
patchBundleService.addPersistentlyDownloadPatchBundle(
|
||||
patchBundleName,
|
||||
patchBundleDownloadLink,
|
||||
patchBundleIntegrationsDownloadLink,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
post("/remove") {
|
||||
val patchBundleName: String by parameters
|
||||
|
||||
patchBundleService.removePersistentlyPatchBundle(patchBundleName)
|
||||
}
|
||||
|
||||
post("/refresh") {
|
||||
patchBundleService.refresh()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,179 +0,0 @@
|
||||
package app.revanced.library.networking.configuration.routing.routes
|
||||
|
||||
import app.revanced.library.networking.configuration.repository.InstallerRepository
|
||||
import app.revanced.library.networking.models.Patch
|
||||
import app.revanced.library.networking.parameters
|
||||
import app.revanced.library.networking.services.PatcherService
|
||||
import io.ktor.http.*
|
||||
import io.ktor.server.application.*
|
||||
import io.ktor.server.request.*
|
||||
import io.ktor.server.response.*
|
||||
import io.ktor.server.routing.*
|
||||
import io.ktor.server.routing.get
|
||||
import io.ktor.server.util.*
|
||||
import org.koin.ktor.ext.get
|
||||
import java.io.File
|
||||
|
||||
/**
|
||||
* Route to the patcher to handles all patcher related requests such as patching, signing and installing patched apps.
|
||||
*/
|
||||
internal fun Route.configurePatcherRoute() {
|
||||
route("/patcher") {
|
||||
configureAppsRoute()
|
||||
configurePatchesRoute()
|
||||
configurePatchOptionsRoute()
|
||||
configurePatchRoute()
|
||||
configureSignRoute()
|
||||
configureInstallationRoute()
|
||||
configureCleanRoute()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Route to list all patchable apps that can be patched.
|
||||
*/
|
||||
private fun Route.configureAppsRoute() {
|
||||
val patcherService = get<PatcherService>()
|
||||
|
||||
get("/apps") {
|
||||
val universal = parameters.contains("universal")
|
||||
|
||||
call.respond(patcherService.getInstalledApps(universal))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Route to get all patches for a specific app and version.
|
||||
*/
|
||||
private fun Route.configurePatchesRoute() {
|
||||
val patcherService = get<PatcherService>()
|
||||
|
||||
get("/patches") {
|
||||
val app = parameters["app"]
|
||||
val version = parameters["version"]
|
||||
val universal = "universal" in parameters
|
||||
|
||||
call.respond(patcherService.getPatches(app, version, universal))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Route to get and set patch options.
|
||||
*/
|
||||
private fun Route.configurePatchOptionsRoute() {
|
||||
val patcherService = get<PatcherService>()
|
||||
|
||||
route("/options") {
|
||||
get {
|
||||
val app: String by parameters
|
||||
val patch: String by parameters
|
||||
|
||||
call.respond(patcherService.getPatchOptions(patchName = patch, app))
|
||||
}
|
||||
|
||||
post {
|
||||
// Abuse serialization capabilities of Patch.PatchOption
|
||||
// because Patch.KeyValuePatchOption isn't serializable.
|
||||
// ONLY the Patch.PatchOption.key and Patch.PatchOption.value properties are used here.
|
||||
val patchOptions: Set<Patch.PatchOption<*>> by call.receive()
|
||||
val patch: String by parameters
|
||||
val app: String by parameters
|
||||
|
||||
patcherService.setPatchOptions(
|
||||
// Use Patch.PatchOption.default for Patch.KeyValuePatchOption.value.
|
||||
patchOptions = patchOptions.map { Patch.KeyValuePatchOption(it) }.toSet(),
|
||||
patchName = patch,
|
||||
app,
|
||||
)
|
||||
|
||||
call.respond(HttpStatusCode.OK)
|
||||
}
|
||||
|
||||
delete {
|
||||
val patch: String by parameters
|
||||
val app: String by parameters
|
||||
|
||||
patcherService.resetPatchOptions(patchName = patch, app)
|
||||
|
||||
call.respond(HttpStatusCode.OK)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Route to patch an app with a set of patches.
|
||||
*/
|
||||
private fun Route.configurePatchRoute() {
|
||||
val installerRepository = get<InstallerRepository>()
|
||||
val patcherService = get<PatcherService>()
|
||||
|
||||
post("/patch") {
|
||||
val patchNames = parameters.getAll("patch")?.toSet() ?: emptySet()
|
||||
val multithreading = "multithreading" in parameters
|
||||
|
||||
// TODO: The path to the APK must be local to the server, otherwise it will not work.
|
||||
val apkPath = parameters["app"]?.let {
|
||||
installerRepository.installer.getInstallation(it)?.apkFilePath
|
||||
} ?: parameters["apkPath"]
|
||||
val apkFile = File(apkPath ?: return@post call.respond(HttpStatusCode.BadRequest))
|
||||
|
||||
patcherService.patch(patchNames, multithreading, apkFile)
|
||||
|
||||
call.respond(HttpStatusCode.OK)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Route to sign the patched APK.
|
||||
*/
|
||||
private fun Route.configureSignRoute() {
|
||||
val patcherService = get<PatcherService>()
|
||||
|
||||
post("/sign") {
|
||||
val signer: String by parameters
|
||||
val keyStorePassword = parameters["keyStorePassword"]
|
||||
val keyStoreEntryAlias: String by parameters
|
||||
val keyStoreEntryPassword: String by parameters
|
||||
|
||||
patcherService.sign(signer, keyStorePassword, keyStoreEntryAlias, keyStoreEntryPassword)
|
||||
|
||||
call.respond(HttpStatusCode.OK)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Route to install or uninstall a patched APK.
|
||||
*/
|
||||
private fun Route.configureInstallationRoute() {
|
||||
val patcherService = get<PatcherService>()
|
||||
|
||||
post("/install") {
|
||||
val mount = parameters["mount"]
|
||||
|
||||
patcherService.install(mount)
|
||||
|
||||
call.respond(HttpStatusCode.OK)
|
||||
}
|
||||
|
||||
post("/uninstall") {
|
||||
val packageName: String by parameters
|
||||
val unmount = "unmount" in parameters
|
||||
|
||||
patcherService.uninstall(packageName, unmount)
|
||||
|
||||
call.respond(HttpStatusCode.OK)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Route to delete temporary files produced by the patcher.
|
||||
*/
|
||||
private fun Route.configureCleanRoute() {
|
||||
val patcherService = get<PatcherService>()
|
||||
|
||||
post("/clean") {
|
||||
patcherService.deleteTemporaryFiles()
|
||||
|
||||
call.respond(HttpStatusCode.OK)
|
||||
}
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
package app.revanced.library.networking.configuration.routing.routes
|
||||
|
||||
import io.ktor.http.*
|
||||
import io.ktor.server.application.*
|
||||
import io.ktor.server.response.*
|
||||
import io.ktor.server.routing.*
|
||||
|
||||
/**
|
||||
* Route to check if the server is up.
|
||||
*/
|
||||
internal fun Route.configurePingRoute() {
|
||||
head("/ping") {
|
||||
call.respond(HttpStatusCode.OK)
|
||||
}
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
package app.revanced.library.networking.configuration.routing.routes
|
||||
|
||||
import app.revanced.library.logging.Logger
|
||||
import io.ktor.server.application.*
|
||||
import io.ktor.server.response.*
|
||||
import io.ktor.server.routing.*
|
||||
import io.ktor.server.websocket.*
|
||||
import io.ktor.websocket.*
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import java.util.*
|
||||
|
||||
internal fun Route.configureRootRoute() {
|
||||
route("/") {
|
||||
configureAboutRoute()
|
||||
configureLoggingRoute()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Route to get information about the server.
|
||||
*/
|
||||
private fun Route.configureAboutRoute() {
|
||||
val name = this::class.java.getResourceAsStream(
|
||||
"/app/revanced/library/networking/version.properties",
|
||||
)?.use { stream ->
|
||||
Properties().apply {
|
||||
load(stream)
|
||||
}.let {
|
||||
"ReVanced Networking Library v${it.getProperty("version")}"
|
||||
}
|
||||
} ?: "ReVanced Networking Library"
|
||||
|
||||
handle {
|
||||
call.respondText(name)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Fix clients disconnecting from the server.
|
||||
/**
|
||||
* Route to get logs from the server.
|
||||
*/
|
||||
private fun Route.configureLoggingRoute() {
|
||||
val sessions = Collections.synchronizedSet<DefaultWebSocketSession?>(LinkedHashSet())
|
||||
|
||||
Logger.addHandler({ log: String, level: java.util.logging.Level, loggerName: String? ->
|
||||
runBlocking {
|
||||
sessions.forEach {
|
||||
try {
|
||||
it.send("[$loggerName] $level: $log")
|
||||
} catch (e: Exception) {
|
||||
sessions -= it
|
||||
}
|
||||
}
|
||||
}
|
||||
}, {}, {})
|
||||
|
||||
webSocket("/logs") {
|
||||
sessions += this
|
||||
}
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
@file:Suppress("unused")
|
||||
|
||||
package app.revanced.library.networking.models
|
||||
|
||||
import kotlinx.serialization.*
|
||||
import java.io.File
|
||||
|
||||
private typealias PackageName = String
|
||||
private typealias PackageVersion = String
|
||||
private typealias PackageVersions = Set<PackageVersion>
|
||||
private typealias CompatiblePackages = Map<PackageName, PackageVersions?>
|
||||
|
||||
@Serializable
|
||||
open class App(
|
||||
internal val name: String,
|
||||
internal val version: String,
|
||||
internal val packageName: String,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
class Patch internal constructor(
|
||||
internal val name: String,
|
||||
internal val description: String?,
|
||||
internal val use: Boolean,
|
||||
internal val compatiblePackages: CompatiblePackages?,
|
||||
) {
|
||||
@Serializable
|
||||
class PatchOption<T> internal constructor(
|
||||
internal val key: String,
|
||||
internal val default: T?,
|
||||
internal val values: Map<String, T?>?,
|
||||
internal val title: String?,
|
||||
internal val description: String?,
|
||||
internal val required: Boolean,
|
||||
internal val valueType: String,
|
||||
)
|
||||
|
||||
class KeyValuePatchOption<T>(
|
||||
val key: String,
|
||||
val value: T?,
|
||||
val valueType: String,
|
||||
) {
|
||||
// Abuse serialization capabilities of Patch.PatchOption which is used in request bodies.
|
||||
// Use Patch.PatchOption.default as Patch.KeyValuePatchOption.value.
|
||||
internal constructor(patchOption: PatchOption<T>) : this(
|
||||
patchOption.key,
|
||||
patchOption.default,
|
||||
patchOption.valueType,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class PatchBundle internal constructor(
|
||||
val name: String,
|
||||
val patchBundleFile: File,
|
||||
val patchBundleIntegrationsFile: File? = null,
|
||||
)
|
||||
@@ -1,26 +0,0 @@
|
||||
package app.revanced.library.networking.services
|
||||
|
||||
import io.ktor.client.*
|
||||
import io.ktor.client.call.*
|
||||
import io.ktor.client.engine.cio.*
|
||||
import io.ktor.client.request.*
|
||||
import io.ktor.utils.io.*
|
||||
import io.ktor.utils.io.jvm.javaio.*
|
||||
import java.io.File
|
||||
|
||||
/**
|
||||
* Service for HTTP client.
|
||||
*/
|
||||
internal class HttpClientService {
|
||||
private val client by lazy { HttpClient(CIO) }
|
||||
|
||||
/**
|
||||
* Download a file from a URL to a file.
|
||||
*
|
||||
* @param file The file to download to.
|
||||
* @param url The URL to download from.
|
||||
*/
|
||||
internal suspend fun downloadToFile(file: File, url: String) {
|
||||
client.get(url).body<ByteReadChannel>().copyTo(file.outputStream())
|
||||
}
|
||||
}
|
||||
@@ -1,85 +0,0 @@
|
||||
package app.revanced.library.networking.services
|
||||
|
||||
import app.revanced.library.networking.configuration.repository.PatchSetRepository
|
||||
import app.revanced.library.networking.configuration.repository.StorageRepository
|
||||
import app.revanced.library.networking.models.PatchBundle
|
||||
import java.io.File
|
||||
|
||||
/**
|
||||
* Service for patch bundles.
|
||||
*
|
||||
* @property storageRepository The storage repository to get storage paths from.
|
||||
* @property patchSetRepository The patch set repository to get patches from.
|
||||
* @property httpClientService The HTTP client service to download patch bundles with.
|
||||
*/
|
||||
internal class PatchBundleService(
|
||||
private val storageRepository: StorageRepository,
|
||||
private val patchSetRepository: PatchSetRepository,
|
||||
private val httpClientService: HttpClientService,
|
||||
) {
|
||||
/**
|
||||
* Get the names of the patch bundles stored.
|
||||
*
|
||||
* @return The set of patch bundle names.
|
||||
*/
|
||||
internal val patchBundleNames: Set<String>
|
||||
get() = storageRepository.patchBundles.keys.toSet()
|
||||
|
||||
/**
|
||||
* Add a local patch bundle to storage persistently.
|
||||
*
|
||||
* @param patchBundleName The name of the patch bundle.
|
||||
* @param patchBundleFilePath The path to the patch bundle file.
|
||||
* @param patchBundleIntegrationsFilePath The path to the patch bundle integrations file.
|
||||
*/
|
||||
internal fun addPersistentlyLocalPatchBundle(
|
||||
patchBundleName: String,
|
||||
patchBundleFilePath: String,
|
||||
patchBundleIntegrationsFilePath: String?,
|
||||
) = storageRepository.addPersistentlyPatchBundle(
|
||||
PatchBundle(
|
||||
name = patchBundleName,
|
||||
patchBundleFile = File(patchBundleFilePath),
|
||||
patchBundleIntegrationsFile = patchBundleIntegrationsFilePath?.let { File(it) },
|
||||
),
|
||||
)
|
||||
|
||||
/**
|
||||
* Add a patch bundle that needs to be downloaded to storage persistently.
|
||||
*
|
||||
* @param patchBundleName The name of the patch bundle.
|
||||
* @param patchBundleDownloadLink The download link to the patch bundle.
|
||||
* @param patchBundleIntegrationsDownloadLink The download link to the patch bundle integrations.
|
||||
*/
|
||||
internal suspend fun addPersistentlyDownloadPatchBundle(
|
||||
patchBundleName: String,
|
||||
patchBundleDownloadLink: String,
|
||||
patchBundleIntegrationsDownloadLink: String?,
|
||||
) {
|
||||
val withIntegrations = patchBundleIntegrationsDownloadLink != null
|
||||
|
||||
storageRepository.newPatchBundle(patchBundleName, withIntegrations).apply {
|
||||
httpClientService.downloadToFile(patchBundleFile, patchBundleDownloadLink)
|
||||
|
||||
if (withIntegrations) {
|
||||
httpClientService.downloadToFile(patchBundleIntegrationsFile!!, patchBundleIntegrationsDownloadLink!!)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a patch bundle from storage persistently.
|
||||
*
|
||||
* @param name The name of the patch bundle to remove.
|
||||
*/
|
||||
internal fun removePersistentlyPatchBundle(name: String) =
|
||||
storageRepository.removePersistentlyPatchBundle(name)
|
||||
|
||||
/**
|
||||
* Reload the patch bundles from storage and read the patch set from them.
|
||||
*/
|
||||
internal fun refresh() {
|
||||
storageRepository.readAndSetPatchBundles()
|
||||
patchSetRepository.readAndSetPatchSet()
|
||||
}
|
||||
}
|
||||
@@ -1,250 +0,0 @@
|
||||
package app.revanced.library.networking.services
|
||||
|
||||
import app.revanced.library.ApkUtils
|
||||
import app.revanced.library.ApkUtils.applyTo
|
||||
import app.revanced.library.installation.installer.Installer
|
||||
import app.revanced.library.networking.configuration.repository.AppRepository
|
||||
import app.revanced.library.networking.configuration.repository.InstallerRepository
|
||||
import app.revanced.library.networking.configuration.repository.PatchSetRepository
|
||||
import app.revanced.library.networking.configuration.repository.StorageRepository
|
||||
import app.revanced.library.networking.models.App
|
||||
import app.revanced.library.networking.models.Patch
|
||||
import app.revanced.patcher.Patcher
|
||||
import app.revanced.patcher.PatcherConfig
|
||||
import java.io.File
|
||||
import java.io.PrintWriter
|
||||
import java.io.StringWriter
|
||||
import java.util.logging.Logger
|
||||
|
||||
/**
|
||||
* Service for patching and installing apps.
|
||||
*
|
||||
* @property storageRepository The storage repository to get storage paths from.
|
||||
* @property patchSetRepository The patch set repository to get patches from.
|
||||
* @property appRepository The app repository to get installed apps from.
|
||||
* @property installerRepository The installer repository to install apps with.
|
||||
*/
|
||||
internal class PatcherService(
|
||||
private val storageRepository: StorageRepository,
|
||||
private val patchSetRepository: PatchSetRepository,
|
||||
private val appRepository: AppRepository,
|
||||
private val installerRepository: InstallerRepository,
|
||||
) {
|
||||
private val logger = Logger.getLogger(PatcherService::class.simpleName)
|
||||
|
||||
/**
|
||||
* Get installed apps.
|
||||
*
|
||||
* @param universal Whether to show apps that only have universal patches.
|
||||
*
|
||||
* @return The installed apps.
|
||||
*/
|
||||
internal fun getInstalledApps(universal: Boolean = true): Set<App> {
|
||||
// TODO: Show apps, that only have universal patches, only if universal is true.
|
||||
return appRepository.installedApps
|
||||
}
|
||||
|
||||
/**
|
||||
* Get patches.
|
||||
*
|
||||
* @param app The app to get patches for.
|
||||
* @param version The version of the app to get patches for.
|
||||
* @param universal Whether to show patches that are compatible with all apps.
|
||||
*
|
||||
* @return The patches.
|
||||
*/
|
||||
internal fun getPatches(
|
||||
app: String? = null,
|
||||
version: String? = null,
|
||||
universal: Boolean = true,
|
||||
) = if (app != null) {
|
||||
patchSetRepository.patchSet.filter { patch ->
|
||||
patch.compatiblePackages?.any { pkg ->
|
||||
pkg.name == app && (version == null || pkg.versions?.contains(version) ?: false)
|
||||
} ?: universal
|
||||
}
|
||||
} else {
|
||||
patchSetRepository.patchSet.filter { patch ->
|
||||
patch.compatiblePackages != null || universal
|
||||
}
|
||||
}.map { patch ->
|
||||
Patch(
|
||||
patch.name!!,
|
||||
patch.description,
|
||||
patch.use,
|
||||
patch.compatiblePackages?.associate { pkg -> pkg.name to pkg.versions },
|
||||
)
|
||||
}.toSet()
|
||||
|
||||
/**
|
||||
* Patch an app.
|
||||
* Due to the likely-hood, that patches for the same app have the same name, duplicates are unhandled.
|
||||
*
|
||||
* @param patchNames The names of the patches to apply.
|
||||
* @param multithreading Whether to use multi-threading for dex file writing.
|
||||
* @param apkFile The APK file to patch.
|
||||
*/
|
||||
internal suspend fun patch(
|
||||
patchNames: Set<String>,
|
||||
multithreading: Boolean = false,
|
||||
apkFile: File,
|
||||
) = Patcher(
|
||||
PatcherConfig(
|
||||
apkFile = apkFile,
|
||||
temporaryFilesPath = storageRepository.temporaryFilesPath,
|
||||
aaptBinaryPath = storageRepository.aaptBinaryPath?.absolutePath,
|
||||
frameworkFileDirectory = storageRepository.temporaryFilesPath.absolutePath,
|
||||
multithreadingDexFileWriter = multithreading,
|
||||
),
|
||||
).use { patcher ->
|
||||
val packageName = patcher.context.packageMetadata.packageName
|
||||
|
||||
patcher.apply {
|
||||
acceptPatches(
|
||||
patchSetRepository.patchSet.filter { patch ->
|
||||
patch.name in patchNames && patch.compatiblePackages?.any { it.name == packageName } ?: true
|
||||
}.toSet(),
|
||||
)
|
||||
|
||||
// TODO: Only accept integrations from patch bundles that contain selected patches.
|
||||
acceptIntegrations(
|
||||
storageRepository.patchBundles.values.mapNotNull {
|
||||
it.patchBundleIntegrationsFile
|
||||
}.toSet(),
|
||||
)
|
||||
}
|
||||
|
||||
patcher.apply(false).collect { patchResult ->
|
||||
patchResult.exception?.let {
|
||||
StringWriter().use { writer ->
|
||||
it.printStackTrace(PrintWriter(writer))
|
||||
logger.severe("${patchResult.patch.name} failed:\n$writer")
|
||||
}
|
||||
} ?: logger.info("${patchResult.patch.name} succeeded")
|
||||
}
|
||||
|
||||
patcher.get()
|
||||
}.let { patcherResult ->
|
||||
apkFile.copyTo(storageRepository.unsignedApkFilePath, overwrite = true).apply {
|
||||
patcherResult.applyTo(this)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sign an APK.
|
||||
*
|
||||
* @param signer The signer to use.
|
||||
* @param keyStorePassword The password of the keystore.
|
||||
* @param keyStoreEntryAlias The alias of the keystore entry.
|
||||
* @param keyStoreEntryPassword The password of the keystore entry.
|
||||
*/
|
||||
internal fun sign(
|
||||
signer: String,
|
||||
keyStorePassword: String?,
|
||||
keyStoreEntryAlias: String,
|
||||
keyStoreEntryPassword: String,
|
||||
) = ApkUtils.signApk(
|
||||
storageRepository.unsignedApkFilePath,
|
||||
storageRepository.outputFilePath,
|
||||
signer,
|
||||
ApkUtils.KeyStoreDetails(
|
||||
storageRepository.keystoreFilePath,
|
||||
keyStorePassword,
|
||||
keyStoreEntryAlias,
|
||||
keyStoreEntryPassword,
|
||||
),
|
||||
)
|
||||
|
||||
/**
|
||||
* Install an APK.
|
||||
*
|
||||
* @param mount The package name to mount the APK to.
|
||||
*/
|
||||
internal suspend fun install(mount: String?) {
|
||||
if (mount != null) {
|
||||
if (installerRepository.mountInstaller == null) {
|
||||
throw IllegalArgumentException("Mount installer not available")
|
||||
}
|
||||
|
||||
installerRepository.mountInstaller!! to Installer.Apk(
|
||||
storageRepository.unsignedApkFilePath,
|
||||
packageName = mount,
|
||||
)
|
||||
} else {
|
||||
installerRepository.installer to Installer.Apk(storageRepository.outputFilePath)
|
||||
}.let { (installer, apk) ->
|
||||
installer.install(apk)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Uninstall an APK.
|
||||
*
|
||||
* @param packageName The package name of the APK to uninstall.
|
||||
* @param unmount Whether to uninstall a mounted APK.
|
||||
*/
|
||||
internal suspend fun uninstall(packageName: String, unmount: Boolean) = if (unmount) {
|
||||
installerRepository.mountInstaller!!
|
||||
} else {
|
||||
installerRepository.installer
|
||||
}.uninstall(packageName)
|
||||
|
||||
/**
|
||||
* Get patch options from [PatchSetRepository.patchSet].
|
||||
* The [app] parameter is necessary in case there are patches with the same name.
|
||||
* Due to the likely-hood, that patches for the same app have the same name, duplicates are unhandled.
|
||||
*
|
||||
* @param patchName The name of the patch to get options for.
|
||||
* @param app The app to get options for.
|
||||
*
|
||||
* @return The patch options for the patch.
|
||||
*/
|
||||
internal fun getPatchOptions(patchName: String, app: String) = patchSetRepository.patchSet.single { patch ->
|
||||
patch.name == patchName && patch.compatiblePackages?.any { it.name == app } ?: true
|
||||
}.options.map { (key, option) ->
|
||||
Patch.PatchOption(
|
||||
key,
|
||||
option.default,
|
||||
option.values,
|
||||
option.title,
|
||||
option.description,
|
||||
option.required,
|
||||
option.valueType,
|
||||
)
|
||||
}.toSet()
|
||||
|
||||
/**
|
||||
* Set patch options.
|
||||
* The [app] parameter is necessary in case there are patches with the same name.
|
||||
* Due to the likely-hood, that patches for the same app have the same name, duplicates are unhandled.
|
||||
*
|
||||
* @param patchOptions The options to set.
|
||||
* @param patchName The name of the patch to set options for.
|
||||
* @param app The app to set options for.
|
||||
*/
|
||||
internal fun setPatchOptions(
|
||||
patchOptions: Set<Patch.KeyValuePatchOption<*>>,
|
||||
patchName: String,
|
||||
app: String,
|
||||
) = patchSetRepository.patchSet.single { patch ->
|
||||
patch.name == patchName && patch.compatiblePackages?.any { it.name == app } ?: true
|
||||
}.options.let { options ->
|
||||
patchOptions.forEach { option ->
|
||||
options[option.key] = option.value
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset patch options and persist them to the storage.
|
||||
*
|
||||
* @param patchName The name of the patch to reset options for.
|
||||
* @param app The app to reset options for.
|
||||
*/
|
||||
internal fun resetPatchOptions(patchName: String, app: String) {
|
||||
patchSetRepository.patchSet.single { patch ->
|
||||
patch.name == patchName && patch.compatiblePackages?.any { it.name == app } ?: true
|
||||
}.options.forEach { (_, option) -> option.reset() }
|
||||
}
|
||||
|
||||
internal fun deleteTemporaryFiles() = storageRepository.deleteTemporaryFiles()
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
version=${projectVersion}
|
||||
@@ -1,283 +0,0 @@
|
||||
public final class app/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 (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 newKeyStore (Ljava/io/OutputStream;Ljava/lang/String;Ljava/util/Set;)V
|
||||
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 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 readPrivateKeyCertificatePair (Ljava/security/KeyStore;Ljava/lang/String;Ljava/lang/String;)Lapp/revanced/library/ApkSigner$PrivateKeyCertificatePair;
|
||||
}
|
||||
|
||||
public final class app/revanced/library/ApkSigner$KeyStoreEntry {
|
||||
public fun <init> (Ljava/lang/String;Ljava/lang/String;Lapp/revanced/library/ApkSigner$PrivateKeyCertificatePair;)V
|
||||
public final fun getAlias ()Ljava/lang/String;
|
||||
public final fun getPassword ()Ljava/lang/String;
|
||||
public final fun getPrivateKeyCertificatePair ()Lapp/revanced/library/ApkSigner$PrivateKeyCertificatePair;
|
||||
}
|
||||
|
||||
public final class app/revanced/library/ApkSigner$PrivateKeyCertificatePair {
|
||||
public fun <init> (Ljava/security/PrivateKey;Ljava/security/cert/X509Certificate;)V
|
||||
public final fun getCertificate ()Ljava/security/cert/X509Certificate;
|
||||
public final fun getPrivateKey ()Ljava/security/PrivateKey;
|
||||
}
|
||||
|
||||
public final class app/revanced/library/ApkSigner$Signer {
|
||||
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;Ljava/io/File;)V
|
||||
}
|
||||
|
||||
public final class app/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 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;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 fun <init> (Ljava/io/File;Ljava/lang/String;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;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 fun getSigner ()Ljava/lang/String;
|
||||
}
|
||||
|
||||
public final class app/revanced/library/Options {
|
||||
public static final field INSTANCE Lapp/revanced/library/Options;
|
||||
public final fun deserialize (Ljava/lang/String;)[Lapp/revanced/library/Options$Patch;
|
||||
public final fun serialize (Ljava/util/Set;Z)Ljava/lang/String;
|
||||
public static synthetic fun serialize$default (Lapp/revanced/library/Options;Ljava/util/Set;ZILjava/lang/Object;)Ljava/lang/String;
|
||||
public final fun setOptions (Ljava/util/Set;Ljava/io/File;)V
|
||||
public final fun setOptions (Ljava/util/Set;Ljava/lang/String;)V
|
||||
}
|
||||
|
||||
public final class app/revanced/library/Options$Patch {
|
||||
public final fun getOptions ()Ljava/util/List;
|
||||
public final fun getPatchName ()Ljava/lang/String;
|
||||
}
|
||||
|
||||
public final class app/revanced/library/Options$Patch$Option {
|
||||
public final fun getKey ()Ljava/lang/String;
|
||||
public final fun getValue ()Ljava/lang/Object;
|
||||
}
|
||||
|
||||
public final class app/revanced/library/PatchUtils {
|
||||
public static final field INSTANCE Lapp/revanced/library/PatchUtils;
|
||||
public final fun getMostCommonCompatibleVersions (Ljava/util/Set;Ljava/util/Set;Z)Ljava/util/Map;
|
||||
public static synthetic fun getMostCommonCompatibleVersions$default (Lapp/revanced/library/PatchUtils;Ljava/util/Set;Ljava/util/Set;ZILjava/lang/Object;)Ljava/util/Map;
|
||||
}
|
||||
|
||||
public final class app/revanced/library/PatchUtils$Json {
|
||||
public static final field INSTANCE Lapp/revanced/library/PatchUtils$Json;
|
||||
public final fun deserialize (Ljava/io/InputStream;Ljava/lang/Class;)Ljava/util/Set;
|
||||
public final fun serialize (Ljava/util/Set;Lkotlin/jvm/functions/Function1;ZLjava/io/OutputStream;)V
|
||||
public static synthetic fun serialize$default (Lapp/revanced/library/PatchUtils$Json;Ljava/util/Set;Lkotlin/jvm/functions/Function1;ZLjava/io/OutputStream;ILjava/lang/Object;)V
|
||||
}
|
||||
|
||||
public final class app/revanced/library/PatchUtils$Json$FullJsonPatch : app/revanced/library/PatchUtils$Json$JsonPatch {
|
||||
public static final field Companion Lapp/revanced/library/PatchUtils$Json$FullJsonPatch$Companion;
|
||||
public final fun getCompatiblePackages ()Ljava/util/Set;
|
||||
public final fun getDependencies ()Ljava/util/Set;
|
||||
public final fun getDescription ()Ljava/lang/String;
|
||||
public final fun getName ()Ljava/lang/String;
|
||||
public final fun getOptions ()Ljava/util/Map;
|
||||
public final fun getRequiresIntegrations ()Z
|
||||
public final fun getUse ()Z
|
||||
public final fun setRequiresIntegrations (Z)V
|
||||
}
|
||||
|
||||
public final class app/revanced/library/PatchUtils$Json$FullJsonPatch$Companion {
|
||||
public final fun fromPatch (Lapp/revanced/patcher/patch/Patch;)Lapp/revanced/library/PatchUtils$Json$FullJsonPatch;
|
||||
}
|
||||
|
||||
public final class app/revanced/library/PatchUtils$Json$FullJsonPatch$FullJsonPatchOption {
|
||||
public static final field Companion Lapp/revanced/library/PatchUtils$Json$FullJsonPatch$FullJsonPatchOption$Companion;
|
||||
public final fun getDefault ()Ljava/lang/Object;
|
||||
public final fun getDescription ()Ljava/lang/String;
|
||||
public final fun getKey ()Ljava/lang/String;
|
||||
public final fun getRequired ()Z
|
||||
public final fun getTitle ()Ljava/lang/String;
|
||||
public final fun getValueType ()Ljava/lang/String;
|
||||
public final fun getValues ()Ljava/util/Map;
|
||||
}
|
||||
|
||||
public final class app/revanced/library/PatchUtils$Json$FullJsonPatch$FullJsonPatchOption$Companion {
|
||||
public final fun fromPatchOption (Lapp/revanced/patcher/patch/options/PatchOption;)Lapp/revanced/library/PatchUtils$Json$FullJsonPatch$FullJsonPatchOption;
|
||||
}
|
||||
|
||||
public abstract interface class app/revanced/library/PatchUtils$Json$JsonPatch {
|
||||
}
|
||||
|
||||
public final class app/revanced/library/Utils {
|
||||
public static final field INSTANCE Lapp/revanced/library/Utils;
|
||||
public final fun isAndroidEnvironment ()Z
|
||||
}
|
||||
|
||||
public abstract class app/revanced/library/adb/AdbManager {
|
||||
public static final field Companion Lapp/revanced/library/adb/AdbManager$Companion;
|
||||
public synthetic fun <init> (Ljava/lang/String;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
|
||||
protected abstract fun getInstaller ()Lapp/revanced/library/installation/installer/Installer;
|
||||
public fun install (Lapp/revanced/library/adb/AdbManager$Apk;)Lkotlin/jvm/functions/Function1;
|
||||
public fun uninstall (Ljava/lang/String;)Lkotlin/jvm/functions/Function1;
|
||||
}
|
||||
|
||||
public final class app/revanced/library/adb/AdbManager$Apk {
|
||||
public fun <init> (Ljava/io/File;Ljava/lang/String;)V
|
||||
public synthetic fun <init> (Ljava/io/File;Ljava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
|
||||
public final fun getFile ()Ljava/io/File;
|
||||
public final fun getPackageName ()Ljava/lang/String;
|
||||
}
|
||||
|
||||
public final class app/revanced/library/adb/AdbManager$Companion {
|
||||
public final fun getAdbManager (Ljava/lang/String;Z)Lapp/revanced/library/adb/AdbManager;
|
||||
public static synthetic fun getAdbManager$default (Lapp/revanced/library/adb/AdbManager$Companion;Ljava/lang/String;ZILjava/lang/Object;)Lapp/revanced/library/adb/AdbManager;
|
||||
}
|
||||
|
||||
public final class app/revanced/library/adb/AdbManager$DeviceNotFoundException : java/lang/Exception {
|
||||
public fun <init> ()V
|
||||
}
|
||||
|
||||
public final class app/revanced/library/adb/AdbManager$FailedToFindInstalledPackageException : java/lang/Exception {
|
||||
}
|
||||
|
||||
public final class app/revanced/library/adb/AdbManager$PackageNameRequiredException : java/lang/Exception {
|
||||
}
|
||||
|
||||
public final class app/revanced/library/adb/AdbManager$RootAdbManager : app/revanced/library/adb/AdbManager {
|
||||
public static final field Utils Lapp/revanced/library/adb/AdbManager$RootAdbManager$Utils;
|
||||
public synthetic fun getInstaller ()Lapp/revanced/library/installation/installer/Installer;
|
||||
public fun install (Lapp/revanced/library/adb/AdbManager$Apk;)Lkotlin/jvm/functions/Function1;
|
||||
public fun uninstall (Ljava/lang/String;)Lkotlin/jvm/functions/Function1;
|
||||
}
|
||||
|
||||
public final class app/revanced/library/adb/AdbManager$RootAdbManager$Utils {
|
||||
}
|
||||
|
||||
public final class app/revanced/library/adb/AdbManager$UserAdbManager : app/revanced/library/adb/AdbManager {
|
||||
public synthetic fun getInstaller ()Lapp/revanced/library/installation/installer/Installer;
|
||||
public fun install (Lapp/revanced/library/adb/AdbManager$Apk;)Lkotlin/jvm/functions/Function1;
|
||||
public fun uninstall (Ljava/lang/String;)Lkotlin/jvm/functions/Function1;
|
||||
}
|
||||
|
||||
public final class app/revanced/library/installation/command/AdbShellCommandRunner : app/revanced/library/installation/command/ShellCommandRunner {
|
||||
}
|
||||
|
||||
public abstract interface class app/revanced/library/installation/command/RunResult {
|
||||
public abstract fun getError ()Ljava/lang/String;
|
||||
public abstract fun getExitCode ()I
|
||||
public abstract fun getOutput ()Ljava/lang/String;
|
||||
public abstract fun waitFor ()V
|
||||
}
|
||||
|
||||
public final class app/revanced/library/installation/command/RunResult$DefaultImpls {
|
||||
public static fun waitFor (Lapp/revanced/library/installation/command/RunResult;)V
|
||||
}
|
||||
|
||||
public abstract class app/revanced/library/installation/command/ShellCommandRunner {
|
||||
protected final fun getLogger ()Ljava/util/logging/Logger;
|
||||
protected abstract fun runCommand (Ljava/lang/String;)Lapp/revanced/library/installation/command/RunResult;
|
||||
}
|
||||
|
||||
public final class app/revanced/library/installation/installer/AdbInstaller : app/revanced/library/installation/installer/Installer {
|
||||
public fun <init> ()V
|
||||
public fun <init> (Ljava/lang/String;)V
|
||||
public synthetic fun <init> (Ljava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
|
||||
public fun getInstallation (Ljava/lang/String;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
||||
public fun install (Lapp/revanced/library/installation/installer/Installer$Apk;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
||||
public fun uninstall (Ljava/lang/String;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
||||
}
|
||||
|
||||
public abstract interface class app/revanced/library/installation/installer/AdbInstallerResult {
|
||||
}
|
||||
|
||||
public final class app/revanced/library/installation/installer/AdbInstallerResult$Failure : app/revanced/library/installation/installer/AdbInstallerResult {
|
||||
public final fun getException ()Ljava/lang/Exception;
|
||||
}
|
||||
|
||||
public final class app/revanced/library/installation/installer/AdbInstallerResult$Success : app/revanced/library/installation/installer/AdbInstallerResult {
|
||||
public static final field INSTANCE Lapp/revanced/library/installation/installer/AdbInstallerResult$Success;
|
||||
}
|
||||
|
||||
public final class app/revanced/library/installation/installer/AdbMountInstaller : app/revanced/library/installation/installer/MountInstaller {
|
||||
public fun <init> ()V
|
||||
public fun <init> (Ljava/lang/String;)V
|
||||
public synthetic fun <init> (Ljava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
|
||||
}
|
||||
|
||||
public class app/revanced/library/installation/installer/Installation {
|
||||
public final fun getApkFilePath ()Ljava/lang/String;
|
||||
}
|
||||
|
||||
public abstract class app/revanced/library/installation/installer/Installer {
|
||||
public abstract fun getInstallation (Ljava/lang/String;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
||||
protected final fun getLogger ()Ljava/util/logging/Logger;
|
||||
public abstract fun install (Lapp/revanced/library/installation/installer/Installer$Apk;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
||||
public abstract fun uninstall (Ljava/lang/String;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
||||
}
|
||||
|
||||
public final class app/revanced/library/installation/installer/Installer$Apk {
|
||||
public fun <init> (Ljava/io/File;Ljava/lang/String;)V
|
||||
public synthetic fun <init> (Ljava/io/File;Ljava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
|
||||
public final fun getFile ()Ljava/io/File;
|
||||
public final fun getPackageName ()Ljava/lang/String;
|
||||
}
|
||||
|
||||
public final class app/revanced/library/installation/installer/MountInstallation : app/revanced/library/installation/installer/Installation {
|
||||
public final fun getInstalledApkFilePath ()Ljava/lang/String;
|
||||
public final fun getMounted ()Z
|
||||
}
|
||||
|
||||
public abstract class app/revanced/library/installation/installer/MountInstaller : app/revanced/library/installation/installer/Installer {
|
||||
public fun getInstallation (Ljava/lang/String;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
||||
protected final fun getShellCommandRunner ()Lapp/revanced/library/installation/command/ShellCommandRunner;
|
||||
public fun install (Lapp/revanced/library/installation/installer/Installer$Apk;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
||||
protected final fun invoke (Ljava/lang/String;)Lapp/revanced/library/installation/command/RunResult;
|
||||
protected final fun move (Ljava/io/File;Ljava/lang/String;)V
|
||||
public fun uninstall (Ljava/lang/String;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
||||
protected final fun write (Ljava/lang/String;Ljava/lang/String;)V
|
||||
}
|
||||
|
||||
public final class app/revanced/library/installation/installer/MountInstallerResult : java/lang/Enum {
|
||||
public static final field FAILURE Lapp/revanced/library/installation/installer/MountInstallerResult;
|
||||
public static final field SUCCESS Lapp/revanced/library/installation/installer/MountInstallerResult;
|
||||
public static fun getEntries ()Lkotlin/enums/EnumEntries;
|
||||
public static fun valueOf (Ljava/lang/String;)Lapp/revanced/library/installation/installer/MountInstallerResult;
|
||||
public static fun values ()[Lapp/revanced/library/installation/installer/MountInstallerResult;
|
||||
}
|
||||
|
||||
public final class app/revanced/library/logging/Logger {
|
||||
public static final field INSTANCE Lapp/revanced/library/logging/Logger;
|
||||
public final fun addHandler (Lkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function0;)V
|
||||
public final fun removeAllHandlers ()V
|
||||
public final fun setDefault ()V
|
||||
public final fun setFormat (Ljava/lang/String;)V
|
||||
public static synthetic fun setFormat$default (Lapp/revanced/library/logging/Logger;Ljava/lang/String;ILjava/lang/Object;)V
|
||||
}
|
||||
|
||||
@@ -1,123 +0,0 @@
|
||||
plugins {
|
||||
alias(libs.plugins.kotlin.multiplatform)
|
||||
alias(libs.plugins.android.library)
|
||||
alias(libs.plugins.binary.compatibility.validator)
|
||||
`maven-publish`
|
||||
signing
|
||||
}
|
||||
|
||||
kotlin {
|
||||
jvm {
|
||||
compilations.all {
|
||||
kotlinOptions {
|
||||
jvmTarget = JavaVersion.VERSION_11.toString()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
androidTarget {
|
||||
compilations.all {
|
||||
kotlinOptions {
|
||||
jvmTarget = JavaVersion.VERSION_11.toString()
|
||||
}
|
||||
}
|
||||
|
||||
publishLibraryVariants("release")
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
androidMain.dependencies {
|
||||
implementation(libs.libsu.nio)
|
||||
implementation(libs.libsu.service)
|
||||
implementation(libs.core.ktx)
|
||||
}
|
||||
|
||||
commonMain.dependencies {
|
||||
implementation(libs.revanced.patcher)
|
||||
implementation(libs.kotlin.reflect)
|
||||
implementation(libs.jadb) // Fork with Shell v2 support.
|
||||
implementation(libs.bcpkix.jdk15on)
|
||||
implementation(libs.jackson.module.kotlin)
|
||||
implementation(libs.apkzlib)
|
||||
implementation(libs.apksig)
|
||||
implementation(libs.guava)
|
||||
}
|
||||
|
||||
commonTest.dependencies {
|
||||
implementation(libs.revanced.patcher)
|
||||
implementation(libs.kotlin.test.junit)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "app.revanced.library"
|
||||
compileSdk = 34
|
||||
defaultConfig {
|
||||
minSdk = 26
|
||||
}
|
||||
|
||||
buildFeatures {
|
||||
aidl = true
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility = JavaVersion.VERSION_11
|
||||
targetCompatibility = JavaVersion.VERSION_11
|
||||
}
|
||||
}
|
||||
|
||||
java {
|
||||
targetCompatibility = JavaVersion.VERSION_11
|
||||
}
|
||||
|
||||
publishing {
|
||||
repositories {
|
||||
maven {
|
||||
name = "GitHubPackages"
|
||||
url = uri("https://maven.pkg.github.com/revanced/revanced-library")
|
||||
credentials {
|
||||
username = System.getenv("GITHUB_ACTOR")
|
||||
password = System.getenv("GITHUB_TOKEN")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
publications {
|
||||
create<MavenPublication>("revanced-library-publication") {
|
||||
version = project.version.toString()
|
||||
|
||||
pom {
|
||||
name = "ReVanced Library"
|
||||
description = "Library containing common utilities for ReVanced"
|
||||
url = "https://revanced.app"
|
||||
|
||||
licenses {
|
||||
license {
|
||||
name = "GNU General Public License v3.0"
|
||||
url = "https://www.gnu.org/licenses/gpl-3.0.en.html"
|
||||
}
|
||||
}
|
||||
|
||||
developers {
|
||||
developer {
|
||||
id = "ReVanced"
|
||||
name = "ReVanced"
|
||||
email = "contact@revanced.app"
|
||||
}
|
||||
}
|
||||
|
||||
scm {
|
||||
connection = "scm:git:git://github.com/revanced/revanced-library.git"
|
||||
developerConnection = "scm:git:git@github.com:revanced/revanced-library.git"
|
||||
url = "https://github.com/revanced/revanced-library"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
signing {
|
||||
useGpgCmd()
|
||||
sign(publishing.publications["revanced-library-publication"])
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
@file:Suppress("DeprecatedCallableAddReplaceWith")
|
||||
|
||||
package app.revanced.library
|
||||
|
||||
import app.revanced.library.installation.command.AdbShellCommandRunner
|
||||
import se.vidstige.jadb.JadbDevice
|
||||
import se.vidstige.jadb.ShellProcessBuilder
|
||||
import java.io.File
|
||||
|
||||
@Deprecated("Do not use this anymore. Instead use AdbCommandRunner.")
|
||||
internal fun JadbDevice.buildCommand(
|
||||
command: String,
|
||||
su: Boolean = true,
|
||||
): ShellProcessBuilder {
|
||||
if (su) return shellProcessBuilder("su -c \'$command\'")
|
||||
|
||||
val args = command.split(" ") as ArrayList<String>
|
||||
val cmd = args.removeFirst()
|
||||
|
||||
return shellProcessBuilder(cmd, *args.toTypedArray())
|
||||
}
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
@Deprecated("Use AdbShellCommandRunner instead.")
|
||||
internal fun JadbDevice.run(
|
||||
command: String,
|
||||
su: Boolean = true,
|
||||
) = buildCommand(command, su).start()
|
||||
|
||||
@Deprecated("Use AdbShellCommandRunner instead.")
|
||||
internal fun JadbDevice.hasSu() = AdbShellCommandRunner(this).hasRootPermission()
|
||||
|
||||
@Deprecated("Use AdbShellCommandRunner instead.")
|
||||
internal fun JadbDevice.push(
|
||||
file: File,
|
||||
targetFilePath: String,
|
||||
) = AdbShellCommandRunner(this).move(file, targetFilePath)
|
||||
|
||||
@Deprecated("Use AdbShellCommandRunner instead.")
|
||||
internal fun JadbDevice.createFile(
|
||||
targetFile: String,
|
||||
content: String,
|
||||
) = AdbShellCommandRunner(this).write(content.byteInputStream(), targetFile)
|
||||
@@ -1,120 +0,0 @@
|
||||
@file:Suppress("MemberVisibilityCanBePrivate")
|
||||
|
||||
package app.revanced.library
|
||||
|
||||
import app.revanced.library.Options.Patch.Option
|
||||
import app.revanced.patcher.PatchSet
|
||||
import app.revanced.patcher.patch.options.PatchOptionException
|
||||
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
|
||||
import java.io.File
|
||||
import java.util.logging.Logger
|
||||
|
||||
@Suppress("unused")
|
||||
object Options {
|
||||
private val logger = Logger.getLogger(Options::class.java.name)
|
||||
|
||||
private val mapper = jacksonObjectMapper()
|
||||
|
||||
/**
|
||||
* Serializes the options for a set of patches.
|
||||
*
|
||||
* @param patches The set of patches to serialize.
|
||||
* @param prettyPrint Whether to pretty print the JSON.
|
||||
* @return The JSON string containing the options.
|
||||
*/
|
||||
fun serialize(
|
||||
patches: PatchSet,
|
||||
prettyPrint: Boolean = false,
|
||||
): String =
|
||||
patches
|
||||
.filter { it.options.any() }
|
||||
.map { patch ->
|
||||
Patch(
|
||||
patch.name!!,
|
||||
patch.options.values.map { option ->
|
||||
val optionValue =
|
||||
try {
|
||||
option.value
|
||||
} catch (e: PatchOptionException) {
|
||||
logger.warning("Using default option value for the ${patch.name} patch: ${e.message}")
|
||||
option.default
|
||||
}
|
||||
|
||||
Option(option.key, optionValue)
|
||||
},
|
||||
)
|
||||
}
|
||||
// See https://github.com/revanced/revanced-patches/pull/2434/commits/60e550550b7641705e81aa72acfc4faaebb225e7.
|
||||
.distinctBy { it.patchName }
|
||||
.let {
|
||||
if (prettyPrint) {
|
||||
mapper.writerWithDefaultPrettyPrinter().writeValueAsString(it)
|
||||
} else {
|
||||
mapper.writeValueAsString(it)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deserializes the options to a set of patches.
|
||||
*
|
||||
* @param json The JSON string containing the options.
|
||||
* @return A set of [Patch]s.
|
||||
* @see Patch
|
||||
*/
|
||||
fun deserialize(json: String): Array<Patch> = mapper.readValue(json, Array<Patch>::class.java)
|
||||
|
||||
/**
|
||||
* Sets the options for a set of patches.
|
||||
*
|
||||
* @param json The JSON string containing the options.
|
||||
*/
|
||||
fun PatchSet.setOptions(json: String) {
|
||||
filter { it.options.any() }.let { patches ->
|
||||
if (patches.isEmpty()) return
|
||||
|
||||
val jsonPatches =
|
||||
deserialize(json).associate {
|
||||
it.patchName to it.options.associate { option -> option.key to option.value }
|
||||
}
|
||||
|
||||
patches.forEach { patch ->
|
||||
jsonPatches[patch.name]?.let { jsonPatchOptions ->
|
||||
jsonPatchOptions.forEach { (option, value) ->
|
||||
try {
|
||||
patch.options[option] = value
|
||||
} catch (e: PatchOptionException) {
|
||||
logger.warning("Could not set option value for the ${patch.name} patch: ${e.message}")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the options for a set of patches.
|
||||
*
|
||||
* @param file The file containing the JSON string containing the options.
|
||||
* @see setOptions
|
||||
*/
|
||||
fun PatchSet.setOptions(file: File) = setOptions(file.readText())
|
||||
|
||||
/**
|
||||
* Data class for a patch and its [Option]s.
|
||||
*
|
||||
* @property patchName The name of the patch.
|
||||
* @property options The [Option]s for the patch.
|
||||
*/
|
||||
class Patch internal constructor(
|
||||
val patchName: String,
|
||||
val options: List<Option>,
|
||||
) {
|
||||
/**
|
||||
* Data class for patch option.
|
||||
*
|
||||
* @property key The name of the option.
|
||||
* @property value The value of the option.
|
||||
*/
|
||||
class Option internal constructor(val key: String, val value: Any?)
|
||||
}
|
||||
}
|
||||
@@ -1,169 +0,0 @@
|
||||
package app.revanced.library
|
||||
|
||||
import app.revanced.patcher.PatchSet
|
||||
import app.revanced.patcher.patch.Patch
|
||||
import app.revanced.patcher.patch.options.PatchOption
|
||||
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
|
||||
import java.io.InputStream
|
||||
import java.io.OutputStream
|
||||
import kotlin.reflect.jvm.jvmName
|
||||
|
||||
typealias PackageName = String
|
||||
typealias Version = String
|
||||
typealias Count = Int
|
||||
|
||||
typealias VersionMap = LinkedHashMap<Version, Count>
|
||||
typealias PackageNameMap = Map<PackageName, VersionMap>
|
||||
|
||||
/**
|
||||
* Utility functions for working with patches.
|
||||
*/
|
||||
@Suppress("MemberVisibilityCanBePrivate", "unused")
|
||||
object PatchUtils {
|
||||
/**
|
||||
* Get the count of versions for each compatible package from a supplied set of [patches] ordered by the most common version.
|
||||
*
|
||||
* @param patches The set of patches to check.
|
||||
* @param packageNames The names of the compatible packages to include. If null, all packages will be included.
|
||||
* @param countUnusedPatches Whether to count patches that are not used.
|
||||
* @return A map of package names to a map of versions to their count.
|
||||
*/
|
||||
fun getMostCommonCompatibleVersions(
|
||||
patches: PatchSet,
|
||||
packageNames: Set<String>? = null,
|
||||
countUnusedPatches: Boolean = false,
|
||||
): PackageNameMap =
|
||||
buildMap {
|
||||
fun filterWantedPackages(compatiblePackages: Iterable<Patch.CompatiblePackage>): Iterable<Patch.CompatiblePackage> {
|
||||
val wantedPackages = packageNames?.toHashSet() ?: return compatiblePackages
|
||||
return compatiblePackages.filter { it.name in wantedPackages }
|
||||
}
|
||||
|
||||
patches
|
||||
.filter { it.use || countUnusedPatches }
|
||||
.flatMap { it.compatiblePackages ?: emptyList() }
|
||||
.let(::filterWantedPackages)
|
||||
.forEach { compatiblePackage ->
|
||||
if (compatiblePackage.versions?.isEmpty() == true) {
|
||||
return@forEach
|
||||
}
|
||||
|
||||
val versionMap = getOrPut(compatiblePackage.name) { linkedMapOf() }
|
||||
|
||||
compatiblePackage.versions?.let { versions ->
|
||||
versions.forEach { version ->
|
||||
versionMap[version] = versionMap.getOrDefault(version, 0) + 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sort the version maps by the most common version.
|
||||
forEach { (packageName, versionMap) ->
|
||||
this[packageName] =
|
||||
versionMap
|
||||
.asIterable()
|
||||
.sortedWith(compareByDescending { it.value })
|
||||
.associate { it.key to it.value } as VersionMap
|
||||
}
|
||||
}
|
||||
|
||||
object Json {
|
||||
private val mapper = jacksonObjectMapper()
|
||||
|
||||
/**
|
||||
* Serializes a set of [Patch]es to a JSON string and writes it to an output stream.
|
||||
*
|
||||
* @param patches The set of [Patch]es to serialize.
|
||||
* @param transform A function to transform the [Patch]es to [JsonPatch]es.
|
||||
* @param prettyPrint Whether to pretty print the JSON.
|
||||
* @param outputStream The output stream to write the JSON to.
|
||||
*/
|
||||
fun serialize(
|
||||
patches: PatchSet,
|
||||
transform: (Patch<*>) -> JsonPatch = { patch -> FullJsonPatch.fromPatch(patch) },
|
||||
prettyPrint: Boolean = false,
|
||||
outputStream: OutputStream,
|
||||
) {
|
||||
patches.map(transform).let { transformed ->
|
||||
if (prettyPrint) {
|
||||
mapper.writerWithDefaultPrettyPrinter().writeValue(outputStream, transformed)
|
||||
} else {
|
||||
mapper.writeValue(outputStream, transformed)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deserializes a JSON string to a set of [FullJsonPatch]es from an input stream.
|
||||
*
|
||||
* @param inputStream The input stream to read the JSON from.
|
||||
* @param jsonPatchElementClass The class of the [JsonPatch]es to deserialize.
|
||||
* @return A set of [JsonPatch]es.
|
||||
* @see FullJsonPatch
|
||||
*/
|
||||
fun <T : JsonPatch> deserialize(
|
||||
inputStream: InputStream,
|
||||
jsonPatchElementClass: Class<T>,
|
||||
): Set<T> =
|
||||
mapper.readValue(
|
||||
inputStream,
|
||||
mapper.typeFactory.constructCollectionType(Set::class.java, jsonPatchElementClass),
|
||||
)
|
||||
|
||||
interface JsonPatch
|
||||
|
||||
/**
|
||||
* A JSON representation of a [Patch].
|
||||
* @see Patch
|
||||
*/
|
||||
class FullJsonPatch internal constructor(
|
||||
val name: String?,
|
||||
val description: String?,
|
||||
val compatiblePackages: Set<Patch.CompatiblePackage>?,
|
||||
val dependencies: Set<String>?,
|
||||
val use: Boolean,
|
||||
var requiresIntegrations: Boolean,
|
||||
val options: Map<String, FullJsonPatchOption<*>>,
|
||||
) : JsonPatch {
|
||||
companion object {
|
||||
fun fromPatch(patch: Patch<*>) =
|
||||
FullJsonPatch(
|
||||
patch.name,
|
||||
patch.description,
|
||||
patch.compatiblePackages,
|
||||
buildSet { patch.dependencies?.forEach { add(it.jvmName) } },
|
||||
patch.use,
|
||||
patch.requiresIntegrations,
|
||||
patch.options.mapValues { FullJsonPatchOption.fromPatchOption(it.value) },
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* A JSON representation of a [PatchOption].
|
||||
* @see PatchOption
|
||||
*/
|
||||
class FullJsonPatchOption<T> internal constructor(
|
||||
val key: String,
|
||||
val default: T?,
|
||||
val values: Map<String, T?>?,
|
||||
val title: String?,
|
||||
val description: String?,
|
||||
val required: Boolean,
|
||||
val valueType: String,
|
||||
) {
|
||||
companion object {
|
||||
fun fromPatchOption(option: PatchOption<*>) =
|
||||
FullJsonPatchOption(
|
||||
option.key,
|
||||
option.default,
|
||||
option.values,
|
||||
option.title,
|
||||
option.description,
|
||||
option.required,
|
||||
option.valueType,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,144 +0,0 @@
|
||||
@file:Suppress("DEPRECATION")
|
||||
|
||||
package app.revanced.library.adb
|
||||
|
||||
import app.revanced.library.adb.AdbManager.Apk
|
||||
import app.revanced.library.installation.installer.AdbInstaller
|
||||
import app.revanced.library.installation.installer.AdbMountInstaller
|
||||
import app.revanced.library.installation.installer.Constants.PLACEHOLDER
|
||||
import app.revanced.library.installation.installer.Installer
|
||||
import app.revanced.library.run
|
||||
import se.vidstige.jadb.JadbDevice
|
||||
import java.io.File
|
||||
|
||||
/**
|
||||
* [AdbManager] to install and uninstall [Apk] files.
|
||||
*
|
||||
* @param deviceSerial The serial of the device. If null, the first connected device will be used.
|
||||
*/
|
||||
@Deprecated("Use an implementation of Installer instead.")
|
||||
@Suppress("unused")
|
||||
sealed class AdbManager private constructor(
|
||||
@Suppress("UNUSED_PARAMETER") deviceSerial: String?,
|
||||
) {
|
||||
protected abstract val installer: Installer<*, *>
|
||||
|
||||
/**
|
||||
* Installs the [Apk] file.
|
||||
*
|
||||
* @param apk The [Apk] file.
|
||||
*/
|
||||
@Suppress("DeprecatedCallableAddReplaceWith")
|
||||
@Deprecated("Use Installer.install instead.")
|
||||
open fun install(apk: Apk) = suspend {
|
||||
installer.install(Installer.Apk(apk.file, apk.packageName))
|
||||
}
|
||||
|
||||
/**
|
||||
* Uninstalls the package.
|
||||
*
|
||||
* @param packageName The package name.
|
||||
*/
|
||||
@Suppress("DeprecatedCallableAddReplaceWith")
|
||||
@Deprecated("Use Installer.uninstall instead.")
|
||||
open fun uninstall(packageName: String) = suspend {
|
||||
installer.uninstall(packageName)
|
||||
}
|
||||
|
||||
@Deprecated("Use Installer instead.")
|
||||
companion object {
|
||||
/**
|
||||
* Gets an [AdbManager] for the supplied device serial.
|
||||
*
|
||||
* @param deviceSerial The device serial. If null, the first connected device will be used.
|
||||
* @param root Whether to use root or not.
|
||||
* @return The [AdbManager].
|
||||
* @throws DeviceNotFoundException If the device can not be found.
|
||||
*/
|
||||
@Suppress("DeprecatedCallableAddReplaceWith")
|
||||
@Deprecated("This is deprecated.")
|
||||
fun getAdbManager(
|
||||
deviceSerial: String? = null,
|
||||
root: Boolean = false,
|
||||
): AdbManager = if (root) RootAdbManager(deviceSerial) else UserAdbManager(deviceSerial)
|
||||
}
|
||||
|
||||
/**
|
||||
* Adb manager for rooted devices.
|
||||
*
|
||||
* @param deviceSerial The device serial. If null, the first connected device will be used.
|
||||
*/
|
||||
@Deprecated("Use AdbMountInstaller instead.", ReplaceWith("AdbMountInstaller(deviceSerial)"))
|
||||
class RootAdbManager internal constructor(deviceSerial: String?) : AdbManager(deviceSerial) {
|
||||
override val installer = AdbMountInstaller(deviceSerial)
|
||||
|
||||
@Suppress("DeprecatedCallableAddReplaceWith")
|
||||
@Deprecated("Use AdbMountInstaller.install instead.")
|
||||
override fun install(apk: Apk) = suspend {
|
||||
installer.install(Installer.Apk(apk.file, apk.packageName))
|
||||
}
|
||||
|
||||
@Suppress("DeprecatedCallableAddReplaceWith")
|
||||
@Deprecated("Use AdbMountInstaller.uninstall instead.")
|
||||
override fun uninstall(packageName: String) = suspend {
|
||||
installer.uninstall(packageName)
|
||||
}
|
||||
|
||||
@Deprecated("This is deprecated.")
|
||||
companion object Utils {
|
||||
private fun JadbDevice.run(
|
||||
command: String,
|
||||
with: String,
|
||||
) = run(command.applyReplacement(with))
|
||||
|
||||
private fun String.applyReplacement(with: String) = replace(PLACEHOLDER, with)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adb manager for non-rooted devices.
|
||||
*
|
||||
* @param deviceSerial The device serial. If null, the first connected device will be used.
|
||||
*/
|
||||
@Deprecated("Use AdbInstaller instead.")
|
||||
class UserAdbManager internal constructor(deviceSerial: String?) : AdbManager(deviceSerial) {
|
||||
override val installer = AdbInstaller(deviceSerial)
|
||||
|
||||
@Suppress("DeprecatedCallableAddReplaceWith")
|
||||
@Deprecated("Use AdbInstaller.install instead.")
|
||||
override fun install(apk: Apk) = suspend {
|
||||
installer.install(Installer.Apk(apk.file, apk.packageName))
|
||||
}
|
||||
|
||||
@Suppress("DeprecatedCallableAddReplaceWith")
|
||||
@Deprecated("Use AdbInstaller.uninstall instead.")
|
||||
override fun uninstall(packageName: String) = suspend {
|
||||
installer.uninstall(packageName)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Apk file for [AdbManager].
|
||||
*
|
||||
* @param file The [Apk] file.
|
||||
* @param packageName The package name of the [Apk] file.
|
||||
*/
|
||||
@Deprecated("Use Installer.Apk instead.")
|
||||
class Apk(val file: File, val packageName: String? = null)
|
||||
|
||||
@Deprecated("Use AdbCommandRunner.DeviceNotFoundException instead.")
|
||||
class DeviceNotFoundException internal constructor(deviceSerial: String? = null) :
|
||||
Exception(
|
||||
deviceSerial?.let {
|
||||
"The device with the ADB device serial \"$deviceSerial\" can not be found"
|
||||
} ?: "No ADB device found",
|
||||
)
|
||||
|
||||
@Deprecated("Use MountInstaller.FailedToFindInstalledPackageException instead.")
|
||||
class FailedToFindInstalledPackageException internal constructor(packageName: String) :
|
||||
Exception("Failed to find installed package \"$packageName\" because no activity was found")
|
||||
|
||||
@Deprecated("Use MountInstaller.PackageNameRequiredException instead.")
|
||||
class PackageNameRequiredException internal constructor() :
|
||||
Exception("Package name is required")
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
package app.revanced.library.installation.installer
|
||||
|
||||
import se.vidstige.jadb.JadbConnection
|
||||
import java.util.logging.Logger
|
||||
|
||||
/**
|
||||
* Utility functions for [Installer].
|
||||
*
|
||||
* @see Installer
|
||||
*/
|
||||
internal object Utils {
|
||||
/**
|
||||
* Gets the device with the given serial.
|
||||
*
|
||||
* @param deviceSerial The device serial. If null, the first connected device will be used.
|
||||
* @param logger The logger.
|
||||
* @return The device.
|
||||
* @throws DeviceNotFoundException If no device with the given serial is found.
|
||||
*/
|
||||
internal fun getDevice(
|
||||
deviceSerial: String? = null,
|
||||
logger: Logger,
|
||||
) = with(JadbConnection().devices) {
|
||||
if (isEmpty()) throw DeviceNotFoundException()
|
||||
|
||||
deviceSerial?.let {
|
||||
firstOrNull { it.serial == deviceSerial } ?: throw DeviceNotFoundException(
|
||||
deviceSerial,
|
||||
)
|
||||
} ?: first().also {
|
||||
logger.warning("No device serial supplied. Using device with serial ${it.serial}")
|
||||
}
|
||||
}!!
|
||||
|
||||
class DeviceNotFoundException internal constructor(deviceSerial: String? = null) : Exception(
|
||||
deviceSerial?.let {
|
||||
"The device with the ADB device serial \"$deviceSerial\" can not be found"
|
||||
} ?: "No ADB device found",
|
||||
)
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
package app.revanced.library
|
||||
|
||||
import app.revanced.library.Options.setOptions
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patcher.patch.annotation.Patch
|
||||
import app.revanced.patcher.patch.options.PatchOption.PatchExtensions.booleanPatchOption
|
||||
import app.revanced.patcher.patch.options.PatchOption.PatchExtensions.stringPatchOption
|
||||
import kotlin.test.Test
|
||||
|
||||
class PatchOptionsTest {
|
||||
private var patches = setOf(PatchOptionsTestPatch)
|
||||
|
||||
private val serializedJson =
|
||||
"[{\"patchName\":\"PatchOptionsTestPatch\",\"options\":[{\"key\":\"key1\",\"value\":null},{\"key\":\"key2\"," +
|
||||
"\"value\":true}]}]"
|
||||
|
||||
private val changedJson =
|
||||
"[{\"patchName\":\"PatchOptionsTestPatch\",\"options\":[{\"key\":\"key1\",\"value\":\"test\"},{\"key\":\"key2" +
|
||||
"\",\"value\":false}]}]"
|
||||
|
||||
@Test
|
||||
fun `serializes and deserializes`() {
|
||||
assert(serializedJson == Options.serialize(patches))
|
||||
|
||||
patches.setOptions(changedJson)
|
||||
|
||||
assert(PatchOptionsTestPatch.option1 == "test")
|
||||
assert(PatchOptionsTestPatch.option2 == false)
|
||||
}
|
||||
|
||||
@Patch("PatchOptionsTestPatch")
|
||||
object PatchOptionsTestPatch : BytecodePatch(emptySet()) {
|
||||
var option1 by stringPatchOption("key1", null, null, "title1", "description1")
|
||||
var option2 by booleanPatchOption("key2", true, null, "title2", "description2")
|
||||
|
||||
override fun execute(context: BytecodeContext) {
|
||||
// Do nothing
|
||||
}
|
||||
}
|
||||
}
|
||||
3002
package-lock.json
generated
3002
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -3,7 +3,7 @@
|
||||
"@saithodev/semantic-release-backmerge": "^4.0.1",
|
||||
"@semantic-release/changelog": "^6.0.3",
|
||||
"@semantic-release/git": "^10.0.1",
|
||||
"gradle-semantic-release-plugin": "^1.9.1",
|
||||
"semantic-release": "^23.0.2"
|
||||
"gradle-semantic-release-plugin": "^1.10.1",
|
||||
"semantic-release": "^24.1.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// TODO: Figure out why this causes problems.
|
||||
rootProject.name = "revanced-library"
|
||||
|
||||
buildCache {
|
||||
local {
|
||||
isEnabled = "CI" !in System.getenv()
|
||||
@@ -6,10 +9,7 @@ buildCache {
|
||||
|
||||
pluginManagement {
|
||||
repositories {
|
||||
gradlePluginPortal()
|
||||
mavenCentral()
|
||||
google()
|
||||
mavenCentral()
|
||||
}
|
||||
}
|
||||
|
||||
include(":library", ":library-networking")
|
||||
|
||||
@@ -3,15 +3,15 @@ package app.revanced.library.installation.installer
|
||||
import android.content.Context
|
||||
import app.revanced.library.installation.command.LocalShellCommandRunner
|
||||
import app.revanced.library.installation.installer.Installer.Apk
|
||||
import app.revanced.library.installation.installer.MountInstaller.NoRootPermissionException
|
||||
import app.revanced.library.installation.installer.RootInstaller.NoRootPermissionException
|
||||
import com.topjohnwu.superuser.ipc.RootService
|
||||
import java.io.Closeable
|
||||
|
||||
/**
|
||||
* [LocalMountInstaller] for installing and uninstalling [Apk] files locally with using root permissions by mounting.
|
||||
* [LocalRootInstaller] for installing and uninstalling [Apk] files locally with using root permissions by mounting.
|
||||
*
|
||||
* @param context The [Context] to use for binding to the [RootService].
|
||||
* @param onReady A callback to be invoked when [LocalMountInstaller] is ready to be used.
|
||||
* @param onReady A callback to be invoked when [LocalRootInstaller] is ready to be used.
|
||||
*
|
||||
* @throws NoRootPermissionException If the device does not have root permission.
|
||||
*
|
||||
@@ -19,13 +19,13 @@ import java.io.Closeable
|
||||
* @see LocalShellCommandRunner
|
||||
*/
|
||||
@Suppress("unused")
|
||||
class LocalMountInstaller(
|
||||
class LocalRootInstaller(
|
||||
context: Context,
|
||||
onReady: LocalMountInstaller.() -> Unit = {},
|
||||
) : MountInstaller(
|
||||
onReady: LocalRootInstaller.() -> Unit = {},
|
||||
) : RootInstaller(
|
||||
{ installer ->
|
||||
LocalShellCommandRunner(context) {
|
||||
(installer as LocalMountInstaller).onReady()
|
||||
(installer as LocalRootInstaller).onReady()
|
||||
}
|
||||
},
|
||||
),
|
||||
@@ -1,9 +1,6 @@
|
||||
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.SigningOptions
|
||||
import com.android.tools.build.apkzlib.zip.ZFile
|
||||
import org.bouncycastle.asn1.x500.X500Name
|
||||
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo
|
||||
import org.bouncycastle.cert.X509v3CertificateBuilder
|
||||
@@ -13,7 +10,6 @@ import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder
|
||||
import java.io.File
|
||||
import java.io.IOException
|
||||
import java.io.InputStream
|
||||
import java.io.OutputStream
|
||||
import java.math.BigInteger
|
||||
import java.security.*
|
||||
import java.security.cert.X509Certificate
|
||||
@@ -197,105 +193,6 @@ object ApkSigner {
|
||||
),
|
||||
)
|
||||
|
||||
/**
|
||||
* Read a [PrivateKeyCertificatePair] from a keystore entry.
|
||||
*
|
||||
* @param keyStore The keystore to read the entry from.
|
||||
* @param keyStoreEntryAlias The alias of the key store entry to read.
|
||||
* @param keyStoreEntryPassword The password for recovering the signing key.
|
||||
*
|
||||
* @return The read [PrivateKeyCertificatePair].
|
||||
*
|
||||
* @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].
|
||||
*
|
||||
* @param keyStoreOutputStream The stream to write the keystore to.
|
||||
* @param keyStorePassword The password for the keystore.
|
||||
* @param entries The entries to add to the keystore.
|
||||
*/
|
||||
@Deprecated("This method will be removed in the future.")
|
||||
fun newKeyStore(
|
||||
keyStoreOutputStream: OutputStream,
|
||||
keyStorePassword: String?,
|
||||
entries: Set<KeyStoreEntry>,
|
||||
) = newKeyStore(entries).store(
|
||||
keyStoreOutputStream,
|
||||
keyStorePassword?.toCharArray(),
|
||||
)
|
||||
|
||||
/**
|
||||
* Create a new [Signer].
|
||||
*
|
||||
* @param privateKeyCertificatePair The private key and certificate pair to use for signing.
|
||||
*
|
||||
* @return The new [Signer].
|
||||
*
|
||||
* @see PrivateKeyCertificatePair
|
||||
* @see Signer
|
||||
*/
|
||||
@Deprecated("This method will be removed in the future.")
|
||||
fun newApkSigner(privateKeyCertificatePair: PrivateKeyCertificatePair) =
|
||||
Signer(
|
||||
SigningExtension(
|
||||
SigningOptions.builder()
|
||||
.setMinSdkVersion(21) // TODO: Extracting from the target APK would be ideal.
|
||||
.setV1SigningEnabled(true)
|
||||
.setV2SigningEnabled(true)
|
||||
.setCertificates(privateKeyCertificatePair.certificate)
|
||||
.setKey(privateKeyCertificatePair.privateKey)
|
||||
.build(),
|
||||
),
|
||||
)
|
||||
|
||||
/**
|
||||
* Create a new [Signer].
|
||||
*
|
||||
* @param signer The name of the 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(
|
||||
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(
|
||||
keyStore: KeyStore,
|
||||
keyStoreEntryAlias: String,
|
||||
keyStoreEntryPassword: String,
|
||||
) = newApkSigner("ReVanced", readKeyCertificatePair(keyStore, keyStoreEntryAlias, keyStoreEntryPassword))
|
||||
|
||||
/**
|
||||
* An entry in a keystore.
|
||||
*
|
||||
@@ -322,48 +219,11 @@ object ApkSigner {
|
||||
val certificate: X509Certificate,
|
||||
)
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
class Signer internal constructor(private val signerBuilder: com.android.apksig.ApkSigner.Builder) {
|
||||
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.
|
||||
*
|
||||
* @param apkFile The APK file to sign.
|
||||
*/
|
||||
@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.
|
||||
*
|
||||
* @param apkZFile The APK [ZFile] to sign.
|
||||
*/
|
||||
@Deprecated("This method will be removed in the future.")
|
||||
fun signApk(apkZFile: ZFile) {
|
||||
logger.info("Signing ${apkZFile.file.name}")
|
||||
|
||||
signingExtension?.register(apkZFile)
|
||||
signerBuilder.setInputApk(inputApkFile)?.setOutputApk(outputApkFile)?.build()?.sign()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -82,7 +82,7 @@ object ApkUtils {
|
||||
// Delete resources that were staged for deletion.
|
||||
if (resources.deleteResources.isNotEmpty()) {
|
||||
targetApkZFile.entries().filter { entry ->
|
||||
resources.deleteResources.any { shouldDelete -> shouldDelete(entry.centralDirectoryHeader.name) }
|
||||
entry.centralDirectoryHeader.name in resources.deleteResources
|
||||
}.forEach(StoredEntry::delete)
|
||||
}
|
||||
}
|
||||
@@ -103,8 +103,7 @@ object ApkUtils {
|
||||
*
|
||||
* @return The newly created private key and certificate pair.
|
||||
*/
|
||||
@Deprecated("This method will be removed in the future.")
|
||||
fun newPrivateKeyCertificatePair(
|
||||
private fun newPrivateKeyCertificatePair(
|
||||
privateKeyCertificatePairDetails: PrivateKeyCertificatePairDetails,
|
||||
keyStoreDetails: KeyStoreDetails,
|
||||
) = newPrivateKeyCertificatePair(
|
||||
@@ -132,8 +131,7 @@ object ApkUtils {
|
||||
*
|
||||
* @return The private key and certificate pair.
|
||||
*/
|
||||
@Deprecated("This method will be removed in the future.")
|
||||
fun readPrivateKeyCertificatePairFromKeyStore(
|
||||
private fun readPrivateKeyCertificatePairFromKeyStore(
|
||||
keyStoreDetails: KeyStoreDetails,
|
||||
) = ApkSigner.readPrivateKeyCertificatePair(
|
||||
ApkSigner.readKeyStore(
|
||||
@@ -168,91 +166,6 @@ object ApkUtils {
|
||||
},
|
||||
).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.
|
||||
*
|
||||
* @param signingOptions The options to use for signing.
|
||||
*/
|
||||
@Deprecated("This method will be removed in the future.")
|
||||
fun File.sign(signingOptions: SigningOptions) = ApkSigner.newApkSigner(
|
||||
signingOptions.signer,
|
||||
readOrNewPrivateKeyCertificatePair(signingOptions),
|
||||
).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.
|
||||
*/
|
||||
@Deprecated("This method will be removed in the future.")
|
||||
fun sign(inputApkFile: File, outputApkFile: File, signingOptions: SigningOptions) = sign(
|
||||
inputApkFile,
|
||||
outputApkFile,
|
||||
signingOptions.signer,
|
||||
readOrNewPrivateKeyCertificatePair(signingOptions),
|
||||
)
|
||||
|
||||
/**
|
||||
* Options for signing an apk.
|
||||
*
|
||||
* @param keyStore The keystore to use for signing.
|
||||
* @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.
|
||||
* @param signer The name of the signer.
|
||||
*/
|
||||
@Deprecated("This class will be removed in the future.")
|
||||
class SigningOptions(
|
||||
val keyStore: File,
|
||||
val keyStorePassword: String?,
|
||||
val alias: String = "ReVanced Key",
|
||||
val password: String = "",
|
||||
val signer: String = "ReVanced",
|
||||
)
|
||||
|
||||
/**
|
||||
* Details for a keystore.
|
||||
*
|
||||
36
src/commonMain/kotlin/app/revanced/library/Options.kt
Normal file
36
src/commonMain/kotlin/app/revanced/library/Options.kt
Normal file
@@ -0,0 +1,36 @@
|
||||
@file:Suppress("MemberVisibilityCanBePrivate")
|
||||
|
||||
package app.revanced.library
|
||||
|
||||
import app.revanced.patcher.patch.OptionException
|
||||
import app.revanced.patcher.patch.Patch
|
||||
import java.util.logging.Logger
|
||||
|
||||
typealias PatchName = String
|
||||
typealias OptionKey = String
|
||||
typealias OptionValue = Any?
|
||||
typealias PatchesOptions = Map<PatchName, Map<OptionKey, OptionValue>>
|
||||
|
||||
private val logger = Logger.getLogger("Options")
|
||||
|
||||
/**
|
||||
* Set the options for a set of patches that have a name.
|
||||
*
|
||||
* @param options The options to set. The key is the patch name and the value is a map of option keys to option values.
|
||||
*/
|
||||
fun Set<Patch<*>>.setOptions(options: PatchesOptions) = filter { it.name != null }.forEach { patch ->
|
||||
options[patch.name]?.forEach setOption@{ (optionKey, optionValue) ->
|
||||
if (optionKey !in patch.options) {
|
||||
return@setOption logger.warning(
|
||||
"Could not set option for the \"${patch.name}\" patch because " +
|
||||
"option with key \"${optionKey}\" does not exist",
|
||||
)
|
||||
}
|
||||
|
||||
try {
|
||||
patch.options[optionKey] = optionValue
|
||||
} catch (e: OptionException) {
|
||||
logger.warning("Could not set option value for the \"${patch.name}\" patch: ${e.message}")
|
||||
}
|
||||
}
|
||||
}
|
||||
52
src/commonMain/kotlin/app/revanced/library/Patch.kt
Normal file
52
src/commonMain/kotlin/app/revanced/library/Patch.kt
Normal file
@@ -0,0 +1,52 @@
|
||||
package app.revanced.library
|
||||
|
||||
import app.revanced.patcher.patch.Package
|
||||
import app.revanced.patcher.patch.Patch
|
||||
|
||||
typealias PackageName = String
|
||||
typealias Version = String
|
||||
typealias Count = Int
|
||||
|
||||
typealias VersionMap = LinkedHashMap<Version, Count>
|
||||
typealias PackageNameMap = Map<PackageName, VersionMap>
|
||||
|
||||
/**
|
||||
* Get the count of versions for each compatible package from the set of [Patch] ordered by the most common version.
|
||||
*
|
||||
* @param packageNames The names of the compatible packages to include. If null, all packages will be included.
|
||||
* @param countUnusedPatches Whether to count patches that are not used.
|
||||
* @return A map of package names to a map of versions to their count.
|
||||
*/
|
||||
fun Set<Patch<*>>.mostCommonCompatibleVersions(
|
||||
packageNames: Set<String>? = null,
|
||||
countUnusedPatches: Boolean = false,
|
||||
): PackageNameMap = buildMap {
|
||||
fun filterWantedPackages(compatiblePackages: List<Package>): List<Package> {
|
||||
val wantedPackages = packageNames?.toHashSet() ?: return compatiblePackages
|
||||
return compatiblePackages.filter { (name, _) -> name in wantedPackages }
|
||||
}
|
||||
|
||||
this@mostCommonCompatibleVersions.filter { it.use || countUnusedPatches }
|
||||
.flatMap { it.compatiblePackages ?: emptyList() }
|
||||
.let(::filterWantedPackages)
|
||||
.forEach { (name, versions) ->
|
||||
if (versions?.isEmpty() == true) {
|
||||
return@forEach
|
||||
}
|
||||
|
||||
val versionMap = getOrPut(name) { linkedMapOf() }
|
||||
|
||||
versions?.forEach { version ->
|
||||
versionMap[version] = versionMap.getOrDefault(version, 0) + 1
|
||||
}
|
||||
}
|
||||
|
||||
// Sort the version maps by the most common version.
|
||||
forEach { (packageName, versionMap) ->
|
||||
this[packageName] =
|
||||
versionMap
|
||||
.asIterable()
|
||||
.sortedWith(compareByDescending { it.value })
|
||||
.associate { it.key to it.value } as VersionMap
|
||||
}
|
||||
}
|
||||
119
src/commonMain/kotlin/app/revanced/library/Serialization.kt
Normal file
119
src/commonMain/kotlin/app/revanced/library/Serialization.kt
Normal file
@@ -0,0 +1,119 @@
|
||||
package app.revanced.library
|
||||
|
||||
import app.revanced.patcher.patch.Option
|
||||
import app.revanced.patcher.patch.Patch
|
||||
import app.revanced.patcher.patch.VersionName
|
||||
import kotlinx.serialization.ExperimentalSerializationApi
|
||||
import kotlinx.serialization.KSerializer
|
||||
import kotlinx.serialization.builtins.*
|
||||
import kotlinx.serialization.descriptors.buildClassSerialDescriptor
|
||||
import kotlinx.serialization.descriptors.element
|
||||
import kotlinx.serialization.encoding.Decoder
|
||||
import kotlinx.serialization.encoding.Encoder
|
||||
import kotlinx.serialization.encoding.encodeStructure
|
||||
import kotlinx.serialization.json.Json
|
||||
import kotlinx.serialization.json.encodeToStream
|
||||
import kotlinx.serialization.serializer
|
||||
import java.io.OutputStream
|
||||
|
||||
private class PatchSerializer : KSerializer<Patch<*>> {
|
||||
override val descriptor = buildClassSerialDescriptor("Patch") {
|
||||
element<String?>("name")
|
||||
element<String?>("description")
|
||||
element<Boolean>("use")
|
||||
element<List<String>>("dependencies")
|
||||
element<Map<PackageName, Set<VersionName>?>?>("compatiblePackages")
|
||||
element("options", OptionSerializer.descriptor)
|
||||
}
|
||||
|
||||
override fun deserialize(decoder: Decoder) = throw NotImplementedError("Deserialization is unsupported")
|
||||
|
||||
@OptIn(ExperimentalSerializationApi::class)
|
||||
override fun serialize(encoder: Encoder, value: Patch<*>) {
|
||||
encoder.encodeStructure(descriptor) {
|
||||
encodeNullableSerializableElement(
|
||||
descriptor,
|
||||
0,
|
||||
String.serializer(),
|
||||
value.name,
|
||||
)
|
||||
encodeNullableSerializableElement(
|
||||
descriptor,
|
||||
1,
|
||||
String.serializer(),
|
||||
value.description,
|
||||
)
|
||||
encodeBooleanElement(
|
||||
descriptor,
|
||||
2,
|
||||
value.use,
|
||||
)
|
||||
encodeSerializableElement(
|
||||
descriptor,
|
||||
3,
|
||||
ListSerializer(String.serializer()),
|
||||
value.dependencies.map { it.name ?: it.toString() },
|
||||
)
|
||||
encodeNullableSerializableElement(
|
||||
descriptor,
|
||||
4,
|
||||
MapSerializer(String.serializer(), SetSerializer(String.serializer()).nullable),
|
||||
value.compatiblePackages?.associate { (packageName, versions) -> packageName to versions },
|
||||
)
|
||||
encodeSerializableElement(
|
||||
descriptor,
|
||||
5,
|
||||
SetSerializer(OptionSerializer),
|
||||
value.options.values.toSet(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private object OptionSerializer : KSerializer<Option<*>> {
|
||||
override val descriptor = buildClassSerialDescriptor("Option") {
|
||||
element<String>("key")
|
||||
element<String?>("title")
|
||||
element<String?>("description")
|
||||
element<Boolean>("required")
|
||||
// Type does not matter for serialization. Using String.
|
||||
element<String>("type")
|
||||
element<String?>("default")
|
||||
// Map value type does not matter for serialization. Using String.
|
||||
element<Map<String, String?>?>("values")
|
||||
}
|
||||
|
||||
override fun deserialize(decoder: Decoder) = throw NotImplementedError("Deserialization is unsupported")
|
||||
|
||||
@OptIn(ExperimentalSerializationApi::class)
|
||||
override fun serialize(encoder: Encoder, value: Option<*>) {
|
||||
encoder.encodeStructure(descriptor) {
|
||||
encodeStringElement(descriptor, 0, value.key)
|
||||
encodeNullableSerializableElement(descriptor, 1, String.serializer(), value.title)
|
||||
encodeNullableSerializableElement(descriptor, 2, String.serializer(), value.description)
|
||||
encodeBooleanElement(descriptor, 3, value.required)
|
||||
encodeSerializableElement(descriptor, 4, String.serializer(), value.type.toString())
|
||||
encodeNullableSerializableElement(descriptor, 5, serializer(value.type), value.default)
|
||||
encodeNullableSerializableElement(descriptor, 6, MapSerializer(String.serializer(), serializer(value.type)), value.values)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val patchPrettySerializer by lazy { Json { prettyPrint = true } }
|
||||
private val patchSerializer by lazy { Json }
|
||||
|
||||
/**
|
||||
* Serialize this set of [Patch] to JSON and write it to the given [outputStream].
|
||||
*
|
||||
* @param outputStream The output stream to write the JSON to.
|
||||
* @param prettyPrint Whether to pretty print the JSON.
|
||||
*/
|
||||
@OptIn(ExperimentalSerializationApi::class)
|
||||
fun Set<Patch<*>>.serializeTo(
|
||||
outputStream: OutputStream,
|
||||
prettyPrint: Boolean = true,
|
||||
) = if (prettyPrint) {
|
||||
patchPrettySerializer
|
||||
} else {
|
||||
patchSerializer
|
||||
}.encodeToStream(SetSerializer(PatchSerializer()), this, outputStream)
|
||||
@@ -1,6 +1,6 @@
|
||||
package app.revanced.library.installation.command
|
||||
|
||||
import app.revanced.library.installation.installer.Utils
|
||||
import app.revanced.library.installation.installer.getDevice
|
||||
import se.vidstige.jadb.JadbDevice
|
||||
import se.vidstige.jadb.RemoteFile
|
||||
import java.io.File
|
||||
@@ -29,7 +29,7 @@ class AdbShellCommandRunner : ShellCommandRunner {
|
||||
* @param deviceSerial deviceSerial The device serial. If null, the first connected device will be used.
|
||||
*/
|
||||
internal constructor(deviceSerial: String?) {
|
||||
device = Utils.getDevice(deviceSerial, logger)
|
||||
device = getDevice(deviceSerial, logger)
|
||||
}
|
||||
|
||||
override fun runCommand(command: String) = device.shellProcessBuilder(command).start().let { process ->
|
||||
@@ -17,7 +17,7 @@ import se.vidstige.jadb.managers.PackageManager
|
||||
class AdbInstaller(
|
||||
deviceSerial: String? = null,
|
||||
) : Installer<AdbInstallerResult, Installation>() {
|
||||
private val device = Utils.getDevice(deviceSerial, logger)
|
||||
private val device = getDevice(deviceSerial, logger)
|
||||
private val adbShellCommandRunner = AdbShellCommandRunner(device)
|
||||
private val packageManager = PackageManager(device)
|
||||
|
||||
@@ -2,21 +2,21 @@ package app.revanced.library.installation.installer
|
||||
|
||||
import app.revanced.library.installation.command.AdbShellCommandRunner
|
||||
import app.revanced.library.installation.installer.Installer.Apk
|
||||
import app.revanced.library.installation.installer.MountInstaller.NoRootPermissionException
|
||||
import app.revanced.library.installation.installer.RootInstaller.NoRootPermissionException
|
||||
|
||||
/**
|
||||
* [AdbMountInstaller] for installing and uninstalling [Apk] files with using ADB root permissions by mounting.
|
||||
* [AdbRootInstaller] for installing and uninstalling [Apk] files with using ADB root permissions by mounting.
|
||||
*
|
||||
* @param deviceSerial The device serial. If null, the first connected device will be used.
|
||||
*
|
||||
* @throws NoRootPermissionException If the device does not have root permission.
|
||||
*
|
||||
* @see MountInstaller
|
||||
* @see RootInstaller
|
||||
* @see AdbShellCommandRunner
|
||||
*/
|
||||
class AdbMountInstaller(
|
||||
class AdbRootInstaller(
|
||||
deviceSerial: String? = null,
|
||||
) : MountInstaller({ AdbShellCommandRunner(deviceSerial) }) {
|
||||
) : RootInstaller({ AdbShellCommandRunner(deviceSerial) }) {
|
||||
init {
|
||||
logger.fine("Connected to $deviceSerial")
|
||||
}
|
||||
@@ -1,14 +1,14 @@
|
||||
package app.revanced.library.installation.installer
|
||||
|
||||
/**
|
||||
* [MountInstallation] of the apk file that is mounted to [installedApkFilePath] with root permissions.
|
||||
* [RootInstallation] of the apk file that is mounted to [installedApkFilePath] with root permissions.
|
||||
*
|
||||
* @param installedApkFilePath The installed apk file path or null if the apk is not installed.
|
||||
* @param apkFilePath The mounting apk file path.
|
||||
* @param mounted Whether the apk is mounted to [installedApkFilePath].
|
||||
*/
|
||||
@Suppress("MemberVisibilityCanBePrivate")
|
||||
class MountInstallation internal constructor(
|
||||
class RootInstallation internal constructor(
|
||||
val installedApkFilePath: String?,
|
||||
apkFilePath: String,
|
||||
val mounted: Boolean,
|
||||
@@ -17,20 +17,20 @@ import app.revanced.library.installation.installer.Constants.TMP_FILE_PATH
|
||||
import app.revanced.library.installation.installer.Constants.UMOUNT
|
||||
import app.revanced.library.installation.installer.Constants.invoke
|
||||
import app.revanced.library.installation.installer.Installer.Apk
|
||||
import app.revanced.library.installation.installer.MountInstaller.NoRootPermissionException
|
||||
import app.revanced.library.installation.installer.RootInstaller.NoRootPermissionException
|
||||
import java.io.File
|
||||
|
||||
/**
|
||||
* [MountInstaller] for installing and uninstalling [Apk] files using root permissions by mounting.
|
||||
* [RootInstaller] for installing and uninstalling [Apk] files using root permissions by mounting.
|
||||
*
|
||||
* @param shellCommandRunnerSupplier A supplier for the [ShellCommandRunner] to use.
|
||||
*
|
||||
* @throws NoRootPermissionException If the device does not have root permission.
|
||||
*/
|
||||
@Suppress("MemberVisibilityCanBePrivate")
|
||||
abstract class MountInstaller internal constructor(
|
||||
shellCommandRunnerSupplier: (MountInstaller) -> ShellCommandRunner,
|
||||
) : Installer<MountInstallerResult, MountInstallation>() {
|
||||
abstract class RootInstaller internal constructor(
|
||||
shellCommandRunnerSupplier: (RootInstaller) -> ShellCommandRunner,
|
||||
) : Installer<RootInstallerResult, RootInstallation>() {
|
||||
|
||||
/**
|
||||
* The command runner used to run commands on the device.
|
||||
@@ -49,7 +49,7 @@ abstract class MountInstaller internal constructor(
|
||||
*
|
||||
* @throws PackageNameRequiredException If the [Apk] does not have a package name.
|
||||
*/
|
||||
override suspend fun install(apk: Apk): MountInstallerResult {
|
||||
override suspend fun install(apk: Apk): RootInstallerResult {
|
||||
logger.info("Installing ${apk.packageName} by mounting")
|
||||
|
||||
val packageName = apk.packageName?.also { it.assertInstalled() } ?: throw PackageNameRequiredException()
|
||||
@@ -67,10 +67,10 @@ abstract class MountInstaller internal constructor(
|
||||
|
||||
DELETE(TMP_FILE_PATH)()
|
||||
|
||||
return MountInstallerResult.SUCCESS
|
||||
return RootInstallerResult.SUCCESS
|
||||
}
|
||||
|
||||
override suspend fun uninstall(packageName: String): MountInstallerResult {
|
||||
override suspend fun uninstall(packageName: String): RootInstallerResult {
|
||||
logger.info("Uninstalling $packageName by unmounting")
|
||||
|
||||
UMOUNT(packageName)()
|
||||
@@ -81,16 +81,16 @@ abstract class MountInstaller internal constructor(
|
||||
|
||||
KILL(packageName)()
|
||||
|
||||
return MountInstallerResult.SUCCESS
|
||||
return RootInstallerResult.SUCCESS
|
||||
}
|
||||
|
||||
override suspend fun getInstallation(packageName: String): MountInstallation? {
|
||||
override suspend fun getInstallation(packageName: String): RootInstallation? {
|
||||
val patchedApkPath = MOUNTED_APK_PATH(packageName)
|
||||
|
||||
val patchedApkExists = EXISTS(patchedApkPath)().exitCode == 0
|
||||
if (patchedApkExists) return null
|
||||
|
||||
return MountInstallation(
|
||||
return RootInstallation(
|
||||
INSTALLED_APK_PATH(packageName)().output.ifEmpty { null },
|
||||
patchedApkPath,
|
||||
MOUNT_GREP(patchedApkPath)().exitCode == 0,
|
||||
@@ -122,13 +122,12 @@ abstract class MountInstaller internal constructor(
|
||||
* @throws FailedToFindInstalledPackageException If the package is not installed.
|
||||
*/
|
||||
private fun String.assertInstalled() {
|
||||
if (INSTALLED_APK_PATH(this)().output.isNotEmpty()) {
|
||||
if (INSTALLED_APK_PATH(this)().output.isEmpty()) {
|
||||
throw FailedToFindInstalledPackageException(this)
|
||||
}
|
||||
}
|
||||
|
||||
internal class FailedToFindInstalledPackageException internal constructor(packageName: String) :
|
||||
Exception("Failed to find installed package \"$packageName\" because no activity was found")
|
||||
internal class FailedToFindInstalledPackageException internal constructor(packageName: String) : Exception("Failed to find installed package \"$packageName\" because no activity was found")
|
||||
|
||||
internal class PackageNameRequiredException internal constructor() : Exception("Package name is required")
|
||||
internal class NoRootPermissionException internal constructor() : Exception("No root permission")
|
||||
@@ -3,11 +3,11 @@ package app.revanced.library.installation.installer
|
||||
import app.revanced.library.installation.installer.Installer.Apk
|
||||
|
||||
/**
|
||||
* The result of installing or uninstalling an [Apk] with root permissions using [MountInstaller].
|
||||
* The result of installing or uninstalling an [Apk] with root permissions using [RootInstaller].
|
||||
*
|
||||
* @see MountInstaller
|
||||
* @see RootInstaller
|
||||
*/
|
||||
enum class MountInstallerResult {
|
||||
enum class RootInstallerResult {
|
||||
/**
|
||||
* The result of installing an [Apk] successfully.
|
||||
*/
|
||||
@@ -0,0 +1,34 @@
|
||||
package app.revanced.library.installation.installer
|
||||
|
||||
import se.vidstige.jadb.JadbConnection
|
||||
import java.util.logging.Logger
|
||||
|
||||
/**
|
||||
* Gets the device with the given serial.
|
||||
*
|
||||
* @param deviceSerial The device serial. If null, the first connected device will be used.
|
||||
* @param logger The logger.
|
||||
* @return The device.
|
||||
* @throws DeviceNotFoundException If no device with the given serial is found.
|
||||
*/
|
||||
internal fun getDevice(
|
||||
deviceSerial: String? = null,
|
||||
logger: Logger,
|
||||
) = with(JadbConnection().devices) {
|
||||
if (isEmpty()) throw DeviceNotFoundException()
|
||||
|
||||
deviceSerial?.let {
|
||||
firstOrNull { it.serial == deviceSerial } ?: throw DeviceNotFoundException(
|
||||
deviceSerial,
|
||||
)
|
||||
} ?: first().also {
|
||||
logger.warning("No device serial supplied. Using device with serial ${it.serial}")
|
||||
}
|
||||
}!!
|
||||
|
||||
class DeviceNotFoundException internal constructor(deviceSerial: String? = null) :
|
||||
Exception(
|
||||
deviceSerial?.let {
|
||||
"The device with the ADB device serial \"$deviceSerial\" can not be found"
|
||||
} ?: "No ADB device found",
|
||||
)
|
||||
@@ -1,27 +1,19 @@
|
||||
package app.revanced.library
|
||||
|
||||
import app.revanced.patcher.PatchSet
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patcher.patch.Patch
|
||||
import app.revanced.patcher.patch.options.PatchOption.PatchExtensions.booleanPatchOption
|
||||
import app.revanced.patcher.patch.options.PatchOption.PatchExtensions.intArrayPatchOption
|
||||
import app.revanced.patcher.patch.options.PatchOption.PatchExtensions.stringPatchOption
|
||||
import java.io.ByteArrayInputStream
|
||||
import java.io.ByteArrayOutputStream
|
||||
import app.revanced.patcher.patch.*
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
internal class PatchUtilsTest {
|
||||
internal class MostCommonCompatibleVersionsTest {
|
||||
private val patches =
|
||||
arrayOf(
|
||||
newPatch("some.package", setOf("a")) { stringPatchOption("string", "value") },
|
||||
newPatch("some.package", setOf("a")) { stringOption("string", "value") },
|
||||
newPatch("some.package", setOf("a", "b"), use = false),
|
||||
newPatch("some.package", setOf("a", "b", "c"), use = false),
|
||||
newPatch("some.other.package", setOf("b"), use = false),
|
||||
newPatch("some.other.package", setOf("b", "c")) { booleanPatchOption("bool", true) },
|
||||
newPatch("some.other.package", setOf("b", "c")) { booleanOption("bool", true) },
|
||||
newPatch("some.other.package", setOf("b", "c", "d")),
|
||||
newPatch("some.other.other.package") { intArrayPatchOption("intArray", arrayOf(1, 2, 3)) },
|
||||
newPatch("some.other.other.package") { intsOption("intArray", listOf(1, 2, 3)) },
|
||||
newPatch("some.other.other.package", setOf("a")),
|
||||
newPatch("some.other.other.package", setOf("b")),
|
||||
newPatch("some.other.other.other.package", use = false),
|
||||
@@ -141,38 +133,24 @@ internal class PatchUtilsTest {
|
||||
assertEqualsVersion(null, patches, "other.package")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `serializes to and deserializes from JSON string correctly`() {
|
||||
val out = ByteArrayOutputStream()
|
||||
PatchUtils.Json.serialize(patches, outputStream = out)
|
||||
|
||||
val deserialized =
|
||||
PatchUtils.Json.deserialize(
|
||||
ByteArrayInputStream(out.toByteArray()),
|
||||
PatchUtils.Json.FullJsonPatch::class.java,
|
||||
)
|
||||
|
||||
assert(patches.size == deserialized.size)
|
||||
}
|
||||
|
||||
private fun assertEqualsVersions(
|
||||
expected: PackageNameMap,
|
||||
patches: PatchSet,
|
||||
patches: Set<Patch<*>>,
|
||||
compatiblePackageNames: Set<String>?,
|
||||
countUnusedPatches: Boolean = false,
|
||||
) = assertEquals(
|
||||
expected,
|
||||
PatchUtils.getMostCommonCompatibleVersions(patches, compatiblePackageNames, countUnusedPatches),
|
||||
patches.mostCommonCompatibleVersions(compatiblePackageNames, countUnusedPatches),
|
||||
)
|
||||
|
||||
private fun assertEqualsVersion(
|
||||
expected: String?,
|
||||
patches: PatchSet,
|
||||
patches: Set<Patch<*>>,
|
||||
compatiblePackageName: String,
|
||||
) {
|
||||
assertEquals(
|
||||
expected,
|
||||
PatchUtils.getMostCommonCompatibleVersions(patches, setOf(compatiblePackageName))
|
||||
patches.mostCommonCompatibleVersions(setOf(compatiblePackageName))
|
||||
.entries.firstOrNull()?.value?.keys?.firstOrNull(),
|
||||
)
|
||||
}
|
||||
@@ -181,19 +159,23 @@ internal class PatchUtilsTest {
|
||||
packageName: String,
|
||||
versions: Set<String>? = null,
|
||||
use: Boolean = true,
|
||||
options: Patch<*>.() -> Unit = {},
|
||||
) = object : BytecodePatch(
|
||||
options: PatchBuilder<*>.() -> Unit = {},
|
||||
) = bytecodePatch(
|
||||
name = "test",
|
||||
compatiblePackages = setOf(CompatiblePackage(packageName, versions?.toSet())),
|
||||
use = use,
|
||||
) {
|
||||
init {
|
||||
options()
|
||||
if (versions == null) {
|
||||
compatibleWith(packageName)
|
||||
} else {
|
||||
compatibleWith(
|
||||
if (versions.isEmpty()) {
|
||||
packageName()
|
||||
} else {
|
||||
packageName(*versions.toTypedArray())
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
override fun execute(context: BytecodeContext) {}
|
||||
|
||||
// Needed to make the patches unique.
|
||||
override fun equals(other: Any?) = false
|
||||
options()
|
||||
}
|
||||
}
|
||||
36
src/commonTest/kotlin/app/revanced/library/OptionsTest.kt
Normal file
36
src/commonTest/kotlin/app/revanced/library/OptionsTest.kt
Normal file
@@ -0,0 +1,36 @@
|
||||
package app.revanced.library
|
||||
|
||||
import app.revanced.patcher.patch.booleanOption
|
||||
import app.revanced.patcher.patch.bytecodePatch
|
||||
import app.revanced.patcher.patch.stringOption
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
class OptionsTest {
|
||||
@Test
|
||||
fun `serializes and deserializes`() {
|
||||
val options = mapOf(
|
||||
"Test patch" to mapOf("key1" to "test", "key2" to false),
|
||||
)
|
||||
|
||||
val patch = bytecodePatch("Test patch") {
|
||||
stringOption("key1")
|
||||
booleanOption("key2", true)
|
||||
}
|
||||
val duplicatePatch = bytecodePatch("Test patch") {
|
||||
stringOption("key1")
|
||||
}
|
||||
val unnamedPatch = bytecodePatch {
|
||||
booleanOption("key1")
|
||||
}
|
||||
|
||||
setOf(patch, duplicatePatch, unnamedPatch).setOptions(options)
|
||||
|
||||
assert(patch.options["key1"].value == "test")
|
||||
assert(patch.options["key2"].value == false)
|
||||
|
||||
assertEquals(patch.options["key1"].value, duplicatePatch.options["key1"].value)
|
||||
|
||||
assert(unnamedPatch.options["key1"].value == null)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package app.revanced.library
|
||||
|
||||
import app.revanced.patcher.patch.booleanOption
|
||||
import app.revanced.patcher.patch.bytecodePatch
|
||||
import app.revanced.patcher.patch.floatsOption
|
||||
import app.revanced.patcher.patch.stringOption
|
||||
import kotlinx.serialization.json.*
|
||||
import java.io.ByteArrayOutputStream
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertIs
|
||||
|
||||
class SerializationTest {
|
||||
private val testPatch = bytecodePatch("Test patch") {
|
||||
compatibleWith("com.example.package"("1.0.0"))
|
||||
compatibleWith("com.example.package2")
|
||||
|
||||
dependsOn(bytecodePatch(), bytecodePatch())
|
||||
|
||||
stringOption("key1", null, null, "title1", "description1")
|
||||
booleanOption("key2", true, null, "title2", "description2")
|
||||
floatsOption("key3", listOf(1.0f), mapOf("list" to listOf(1f)), "title3", "description3")
|
||||
}
|
||||
|
||||
private var patches = setOf(testPatch)
|
||||
|
||||
@Test
|
||||
fun `serializes and deserializes`() {
|
||||
val serializedJson = ByteArrayOutputStream().apply { patches.serializeTo(this) }.toString()
|
||||
val deserializedJson = Json.parseToJsonElement(serializedJson)
|
||||
|
||||
// Test patch serialization.
|
||||
|
||||
assertIs<JsonArray>(deserializedJson)
|
||||
|
||||
val deserializedPatch = deserializedJson[0].jsonObject
|
||||
|
||||
assert(deserializedPatch["name"]!!.jsonPrimitive.content == "Test patch")
|
||||
|
||||
assert(deserializedPatch["compatiblePackages"]!!.jsonObject.size == 2) {
|
||||
"The patch should be compatible with two packages."
|
||||
}
|
||||
|
||||
assert(deserializedPatch["dependencies"]!!.jsonArray.size == 2) {
|
||||
"Even though the dependencies are named the same, they are different objects."
|
||||
}
|
||||
|
||||
// Test option serialization.
|
||||
|
||||
val options = deserializedPatch["options"]!!.jsonArray
|
||||
|
||||
assert(options.size == 3) { "The patch should have three options." }
|
||||
|
||||
assert(options[0].jsonObject["title"]!!.jsonPrimitive.content == "title1")
|
||||
assert(options[0].jsonObject["default"]!!.jsonPrimitive.contentOrNull == null)
|
||||
assert(options[1].jsonObject["default"]!!.jsonPrimitive.boolean)
|
||||
assert(options[2].jsonObject["values"]!!.jsonObject["list"]!!.jsonArray[0].jsonPrimitive.float == 1f)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user