chore(android): add persistent release-signing keystore generator

An Android APK's signature identifies the app to the OS; a new build must
carry the same one as the last install or Android refuses it as an update.
generate-keystore.sh creates the keystore once, interactively, and refuses
to run again once one exists to avoid ever changing it by accident. The
resulting file is git-ignored — it's a secret that must live outside the
repo, backed up separately.
This commit is contained in:
2026-07-02 21:53:53 +02:00
parent 34b4313a36
commit d0037747b5
3 changed files with 104 additions and 0 deletions
+2
View File
@@ -74,6 +74,8 @@ temp/
*.key *.key
*.pfx *.pfx
*.p12 *.p12
*.keystore
*.jks
secrets/ secrets/
# Wallet data and local runtime state # Wallet data and local runtime state
+37
View File
@@ -0,0 +1,37 @@
# Android release-signing keystore
This folder holds the persistent keystore used to sign release APKs built by
`docker/build.sh android`. Every release must be signed with the **same**
key, or Android refuses to install a new build over a previously installed
one (`INSTALL_FAILED_UPDATE_INCOMPATIBLE`) and forces the user to uninstall
first — which deletes the app's data.
## First-time setup
```bash
./docker/keystore/generate-keystore.sh
```
Run this **once**, on whichever machine will keep producing release builds.
It creates `release.keystore` in this folder and asks for a keystore
password (and, optionally, a separate key password). Nothing is written to
git — `release.keystore` is ignored by `.gitignore`, and the script never
saves the passwords anywhere.
`docker/build.sh android` will refuse to run without this file, and will
prompt you for the same passwords at every build.
## Back it up
The keystore file and its passwords cannot be regenerated: if lost, no
future release can ever update existing installs in place again — every
user would need to uninstall and reinstall from scratch. Copy
`release.keystore` and the passwords to a password manager or encrypted
backup outside this repository as soon as you generate them.
## What NOT to do
- Do not commit `release.keystore` (or any `*.jks`/`*.keystore` file) to git.
- Do not re-run `generate-keystore.sh` once a keystore already exists — it
refuses on purpose; delete the file yourself only if you fully accept the
consequences above.
+65
View File
@@ -0,0 +1,65 @@
#!/usr/bin/env bash
# Generates the persistent Android release-signing keystore used by
# docker/build.sh. Every APK built with this keystore carries the same
# signature, which is what lets Android treat a new release as an update to
# a previously installed one instead of a conflicting, different app.
#
# Run this ONCE. Re-running it after the keystore already exists is refused
# below on purpose: regenerating it changes the signature, and every device
# with a prior release installed would then need a full uninstall (and lose
# any app data that isn't in the wallet file itself) to receive the next
# update.
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
KEYSTORE_PATH="${SCRIPT_DIR}/release.keystore"
ALIAS="palladiumwallet"
if [[ -f "$KEYSTORE_PATH" ]]; then
echo "A keystore already exists at $KEYSTORE_PATH — refusing to overwrite it." >&2
echo "Delete it manually first only if you understand the consequences above." >&2
exit 1
fi
command -v keytool &>/dev/null || {
echo "keytool not found on PATH — install a JDK (e.g. openjdk-17-jdk) and retry." >&2
exit 1
}
echo "Creating the Palladium Wallet Android release-signing keystore."
echo "This file and the passwords you enter now must be kept safe OUTSIDE this"
echo "repository (password manager, encrypted backup, ...). They are never"
echo "committed to git. Losing them means no future release can ever update"
echo "existing installs in place — only a fresh keystore + full user reinstall."
echo
read -r -s -p "Keystore password (min 6 characters): " KS_PASS
echo
read -r -s -p "Confirm keystore password: " KS_PASS_CONFIRM
echo
if [[ "$KS_PASS" != "$KS_PASS_CONFIRM" ]]; then
echo "Passwords do not match." >&2
exit 1
fi
if [[ "${#KS_PASS}" -lt 6 ]]; then
echo "Password too short (keytool requires at least 6 characters)." >&2
exit 1
fi
read -r -s -p "Key password (press Enter to reuse the keystore password): " KEY_PASS
echo
KEY_PASS="${KEY_PASS:-$KS_PASS}"
export KS_PASS KEY_PASS
keytool -genkeypair -v \
-keystore "$KEYSTORE_PATH" \
-alias "$ALIAS" \
-keyalg RSA -keysize 2048 -validity 10000 \
-storepass:env KS_PASS -keypass:env KEY_PASS \
-dname "CN=PalladiumWallet, OU=PalladiumWallet, O=PalladiumWallet, C=IT"
unset KS_PASS KEY_PASS
echo
echo "Keystore created at $KEYSTORE_PATH (git-ignored, alias: $ALIAS)."
echo "Back it up now, together with the passwords — it cannot be regenerated."
echo "./docker/build.sh android will prompt for these same passwords at build time."