Drop v1 signature & UI improvement

This commit is contained in:
Nullptr 2022-09-06 21:20:06 +08:00
parent b1691a95e2
commit 2e2c818de6
No known key found for this signature in database
7 changed files with 15 additions and 67 deletions

View File

@ -25,8 +25,6 @@ object Patcher {
add("-o"); add(lspApp.tmpApkDir.absolutePath) add("-o"); add(lspApp.tmpApkDir.absolutePath)
if (config.debuggable) add("-d") if (config.debuggable) add("-d")
add("-l"); add(config.sigBypassLevel.toString()) add("-l"); add(config.sigBypassLevel.toString())
add("--v1"); add(config.v1.toString())
add("--v2"); add(config.v2.toString())
if (config.useManager) add("--manager") if (config.useManager) add("--manager")
if (config.overrideVersionCode) add("-r") if (config.overrideVersionCode) add("-r")
if (Configs.detailPatchLogs) add("-v") if (Configs.detailPatchLogs) add("-v")

View File

@ -176,7 +176,6 @@ private fun sigBypassLvStr(level: Int) = when (level) {
else -> throw IllegalArgumentException("Invalid sigBypassLv: $level") else -> throw IllegalArgumentException("Invalid sigBypassLv: $level")
} }
@OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
private fun PatchOptionsBody(modifier: Modifier, onAddEmbed: () -> Unit) { private fun PatchOptionsBody(modifier: Modifier, onAddEmbed: () -> Unit) {
val viewModel = viewModel<NewPatchViewModel>() val viewModel = viewModel<NewPatchViewModel>()
@ -236,34 +235,6 @@ private fun PatchOptionsBody(modifier: Modifier, onAddEmbed: () -> Unit) {
title = stringResource(R.string.patch_override_version_code), title = stringResource(R.string.patch_override_version_code),
desc = stringResource(R.string.patch_override_version_code_desc) desc = stringResource(R.string.patch_override_version_code_desc)
) )
var signExpanded by remember { mutableStateOf(false) }
AnywhereDropdown(
expanded = signExpanded,
onDismissRequest = { signExpanded = false },
onClick = { signExpanded = true },
surface = {
SettingsItem(
icon = Icons.Outlined.Edit,
title = stringResource(R.string.patch_sign),
desc = viewModel.sign
.mapIndexedNotNull { index, on -> if (on) "V" + (index + 1) else null }
.joinToString(" + ")
.ifEmpty { "None" }
)
}
) {
repeat(2) { index ->
DropdownMenuItem(
text = {
Row(verticalAlignment = Alignment.CenterVertically) {
Checkbox(checked = viewModel.sign[index], onCheckedChange = { viewModel.sign[index] = !viewModel.sign[index] })
Text("V" + (index + 1))
}
},
onClick = { viewModel.sign[index] = !viewModel.sign[index] }
)
}
}
var bypassExpanded by remember { mutableStateOf(false) } var bypassExpanded by remember { mutableStateOf(false) }
AnywhereDropdown( AnywhereDropdown(
expanded = bypassExpanded, expanded = bypassExpanded,

View File

@ -37,7 +37,6 @@ class NewPatchViewModel : ViewModel() {
var useManager by mutableStateOf(true) var useManager by mutableStateOf(true)
var debuggable by mutableStateOf(false) var debuggable by mutableStateOf(false)
var overrideVersionCode by mutableStateOf(false) var overrideVersionCode by mutableStateOf(false)
val sign = mutableStateListOf(false, true)
var sigBypassLevel by mutableStateOf(2) var sigBypassLevel by mutableStateOf(2)
var embeddedModules = emptyList<AppInfo>() var embeddedModules = emptyList<AppInfo>()
@ -89,7 +88,7 @@ class NewPatchViewModel : ViewModel() {
Log.d(TAG, "Submit patch") Log.d(TAG, "Submit patch")
if (useManager) embeddedModules = emptyList() if (useManager) embeddedModules = emptyList()
patchOptions = Patcher.Options( patchOptions = Patcher.Options(
config = PatchConfig(useManager, debuggable, overrideVersionCode, sign[0], sign[1], sigBypassLevel, null, null), config = PatchConfig(useManager, debuggable, overrideVersionCode, sigBypassLevel, null, null),
apkPaths = listOf(patchApp.app.sourceDir) + (patchApp.app.splitSourceDirs ?: emptyArray()), apkPaths = listOf(patchApp.app.sourceDir) + (patchApp.app.splitSourceDirs ?: emptyArray()),
embeddedModules = embeddedModules.flatMap { listOf(it.app.sourceDir) + (it.app.splitSourceDirs ?: emptyArray()) } embeddedModules = embeddedModules.flatMap { listOf(it.app.sourceDir) + (it.app.splitSourceDirs ?: emptyArray()) }
) )

View File

@ -21,12 +21,10 @@ import org.lsposed.lspatch.Constants.PATCH_FILE_SUFFIX
import org.lsposed.lspatch.config.ConfigManager import org.lsposed.lspatch.config.ConfigManager
import org.lsposed.lspatch.config.Configs import org.lsposed.lspatch.config.Configs
import org.lsposed.lspatch.lspApp import org.lsposed.lspatch.lspApp
import org.lsposed.patch.util.ManifestParser
import java.io.File import java.io.File
import java.io.IOException import java.io.IOException
import java.text.Collator import java.text.Collator
import java.util.* import java.util.*
import java.util.zip.ZipFile
import kotlin.coroutines.resume import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine import kotlin.coroutines.suspendCoroutine
@ -150,9 +148,8 @@ object LSPPackageManager {
suspend fun getAppInfoFromApks(apks: List<Uri>): Result<AppInfo> { suspend fun getAppInfoFromApks(apks: List<Uri>): Result<AppInfo> {
return withContext(Dispatchers.IO) { return withContext(Dispatchers.IO) {
runCatching { runCatching {
val app = ApplicationInfo() var primary: ApplicationInfo? = null
if (apks.size > 1) app.splitSourceDirs = Array<String?>(apks.size - 1) { null } val splits = apks.mapNotNull { uri ->
apks.forEachIndexed { index, uri ->
val src = DocumentFile.fromSingleUri(lspApp, uri) val src = DocumentFile.fromSingleUri(lspApp, uri)
?: throw IOException("DocumentFile is null") ?: throw IOException("DocumentFile is null")
val dst = lspApp.tmpApkDir.resolve(src.name!!) val dst = lspApp.tmpApkDir.resolve(src.name!!)
@ -163,21 +160,18 @@ object LSPPackageManager {
input.copyTo(output) input.copyTo(output)
} }
} }
ZipFile(dst).use { zip -> if (primary == null) {
val entry = zip.getEntry("AndroidManifest.xml") primary = lspApp.packageManager.getPackageArchiveInfo(dst.absolutePath, 0)?.applicationInfo
?: throw IOException("AndroidManifest.xml is not found") if (primary != null) return@mapNotNull null
zip.getInputStream(entry).use {
val info = ManifestParser.parseManifestFile(it)
if (app.packageName != null && app.packageName != info.packageName) {
throw IOException("Selected apks are not of the same app")
}
app.packageName = info.packageName
}
} }
if (index == 0) app.sourceDir = dst.absolutePath dst.absolutePath
else app.splitSourceDirs[index - 1] = dst.absolutePath
} }
AppInfo(app, app.packageName)
// TODO: Check selected apks are from the same app
if (primary == null) throw IllegalArgumentException("No primary apk")
val label = lspApp.packageManager.getApplicationLabel(primary!!).toString()
if (splits.isNotEmpty()) primary!!.splitSourceDirs = splits.toTypedArray()
AppInfo(primary!!, label)
}.recoverCatching { t -> }.recoverCatching { t ->
cleanTmpApkDir() cleanTmpApkDir()
Log.e(TAG, "Failed to load apks", t) Log.e(TAG, "Failed to load apks", t)

View File

@ -53,7 +53,6 @@
<string name="patch_portable_desc">Patch an app with modules embedded.\nThe patched app can run without the manager, but cannot be managed dynamically.\nPortable patched apps can be used on devices that do not have LSPatch Manager installed.</string> <string name="patch_portable_desc">Patch an app with modules embedded.\nThe patched app can run without the manager, but cannot be managed dynamically.\nPortable patched apps can be used on devices that do not have LSPatch Manager installed.</string>
<string name="patch_embed_modules">Embed modules</string> <string name="patch_embed_modules">Embed modules</string>
<string name="patch_debuggable">Debuggable</string> <string name="patch_debuggable">Debuggable</string>
<string name="patch_sign">Sign</string>
<string name="patch_sigbypass">Signature bypass</string> <string name="patch_sigbypass">Signature bypass</string>
<string name="patch_sigbypasslv0">lv0: Off</string> <string name="patch_sigbypasslv0">lv0: Off</string>
<string name="patch_sigbypasslv1">lv1: Bypass PM</string> <string name="patch_sigbypasslv1">lv1: Bypass PM</string>

View File

@ -79,12 +79,6 @@ public class LSPatch {
@Parameter(names = {"-k", "--keystore"}, arity = 4, description = "Set custom signature keystore. Followed by 4 arguments: keystore path, keystore password, keystore alias, keystore alias password") @Parameter(names = {"-k", "--keystore"}, arity = 4, description = "Set custom signature keystore. Followed by 4 arguments: keystore path, keystore password, keystore alias, keystore alias password")
private List<String> keystoreArgs = Arrays.asList(null, "123456", "key0", "123456"); private List<String> keystoreArgs = Arrays.asList(null, "123456", "key0", "123456");
@Parameter(names = {"--v1"}, arity = 1, description = "Sign with v1 signature")
private boolean v1 = false;
@Parameter(names = {"--v2"}, arity = 1, description = "Sign with v2 signature")
private boolean v2 = true;
@Parameter(names = {"--manager"}, description = "Use manager (Cannot work with embedding modules)") @Parameter(names = {"--manager"}, description = "Use manager (Cannot work with embedding modules)")
private boolean useManager = false; private boolean useManager = false;
@ -207,8 +201,7 @@ public class LSPatch {
var entry = (KeyStore.PrivateKeyEntry) keyStore.getEntry(keystoreArgs.get(2), new KeyStore.PasswordProtection(keystoreArgs.get(3).toCharArray())); var entry = (KeyStore.PrivateKeyEntry) keyStore.getEntry(keystoreArgs.get(2), new KeyStore.PasswordProtection(keystoreArgs.get(3).toCharArray()));
new SigningExtension(SigningOptions.builder() new SigningExtension(SigningOptions.builder()
.setMinSdkVersion(28) .setMinSdkVersion(28)
.setV1SigningEnabled(v1) .setV2SigningEnabled(true)
.setV2SigningEnabled(v2)
.setCertificates((X509Certificate[]) entry.getCertificateChain()) .setCertificates((X509Certificate[]) entry.getCertificateChain())
.setKey(entry.getPrivateKey()) .setKey(entry.getPrivateKey())
.build()).register(dstZFile); .build()).register(dstZFile);
@ -239,7 +232,7 @@ public class LSPatch {
logger.i("Patching apk..."); logger.i("Patching apk...");
// modify manifest // modify manifest
final var config = new PatchConfig(useManager, debuggableFlag, overrideVersionCode, v1, v2, sigbypassLevel, originalSignature, appComponentFactory); final var config = new PatchConfig(useManager, debuggableFlag, overrideVersionCode, sigbypassLevel, originalSignature, appComponentFactory);
final var configBytes = new Gson().toJson(config).getBytes(StandardCharsets.UTF_8); final var configBytes = new Gson().toJson(config).getBytes(StandardCharsets.UTF_8);
final var metadata = Base64.getEncoder().encodeToString(configBytes); final var metadata = Base64.getEncoder().encodeToString(configBytes);
try (var is = new ByteArrayInputStream(modifyManifestFile(manifestEntry.open(), metadata))) { try (var is = new ByteArrayInputStream(modifyManifestFile(manifestEntry.open(), metadata))) {

View File

@ -5,8 +5,6 @@ public class PatchConfig {
public final boolean useManager; public final boolean useManager;
public final boolean debuggable; public final boolean debuggable;
public final boolean overrideVersionCode; public final boolean overrideVersionCode;
public final boolean v1;
public final boolean v2;
public final int sigBypassLevel; public final int sigBypassLevel;
public final String originalSignature; public final String originalSignature;
public final String appComponentFactory; public final String appComponentFactory;
@ -16,8 +14,6 @@ public class PatchConfig {
boolean useManager, boolean useManager,
boolean debuggable, boolean debuggable,
boolean overrideVersionCode, boolean overrideVersionCode,
boolean v1,
boolean v2,
int sigBypassLevel, int sigBypassLevel,
String originalSignature, String originalSignature,
String appComponentFactory String appComponentFactory
@ -25,8 +21,6 @@ public class PatchConfig {
this.useManager = useManager; this.useManager = useManager;
this.debuggable = debuggable; this.debuggable = debuggable;
this.overrideVersionCode = overrideVersionCode; this.overrideVersionCode = overrideVersionCode;
this.v1 = v1;
this.v2 = v2;
this.sigBypassLevel = sigBypassLevel; this.sigBypassLevel = sigBypassLevel;
this.originalSignature = originalSignature; this.originalSignature = originalSignature;
this.appComponentFactory = appComponentFactory; this.appComponentFactory = appComponentFactory;