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:
@@ -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
|
||||||
|
|||||||
@@ -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.
|
||||||
Executable
+65
@@ -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."
|
||||||
Reference in New Issue
Block a user