From f62a1793601fcfc489f54c558265115530ab6b8d Mon Sep 17 00:00:00 2001 From: LisoUseInAIKyrios <118716522+LisoUseInAIKyrios@users.noreply.github.com> Date: Sun, 31 May 2026 16:29:50 +0300 Subject: [PATCH 01/11] fix: Update to latest ARSCLib --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 2455728..e5f0136 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -6,7 +6,7 @@ kotlin = "2.3.21" # CLI picocli = "4.7.7" arsclib = "d78a66bcee" -morphe-patcher = "1.5.1" +morphe-patcher = "1.5.2-dev.1" morphe-library = "1.3.0" # Compose Desktop From e6f40e4a94dd7f76369fe2a0458a1ea7c6a1b1d1 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Sun, 31 May 2026 13:31:26 +0000 Subject: [PATCH 02/11] chore: Release v1.9.1-dev.1 [skip ci] ## [1.9.1-dev.1](https://github.com/MorpheApp/morphe-cli/compare/v1.9.0...v1.9.1-dev.1) (2026-05-31) ### Bug Fixes * Update to latest ARSCLib ([f62a179](https://github.com/MorpheApp/morphe-cli/commit/f62a1793601fcfc489f54c558265115530ab6b8d)) --- CHANGELOG.md | 7 +++++++ gradle.properties | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 81ebde8..e559afe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +## [1.9.1-dev.1](https://github.com/MorpheApp/morphe-cli/compare/v1.9.0...v1.9.1-dev.1) (2026-05-31) + + +### Bug Fixes + +* Update to latest ARSCLib ([f62a179](https://github.com/MorpheApp/morphe-cli/commit/f62a1793601fcfc489f54c558265115530ab6b8d)) + # [1.9.0](https://github.com/MorpheApp/morphe-cli/compare/v1.8.1...v1.9.0) (2026-05-29) diff --git a/gradle.properties b/gradle.properties index 75a6fa3..a27c30e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ org.gradle.parallel = true org.gradle.caching = true kotlin.code.style = official -version = 1.9.0 +version = 1.9.1-dev.1 From 83d39692541ca81b7bb555dfd60a001fbb97b3f1 Mon Sep 17 00:00:00 2001 From: LisoUseInAIKyrios <118716522+LisoUseInAIKyrios@users.noreply.github.com> Date: Sun, 31 May 2026 18:43:28 +0300 Subject: [PATCH 03/11] fix: Update dependencies --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index e5f0136..0c85fa0 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -5,7 +5,7 @@ kotlin = "2.3.21" # CLI picocli = "4.7.7" -arsclib = "d78a66bcee" +arsclib = "a28c6fb2a7" morphe-patcher = "1.5.2-dev.1" morphe-library = "1.3.0" From 51cc4f15357cdee4961e689be207ac88abf7818a Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Sun, 31 May 2026 15:45:19 +0000 Subject: [PATCH 04/11] chore: Release v1.9.1-dev.2 [skip ci] ## [1.9.1-dev.2](https://github.com/MorpheApp/morphe-cli/compare/v1.9.1-dev.1...v1.9.1-dev.2) (2026-05-31) ### Bug Fixes * Update dependencies ([83d3969](https://github.com/MorpheApp/morphe-cli/commit/83d39692541ca81b7bb555dfd60a001fbb97b3f1)) --- CHANGELOG.md | 7 +++++++ gradle.properties | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e559afe..0a66a2b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +## [1.9.1-dev.2](https://github.com/MorpheApp/morphe-cli/compare/v1.9.1-dev.1...v1.9.1-dev.2) (2026-05-31) + + +### Bug Fixes + +* Update dependencies ([83d3969](https://github.com/MorpheApp/morphe-cli/commit/83d39692541ca81b7bb555dfd60a001fbb97b3f1)) + ## [1.9.1-dev.1](https://github.com/MorpheApp/morphe-cli/compare/v1.9.0...v1.9.1-dev.1) (2026-05-31) diff --git a/gradle.properties b/gradle.properties index a27c30e..b75e1e1 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ org.gradle.parallel = true org.gradle.caching = true kotlin.code.style = official -version = 1.9.1-dev.1 +version = 1.9.1-dev.2 From c7b7854aa64a7cb528a0d543138ef278c88997cb Mon Sep 17 00:00:00 2001 From: LisoUseInAIKyrios <118716522+LisoUseInAIKyrios@users.noreply.github.com> Date: Sun, 31 May 2026 21:32:03 +0300 Subject: [PATCH 05/11] docs: Restore example of multiple patch bundles --- docs/1_usage.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/1_usage.md b/docs/1_usage.md index 930c302..63f21b5 100644 --- a/docs/1_usage.md +++ b/docs/1_usage.md @@ -54,6 +54,12 @@ You can combine the option `-e`, `-d`, `--ei`, `--di` and `--exclusive`. Here is java -jar morphe-cli.jar patch --patches patches.mpp --exclusive -e "Patch name" --ei 123 input.apk ``` +You can also use multiple MPP files. Enable/disable and other bundle specific arguments are applied to the last `--patches` argument: + + ```bash + java -jar morphe-cli.jar patch --patches patches-a.mpp -e "patch a" --patches patches-b.mpp -e "patch b" input.apk + ``` + > [!TIP] > You can use the option `-i` to automatically install the patched app after patching. From 0dd6f2cb433834c983886c51f85c8bcfae4d087c Mon Sep 17 00:00:00 2001 From: Lui22 <30185757+Lui22@users.noreply.github.com> Date: Mon, 1 Jun 2026 22:26:39 +0500 Subject: [PATCH 06/11] chore: Fix comment typo (#162) --- docs/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/README.md b/docs/README.md index fb4620f..0ecbd1e 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,6 +1,6 @@ # 💻 Documentation and guides of Morphe CLI -This documentation contains topics around [Morphe CLI](https://github.com/MorpheApp/morphes-cli). +This documentation contains topics around [Morphe CLI](https://github.com/MorpheApp/morphe-cli). ## 📖 Table of contents From aa71c7ee01b3063410826441a82f946d0fa8ed26 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 2 Jun 2026 01:28:24 +0300 Subject: [PATCH 07/11] chore(deps): bump ktor from 3.4.3 to 3.5.0 (#164) --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 0c85fa0..71aaf7a 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -13,7 +13,7 @@ morphe-library = "1.3.0" compose = "1.10.3" # Networking -ktor = "3.4.3" +ktor = "3.5.0" # DI koin-bom = "4.2.1" From e0efa02ac3da0db8f7d5162580c245548d61e8c5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 2 Jun 2026 01:34:58 +0300 Subject: [PATCH 08/11] chore(deps): bump io.mockk:mockk from 1.14.9 to 1.14.11 (#165) --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 71aaf7a..7b8bfdb 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -29,7 +29,7 @@ kotlinx-serialization = "1.11.0" jna = "5.18.1" # Testing -mockk = "1.14.9" +mockk = "1.14.11" # Logging slf4j = "2.0.18" From 166f9409b1cbe00af7663545c41548ead2c189c5 Mon Sep 17 00:00:00 2001 From: Prateek <129204458+prateek-who@users.noreply.github.com> Date: Tue, 2 Jun 2026 11:13:02 +0530 Subject: [PATCH 09/11] fix: signing improvements (#160) When the default keystore alias/password fails, we log that failure and retry with legacy credentials. Before, the primary failure was swallowed and if the legacy stuff also failed, only the legacy error surfaced. Now we log both the primary failure and legacy error if legacy also fails (legacy attached as suppressed). --- .../app/morphe/cli/command/PatchCommand.kt | 42 +++++---------- .../kotlin/app/morphe/engine/PatchEngine.kt | 26 +++------ .../app/morphe/engine/util/KeystoreSigner.kt | 54 +++++++++++++++++++ 3 files changed, 73 insertions(+), 49 deletions(-) create mode 100644 src/main/kotlin/app/morphe/engine/util/KeystoreSigner.kt diff --git a/src/main/kotlin/app/morphe/cli/command/PatchCommand.kt b/src/main/kotlin/app/morphe/cli/command/PatchCommand.kt index e24a171..4134eb3 100644 --- a/src/main/kotlin/app/morphe/cli/command/PatchCommand.kt +++ b/src/main/kotlin/app/morphe/cli/command/PatchCommand.kt @@ -15,9 +15,8 @@ import app.morphe.engine.isWindows 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.DEFAULT_SIGNER_NAME -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.engine.util.signWithLegacyFallback import app.morphe.engine.patches.LoadedBundle import app.morphe.engine.patches.PatchBundleLoader import app.morphe.library.installation.installer.* @@ -836,33 +835,18 @@ internal object PatchCommand : Callable { patchingResult.addStepResult( PatchingStep.SIGNING, { - 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 - } + signWithLegacyFallback( + primary = ApkUtils.KeyStoreDetails( + keystoreFilePath, + keyStorePassword, + keyStoreEntryAlias, + keyStoreEntryPassword, + ), + allowLegacyFallback = keyStoreEntryAlias == DEFAULT_KEYSTORE_ALIAS && + keyStoreEntryPassword == DEFAULT_KEYSTORE_PASSWORD, + logger = logger, + ) { details -> + ApkUtils.signApk(patchedApkFile, outputFilePath, signer, details) } } ) diff --git a/src/main/kotlin/app/morphe/engine/PatchEngine.kt b/src/main/kotlin/app/morphe/engine/PatchEngine.kt index cddc9cb..26d64a2 100644 --- a/src/main/kotlin/app/morphe/engine/PatchEngine.kt +++ b/src/main/kotlin/app/morphe/engine/PatchEngine.kt @@ -8,6 +8,7 @@ package app.morphe.engine +import app.morphe.engine.util.signWithLegacyFallback import app.morphe.patcher.Patcher import app.morphe.patcher.PatcherConfig import app.morphe.patcher.apk.ApkMerger @@ -244,7 +245,11 @@ object PatchEngine { } try { - fun signApk(details: ApkUtils.KeyStoreDetails) { + signWithLegacyFallback( + primary = keystoreDetails, + allowLegacyFallback = config.keystoreDetails == null, + logger = logger, + ) { details -> ApkUtils.signApk( rebuiltApk, tempOutput, @@ -252,25 +257,6 @@ object PatchEngine { details, ) } - - 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())) diff --git a/src/main/kotlin/app/morphe/engine/util/KeystoreSigner.kt b/src/main/kotlin/app/morphe/engine/util/KeystoreSigner.kt new file mode 100644 index 0000000..c859af7 --- /dev/null +++ b/src/main/kotlin/app/morphe/engine/util/KeystoreSigner.kt @@ -0,0 +1,54 @@ +/* + * Copyright 2026 Morphe. + * https://github.com/MorpheApp/morphe-cli + */ + +package app.morphe.engine.util + +import app.morphe.engine.PatchEngine +import app.morphe.patcher.apk.ApkUtils +import java.util.logging.Logger + +/** + * Signs an APK with [primary] credentials, falling back to the legacy ("Morphe Key" / empty password) entry. + * The legacy retry only fires when [allowLegacyFallback] is true AND the keystore file already exists, + * i.e. the user is on default credentials and we're reading a pre-existing keystore that might predate the current alias. + * This preserves the exact condition both call sites (CLI + engine) used before. + * + * On double failure the PRIMARY exception is thrown (legacy attached as suppressed). + * The primary error is the meaningful one: the user expects the current Morphe key, + * so "no 'Morphe' entry" is more actionable than whatever the legacy retry hit. + * The old behavior threw the *legacy* failure, which surfaced confusing errors. + * + * [sign] performs the actual signing; callers wrap this call with their own progress / step-result reporting. + */ +fun signWithLegacyFallback( + primary: ApkUtils.KeyStoreDetails, + allowLegacyFallback: Boolean, + logger: Logger, + sign: (ApkUtils.KeyStoreDetails) -> Unit, +) { + try { + sign(primary) + } catch (primaryError: Exception) { + if (!allowLegacyFallback || !primary.keyStore.exists()) throw primaryError + + // Never silently swallow the real cause. Always log it before the back-compat path. + logger.info( + "Default keystore credentials failed (${primaryError.message}). Retrying with legacy credentials" + ) + + val legacy = ApkUtils.KeyStoreDetails( + primary.keyStore, + primary.keyStorePassword, + PatchEngine.Config.LEGACY_KEYSTORE_ALIAS, + PatchEngine.Config.LEGACY_KEYSTORE_PASSWORD, + ) + try { + sign(legacy) + } catch (legacyError: Exception) { + primaryError.addSuppressed(legacyError) + throw primaryError + } + } +} From ccb26e21c086858f6f81923efadf037fe4b0a680 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Tue, 2 Jun 2026 05:44:27 +0000 Subject: [PATCH 10/11] chore: Release v1.9.1-dev.3 [skip ci] ## [1.9.1-dev.3](https://github.com/MorpheApp/morphe-cli/compare/v1.9.1-dev.2...v1.9.1-dev.3) (2026-06-02) ### Bug Fixes * signing improvements ([#160](https://github.com/MorpheApp/morphe-cli/issues/160)) ([166f940](https://github.com/MorpheApp/morphe-cli/commit/166f9409b1cbe00af7663545c41548ead2c189c5)) --- CHANGELOG.md | 7 +++++++ gradle.properties | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0a66a2b..7076d12 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +## [1.9.1-dev.3](https://github.com/MorpheApp/morphe-cli/compare/v1.9.1-dev.2...v1.9.1-dev.3) (2026-06-02) + + +### Bug Fixes + +* signing improvements ([#160](https://github.com/MorpheApp/morphe-cli/issues/160)) ([166f940](https://github.com/MorpheApp/morphe-cli/commit/166f9409b1cbe00af7663545c41548ead2c189c5)) + ## [1.9.1-dev.2](https://github.com/MorpheApp/morphe-cli/compare/v1.9.1-dev.1...v1.9.1-dev.2) (2026-05-31) diff --git a/gradle.properties b/gradle.properties index b75e1e1..f363fc2 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ org.gradle.parallel = true org.gradle.caching = true kotlin.code.style = official -version = 1.9.1-dev.2 +version = 1.9.1-dev.3 From 170ad268c9faf862909a3d4019b297ead181a889 Mon Sep 17 00:00:00 2001 From: LisoUseInAIKyrios <118716522+LisoUseInAIKyrios@users.noreply.github.com> Date: Mon, 8 Jun 2026 15:08:15 +0300 Subject: [PATCH 11/11] chore: Update patcher --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 7b8bfdb..e99be64 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -6,7 +6,7 @@ kotlin = "2.3.21" # CLI picocli = "4.7.7" arsclib = "a28c6fb2a7" -morphe-patcher = "1.5.2-dev.1" +morphe-patcher = "1.5.2-dev.2" # TODO: Change to stable release morphe-library = "1.3.0" # Compose Desktop