Skip to content

Commit

Permalink
chore: Merge branch dev to main (#1329)
Browse files Browse the repository at this point in the history
  • Loading branch information
oSumAtrIX authored Oct 4, 2023
2 parents 5838550 + 7ae0915 commit d9acd0d
Show file tree
Hide file tree
Showing 26 changed files with 343 additions and 610 deletions.
2 changes: 1 addition & 1 deletion android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"

// ReVanced
implementation "app.revanced:revanced-patcher:14.2.2"
implementation "app.revanced:revanced-patcher:16.0.0"

// Signing & aligning
implementation("org.bouncycastle:bcpkix-jdk15on:1.70")
Expand Down
4 changes: 4 additions & 0 deletions android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity
android:name=".ExportSettingsActivity"
android:exported="true">
</activity>
<meta-data
android:name="flutterEmbedding"
android:value="2" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package app.revanced.manager.flutter

import android.app.Activity
import android.content.Context
import android.content.Intent
import android.content.pm.PackageInfo
import android.content.pm.PackageManager
import android.os.Bundle
import android.util.Base64
import org.json.JSONObject
import java.io.ByteArrayInputStream
import java.io.File
import java.security.cert.CertificateFactory
import java.security.cert.X509Certificate
import java.security.MessageDigest

class ExportSettingsActivity : Activity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val callingPackageName = getCallingPackage()!!

if (getFingerprint(callingPackageName) == getFingerprint(getPackageName())) {
// Create JSON Object
val json = JSONObject()

// Default Data
json.put("keystorePassword", "s3cur3p@ssw0rd")

// Load Shared Preferences
val sharedPreferences = getSharedPreferences("FlutterSharedPreferences", Context.MODE_PRIVATE)
val allEntries: Map<String, *> = sharedPreferences.getAll()
for ((key, value) in allEntries.entries) {
json.put(
key.replace("flutter.", ""),
if (value is Boolean) if (value) 1 else 0 else value
)
}

// Load keystore
val keystoreFile = File(getExternalFilesDir(null), "/revanced-manager.keystore")
if (keystoreFile.exists()) {
val keystoreBytes = keystoreFile.readBytes()
val keystoreBase64 = Base64.encodeToString(keystoreBytes, Base64.DEFAULT)
json.put("keystore", keystoreBase64)
}

// Load saved patches
val storedPatchesFile = File(filesDir.parentFile.absolutePath, "/app_flutter/selected-patches.json")
if (storedPatchesFile.exists()) {
val patchesBytes = storedPatchesFile.readBytes()
val patches = String(patchesBytes, Charsets.UTF_8)
json.put("patches", JSONObject(patches))
}

// Send data back
val resultIntent = Intent()
resultIntent.putExtra("data", json.toString())
setResult(Activity.RESULT_OK, resultIntent)
finish()
} else {
val resultIntent = Intent()
setResult(Activity.RESULT_CANCELED)
finish()
}
}

fun getFingerprint(packageName: String): String {
// Get the signature of the app that matches the package name
val packageInfo = packageManager.getPackageInfo(packageName, PackageManager.GET_SIGNATURES)
val signature = packageInfo.signatures[0]

// Get the raw certificate data
val rawCert = signature.toByteArray()

// Generate an X509Certificate from the data
val certFactory = CertificateFactory.getInstance("X509")
val x509Cert = certFactory.generateCertificate(ByteArrayInputStream(rawCert)) as X509Certificate

// Get the SHA256 fingerprint
val fingerprint = MessageDigest.getInstance("SHA256").digest(x509Cert.encoded).joinToString("") {
"%02x".format(it)
}

return fingerprint
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,21 @@ import app.revanced.manager.flutter.utils.signing.Signer
import app.revanced.manager.flutter.utils.zip.ZipFile
import app.revanced.manager.flutter.utils.zip.structures.ZipEntry
import app.revanced.patcher.PatchBundleLoader
import app.revanced.patcher.PatchSet
import app.revanced.patcher.Patcher
import app.revanced.patcher.PatcherOptions
import app.revanced.patcher.extensions.PatchExtensions.compatiblePackages
import app.revanced.patcher.extensions.PatchExtensions.dependencies
import app.revanced.patcher.extensions.PatchExtensions.description
import app.revanced.patcher.extensions.PatchExtensions.include
import app.revanced.patcher.extensions.PatchExtensions.patchName
import app.revanced.patcher.patch.PatchResult
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodChannel
import kotlinx.coroutines.cancel
import kotlinx.coroutines.runBlocking
import org.json.JSONArray
import org.json.JSONObject
import java.io.File
import java.io.PrintWriter
import java.io.StringWriter
import java.lang.Error
import java.util.logging.LogRecord
import java.util.logging.Logger

Expand All @@ -33,6 +32,8 @@ class MainActivity : FlutterActivity() {
private var cancel: Boolean = false
private var stopResult: MethodChannel.Result? = null

private lateinit var patches: PatchSet

override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)

Expand All @@ -48,7 +49,6 @@ class MainActivity : FlutterActivity() {
mainChannel.setMethodCallHandler { call, result ->
when (call.method) {
"runPatcher" -> {
val patchBundleFilePath = call.argument<String>("patchBundleFilePath")
val originalFilePath = call.argument<String>("originalFilePath")
val inputFilePath = call.argument<String>("inputFilePath")
val patchedFilePath = call.argument<String>("patchedFilePath")
Expand All @@ -59,7 +59,7 @@ class MainActivity : FlutterActivity() {
val keyStoreFilePath = call.argument<String>("keyStoreFilePath")
val keystorePassword = call.argument<String>("keystorePassword")

if (patchBundleFilePath != null &&
if (
originalFilePath != null &&
inputFilePath != null &&
patchedFilePath != null &&
Expand All @@ -73,7 +73,6 @@ class MainActivity : FlutterActivity() {
cancel = false
runPatcher(
result,
patchBundleFilePath,
originalFilePath,
inputFilePath,
patchedFilePath,
Expand All @@ -93,29 +92,44 @@ class MainActivity : FlutterActivity() {
}

"getPatches" -> {
val patchBundleFilePath = call.argument<String>("patchBundleFilePath")
val cacheDirPath = call.argument<String>("cacheDirPath")
val patchBundleFilePath = call.argument<String>("patchBundleFilePath")!!
val cacheDirPath = call.argument<String>("cacheDirPath")!!

if (patchBundleFilePath != null) {
val patches = PatchBundleLoader.Dex(
try {
patches = PatchBundleLoader.Dex(
File(patchBundleFilePath),
optimizedDexDirectory = File(cacheDirPath)
).map { patch ->
val map = HashMap<String, Any>()
map["\"name\""] = "\"${patch.patchName.replace("\"","\\\"")}\""
map["\"description\""] = "\"${patch.description?.replace("\"","\\\"")}\""
map["\"excluded\""] = !patch.include
map["\"dependencies\""] = patch.dependencies?.map { "\"${it.java.patchName}\"" } ?: emptyList<Any>()
map["\"compatiblePackages\""] = patch.compatiblePackages?.map {
val map2 = HashMap<String, Any>()
map2["\"name\""] = "\"${it.name}\""
map2["\"versions\""] = it.versions.map { version -> "\"${version}\"" }
map2
} ?: emptyList<Any>()
map
)
} catch (ex: Exception) {
return@setMethodCallHandler result.notImplemented()
} catch (err: Error) {
return@setMethodCallHandler result.notImplemented()
}

JSONArray().apply {
patches.forEach {
JSONObject().apply {
put("name", it.name)
put("description", it.description)
put("excluded", !it.use)
put("compatiblePackages", JSONArray().apply {
it.compatiblePackages?.forEach { compatiblePackage ->
val compatiblePackageJson = JSONObject().apply {
put("name", compatiblePackage.name)
put(
"versions",
JSONArray().apply {
compatiblePackage.versions?.forEach { version ->
put(version)
}
})
}
put(compatiblePackageJson)
}
})
}.let(::put)
}
result.success(patches)
} else result.notImplemented()
}.toString().let(result::success)
}

else -> result.notImplemented()
Expand All @@ -125,7 +139,6 @@ class MainActivity : FlutterActivity() {

private fun runPatcher(
result: MethodChannel.Result,
patchBundleFilePath: String,
originalFilePath: String,
inputFilePath: String,
patchedFilePath: String,
Expand Down Expand Up @@ -168,8 +181,11 @@ class MainActivity : FlutterActivity() {
}

object : java.util.logging.Handler() {
override fun publish(record: LogRecord) =
override fun publish(record: LogRecord) {
if (record.loggerName?.startsWith("app.revanced") != true) return

updateProgress(-1.0, "", record.message)
}

override fun flush() = Unit
override fun close() = flush()
Expand Down Expand Up @@ -209,18 +225,15 @@ class MainActivity : FlutterActivity() {

updateProgress(0.1, "Loading patches...", "Loading patches")

val patches = PatchBundleLoader.Dex(
File(patchBundleFilePath),
optimizedDexDirectory = cacheDir
).filter { patch ->
val patches = patches.filter { patch ->
val isCompatible = patch.compatiblePackages?.any {
it.name == patcher.context.packageMetadata.packageName
} ?: false

val compatibleOrUniversal =
isCompatible || patch.compatiblePackages.isNullOrEmpty()

compatibleOrUniversal && selectedPatches.any { it == patch.patchName }
compatibleOrUniversal && selectedPatches.any { it == patch.name }
}

if (cancel) {
Expand Down Expand Up @@ -251,9 +264,9 @@ class MainActivity : FlutterActivity() {
val msg = patchResult.exception?.let {
val writer = StringWriter()
it.printStackTrace(PrintWriter(writer))
"${patchResult.patchName} failed: $writer"
"${patchResult.patch.name} failed: $writer"
} ?: run {
"${patchResult.patchName} succeeded"
"${patchResult.patch.name} succeeded"
}

updateProgress(progress, "", msg)
Expand Down Expand Up @@ -317,7 +330,7 @@ class MainActivity : FlutterActivity() {
val stack = ex.stackTraceToString()
updateProgress(
-100.0,
"Aborted",
"Failed",
"An error occurred:\n$stack"
)
}
Expand Down
21 changes: 6 additions & 15 deletions assets/i18n/en_US.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,13 @@
"widgetTitle": "Dashboard",

"updatesSubtitle": "Updates",
"patchedSubtitle": "Patched applications",
"patchedSubtitle": "Patched apps",

"noUpdates": "No updates available",

"WIP": "Work in progress...",

"noInstallations": "No patched applications installed",
"noInstallations": "No patched apps installed",
"installUpdate": "Continue to install the update?",

"updateDialogTitle": "Update Manager",
Expand All @@ -56,9 +56,7 @@
"updatesDisabled": "Updating a patched app is currently disabled. Repatch the app again."
},
"applicationItem": {
"patchButton": "Patch",
"infoButton": "Info",
"changelogLabel": "Changelog"
"infoButton": "Info"
},
"latestCommitCard": {
"loadingLabel": "Loading...",
Expand All @@ -71,9 +69,8 @@
"widgetTitle": "Patcher",
"patchButton": "Patch",

"patchDialogText": "You have selected a resource patch and a split APK installation has been detected, so patching errors may occur.\nAre you sure you want to proceed?",
"armv7WarningDialogText": "Patching on ARMv7 devices is not yet supported and might fail. Proceed anyways?",
"splitApkWarningDialogText": "Patching a split APK is not yet supported and might fail. Proceed anyways?",

"removedPatchesWarningDialogText": "The following patches have been removed since the last time you used them.\n\n{patches}\n\nProceed anyways?"
},
"appSelectorCard": {
Expand Down Expand Up @@ -148,9 +145,8 @@
"installTypeDescription": "Select the installation type to proceed with.",

"installButton": "Install",
"installRootType": "Root",
"installNonRootType": "Non-root",
"installRecommendedType": "Recommended",
"installRootType": "Mount",
"installNonRootType": "Normal",

"pressBackAgain": "Press back again to cancel",
"openButton": "Open",
Expand All @@ -162,10 +158,6 @@
"exportApkButtonTooltip": "Export patched APK",
"exportLogButtonTooltip": "Export log",

"installErrorDialogTitle": "Error",
"installErrorDialogText1": "Root install is not possible with the current patches selection.\nRepatch your app or choose non-root install.",
"installErrorDialogText2": "Non-root install is not possible with the current patches selection.\nRepatch your app or choose root install if you have your device rooted.",
"installErrorDialogText3": "Root install is not possible as the original APK was selected from storage.\nSelect an installed app or choose non-root install.",
"noExit": "Installer is still running, cannot exit..."
},
"settingsView": {
Expand Down Expand Up @@ -285,7 +277,6 @@
"rootDialogText": "App was installed with superuser permissions, but currently ReVanced Manager has no permissions.\nPlease grant superuser permissions first.",

"packageNameLabel": "Package name",
"originalPackageNameLabel": "Original package name",
"installTypeLabel": "Installation type",
"rootTypeLabel": "Root",
"nonRootTypeLabel": "Non-root",
Expand Down
2 changes: 1 addition & 1 deletion docs/4_building.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ This page will guide you through building ReVanced Manager from source.

3. Create a GitHub personal access token with the `read:packages` scope [here](https://github.com/settings/tokens/new?scopes=read:packages&description=ReVanced)

4. Add your GitHub username and the token to `~/.gradle/gradle.properties`
4. Add your GitHub username and the token to `~/android/gradle.properties`

```properties
gpr.user = YourUsername
Expand Down
Loading

0 comments on commit d9acd0d

Please sign in to comment.