Skip to content

Commit 166f940

Browse files
authored
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).
1 parent e0efa02 commit 166f940

3 files changed

Lines changed: 73 additions & 49 deletions

File tree

src/main/kotlin/app/morphe/cli/command/PatchCommand.kt

Lines changed: 13 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,8 @@ import app.morphe.engine.isWindows
1515
import app.morphe.engine.PatchEngine.Config.Companion.DEFAULT_KEYSTORE_ALIAS
1616
import app.morphe.engine.PatchEngine.Config.Companion.DEFAULT_KEYSTORE_PASSWORD
1717
import app.morphe.engine.PatchEngine.Config.Companion.DEFAULT_SIGNER_NAME
18-
import app.morphe.engine.PatchEngine.Config.Companion.LEGACY_KEYSTORE_ALIAS
19-
import app.morphe.engine.PatchEngine.Config.Companion.LEGACY_KEYSTORE_PASSWORD
2018
import app.morphe.engine.UpdateChecker
19+
import app.morphe.engine.util.signWithLegacyFallback
2120
import app.morphe.engine.patches.LoadedBundle
2221
import app.morphe.engine.patches.PatchBundleLoader
2322
import app.morphe.library.installation.installer.*
@@ -836,33 +835,18 @@ internal object PatchCommand : Callable<Int> {
836835
patchingResult.addStepResult(
837836
PatchingStep.SIGNING,
838837
{
839-
fun signApk(alias: String, password: String) {
840-
ApkUtils.signApk(
841-
patchedApkFile,
842-
outputFilePath,
843-
signer,
844-
ApkUtils.KeyStoreDetails(
845-
keystoreFilePath,
846-
keyStorePassword,
847-
alias,
848-
password,
849-
)
850-
)
851-
}
852-
try {
853-
signApk(keyStoreEntryAlias, keyStoreEntryPassword)
854-
} catch (e: Exception){
855-
// Retry with legacy keystore defaults.
856-
if (keyStoreEntryAlias == DEFAULT_KEYSTORE_ALIAS &&
857-
keyStoreEntryPassword == DEFAULT_KEYSTORE_PASSWORD &&
858-
keystoreFilePath.exists()
859-
) {
860-
logger.info("Using legacy keystore credentials")
861-
862-
signApk(LEGACY_KEYSTORE_ALIAS, LEGACY_KEYSTORE_PASSWORD)
863-
} else {
864-
throw e
865-
}
838+
signWithLegacyFallback(
839+
primary = ApkUtils.KeyStoreDetails(
840+
keystoreFilePath,
841+
keyStorePassword,
842+
keyStoreEntryAlias,
843+
keyStoreEntryPassword,
844+
),
845+
allowLegacyFallback = keyStoreEntryAlias == DEFAULT_KEYSTORE_ALIAS &&
846+
keyStoreEntryPassword == DEFAULT_KEYSTORE_PASSWORD,
847+
logger = logger,
848+
) { details ->
849+
ApkUtils.signApk(patchedApkFile, outputFilePath, signer, details)
866850
}
867851
}
868852
)

src/main/kotlin/app/morphe/engine/PatchEngine.kt

Lines changed: 6 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
package app.morphe.engine
1010

11+
import app.morphe.engine.util.signWithLegacyFallback
1112
import app.morphe.patcher.Patcher
1213
import app.morphe.patcher.PatcherConfig
1314
import app.morphe.patcher.apk.ApkMerger
@@ -244,33 +245,18 @@ object PatchEngine {
244245
}
245246

246247
try {
247-
fun signApk(details: ApkUtils.KeyStoreDetails) {
248+
signWithLegacyFallback(
249+
primary = keystoreDetails,
250+
allowLegacyFallback = config.keystoreDetails == null,
251+
logger = logger,
252+
) { details ->
248253
ApkUtils.signApk(
249254
rebuiltApk,
250255
tempOutput,
251256
config.signerName,
252257
details,
253258
)
254259
}
255-
256-
try {
257-
signApk(keystoreDetails)
258-
} catch (e: Exception) {
259-
// Retry with legacy keystore defaults.
260-
if (config.keystoreDetails == null && keystoreDetails.keyStore.exists()) {
261-
logger.info("Using legacy keystore credentials")
262-
263-
val legacyKeystoreDetails = ApkUtils.KeyStoreDetails(
264-
keystoreDetails.keyStore,
265-
null,
266-
Config.LEGACY_KEYSTORE_ALIAS,
267-
Config.LEGACY_KEYSTORE_PASSWORD,
268-
)
269-
signApk(legacyKeystoreDetails)
270-
} else {
271-
throw e
272-
}
273-
}
274260
stepResults.add(StepResult(PatchStep.SIGNING, true))
275261
} catch (e: Exception) {
276262
stepResults.add(StepResult(PatchStep.SIGNING, false, e.toString()))
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/*
2+
* Copyright 2026 Morphe.
3+
* https://github.com/MorpheApp/morphe-cli
4+
*/
5+
6+
package app.morphe.engine.util
7+
8+
import app.morphe.engine.PatchEngine
9+
import app.morphe.patcher.apk.ApkUtils
10+
import java.util.logging.Logger
11+
12+
/**
13+
* Signs an APK with [primary] credentials, falling back to the legacy ("Morphe Key" / empty password) entry.
14+
* The legacy retry only fires when [allowLegacyFallback] is true AND the keystore file already exists,
15+
* i.e. the user is on default credentials and we're reading a pre-existing keystore that might predate the current alias.
16+
* This preserves the exact condition both call sites (CLI + engine) used before.
17+
*
18+
* On double failure the PRIMARY exception is thrown (legacy attached as suppressed).
19+
* The primary error is the meaningful one: the user expects the current Morphe key,
20+
* so "no 'Morphe' entry" is more actionable than whatever the legacy retry hit.
21+
* The old behavior threw the *legacy* failure, which surfaced confusing errors.
22+
*
23+
* [sign] performs the actual signing; callers wrap this call with their own progress / step-result reporting.
24+
*/
25+
fun signWithLegacyFallback(
26+
primary: ApkUtils.KeyStoreDetails,
27+
allowLegacyFallback: Boolean,
28+
logger: Logger,
29+
sign: (ApkUtils.KeyStoreDetails) -> Unit,
30+
) {
31+
try {
32+
sign(primary)
33+
} catch (primaryError: Exception) {
34+
if (!allowLegacyFallback || !primary.keyStore.exists()) throw primaryError
35+
36+
// Never silently swallow the real cause. Always log it before the back-compat path.
37+
logger.info(
38+
"Default keystore credentials failed (${primaryError.message}). Retrying with legacy credentials"
39+
)
40+
41+
val legacy = ApkUtils.KeyStoreDetails(
42+
primary.keyStore,
43+
primary.keyStorePassword,
44+
PatchEngine.Config.LEGACY_KEYSTORE_ALIAS,
45+
PatchEngine.Config.LEGACY_KEYSTORE_PASSWORD,
46+
)
47+
try {
48+
sign(legacy)
49+
} catch (legacyError: Exception) {
50+
primaryError.addSuppressed(legacyError)
51+
throw primaryError
52+
}
53+
}
54+
}

0 commit comments

Comments
 (0)