fix(android): require Play signing identity for links

This commit is contained in:
SimpleTest 2026-07-24 12:30:45 +03:00
parent 07cf978415
commit 8e74f8601e
8 changed files with 243 additions and 17 deletions

View File

@ -98,6 +98,11 @@ WNH_FIREBASE_GCM_SENDER_ID=
# production. Keep both empty until the matching signed APK/AAB is available.
ANDROID_APP_LINKS_PACKAGE_NAME=
ANDROID_APP_LINKS_SHA256_CERT_FINGERPRINTS=
# Production-only evidence from Google Play Console. This must contain the
# Play App Signing certificate fingerprint(s), not the local upload key, and
# every value must also appear in ANDROID_APP_LINKS_SHA256_CERT_FINGERPRINTS.
# Development and test leave this empty.
ANDROID_PLAY_APP_SIGNING_SHA256_CERT_FINGERPRINTS=
# Public identifier of the locally held Google Play upload key. The private
# keystore and its randomized password live outside the repository under
# ~/.config/who_need_help/android-release/.

View File

@ -122,6 +122,13 @@ separate app-signing key used for distributed APKs:
- <https://support.google.com/googleplay/android-developer/answer/9859152>
- <https://docs.docker.com/build/building/secrets/>
The production checkout therefore keeps the locally measured upload
certificate and the Play Console app-signing certificate as distinct evidence.
`ANDROID_APP_LINKS_SHA256_CERT_FINGERPRINTS` publishes every active identity,
while `ANDROID_PLAY_APP_SIGNING_SHA256_CERT_FINGERPRINTS` must contain the
Play-delivered identity as a verified subset. A release is not marked ready
from the upload certificate alone.
## Public development and staging builds
The installable `development` and `staging` build types use the explicit public

View File

@ -160,15 +160,19 @@ separate upload material under
```dotenv
WNH_ANDROID_SIGNING_KEY_ALIAS=who-need-help-upload
ANDROID_APP_LINKS_PACKAGE_NAME=org.whoneedhelp.mobile
ANDROID_APP_LINKS_SHA256_CERT_FINGERPRINTS=UPLOAD_OR_PLAY_SHA256
ANDROID_APP_LINKS_SHA256_CERT_FINGERPRINTS=UPLOAD_SHA256,PLAY_APP_SIGNING_SHA256
ANDROID_PLAY_APP_SIGNING_SHA256_CERT_FINGERPRINTS=PLAY_APP_SIGNING_SHA256
```
Run `./scripts/android-release-build.sh` from that production release checkout.
It produces an APK, Play AAB, package report, signing report, and lint report.
After Play App Signing is enabled, add the Play signing certificate fingerprint
to the comma-separated App Links value; the upload certificate alone does not
describe Play-delivered APKs. The production environment validator accepts
multiple SHA-256 fingerprints and rejects partial or malformed configuration.
describe Play-delivered APKs. Record the same Play fingerprint separately in
`ANDROID_PLAY_APP_SIGNING_SHA256_CERT_FINGERPRINTS`; release readiness verifies
that every Play identity is present in the public App Links list. The production
environment validator accepts multiple SHA-256 fingerprints and rejects partial,
malformed, upload-only, or inconsistent configuration.
### Release capability inputs

View File

@ -103,6 +103,20 @@ firebase_client_values_valid() {
-n "${application_id#"$prefix"}" ]]
}
valid_sha256_fingerprint_list() {
local fingerprint compact
local -a fingerprint_list
IFS=',' read -r -a fingerprint_list <<<"$1"
[[ ${#fingerprint_list[@]} -gt 0 ]] || return 1
for fingerprint in "${fingerprint_list[@]}"; do
compact=${fingerprint//:/}
compact=${compact//[[:space:]]/}
[[ "$compact" =~ ^[0-9A-Fa-f]{64}$ ]] || return 1
done
}
failures=0
warnings=0
@ -248,17 +262,55 @@ case "$deployment_env" in
production) expected_android_package=org.whoneedhelp.mobile ;;
esac
if all_empty ANDROID_APP_LINKS_PACKAGE_NAME ANDROID_APP_LINKS_SHA256_CERT_FINGERPRINTS; then
if all_empty ANDROID_APP_LINKS_PACKAGE_NAME \
ANDROID_APP_LINKS_SHA256_CERT_FINGERPRINTS \
ANDROID_PLAY_APP_SIGNING_SHA256_CERT_FINGERPRINTS; then
missing "Android App Links" "package name and signing certificate fingerprint"
elif all_set ANDROID_APP_LINKS_PACKAGE_NAME ANDROID_APP_LINKS_SHA256_CERT_FINGERPRINTS; then
if [[ -n "$expected_android_package" &&
"$(value ANDROID_APP_LINKS_PACKAGE_NAME)" == "$expected_android_package" ]]; then
ready "Android App Links" "package and signing fingerprints match this environment"
else
if [[ -z "$expected_android_package" ||
"$(value ANDROID_APP_LINKS_PACKAGE_NAME)" != "$expected_android_package" ]]; then
invalid "Android App Links" "package does not match DEPLOYMENT_ENV=$deployment_env"
elif ! valid_sha256_fingerprint_list \
"$(value ANDROID_APP_LINKS_SHA256_CERT_FINGERPRINTS)"; then
invalid "Android App Links" "published signing fingerprints are malformed"
elif [[ "$deployment_env" != production ]]; then
ready "Android App Links" "package and signing fingerprints match this environment"
elif ! is_set ANDROID_PLAY_APP_SIGNING_SHA256_CERT_FINGERPRINTS; then
missing "Android App Links" "production requires the Play App Signing SHA-256 fingerprint"
elif ! valid_sha256_fingerprint_list \
"$(value ANDROID_PLAY_APP_SIGNING_SHA256_CERT_FINGERPRINTS)"; then
invalid "Android App Links" "Play App Signing fingerprints are malformed"
else
published_fingerprints=$(value ANDROID_APP_LINKS_SHA256_CERT_FINGERPRINTS)
play_fingerprints=$(value ANDROID_PLAY_APP_SIGNING_SHA256_CERT_FINGERPRINTS)
all_play_fingerprints_published=true
IFS=',' read -r -a play_fingerprint_list <<<"$play_fingerprints"
IFS=',' read -r -a published_fingerprint_list <<<"$published_fingerprints"
for play_fingerprint in "${play_fingerprint_list[@]}"; do
compact_play=${play_fingerprint//:/}
compact_play=${compact_play//[[:space:]]/}
play_found=false
for published_fingerprint in "${published_fingerprint_list[@]}"; do
compact_published=${published_fingerprint//:/}
compact_published=${compact_published//[[:space:]]/}
if [[ "${compact_play^^}" == "${compact_published^^}" ]]; then
play_found=true
break
fi
done
if [[ "$play_found" != true ]]; then
all_play_fingerprints_published=false
break
fi
done
if [[ "$all_play_fingerprints_published" == true ]]; then
ready "Android App Links" "published identities include the Play App Signing certificate"
else
invalid "Android App Links" "Play App Signing fingerprint is absent from the published identities"
fi
fi
else
partial "Android App Links" "package and signing fingerprints must be configured together"
partial "Android App Links" "package and signing fingerprints are incomplete"
fi
android_signing_alias=

View File

@ -46,7 +46,7 @@ if ! printf '%s\n' "$domain" |
exit 1
fi
for command in awk docker git grep mktemp openssl stat; do
for command in awk docker git grep mktemp openssl stat tr; do
if ! command -v "$command" >/dev/null 2>&1; then
echo "Required command is unavailable: $command" >&2
exit 1
@ -89,6 +89,7 @@ fcm_project_id=${PRODUCTION_FCM_PROJECT_ID:-}
fcm_service_account_json_base64=${PRODUCTION_FCM_SERVICE_ACCOUNT_JSON_BASE64:-}
android_app_links_package_name=${PRODUCTION_ANDROID_APP_LINKS_PACKAGE_NAME:-}
android_app_links_fingerprints=${PRODUCTION_ANDROID_APP_LINKS_SHA256_CERT_FINGERPRINTS:-}
android_play_app_signing_fingerprints=${PRODUCTION_ANDROID_PLAY_APP_SIGNING_SHA256_CERT_FINGERPRINTS:-}
test_domain=${PRODUCTION_TEST_DOMAIN:-"test.$domain"}
test_upstream=${PRODUCTION_TEST_UPSTREAM:-who-need-help-test:4000}
edge_compose_project_name=${PRODUCTION_EDGE_COMPOSE_PROJECT_NAME:-who_need_help_edge}
@ -114,6 +115,7 @@ require_single_line_env_value PRODUCTION_FCM_PROJECT_ID "$fcm_project_id"
require_single_line_env_value PRODUCTION_FCM_SERVICE_ACCOUNT_JSON_BASE64 "$fcm_service_account_json_base64"
require_single_line_env_value PRODUCTION_ANDROID_APP_LINKS_PACKAGE_NAME "$android_app_links_package_name"
require_single_line_env_value PRODUCTION_ANDROID_APP_LINKS_SHA256_CERT_FINGERPRINTS "$android_app_links_fingerprints"
require_single_line_env_value PRODUCTION_ANDROID_PLAY_APP_SIGNING_SHA256_CERT_FINGERPRINTS "$android_play_app_signing_fingerprints"
require_single_line_env_value PRODUCTION_TEST_DOMAIN "$test_domain"
require_single_line_env_value PRODUCTION_TEST_UPSTREAM "$test_upstream"
require_single_line_env_value PRODUCTION_EDGE_COMPOSE_PROJECT_NAME "$edge_compose_project_name"
@ -129,9 +131,17 @@ if { [ -n "$google_oauth_client_id" ] || [ -n "$google_oauth_client_secret" ]; }
exit 1
fi
if { [ -n "$android_app_links_package_name" ] || [ -n "$android_app_links_fingerprints" ]; } &&
{ [ -z "$android_app_links_package_name" ] || [ -z "$android_app_links_fingerprints" ]; }; then
echo "Production Android App Links package and fingerprints must either both be set or both be empty." >&2
if {
[ -n "$android_app_links_package_name" ] ||
[ -n "$android_app_links_fingerprints" ] ||
[ -n "$android_play_app_signing_fingerprints" ]
} &&
{
[ -z "$android_app_links_package_name" ] ||
[ -z "$android_app_links_fingerprints" ] ||
[ -z "$android_play_app_signing_fingerprints" ]
}; then
echo "Production Android App Links require the package, published fingerprints, and Play App Signing fingerprints together." >&2
exit 1
fi
@ -223,6 +233,42 @@ if [ -n "$android_app_links_package_name" ] &&
exit 1
fi
if [ -n "$android_app_links_fingerprints" ]; then
if ! printf '%s\n' "$android_app_links_fingerprints" |
tr ',' '\n' |
while IFS= read -r fingerprint; do
compact_fingerprint=$(printf '%s' "$fingerprint" | tr -d ':[:space:]')
printf '%s\n' "$compact_fingerprint" |
grep -Eq '^[0-9A-Fa-f]{64}$' || exit 1
done; then
echo "PRODUCTION_ANDROID_APP_LINKS_SHA256_CERT_FINGERPRINTS contains an invalid SHA-256 fingerprint." >&2
exit 1
fi
published_compact_fingerprints=$(
printf '%s' "$android_app_links_fingerprints" |
tr ',' '\n' |
tr -d ':[:space:]' |
tr '[:lower:]' '[:upper:]'
)
if ! printf '%s\n' "$android_play_app_signing_fingerprints" |
tr ',' '\n' |
while IFS= read -r play_fingerprint; do
compact_play_fingerprint=$(
printf '%s' "$play_fingerprint" |
tr -d ':[:space:]' |
tr '[:lower:]' '[:upper:]'
)
printf '%s\n' "$compact_play_fingerprint" |
grep -Eq '^[0-9A-F]{64}$' || exit 1
printf '%s\n' "$published_compact_fingerprints" |
grep -Fqx "$compact_play_fingerprint" || exit 1
done; then
echo "Every production Play App Signing fingerprint must also be published in the Android App Links fingerprint list." >&2
exit 1
fi
fi
case "$compose_project_name" in
*[!a-zA-Z0-9_-]* | '')
echo "PRODUCTION_COMPOSE_PROJECT_NAME must contain only letters, numbers, underscores, or hyphens." >&2
@ -360,6 +406,7 @@ FCM_PROJECT_ID_VALUE=$fcm_project_id \
FCM_SERVICE_ACCOUNT_JSON_BASE64_VALUE=$fcm_service_account_json_base64 \
ANDROID_APP_LINKS_PACKAGE_NAME_VALUE=$android_app_links_package_name \
ANDROID_APP_LINKS_FINGERPRINTS_VALUE=$android_app_links_fingerprints \
ANDROID_PLAY_APP_SIGNING_FINGERPRINTS_VALUE=$android_play_app_signing_fingerprints \
EDGE_COMPOSE_PROJECT_NAME_VALUE=$edge_compose_project_name \
PRIMARY_UPSTREAM_VALUE="$public_upstream_name:4000" \
TEST_DOMAIN_VALUE=$test_domain \
@ -427,6 +474,7 @@ TEST_UPSTREAM_VALUE=$test_upstream \
replacement["FCM_SERVICE_ACCOUNT_JSON_BASE64"] = ENVIRON["FCM_SERVICE_ACCOUNT_JSON_BASE64_VALUE"]
replacement["ANDROID_APP_LINKS_PACKAGE_NAME"] = ENVIRON["ANDROID_APP_LINKS_PACKAGE_NAME_VALUE"]
replacement["ANDROID_APP_LINKS_SHA256_CERT_FINGERPRINTS"] = ENVIRON["ANDROID_APP_LINKS_FINGERPRINTS_VALUE"]
replacement["ANDROID_PLAY_APP_SIGNING_SHA256_CERT_FINGERPRINTS"] = ENVIRON["ANDROID_PLAY_APP_SIGNING_FINGERPRINTS_VALUE"]
replacement["WNH_ANDROID_SIGNING_KEY_ALIAS"] = "who-need-help-upload"
replacement["WNH_ANDROID_DEVELOPMENT_SIGNING_KEY_ALIAS"] = ""
replacement["WNH_ANDROID_STAGING_SIGNING_KEY_ALIAS"] = ""

View File

@ -334,6 +334,7 @@ printf '%s\n' \
'WNH_BASE_URL=https://dev.help.test' \
'ANDROID_APP_LINKS_PACKAGE_NAME=org.whoneedhelp.mobile.development' \
"ANDROID_APP_LINKS_SHA256_CERT_FINGERPRINTS=$android_fingerprint" \
'ANDROID_PLAY_APP_SIGNING_SHA256_CERT_FINGERPRINTS=' \
>"$android_env"
chmod 600 "$android_env"
./scripts/validate-android-environment.sh \
@ -354,7 +355,7 @@ sed -i \
./scripts/validate-android-environment.sh "$android_env" test >/dev/null
sed -i \
's|^DEPLOYMENT_ENV=.*|DEPLOYMENT_ENV=production|; s|^ANDROID_APP_LINKS_PACKAGE_NAME=.*|ANDROID_APP_LINKS_PACKAGE_NAME=org.whoneedhelp.mobile|' \
"s|^DEPLOYMENT_ENV=.*|DEPLOYMENT_ENV=production|; s|^ANDROID_APP_LINKS_PACKAGE_NAME=.*|ANDROID_APP_LINKS_PACKAGE_NAME=org.whoneedhelp.mobile|; s|^ANDROID_PLAY_APP_SIGNING_SHA256_CERT_FINGERPRINTS=.*|ANDROID_PLAY_APP_SIGNING_SHA256_CERT_FINGERPRINTS=$android_fingerprint|" \
"$android_env"
./scripts/validate-android-environment.sh \
"$android_env" production >/dev/null
@ -602,6 +603,7 @@ PRODUCTION_FCM_PROJECT_ID=quality-production \
PRODUCTION_FCM_SERVICE_ACCOUNT_JSON_BASE64="$quality_fcm_base64" \
PRODUCTION_ANDROID_APP_LINKS_PACKAGE_NAME=org.whoneedhelp.mobile \
PRODUCTION_ANDROID_APP_LINKS_SHA256_CERT_FINGERPRINTS=A5:74:2B:AE:70:C6:D0:34:E3:75:44:B6:2E:37:A3:75:C0:E0:05:64:74:50:F4:0F:29:B2:A9:84:F9:FD:B8:FB \
PRODUCTION_ANDROID_PLAY_APP_SIGNING_SHA256_CERT_FINGERPRINTS=A5:74:2B:AE:70:C6:D0:34:E3:75:44:B6:2E:37:A3:75:C0:E0:05:64:74:50:F4:0F:29:B2:A9:84:F9:FD:B8:FB \
PRODUCTION_SUPPORT_INBOX_ADDRESS=support@help.test \
./scripts/init-production-env.sh help.test "$production_env" >/dev/null
test "$(stat -c '%a' "$production_env")" = 600
@ -641,11 +643,21 @@ fi
if PRODUCTION_CODEX_SESSION_ID=00000000-0000-0000-0000-000000000001 \
PRODUCTION_ANDROID_APP_LINKS_PACKAGE_NAME=org.whoneedhelp.mobile.staging \
PRODUCTION_ANDROID_APP_LINKS_SHA256_CERT_FINGERPRINTS=A5:74:2B:AE:70:C6:D0:34:E3:75:44:B6:2E:37:A3:75:C0:E0:05:64:74:50:F4:0F:29:B2:A9:84:F9:FD:B8:FB \
PRODUCTION_ANDROID_PLAY_APP_SIGNING_SHA256_CERT_FINGERPRINTS=A5:74:2B:AE:70:C6:D0:34:E3:75:44:B6:2E:37:A3:75:C0:E0:05:64:74:50:F4:0F:29:B2:A9:84:F9:FD:B8:FB \
./scripts/init-production-env.sh help.test \
"$scan_dir/production.staging-package.env" >/dev/null 2>&1; then
echo "Production environment initializer accepted the staging Android package." >&2
exit 1
fi
if PRODUCTION_CODEX_SESSION_ID=00000000-0000-0000-0000-000000000001 \
PRODUCTION_ANDROID_APP_LINKS_PACKAGE_NAME=org.whoneedhelp.mobile \
PRODUCTION_ANDROID_APP_LINKS_SHA256_CERT_FINGERPRINTS=A5:74:2B:AE:70:C6:D0:34:E3:75:44:B6:2E:37:A3:75:C0:E0:05:64:74:50:F4:0F:29:B2:A9:84:F9:FD:B8:FB \
PRODUCTION_ANDROID_PLAY_APP_SIGNING_SHA256_CERT_FINGERPRINTS=D7:C4:F1:12:4D:F4:68:E5:B3:54:DE:D8:96:E8:01:51:29:41:F1:8A:71:0C:18:B0:E7:98:AA:2B:81:DA:11:DF \
./scripts/init-production-env.sh help.test \
"$scan_dir/production.unpublished-play-signing.env" >/dev/null 2>&1; then
echo "Production environment initializer accepted a Play fingerprint absent from assetlinks." >&2
exit 1
fi
if PRODUCTION_CODEX_SESSION_ID=00000000-0000-0000-0000-000000000001 \
PRODUCTION_WEB_PUSH_VAPID_PUBLIC_KEY=quality-vapid-public \
PRODUCTION_WEB_PUSH_VAPID_PRIVATE_KEY=quality-vapid-private \
@ -739,6 +751,38 @@ if ./scripts/check-environment-readiness.sh \
exit 1
fi
upload_only_app_links_env="$scan_dir/production.upload-only-app-links.env"
cp "$production_env" "$upload_only_app_links_env"
sed -i \
's|^ANDROID_PLAY_APP_SIGNING_SHA256_CERT_FINGERPRINTS=.*|ANDROID_PLAY_APP_SIGNING_SHA256_CERT_FINGERPRINTS=|' \
"$upload_only_app_links_env"
if ./scripts/validate-production-env.sh \
"$upload_only_app_links_env" help.test >/dev/null 2>&1; then
echo "Production validation accepted upload-only Android App Links." >&2
exit 1
fi
if ./scripts/check-environment-readiness.sh \
"$upload_only_app_links_env" --require-release >/dev/null 2>&1; then
echo "Environment readiness accepted upload-only Android App Links." >&2
exit 1
fi
unpublished_play_app_links_env="$scan_dir/production.unpublished-play-app-links.env"
cp "$production_env" "$unpublished_play_app_links_env"
sed -i \
's|^ANDROID_PLAY_APP_SIGNING_SHA256_CERT_FINGERPRINTS=.*|ANDROID_PLAY_APP_SIGNING_SHA256_CERT_FINGERPRINTS=D7:C4:F1:12:4D:F4:68:E5:B3:54:DE:D8:96:E8:01:51:29:41:F1:8A:71:0C:18:B0:E7:98:AA:2B:81:DA:11:DF|' \
"$unpublished_play_app_links_env"
if ./scripts/validate-production-env.sh \
"$unpublished_play_app_links_env" help.test >/dev/null 2>&1; then
echo "Production validation accepted an unpublished Play App Signing fingerprint." >&2
exit 1
fi
if ./scripts/check-environment-readiness.sh \
"$unpublished_play_app_links_env" --require-release >/dev/null 2>&1; then
echo "Environment readiness accepted an unpublished Play App Signing fingerprint." >&2
exit 1
fi
grep -Fx 'COMPOSE_PROJECT_NAME=who_need_help_production' "$production_env" >/dev/null
grep -E '^APP_IMAGE=who-need-help:production-[0-9a-f]{12}$' "$production_env" >/dev/null
grep -Fx 'EDGE_COMPOSE_PROJECT_NAME=who_need_help_edge' "$production_env" >/dev/null
@ -746,6 +790,7 @@ grep -Fx 'PRIMARY_DOMAIN=help.test' "$production_env" >/dev/null
grep -Fx 'TEST_DOMAIN=test.help.test' "$production_env" >/dev/null
grep -Fx 'ANDROID_APP_LINKS_PACKAGE_NAME=org.whoneedhelp.mobile' "$production_env" >/dev/null
grep -Fx 'ANDROID_APP_LINKS_SHA256_CERT_FINGERPRINTS=A5:74:2B:AE:70:C6:D0:34:E3:75:44:B6:2E:37:A3:75:C0:E0:05:64:74:50:F4:0F:29:B2:A9:84:F9:FD:B8:FB' "$production_env" >/dev/null
grep -Fx 'ANDROID_PLAY_APP_SIGNING_SHA256_CERT_FINGERPRINTS=A5:74:2B:AE:70:C6:D0:34:E3:75:44:B6:2E:37:A3:75:C0:E0:05:64:74:50:F4:0F:29:B2:A9:84:F9:FD:B8:FB' "$production_env" >/dev/null
./scripts/validate-edge-env.sh "$production_env" >/dev/null
test_checkout="$scan_dir/test-checkout"

View File

@ -65,6 +65,12 @@ phx_port=$(read_unique PHX_URL_PORT)
base_url=$(read_unique WNH_BASE_URL)
app_links_package=$(read_unique ANDROID_APP_LINKS_PACKAGE_NAME)
app_links_fingerprints=$(read_unique ANDROID_APP_LINKS_SHA256_CERT_FINGERPRINTS)
play_app_signing_fingerprints=
if [[ "$expected_environment" == production ]]; then
play_app_signing_fingerprints=$(
read_unique ANDROID_PLAY_APP_SIGNING_SHA256_CERT_FINGERPRINTS
)
fi
[[ "$deployment_environment" == "$expected_environment" ]] || {
echo "Android build requires DEPLOYMENT_ENV=$expected_environment." >&2
@ -107,4 +113,30 @@ for fingerprint in "${fingerprints[@]}"; do
}
done
if [[ "$expected_environment" == production ]]; then
IFS=',' read -r -a play_fingerprints <<<"$play_app_signing_fingerprints"
for play_fingerprint in "${play_fingerprints[@]}"; do
compact_play=${play_fingerprint//:/}
compact_play=${compact_play//[[:space:]]/}
[[ "$compact_play" =~ ^[0-9A-Fa-f]{64}$ ]] || {
echo "ANDROID_PLAY_APP_SIGNING_SHA256_CERT_FINGERPRINTS contains an invalid value." >&2
exit 1
}
play_found=false
for fingerprint in "${fingerprints[@]}"; do
compact=${fingerprint//:/}
compact=${compact//[[:space:]]/}
if [[ "${compact^^}" == "${compact_play^^}" ]]; then
play_found=true
break
fi
done
[[ "$play_found" == true ]] || {
echo "The Play App Signing fingerprint is absent from the published App Links identities." >&2
exit 1
}
done
fi
echo "Verified $expected_environment Android origin, application ID, and App Links identity."

View File

@ -131,6 +131,7 @@ fcm_service_account_file=$(optional_value FCM_SERVICE_ACCOUNT_FILE)
fcm_service_account_json_base64=$(optional_value FCM_SERVICE_ACCOUNT_JSON_BASE64)
android_app_links_package_name=$(optional_value ANDROID_APP_LINKS_PACKAGE_NAME)
android_app_links_fingerprints=$(optional_value ANDROID_APP_LINKS_SHA256_CERT_FINGERPRINTS)
android_play_app_signing_fingerprints=$(optional_value ANDROID_PLAY_APP_SIGNING_SHA256_CERT_FINGERPRINTS)
codex_session_id=$(require_value CODEX_SESSION_ID)
edge_compose_project_name=$(require_value EDGE_COMPOSE_PROJECT_NAME)
caddy_image=$(require_value CADDY_IMAGE)
@ -444,9 +445,13 @@ if [[ -n "$fcm_project_id" || -n "$fcm_service_account_file" ||
fi
fi
if [[ -n "$android_app_links_package_name" || -n "$android_app_links_fingerprints" ]]; then
[[ -n "$android_app_links_package_name" && -n "$android_app_links_fingerprints" ]] || {
echo "Android App Links package and fingerprints must either both be set or both be empty." >&2
if [[ -n "$android_app_links_package_name" ||
-n "$android_app_links_fingerprints" ||
-n "$android_play_app_signing_fingerprints" ]]; then
[[ -n "$android_app_links_package_name" &&
-n "$android_app_links_fingerprints" &&
-n "$android_play_app_signing_fingerprints" ]] || {
echo "Production Android App Links require the package, published fingerprints, and Play App Signing fingerprints together." >&2
exit 1
}
[[ "$android_app_links_package_name" =~ ^[A-Za-z][A-Za-z0-9_]*(\.[A-Za-z][A-Za-z0-9_]*)+$ ]] || {
@ -471,6 +476,34 @@ if [[ -n "$android_app_links_package_name" || -n "$android_app_links_fingerprint
exit 1
}
done
IFS=',' read -r -a play_fingerprints <<<"$android_play_app_signing_fingerprints"
[[ ${#play_fingerprints[@]} -gt 0 ]] || {
echo "ANDROID_PLAY_APP_SIGNING_SHA256_CERT_FINGERPRINTS is empty." >&2
exit 1
}
for play_fingerprint in "${play_fingerprints[@]}"; do
compact_play_fingerprint=${play_fingerprint//:/}
compact_play_fingerprint=${compact_play_fingerprint//[[:space:]]/}
[[ "$compact_play_fingerprint" =~ ^[0-9A-Fa-f]{64}$ ]] || {
echo "ANDROID_PLAY_APP_SIGNING_SHA256_CERT_FINGERPRINTS contains an invalid SHA-256 fingerprint." >&2
exit 1
}
play_fingerprint_found=false
for fingerprint in "${android_fingerprints[@]}"; do
compact_fingerprint=${fingerprint//:/}
compact_fingerprint=${compact_fingerprint//[[:space:]]/}
if [[ "${compact_fingerprint^^}" == "${compact_play_fingerprint^^}" ]]; then
play_fingerprint_found=true
break
fi
done
[[ "$play_fingerprint_found" == true ]] || {
echo "Every Play App Signing fingerprint must also be published in ANDROID_APP_LINKS_SHA256_CERT_FINGERPRINTS." >&2
exit 1
}
done
fi
case "$codex_session_id" in