From 42de60e95bb29a2cac15979fc08763973c279bb3 Mon Sep 17 00:00:00 2001 From: oSumAtrIX Date: Sun, 7 Apr 2024 22:33:03 +0200 Subject: [PATCH] feat: Add networking module --- build.gradle.kts | 149 ++-------- gradle/libs.versions.toml | 26 +- library-networking/api/library-networking.api | 143 +++++++++ library-networking/build.gradle.kts | 97 ++++++ .../revanced/library/networking/Extensions.kt | 6 + .../app/revanced/library/networking/Server.kt | 281 ++++++++++++++++++ .../networking/configuration/Dependencies.kt | 43 +++ .../library/networking/configuration/Http.kt | 33 ++ .../networking/configuration/Security.kt | 28 ++ .../networking/configuration/Serialization.kt | 92 ++++++ .../configuration/repository/AppRepository.kt | 32 ++ .../repository/InstallerRepository.kt | 17 ++ .../repository/PatchSetRepository.kt | 41 +++ .../repository/StorageRepository.kt | 93 ++++++ .../configuration/routing/Routing.kt | 23 ++ .../routing/routes/PatchBundlesRoute.kt | 57 ++++ .../routing/routes/PatcherRoute.kt | 179 +++++++++++ .../configuration/routing/routes/PingRoute.kt | 15 + .../configuration/routing/routes/RootRoute.kt | 60 ++++ .../networking/models/PatcherModels.kt | 57 ++++ .../networking/services/HttpClientService.kt | 26 ++ .../networking/services/PatchBundleService.kt | 85 ++++++ .../networking/services/PatcherService.kt | 250 ++++++++++++++++ .../library/networking/version.properties | 1 + .../api/android/library.api | 18 +- .../api/jvm/library.api | 16 +- library/build.gradle.kts | 123 ++++++++ .../ILocalShellCommandRunnerRootService.aidl | 0 .../command/LocalShellCommandRunner.kt | 0 .../LocalShellCommandRunnerRootService.kt | 0 .../installation/installer/LocalInstaller.kt | 0 .../installer/LocalInstallerResult.kt | 0 .../installer/LocalInstallerService.kt | 0 .../installer/LocalMountInstaller.kt | 14 +- .../kotlin/app/revanced/library/ApkSigner.kt | 0 .../kotlin/app/revanced/library/ApkUtils.kt | 0 .../kotlin/app/revanced/library/Commands.kt | 0 .../kotlin/app/revanced/library/Options.kt | 0 .../kotlin/app/revanced/library/PatchUtils.kt | 0 .../kotlin/app/revanced/library/Utils.kt | 0 .../app/revanced/library/adb/AdbManager.kt | 14 +- .../command/AdbShellCommandRunner.kt | 0 .../library/installation/command/RunResult.kt | 0 .../command/ShellCommandRunner.kt | 0 .../installation/installer/AdbInstaller.kt | 0 .../installer/AdbInstallerResult.kt | 0 .../installer/AdbMountInstaller.kt | 10 +- .../installation/installer/Constants.kt | 0 .../installation/installer/Installation.kt | 0 .../installation/installer/Installer.kt | 0 .../installer/MountInstallation.kt | 4 +- .../installation/installer/MountInstaller.kt | 22 +- .../installer/MountInstallerResult.kt | 6 +- .../library/installation/installer/Utils.kt | 0 .../app/revanced/library/logging/Logger.kt | 0 .../app/revanced/library/PatchOptionsTest.kt | 0 .../app/revanced/library/PatchUtilsTest.kt | 0 settings.gradle.kts | 8 +- 58 files changed, 1880 insertions(+), 189 deletions(-) create mode 100644 library-networking/api/library-networking.api create mode 100644 library-networking/build.gradle.kts create mode 100644 library-networking/src/main/kotlin/app/revanced/library/networking/Extensions.kt create mode 100644 library-networking/src/main/kotlin/app/revanced/library/networking/Server.kt create mode 100644 library-networking/src/main/kotlin/app/revanced/library/networking/configuration/Dependencies.kt create mode 100644 library-networking/src/main/kotlin/app/revanced/library/networking/configuration/Http.kt create mode 100644 library-networking/src/main/kotlin/app/revanced/library/networking/configuration/Security.kt create mode 100644 library-networking/src/main/kotlin/app/revanced/library/networking/configuration/Serialization.kt create mode 100644 library-networking/src/main/kotlin/app/revanced/library/networking/configuration/repository/AppRepository.kt create mode 100644 library-networking/src/main/kotlin/app/revanced/library/networking/configuration/repository/InstallerRepository.kt create mode 100644 library-networking/src/main/kotlin/app/revanced/library/networking/configuration/repository/PatchSetRepository.kt create mode 100644 library-networking/src/main/kotlin/app/revanced/library/networking/configuration/repository/StorageRepository.kt create mode 100644 library-networking/src/main/kotlin/app/revanced/library/networking/configuration/routing/Routing.kt create mode 100644 library-networking/src/main/kotlin/app/revanced/library/networking/configuration/routing/routes/PatchBundlesRoute.kt create mode 100644 library-networking/src/main/kotlin/app/revanced/library/networking/configuration/routing/routes/PatcherRoute.kt create mode 100644 library-networking/src/main/kotlin/app/revanced/library/networking/configuration/routing/routes/PingRoute.kt create mode 100644 library-networking/src/main/kotlin/app/revanced/library/networking/configuration/routing/routes/RootRoute.kt create mode 100644 library-networking/src/main/kotlin/app/revanced/library/networking/models/PatcherModels.kt create mode 100644 library-networking/src/main/kotlin/app/revanced/library/networking/services/HttpClientService.kt create mode 100644 library-networking/src/main/kotlin/app/revanced/library/networking/services/PatchBundleService.kt create mode 100644 library-networking/src/main/kotlin/app/revanced/library/networking/services/PatcherService.kt create mode 100644 library-networking/src/main/resources/app/revanced/library/networking/version.properties rename api/android/revanced-library.api => library/api/android/library.api (96%) rename api/jvm/revanced-library.api => library/api/jvm/library.api (96%) create mode 100644 library/build.gradle.kts rename {src => library/src}/androidMain/aidl/app/revanced/library/installation/command/ILocalShellCommandRunnerRootService.aidl (100%) rename {src => library/src}/androidMain/kotlin/app/revanced/library/installation/command/LocalShellCommandRunner.kt (100%) rename {src => library/src}/androidMain/kotlin/app/revanced/library/installation/command/LocalShellCommandRunnerRootService.kt (100%) rename {src => library/src}/androidMain/kotlin/app/revanced/library/installation/installer/LocalInstaller.kt (100%) rename {src => library/src}/androidMain/kotlin/app/revanced/library/installation/installer/LocalInstallerResult.kt (100%) rename {src => library/src}/androidMain/kotlin/app/revanced/library/installation/installer/LocalInstallerService.kt (100%) rename src/androidMain/kotlin/app/revanced/library/installation/installer/LocalRootInstaller.kt => library/src/androidMain/kotlin/app/revanced/library/installation/installer/LocalMountInstaller.kt (61%) rename {src => library/src}/commonMain/kotlin/app/revanced/library/ApkSigner.kt (100%) rename {src => library/src}/commonMain/kotlin/app/revanced/library/ApkUtils.kt (100%) rename {src => library/src}/commonMain/kotlin/app/revanced/library/Commands.kt (100%) rename {src => library/src}/commonMain/kotlin/app/revanced/library/Options.kt (100%) rename {src => library/src}/commonMain/kotlin/app/revanced/library/PatchUtils.kt (100%) rename {src => library/src}/commonMain/kotlin/app/revanced/library/Utils.kt (100%) rename {src => library/src}/commonMain/kotlin/app/revanced/library/adb/AdbManager.kt (90%) rename {src => library/src}/commonMain/kotlin/app/revanced/library/installation/command/AdbShellCommandRunner.kt (100%) rename {src => library/src}/commonMain/kotlin/app/revanced/library/installation/command/RunResult.kt (100%) rename {src => library/src}/commonMain/kotlin/app/revanced/library/installation/command/ShellCommandRunner.kt (100%) rename {src => library/src}/commonMain/kotlin/app/revanced/library/installation/installer/AdbInstaller.kt (100%) rename {src => library/src}/commonMain/kotlin/app/revanced/library/installation/installer/AdbInstallerResult.kt (100%) rename src/commonMain/kotlin/app/revanced/library/installation/installer/AdbRootInstaller.kt => library/src/commonMain/kotlin/app/revanced/library/installation/installer/AdbMountInstaller.kt (62%) rename {src => library/src}/commonMain/kotlin/app/revanced/library/installation/installer/Constants.kt (100%) rename {src => library/src}/commonMain/kotlin/app/revanced/library/installation/installer/Installation.kt (100%) rename {src => library/src}/commonMain/kotlin/app/revanced/library/installation/installer/Installer.kt (100%) rename src/commonMain/kotlin/app/revanced/library/installation/installer/RootInstallation.kt => library/src/commonMain/kotlin/app/revanced/library/installation/installer/MountInstallation.kt (74%) rename src/commonMain/kotlin/app/revanced/library/installation/installer/RootInstaller.kt => library/src/commonMain/kotlin/app/revanced/library/installation/installer/MountInstaller.kt (86%) rename src/commonMain/kotlin/app/revanced/library/installation/installer/RootInstallerResult.kt => library/src/commonMain/kotlin/app/revanced/library/installation/installer/MountInstallerResult.kt (79%) rename {src => library/src}/commonMain/kotlin/app/revanced/library/installation/installer/Utils.kt (100%) rename {src => library/src}/commonMain/kotlin/app/revanced/library/logging/Logger.kt (100%) rename {src => library/src}/commonTest/kotlin/app/revanced/library/PatchOptionsTest.kt (100%) rename {src => library/src}/commonTest/kotlin/app/revanced/library/PatchUtilsTest.kt (100%) diff --git a/build.gradle.kts b/build.gradle.kts index 643dd26..cfcf1c6 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,143 +1,30 @@ plugins { - alias(libs.plugins.kotlin.multiplatform) - alias(libs.plugins.android.library) - alias(libs.plugins.binary.compatibility.validator) - `maven-publish` - signing + 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 } group = "app.revanced" -// 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 { - 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 { +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. repositories { + mavenCentral() + mavenLocal() + google() maven { - name = "GitHubPackages" - url = uri("https://maven.pkg.github.com/revanced/revanced-library") + // A repository must be specified for some reason. "registry" is a dummy. + url = uri("https://maven.pkg.github.com/revanced/registry") credentials { - username = System.getenv("GITHUB_ACTOR") - password = System.getenv("GITHUB_TOKEN") + 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") } } - - publications { - create("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"]) } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 03a7a0b..d9debb6 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -2,13 +2,18 @@ jackson-module-kotlin = "2.15.0" 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.0" +android = "8.3.2" bcpkix-jdk15on = "1.70" guava = "33.0.0-jre" libsu = "5.2.2" core-ktx = "1.12.0" +ktor = "2.3.9" +koin = "3.5.3" +logback = "1.4.14" [libraries] jackson-module-kotlin = { module = "com.fasterxml.jackson.module:jackson-module-kotlin", version.ref = "jackson-module-kotlin" } @@ -24,9 +29,26 @@ 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" } [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-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } +kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" } kotlin-multiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" } +kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" } diff --git a/library-networking/api/library-networking.api b/library-networking/api/library-networking.api new file mode 100644 index 0000000..ccabc7c --- /dev/null +++ b/library-networking/api/library-networking.api @@ -0,0 +1,143 @@ +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 (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 (Ljava/lang/String;Ljava/lang/String;)V +} + +public final class app/revanced/library/networking/Server$SerializersConfiguration { + public fun ()V + public fun (Ljava/util/Map;)V + public synthetic fun (Ljava/util/Map;ILkotlin/jvm/internal/DefaultConstructorMarker;)V +} + +public final class app/revanced/library/networking/ServerBuilder { + public fun ()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 ()V +} + +public abstract class app/revanced/library/networking/configuration/repository/InstallerRepository { + public fun ()V +} + +public abstract class app/revanced/library/networking/configuration/repository/PatchSetRepository { + public fun (Lapp/revanced/library/networking/configuration/repository/StorageRepository;)V +} + +public abstract class app/revanced/library/networking/configuration/repository/StorageRepository { + public fun (Ljava/io/File;Ljava/io/File;Ljava/io/File;Ljava/io/File;)V + public synthetic fun (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 (ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;Lkotlinx/serialization/internal/SerializationConstructorMarker;)V + public fun (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 (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 (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; +} + diff --git a/library-networking/build.gradle.kts b/library-networking/build.gradle.kts new file mode 100644 index 0000000..f09cd27 --- /dev/null +++ b/library-networking/build.gradle.kts @@ -0,0 +1,97 @@ +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("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"]) +} diff --git a/library-networking/src/main/kotlin/app/revanced/library/networking/Extensions.kt b/library-networking/src/main/kotlin/app/revanced/library/networking/Extensions.kt new file mode 100644 index 0000000..b40f95e --- /dev/null +++ b/library-networking/src/main/kotlin/app/revanced/library/networking/Extensions.kt @@ -0,0 +1,6 @@ +package app.revanced.library.networking + +import io.ktor.server.application.* +import io.ktor.util.pipeline.* + +internal val PipelineContext<*, ApplicationCall>.parameters get() = call.parameters diff --git a/library-networking/src/main/kotlin/app/revanced/library/networking/Server.kt b/library-networking/src/main/kotlin/app/revanced/library/networking/Server.kt new file mode 100644 index 0000000..cf963c8 --- /dev/null +++ b/library-networking/src/main/kotlin/app/revanced/library/networking/Server.kt @@ -0,0 +1,281 @@ +@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 = 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 + + fun configurePatchOptionSerializers(vararg pairs: Pair) { + 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) { + // 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): PatchSet { + return PatchBundleLoader.Jar(*patchBundles.map { it.patchBundleFile }.toTypedArray()) + } + } + + val appRepository = object : AppRepository() { + override fun readInstalledApps() = emptySet() + } + + 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>(), + ) + } + }.start() +} diff --git a/library-networking/src/main/kotlin/app/revanced/library/networking/configuration/Dependencies.kt b/library-networking/src/main/kotlin/app/revanced/library/networking/configuration/Dependencies.kt new file mode 100644 index 0000000..9e48cf4 --- /dev/null +++ b/library-networking/src/main/kotlin/app/revanced/library/networking/configuration/Dependencies.kt @@ -0,0 +1,43 @@ +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, + ) + } +} diff --git a/library-networking/src/main/kotlin/app/revanced/library/networking/configuration/Http.kt b/library-networking/src/main/kotlin/app/revanced/library/networking/configuration/Http.kt new file mode 100644 index 0000000..78c6c92 --- /dev/null +++ b/library-networking/src/main/kotlin/app/revanced/library/networking/configuration/Http.kt @@ -0,0 +1,33 @@ +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())) } + } +} diff --git a/library-networking/src/main/kotlin/app/revanced/library/networking/configuration/Security.kt b/library-networking/src/main/kotlin/app/revanced/library/networking/configuration/Security.kt new file mode 100644 index 0000000..ed6b286 --- /dev/null +++ b/library-networking/src/main/kotlin/app/revanced/library/networking/configuration/Security.kt @@ -0,0 +1,28 @@ +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 + } + } + } + } +} diff --git a/library-networking/src/main/kotlin/app/revanced/library/networking/configuration/Serialization.kt b/library-networking/src/main/kotlin/app/revanced/library/networking/configuration/Serialization.kt new file mode 100644 index 0000000..f4a1e84 --- /dev/null +++ b/library-networking/src/main/kotlin/app/revanced/library/networking/configuration/Serialization.kt @@ -0,0 +1,92 @@ +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) { + val knownPatchOptionValueTypes = mapOf( + "String" to typeOf>(), + "Int" to typeOf>(), + "Boolean" to typeOf>(), + "Long" to typeOf>(), + "Float" to typeOf>(), + "StringArray" to typeOf>>(), + "IntArray" to typeOf>(), + "BooleanArray" to typeOf>(), + "LongArray" to typeOf>(), + "FloatArray" to typeOf>(), + ) + 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> { + override val descriptor = serializer(typeOf>()).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)) +} diff --git a/library-networking/src/main/kotlin/app/revanced/library/networking/configuration/repository/AppRepository.kt b/library-networking/src/main/kotlin/app/revanced/library/networking/configuration/repository/AppRepository.kt new file mode 100644 index 0000000..78a0095 --- /dev/null +++ b/library-networking/src/main/kotlin/app/revanced/library/networking/configuration/repository/AppRepository.kt @@ -0,0 +1,32 @@ +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 + private set + + init { + readAndSetInstalledApps() + } + + /** + * Read a set of [App] from a storage. + * + * @return The set of [App] read. + */ + internal abstract fun readInstalledApps(): Set + + /** + * Read a set of [App] using [readInstalledApps] and set [installedApps] to it. + */ + internal fun readAndSetInstalledApps() { + this.installedApps = readInstalledApps() + } +} diff --git a/library-networking/src/main/kotlin/app/revanced/library/networking/configuration/repository/InstallerRepository.kt b/library-networking/src/main/kotlin/app/revanced/library/networking/configuration/repository/InstallerRepository.kt new file mode 100644 index 0000000..d5f77a4 --- /dev/null +++ b/library-networking/src/main/kotlin/app/revanced/library/networking/configuration/repository/InstallerRepository.kt @@ -0,0 +1,17 @@ +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 +} diff --git a/library-networking/src/main/kotlin/app/revanced/library/networking/configuration/repository/PatchSetRepository.kt b/library-networking/src/main/kotlin/app/revanced/library/networking/configuration/repository/PatchSetRepository.kt new file mode 100644 index 0000000..b5fe224 --- /dev/null +++ b/library-networking/src/main/kotlin/app/revanced/library/networking/configuration/repository/PatchSetRepository.kt @@ -0,0 +1,41 @@ +@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): 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()) + } +} diff --git a/library-networking/src/main/kotlin/app/revanced/library/networking/configuration/repository/StorageRepository.kt b/library-networking/src/main/kotlin/app/revanced/library/networking/configuration/repository/StorageRepository.kt new file mode 100644 index 0000000..de1a252 --- /dev/null +++ b/library-networking/src/main/kotlin/app/revanced/library/networking/configuration/repository/StorageRepository.kt @@ -0,0 +1,93 @@ +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 + 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 + + /** + * Write a set of [patchBundles] to a storage. + * + * @param patchBundles The set of patch bundles to write. + */ + internal abstract fun writePatchBundles(patchBundles: Set) + + /** + * 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() + } +} diff --git a/library-networking/src/main/kotlin/app/revanced/library/networking/configuration/routing/Routing.kt b/library-networking/src/main/kotlin/app/revanced/library/networking/configuration/routing/Routing.kt new file mode 100644 index 0000000..b0b2823 --- /dev/null +++ b/library-networking/src/main/kotlin/app/revanced/library/networking/configuration/routing/Routing.kt @@ -0,0 +1,23 @@ +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() + } + } +} diff --git a/library-networking/src/main/kotlin/app/revanced/library/networking/configuration/routing/routes/PatchBundlesRoute.kt b/library-networking/src/main/kotlin/app/revanced/library/networking/configuration/routing/routes/PatchBundlesRoute.kt new file mode 100644 index 0000000..1e83687 --- /dev/null +++ b/library-networking/src/main/kotlin/app/revanced/library/networking/configuration/routing/routes/PatchBundlesRoute.kt @@ -0,0 +1,57 @@ +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() + + 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() + } + } +} diff --git a/library-networking/src/main/kotlin/app/revanced/library/networking/configuration/routing/routes/PatcherRoute.kt b/library-networking/src/main/kotlin/app/revanced/library/networking/configuration/routing/routes/PatcherRoute.kt new file mode 100644 index 0000000..4c0a0c1 --- /dev/null +++ b/library-networking/src/main/kotlin/app/revanced/library/networking/configuration/routing/routes/PatcherRoute.kt @@ -0,0 +1,179 @@ +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() + + 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() + + 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() + + 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> 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() + val patcherService = get() + + 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() + + 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() + + 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() + + post("/clean") { + patcherService.deleteTemporaryFiles() + + call.respond(HttpStatusCode.OK) + } +} diff --git a/library-networking/src/main/kotlin/app/revanced/library/networking/configuration/routing/routes/PingRoute.kt b/library-networking/src/main/kotlin/app/revanced/library/networking/configuration/routing/routes/PingRoute.kt new file mode 100644 index 0000000..5def4bf --- /dev/null +++ b/library-networking/src/main/kotlin/app/revanced/library/networking/configuration/routing/routes/PingRoute.kt @@ -0,0 +1,15 @@ +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) + } +} diff --git a/library-networking/src/main/kotlin/app/revanced/library/networking/configuration/routing/routes/RootRoute.kt b/library-networking/src/main/kotlin/app/revanced/library/networking/configuration/routing/routes/RootRoute.kt new file mode 100644 index 0000000..409a6a3 --- /dev/null +++ b/library-networking/src/main/kotlin/app/revanced/library/networking/configuration/routing/routes/RootRoute.kt @@ -0,0 +1,60 @@ +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(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 + } +} diff --git a/library-networking/src/main/kotlin/app/revanced/library/networking/models/PatcherModels.kt b/library-networking/src/main/kotlin/app/revanced/library/networking/models/PatcherModels.kt new file mode 100644 index 0000000..ec76011 --- /dev/null +++ b/library-networking/src/main/kotlin/app/revanced/library/networking/models/PatcherModels.kt @@ -0,0 +1,57 @@ +@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 +private typealias CompatiblePackages = Map + +@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 internal constructor( + internal val key: String, + internal val default: T?, + internal val values: Map?, + internal val title: String?, + internal val description: String?, + internal val required: Boolean, + internal val valueType: String, + ) + + class KeyValuePatchOption( + 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) : this( + patchOption.key, + patchOption.default, + patchOption.valueType, + ) + } +} + +class PatchBundle internal constructor( + val name: String, + val patchBundleFile: File, + val patchBundleIntegrationsFile: File? = null, +) diff --git a/library-networking/src/main/kotlin/app/revanced/library/networking/services/HttpClientService.kt b/library-networking/src/main/kotlin/app/revanced/library/networking/services/HttpClientService.kt new file mode 100644 index 0000000..8d843d8 --- /dev/null +++ b/library-networking/src/main/kotlin/app/revanced/library/networking/services/HttpClientService.kt @@ -0,0 +1,26 @@ +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().copyTo(file.outputStream()) + } +} diff --git a/library-networking/src/main/kotlin/app/revanced/library/networking/services/PatchBundleService.kt b/library-networking/src/main/kotlin/app/revanced/library/networking/services/PatchBundleService.kt new file mode 100644 index 0000000..a4dd453 --- /dev/null +++ b/library-networking/src/main/kotlin/app/revanced/library/networking/services/PatchBundleService.kt @@ -0,0 +1,85 @@ +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 + 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() + } +} diff --git a/library-networking/src/main/kotlin/app/revanced/library/networking/services/PatcherService.kt b/library-networking/src/main/kotlin/app/revanced/library/networking/services/PatcherService.kt new file mode 100644 index 0000000..c7719ff --- /dev/null +++ b/library-networking/src/main/kotlin/app/revanced/library/networking/services/PatcherService.kt @@ -0,0 +1,250 @@ +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 { + // 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, + 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>, + 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() +} diff --git a/library-networking/src/main/resources/app/revanced/library/networking/version.properties b/library-networking/src/main/resources/app/revanced/library/networking/version.properties new file mode 100644 index 0000000..308c9f8 --- /dev/null +++ b/library-networking/src/main/resources/app/revanced/library/networking/version.properties @@ -0,0 +1 @@ +version=${projectVersion} \ No newline at end of file diff --git a/api/android/revanced-library.api b/library/api/android/library.api similarity index 96% rename from api/android/revanced-library.api rename to library/api/android/library.api index 9f89984..0dce99c 100644 --- a/api/android/revanced-library.api +++ b/library/api/android/library.api @@ -249,7 +249,7 @@ 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/AdbRootInstaller : app/revanced/library/installation/installer/RootInstaller { +public final class app/revanced/library/installation/installer/AdbMountInstaller : app/revanced/library/installation/installer/MountInstaller { public fun ()V public fun (Ljava/lang/String;)V public synthetic fun (Ljava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V @@ -297,18 +297,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/LocalRootInstaller : app/revanced/library/installation/installer/RootInstaller, java/io/Closeable { +public final class app/revanced/library/installation/installer/LocalMountInstaller : app/revanced/library/installation/installer/MountInstaller, java/io/Closeable { public fun (Landroid/content/Context;Lkotlin/jvm/functions/Function1;)V public synthetic fun (Landroid/content/Context;Lkotlin/jvm/functions/Function1;ILkotlin/jvm/internal/DefaultConstructorMarker;)V public fun close ()V } -public final class app/revanced/library/installation/installer/RootInstallation : app/revanced/library/installation/installer/Installation { +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/RootInstaller : app/revanced/library/installation/installer/Installer { +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; @@ -318,12 +318,12 @@ public abstract class app/revanced/library/installation/installer/RootInstaller 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 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/RootInstallerResult; - public static fun values ()[Lapp/revanced/library/installation/installer/RootInstallerResult; + 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 { diff --git a/api/jvm/revanced-library.api b/library/api/jvm/library.api similarity index 96% rename from api/jvm/revanced-library.api rename to library/api/jvm/library.api index 5a525d9..64367f9 100644 --- a/api/jvm/revanced-library.api +++ b/library/api/jvm/library.api @@ -225,7 +225,7 @@ 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/AdbRootInstaller : app/revanced/library/installation/installer/RootInstaller { +public final class app/revanced/library/installation/installer/AdbMountInstaller : app/revanced/library/installation/installer/MountInstaller { public fun ()V public fun (Ljava/lang/String;)V public synthetic fun (Ljava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V @@ -249,12 +249,12 @@ public final class app/revanced/library/installation/installer/Installer$Apk { public final fun getPackageName ()Ljava/lang/String; } -public final class app/revanced/library/installation/installer/RootInstallation : app/revanced/library/installation/installer/Installation { +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/RootInstaller : app/revanced/library/installation/installer/Installer { +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; @@ -264,12 +264,12 @@ public abstract class app/revanced/library/installation/installer/RootInstaller 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 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/RootInstallerResult; - public static fun values ()[Lapp/revanced/library/installation/installer/RootInstallerResult; + 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 { diff --git a/library/build.gradle.kts b/library/build.gradle.kts new file mode 100644 index 0000000..bcc734d --- /dev/null +++ b/library/build.gradle.kts @@ -0,0 +1,123 @@ +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("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"]) +} diff --git a/src/androidMain/aidl/app/revanced/library/installation/command/ILocalShellCommandRunnerRootService.aidl b/library/src/androidMain/aidl/app/revanced/library/installation/command/ILocalShellCommandRunnerRootService.aidl similarity index 100% rename from src/androidMain/aidl/app/revanced/library/installation/command/ILocalShellCommandRunnerRootService.aidl rename to library/src/androidMain/aidl/app/revanced/library/installation/command/ILocalShellCommandRunnerRootService.aidl diff --git a/src/androidMain/kotlin/app/revanced/library/installation/command/LocalShellCommandRunner.kt b/library/src/androidMain/kotlin/app/revanced/library/installation/command/LocalShellCommandRunner.kt similarity index 100% rename from src/androidMain/kotlin/app/revanced/library/installation/command/LocalShellCommandRunner.kt rename to library/src/androidMain/kotlin/app/revanced/library/installation/command/LocalShellCommandRunner.kt diff --git a/src/androidMain/kotlin/app/revanced/library/installation/command/LocalShellCommandRunnerRootService.kt b/library/src/androidMain/kotlin/app/revanced/library/installation/command/LocalShellCommandRunnerRootService.kt similarity index 100% rename from src/androidMain/kotlin/app/revanced/library/installation/command/LocalShellCommandRunnerRootService.kt rename to library/src/androidMain/kotlin/app/revanced/library/installation/command/LocalShellCommandRunnerRootService.kt diff --git a/src/androidMain/kotlin/app/revanced/library/installation/installer/LocalInstaller.kt b/library/src/androidMain/kotlin/app/revanced/library/installation/installer/LocalInstaller.kt similarity index 100% rename from src/androidMain/kotlin/app/revanced/library/installation/installer/LocalInstaller.kt rename to library/src/androidMain/kotlin/app/revanced/library/installation/installer/LocalInstaller.kt diff --git a/src/androidMain/kotlin/app/revanced/library/installation/installer/LocalInstallerResult.kt b/library/src/androidMain/kotlin/app/revanced/library/installation/installer/LocalInstallerResult.kt similarity index 100% rename from src/androidMain/kotlin/app/revanced/library/installation/installer/LocalInstallerResult.kt rename to library/src/androidMain/kotlin/app/revanced/library/installation/installer/LocalInstallerResult.kt diff --git a/src/androidMain/kotlin/app/revanced/library/installation/installer/LocalInstallerService.kt b/library/src/androidMain/kotlin/app/revanced/library/installation/installer/LocalInstallerService.kt similarity index 100% rename from src/androidMain/kotlin/app/revanced/library/installation/installer/LocalInstallerService.kt rename to library/src/androidMain/kotlin/app/revanced/library/installation/installer/LocalInstallerService.kt diff --git a/src/androidMain/kotlin/app/revanced/library/installation/installer/LocalRootInstaller.kt b/library/src/androidMain/kotlin/app/revanced/library/installation/installer/LocalMountInstaller.kt similarity index 61% rename from src/androidMain/kotlin/app/revanced/library/installation/installer/LocalRootInstaller.kt rename to library/src/androidMain/kotlin/app/revanced/library/installation/installer/LocalMountInstaller.kt index 4247e83..04ecb4e 100644 --- a/src/androidMain/kotlin/app/revanced/library/installation/installer/LocalRootInstaller.kt +++ b/library/src/androidMain/kotlin/app/revanced/library/installation/installer/LocalMountInstaller.kt @@ -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.RootInstaller.NoRootPermissionException +import app.revanced.library.installation.installer.MountInstaller.NoRootPermissionException import com.topjohnwu.superuser.ipc.RootService import java.io.Closeable /** - * [LocalRootInstaller] for installing and uninstalling [Apk] files locally with using root permissions by mounting. + * [LocalMountInstaller] 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 [LocalRootInstaller] is ready to be used. + * @param onReady A callback to be invoked when [LocalMountInstaller] 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 LocalRootInstaller( +class LocalMountInstaller( context: Context, - onReady: LocalRootInstaller.() -> Unit = {}, -) : RootInstaller( + onReady: LocalMountInstaller.() -> Unit = {}, +) : MountInstaller( { installer -> LocalShellCommandRunner(context) { - (installer as LocalRootInstaller).onReady() + (installer as LocalMountInstaller).onReady() } }, ), diff --git a/src/commonMain/kotlin/app/revanced/library/ApkSigner.kt b/library/src/commonMain/kotlin/app/revanced/library/ApkSigner.kt similarity index 100% rename from src/commonMain/kotlin/app/revanced/library/ApkSigner.kt rename to library/src/commonMain/kotlin/app/revanced/library/ApkSigner.kt diff --git a/src/commonMain/kotlin/app/revanced/library/ApkUtils.kt b/library/src/commonMain/kotlin/app/revanced/library/ApkUtils.kt similarity index 100% rename from src/commonMain/kotlin/app/revanced/library/ApkUtils.kt rename to library/src/commonMain/kotlin/app/revanced/library/ApkUtils.kt diff --git a/src/commonMain/kotlin/app/revanced/library/Commands.kt b/library/src/commonMain/kotlin/app/revanced/library/Commands.kt similarity index 100% rename from src/commonMain/kotlin/app/revanced/library/Commands.kt rename to library/src/commonMain/kotlin/app/revanced/library/Commands.kt diff --git a/src/commonMain/kotlin/app/revanced/library/Options.kt b/library/src/commonMain/kotlin/app/revanced/library/Options.kt similarity index 100% rename from src/commonMain/kotlin/app/revanced/library/Options.kt rename to library/src/commonMain/kotlin/app/revanced/library/Options.kt diff --git a/src/commonMain/kotlin/app/revanced/library/PatchUtils.kt b/library/src/commonMain/kotlin/app/revanced/library/PatchUtils.kt similarity index 100% rename from src/commonMain/kotlin/app/revanced/library/PatchUtils.kt rename to library/src/commonMain/kotlin/app/revanced/library/PatchUtils.kt diff --git a/src/commonMain/kotlin/app/revanced/library/Utils.kt b/library/src/commonMain/kotlin/app/revanced/library/Utils.kt similarity index 100% rename from src/commonMain/kotlin/app/revanced/library/Utils.kt rename to library/src/commonMain/kotlin/app/revanced/library/Utils.kt diff --git a/src/commonMain/kotlin/app/revanced/library/adb/AdbManager.kt b/library/src/commonMain/kotlin/app/revanced/library/adb/AdbManager.kt similarity index 90% rename from src/commonMain/kotlin/app/revanced/library/adb/AdbManager.kt rename to library/src/commonMain/kotlin/app/revanced/library/adb/AdbManager.kt index 1eefdd0..44b38a3 100644 --- a/src/commonMain/kotlin/app/revanced/library/adb/AdbManager.kt +++ b/library/src/commonMain/kotlin/app/revanced/library/adb/AdbManager.kt @@ -4,7 +4,7 @@ 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.AdbRootInstaller +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 @@ -68,18 +68,18 @@ sealed class AdbManager private constructor( * * @param deviceSerial The device serial. If null, the first connected device will be used. */ - @Deprecated("Use AdbRootInstaller instead.", ReplaceWith("AdbRootInstaller(deviceSerial)")) + @Deprecated("Use AdbMountInstaller instead.", ReplaceWith("AdbMountInstaller(deviceSerial)")) class RootAdbManager internal constructor(deviceSerial: String?) : AdbManager(deviceSerial) { - override val installer = AdbRootInstaller(deviceSerial) + override val installer = AdbMountInstaller(deviceSerial) @Suppress("DeprecatedCallableAddReplaceWith") - @Deprecated("Use AdbRootInstaller.install instead.") + @Deprecated("Use AdbMountInstaller.install instead.") override fun install(apk: Apk) = suspend { installer.install(Installer.Apk(apk.file, apk.packageName)) } @Suppress("DeprecatedCallableAddReplaceWith") - @Deprecated("Use AdbRootInstaller.uninstall instead.") + @Deprecated("Use AdbMountInstaller.uninstall instead.") override fun uninstall(packageName: String) = suspend { installer.uninstall(packageName) } @@ -134,11 +134,11 @@ sealed class AdbManager private constructor( } ?: "No ADB device found", ) - @Deprecated("Use RootInstaller.FailedToFindInstalledPackageException instead.") + @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 RootInstaller.PackageNameRequiredException instead.") + @Deprecated("Use MountInstaller.PackageNameRequiredException instead.") class PackageNameRequiredException internal constructor() : Exception("Package name is required") } diff --git a/src/commonMain/kotlin/app/revanced/library/installation/command/AdbShellCommandRunner.kt b/library/src/commonMain/kotlin/app/revanced/library/installation/command/AdbShellCommandRunner.kt similarity index 100% rename from src/commonMain/kotlin/app/revanced/library/installation/command/AdbShellCommandRunner.kt rename to library/src/commonMain/kotlin/app/revanced/library/installation/command/AdbShellCommandRunner.kt diff --git a/src/commonMain/kotlin/app/revanced/library/installation/command/RunResult.kt b/library/src/commonMain/kotlin/app/revanced/library/installation/command/RunResult.kt similarity index 100% rename from src/commonMain/kotlin/app/revanced/library/installation/command/RunResult.kt rename to library/src/commonMain/kotlin/app/revanced/library/installation/command/RunResult.kt diff --git a/src/commonMain/kotlin/app/revanced/library/installation/command/ShellCommandRunner.kt b/library/src/commonMain/kotlin/app/revanced/library/installation/command/ShellCommandRunner.kt similarity index 100% rename from src/commonMain/kotlin/app/revanced/library/installation/command/ShellCommandRunner.kt rename to library/src/commonMain/kotlin/app/revanced/library/installation/command/ShellCommandRunner.kt diff --git a/src/commonMain/kotlin/app/revanced/library/installation/installer/AdbInstaller.kt b/library/src/commonMain/kotlin/app/revanced/library/installation/installer/AdbInstaller.kt similarity index 100% rename from src/commonMain/kotlin/app/revanced/library/installation/installer/AdbInstaller.kt rename to library/src/commonMain/kotlin/app/revanced/library/installation/installer/AdbInstaller.kt diff --git a/src/commonMain/kotlin/app/revanced/library/installation/installer/AdbInstallerResult.kt b/library/src/commonMain/kotlin/app/revanced/library/installation/installer/AdbInstallerResult.kt similarity index 100% rename from src/commonMain/kotlin/app/revanced/library/installation/installer/AdbInstallerResult.kt rename to library/src/commonMain/kotlin/app/revanced/library/installation/installer/AdbInstallerResult.kt diff --git a/src/commonMain/kotlin/app/revanced/library/installation/installer/AdbRootInstaller.kt b/library/src/commonMain/kotlin/app/revanced/library/installation/installer/AdbMountInstaller.kt similarity index 62% rename from src/commonMain/kotlin/app/revanced/library/installation/installer/AdbRootInstaller.kt rename to library/src/commonMain/kotlin/app/revanced/library/installation/installer/AdbMountInstaller.kt index d2d771f..30e5081 100644 --- a/src/commonMain/kotlin/app/revanced/library/installation/installer/AdbRootInstaller.kt +++ b/library/src/commonMain/kotlin/app/revanced/library/installation/installer/AdbMountInstaller.kt @@ -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.RootInstaller.NoRootPermissionException +import app.revanced.library.installation.installer.MountInstaller.NoRootPermissionException /** - * [AdbRootInstaller] for installing and uninstalling [Apk] files with using ADB root permissions by mounting. + * [AdbMountInstaller] 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 RootInstaller + * @see MountInstaller * @see AdbShellCommandRunner */ -class AdbRootInstaller( +class AdbMountInstaller( deviceSerial: String? = null, -) : RootInstaller({ AdbShellCommandRunner(deviceSerial) }) { +) : MountInstaller({ AdbShellCommandRunner(deviceSerial) }) { init { logger.fine("Connected to $deviceSerial") } diff --git a/src/commonMain/kotlin/app/revanced/library/installation/installer/Constants.kt b/library/src/commonMain/kotlin/app/revanced/library/installation/installer/Constants.kt similarity index 100% rename from src/commonMain/kotlin/app/revanced/library/installation/installer/Constants.kt rename to library/src/commonMain/kotlin/app/revanced/library/installation/installer/Constants.kt diff --git a/src/commonMain/kotlin/app/revanced/library/installation/installer/Installation.kt b/library/src/commonMain/kotlin/app/revanced/library/installation/installer/Installation.kt similarity index 100% rename from src/commonMain/kotlin/app/revanced/library/installation/installer/Installation.kt rename to library/src/commonMain/kotlin/app/revanced/library/installation/installer/Installation.kt diff --git a/src/commonMain/kotlin/app/revanced/library/installation/installer/Installer.kt b/library/src/commonMain/kotlin/app/revanced/library/installation/installer/Installer.kt similarity index 100% rename from src/commonMain/kotlin/app/revanced/library/installation/installer/Installer.kt rename to library/src/commonMain/kotlin/app/revanced/library/installation/installer/Installer.kt diff --git a/src/commonMain/kotlin/app/revanced/library/installation/installer/RootInstallation.kt b/library/src/commonMain/kotlin/app/revanced/library/installation/installer/MountInstallation.kt similarity index 74% rename from src/commonMain/kotlin/app/revanced/library/installation/installer/RootInstallation.kt rename to library/src/commonMain/kotlin/app/revanced/library/installation/installer/MountInstallation.kt index 95c7257..4f73f8a 100644 --- a/src/commonMain/kotlin/app/revanced/library/installation/installer/RootInstallation.kt +++ b/library/src/commonMain/kotlin/app/revanced/library/installation/installer/MountInstallation.kt @@ -1,14 +1,14 @@ package app.revanced.library.installation.installer /** - * [RootInstallation] of the apk file that is mounted to [installedApkFilePath] with root permissions. + * [MountInstallation] 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 RootInstallation internal constructor( +class MountInstallation internal constructor( val installedApkFilePath: String?, apkFilePath: String, val mounted: Boolean, diff --git a/src/commonMain/kotlin/app/revanced/library/installation/installer/RootInstaller.kt b/library/src/commonMain/kotlin/app/revanced/library/installation/installer/MountInstaller.kt similarity index 86% rename from src/commonMain/kotlin/app/revanced/library/installation/installer/RootInstaller.kt rename to library/src/commonMain/kotlin/app/revanced/library/installation/installer/MountInstaller.kt index 9fd4fac..1539a35 100644 --- a/src/commonMain/kotlin/app/revanced/library/installation/installer/RootInstaller.kt +++ b/library/src/commonMain/kotlin/app/revanced/library/installation/installer/MountInstaller.kt @@ -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.RootInstaller.NoRootPermissionException +import app.revanced.library.installation.installer.MountInstaller.NoRootPermissionException import java.io.File /** - * [RootInstaller] for installing and uninstalling [Apk] files using root permissions by mounting. + * [MountInstaller] 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 RootInstaller internal constructor( - shellCommandRunnerSupplier: (RootInstaller) -> ShellCommandRunner, -) : Installer() { +abstract class MountInstaller internal constructor( + shellCommandRunnerSupplier: (MountInstaller) -> ShellCommandRunner, +) : Installer() { /** * The command runner used to run commands on the device. @@ -49,7 +49,7 @@ abstract class RootInstaller internal constructor( * * @throws PackageNameRequiredException If the [Apk] does not have a package name. */ - override suspend fun install(apk: Apk): RootInstallerResult { + override suspend fun install(apk: Apk): MountInstallerResult { logger.info("Installing ${apk.packageName} by mounting") val packageName = apk.packageName?.also { it.assertInstalled() } ?: throw PackageNameRequiredException() @@ -67,10 +67,10 @@ abstract class RootInstaller internal constructor( DELETE(TMP_FILE_PATH)() - return RootInstallerResult.SUCCESS + return MountInstallerResult.SUCCESS } - override suspend fun uninstall(packageName: String): RootInstallerResult { + override suspend fun uninstall(packageName: String): MountInstallerResult { logger.info("Uninstalling $packageName by unmounting") UMOUNT(packageName)() @@ -81,16 +81,16 @@ abstract class RootInstaller internal constructor( KILL(packageName)() - return RootInstallerResult.SUCCESS + return MountInstallerResult.SUCCESS } - override suspend fun getInstallation(packageName: String): RootInstallation? { + override suspend fun getInstallation(packageName: String): MountInstallation? { val patchedApkPath = MOUNTED_APK_PATH(packageName) val patchedApkExists = EXISTS(patchedApkPath)().exitCode == 0 if (patchedApkExists) return null - return RootInstallation( + return MountInstallation( INSTALLED_APK_PATH(packageName)().output.ifEmpty { null }, patchedApkPath, MOUNT_GREP(patchedApkPath)().exitCode == 0, diff --git a/src/commonMain/kotlin/app/revanced/library/installation/installer/RootInstallerResult.kt b/library/src/commonMain/kotlin/app/revanced/library/installation/installer/MountInstallerResult.kt similarity index 79% rename from src/commonMain/kotlin/app/revanced/library/installation/installer/RootInstallerResult.kt rename to library/src/commonMain/kotlin/app/revanced/library/installation/installer/MountInstallerResult.kt index f9fe940..72783ea 100644 --- a/src/commonMain/kotlin/app/revanced/library/installation/installer/RootInstallerResult.kt +++ b/library/src/commonMain/kotlin/app/revanced/library/installation/installer/MountInstallerResult.kt @@ -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 [RootInstaller]. + * The result of installing or uninstalling an [Apk] with root permissions using [MountInstaller]. * - * @see RootInstaller + * @see MountInstaller */ -enum class RootInstallerResult { +enum class MountInstallerResult { /** * The result of installing an [Apk] successfully. */ diff --git a/src/commonMain/kotlin/app/revanced/library/installation/installer/Utils.kt b/library/src/commonMain/kotlin/app/revanced/library/installation/installer/Utils.kt similarity index 100% rename from src/commonMain/kotlin/app/revanced/library/installation/installer/Utils.kt rename to library/src/commonMain/kotlin/app/revanced/library/installation/installer/Utils.kt diff --git a/src/commonMain/kotlin/app/revanced/library/logging/Logger.kt b/library/src/commonMain/kotlin/app/revanced/library/logging/Logger.kt similarity index 100% rename from src/commonMain/kotlin/app/revanced/library/logging/Logger.kt rename to library/src/commonMain/kotlin/app/revanced/library/logging/Logger.kt diff --git a/src/commonTest/kotlin/app/revanced/library/PatchOptionsTest.kt b/library/src/commonTest/kotlin/app/revanced/library/PatchOptionsTest.kt similarity index 100% rename from src/commonTest/kotlin/app/revanced/library/PatchOptionsTest.kt rename to library/src/commonTest/kotlin/app/revanced/library/PatchOptionsTest.kt diff --git a/src/commonTest/kotlin/app/revanced/library/PatchUtilsTest.kt b/library/src/commonTest/kotlin/app/revanced/library/PatchUtilsTest.kt similarity index 100% rename from src/commonTest/kotlin/app/revanced/library/PatchUtilsTest.kt rename to library/src/commonTest/kotlin/app/revanced/library/PatchUtilsTest.kt diff --git a/settings.gradle.kts b/settings.gradle.kts index e164b40..2a7fbb4 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,6 +1,3 @@ -// TODO: Figure out why this causes problems. -rootProject.name = "revanced-library" - buildCache { local { isEnabled = "CI" !in System.getenv() @@ -9,7 +6,10 @@ buildCache { pluginManagement { repositories { - google() + gradlePluginPortal() mavenCentral() + google() } } + +include(":library", ":library-networking")