diff --git a/src/main/kotlin/app/morphe/cli/command/PatchCommand.kt b/src/main/kotlin/app/morphe/cli/command/PatchCommand.kt index 80432c6..4f74c7c 100644 --- a/src/main/kotlin/app/morphe/cli/command/PatchCommand.kt +++ b/src/main/kotlin/app/morphe/cli/command/PatchCommand.kt @@ -19,13 +19,23 @@ import app.morphe.cli.command.model.mergeWith import app.morphe.cli.command.model.toPatchBundle import app.morphe.cli.command.model.toSerializablePatch import app.morphe.cli.command.model.withUpdatedBundle +import app.morphe.engine.PatchEngine +import app.morphe.engine.PatchEngine.Config.Companion.DEFAULT_KEYSTORE_ALIAS +import app.morphe.engine.PatchEngine.Config.Companion.DEFAULT_KEYSTORE_PASSWORD +import app.morphe.engine.PatchEngine.Config.Companion.LEGACY_KEYSTORE_ALIAS +import app.morphe.engine.PatchEngine.Config.Companion.LEGACY_KEYSTORE_PASSWORD import app.morphe.engine.UpdateChecker -import app.morphe.patcher.apk.ApkUtils -import app.morphe.patcher.apk.ApkUtils.applyTo -import app.morphe.library.installation.installer.* +import app.morphe.library.installation.installer.AdbInstaller +import app.morphe.library.installation.installer.AdbInstallerResult +import app.morphe.library.installation.installer.AdbRootInstaller +import app.morphe.library.installation.installer.DeviceNotFoundException +import app.morphe.library.installation.installer.Installer +import app.morphe.library.installation.installer.RootInstallerResult import app.morphe.patcher.Patcher import app.morphe.patcher.PatcherConfig import app.morphe.patcher.apk.ApkMerger +import app.morphe.patcher.apk.ApkUtils +import app.morphe.patcher.apk.ApkUtils.applyTo import app.morphe.patcher.logging.toMorpheLogger import app.morphe.patcher.patch.Patch import app.morphe.patcher.patch.loadPatchesFromJar @@ -196,13 +206,13 @@ internal object PatchCommand : Callable { description = ["Alias of the private key and certificate pair keystore entry."], showDefaultValue = ALWAYS, ) - private var keyStoreEntryAlias = "Morphe Key" + private var keyStoreEntryAlias = PatchEngine.Config.DEFAULT_KEYSTORE_ALIAS @CommandLine.Option( names = ["--keystore-entry-password"], description = ["Password of the keystore entry."], ) - private var keyStoreEntryPassword = "" // Empty password by default + private var keyStoreEntryPassword = PatchEngine.Config.DEFAULT_KEYSTORE_PASSWORD @CommandLine.Option( names = ["--signer"], @@ -666,17 +676,34 @@ internal object PatchCommand : Callable { patchingResult.addStepResult( PatchingStep.SIGNING, { - ApkUtils.signApk( - patchedApkFile, - outputFilePath, - signer, - ApkUtils.KeyStoreDetails( - keystoreFilePath, - keyStorePassword, - keyStoreEntryAlias, - keyStoreEntryPassword, - ), - ) + fun signApk(alias: String, password: String) { + ApkUtils.signApk( + patchedApkFile, + outputFilePath, + signer, + ApkUtils.KeyStoreDetails( + keystoreFilePath, + keyStorePassword, + alias, + password, + ) + ) + } + try { + signApk(keyStoreEntryAlias, keyStoreEntryPassword) + } catch (e: Exception){ + // Retry with legacy keystore defaults. + if (keyStoreEntryAlias == DEFAULT_KEYSTORE_ALIAS && + keyStoreEntryPassword == DEFAULT_KEYSTORE_PASSWORD && + keystoreFilePath.exists() + ) { + logger.info("Using legacy keystore credentials") + + signApk(LEGACY_KEYSTORE_ALIAS, LEGACY_KEYSTORE_PASSWORD) + } else { + throw e + } + } } ) } else { diff --git a/src/main/kotlin/app/morphe/engine/PatchEngine.kt b/src/main/kotlin/app/morphe/engine/PatchEngine.kt index d1d81fa..ec6c9fa 100644 --- a/src/main/kotlin/app/morphe/engine/PatchEngine.kt +++ b/src/main/kotlin/app/morphe/engine/PatchEngine.kt @@ -27,9 +27,11 @@ import java.io.StringWriter import java.nio.file.Files import java.util.logging.Logger -/** +/* * Single patching pipeline shared by CLI and GUI. (Eventually. Right now we are still having 2 pipelines) */ + + object PatchEngine { enum class PatchStep { @@ -54,7 +56,14 @@ object PatchEngine { val aaptBinaryPath: File? = null, val tempDir: File? = null, val failOnError: Boolean = true, - ) + ) { + companion object { + internal const val DEFAULT_KEYSTORE_ALIAS = "Morphe" + internal const val DEFAULT_KEYSTORE_PASSWORD = "Morphe" + internal const val LEGACY_KEYSTORE_ALIAS = "Morphe Key" + internal const val LEGACY_KEYSTORE_PASSWORD = "" + } + } data class Result( val success: Boolean, @@ -215,18 +224,40 @@ object PatchEngine { if (!config.unsigned) { onProgress("Signing APK...") try { + fun signApk(details: ApkUtils.KeyStoreDetails) { + ApkUtils.signApk( + rebuiltApk, + tempOutput, + config.signerName, + details, + ) + } + val keystoreDetails = config.keystoreDetails ?: ApkUtils.KeyStoreDetails( File(tempDir, "morphe.keystore"), null, - "Morphe Key", - "", - ) - ApkUtils.signApk( - rebuiltApk, - tempOutput, - config.signerName, - keystoreDetails, + Config.DEFAULT_KEYSTORE_ALIAS, + Config.DEFAULT_KEYSTORE_PASSWORD, ) + + try { + signApk(keystoreDetails) + } catch (e: Exception){ + // Retry with legacy keystore defaults. + if (config.keystoreDetails == null && keystoreDetails.keyStore.exists()) { + logger.info("Using legacy keystore credentials") + + val legacyKeystoreDetails = ApkUtils.KeyStoreDetails( + keystoreDetails.keyStore, + null, + Config.LEGACY_KEYSTORE_ALIAS, + Config.LEGACY_KEYSTORE_PASSWORD, + ) + signApk(legacyKeystoreDetails) + } else { + throw e + } + } stepResults.add(StepResult(PatchStep.SIGNING, true)) } catch (e: Exception) { stepResults.add(StepResult(PatchStep.SIGNING, false, e.toString()))