Files
2026-10-13 21:27:42 -04:00

77 lines
4.2 KiB
Bash
Executable File

#!/usr/bin/env bash
set -euo pipefail
die() { echo "::error::$*" >&2; exit 1; }
[ $# -eq 3 ] || die "usage: sign-apk.sh <in.apk> <variant> <out.apk>"
in=$1 variant=$2 out=$3
here=$(cd "$(dirname "$0")" && pwd)
repo=$(cd "$here/../.." && pwd)
pkg=$(awk -v v="$variant" '!/^#/ && $1 == v { print $2 }' "$here/variants.txt")
[ -n "$pkg" ] || die "no variant '$variant' in tools/release/variants.txt"
expected=${RELEASE_SIGNER_SHA256:-$(tr -d ' \n' < "$repo/keystore/release-signer.sha256" 2>/dev/null || true)}
[[ $expected =~ ^[0-9a-f]{64}$ ]] \
|| die "keystore/release-signer.sha256 is missing: make the key first (tools/release/make-release-key.sh)"
: "${RELEASE_KEYSTORE:?}" "${RELEASE_STORE_PASSWORD:?}" "${RELEASE_KEY_ALIAS:?}" "${BUILD_TOOLS:?}"
[ -s "$RELEASE_KEYSTORE" ] || die "the release keystore is empty - is the secret set for this environment?"
TESTKEY="$repo/keystore/testkey.p12"
TESTKEY_SHA256=a40da80a59d170caa950cf15c18c454d47a39b26989d8b640ecd745ba71bf5dc
export TESTKEY_PASSWORD=android
work=$(mktemp -d)
trap 'rm -rf "$work"' EXIT
P=com.droiddeck.launcher
if [ "$pkg" = "$P" ]; then
python3 "$here/axml_rename.py" "$in" "$work/renamed.apk"
else
python3 "$here/axml_rename.py" "$in" "$work/renamed.apk" \
"$P=$pkg" "$P.androidx-startup=$pkg.androidx-startup" "$P.logs=$pkg.logs" \
"$P.documents=$pkg.documents" "$P.home=$pkg.home" "$P.agent=$pkg.agent" \
"$P.DYNAMIC_RECEIVER_NOT_EXPORTED_PERMISSION=$pkg.DYNAMIC_RECEIVER_NOT_EXPORTED_PERMISSION"
fi
got=$("$BUILD_TOOLS/aapt" dump badging "$work/renamed.apk" | sed -n "s/^package: name='\([^']*\)'.*/\1/p")
[ "$got" = "$pkg" ] || die "$variant: the apk says package '$got', not '$pkg'"
if [ "$pkg" != "$P" ]; then
tree=$("$BUILD_TOOLS/aapt" dump xmltree "$work/renamed.apk" AndroidManifest.xml)
grep -E 'android:(authorities|taskAffinity)' <<<"$tree" | grep -F "\"$P." \
&& die "$variant: the manifest still names $P in an authority or task"
fi
"$BUILD_TOOLS/zipalign" -p -f 4 "$work/renamed.apk" "$work/aligned.apk"
"$BUILD_TOOLS/apksigner" rotate --out "$work/lineage" \
--old-signer --ks "$TESTKEY" --ks-type PKCS12 --ks-pass env:TESTKEY_PASSWORD \
--ks-key-alias testkey --key-pass env:TESTKEY_PASSWORD --set-rollback false \
--new-signer --ks "$RELEASE_KEYSTORE" --ks-type PKCS12 --ks-pass env:RELEASE_STORE_PASSWORD \
--ks-key-alias "$RELEASE_KEY_ALIAS" --key-pass env:RELEASE_STORE_PASSWORD
"$BUILD_TOOLS/apksigner" sign \
--ks "$TESTKEY" --ks-type PKCS12 --ks-pass env:TESTKEY_PASSWORD \
--ks-key-alias testkey --key-pass env:TESTKEY_PASSWORD \
--next-signer --ks "$RELEASE_KEYSTORE" --ks-type PKCS12 --ks-pass env:RELEASE_STORE_PASSWORD \
--ks-key-alias "$RELEASE_KEY_ALIAS" --key-pass env:RELEASE_STORE_PASSWORD \
--lineage "$work/lineage" --rotation-min-sdk-version 28 \
--v1-signing-enabled true --v2-signing-enabled true --v3-signing-enabled true --v4-signing-enabled false \
--out "$out" "$work/aligned.apk"
rm -f "$out.idsig"
"$BUILD_TOOLS/apksigner" verify --min-sdk-version 26 "$out" >/dev/null || die "$variant: does not verify"
listing=$(unzip -l "$out")
grep -qE 'META-INF/.*\.(SF|RSA)$' <<<"$listing" || die "$variant: no JAR signature (old installers)"
certs=$("$BUILD_TOOLS/apksigner" verify --min-sdk-version 28 --print-certs "$out")
v3=$(sed -n 's/^.*Signer.* certificate SHA-256 digest: //p' <<<"$certs" | sort -u)
if [ "$v3" != "$expected" ]; then
echo "$certs" >&2
die "$variant: Android 9+ sees signer(s) [$(tr '\n' ' ' <<<"$v3")], not only DroidDeck's key $expected"
fi
lineage=$("$BUILD_TOOLS/apksigner" lineage --in "$out" --print-certs)
grep -q "Signer #1 in lineage certificate SHA-256 digest: $TESTKEY_SHA256" <<<"$lineage" \
|| die "$variant: the lineage does not start at the testkey - old installs could not update"
grep -q "Signer #2 in lineage certificate SHA-256 digest: $expected" <<<"$lineage" \
|| die "$variant: the lineage does not hand over to DroidDeck's key"
rollback=$(awk '/Signer #1 in lineage/{s=1} /Signer #2 in lineage/{s=0} s && /rollback capability/' <<<"$lineage")
grep -q false <<<"$rollback" \
|| die "$variant: the testkey kept its rollback right - a testkey-signed apk could replace this one"
echo "$variant ($pkg): signed, hand-over from the testkey, v3 signer $expected"