who_need_help/scripts/validate-android-environment.sh

183 lines
5.2 KiB
Bash
Executable File

#!/usr/bin/env bash
set -euo pipefail
ROOT=$(CDPATH='' cd -- "$(dirname -- "$0")/.." && pwd)
env_file=${1:-"$ROOT/.env"}
expected_environment=${2:-}
if [[ "$env_file" != /* ]]; then
env_file="$ROOT/$env_file"
fi
case "$expected_environment" in
development) expected_package=org.whoneedhelp.mobile.development ;;
test) expected_package=org.whoneedhelp.mobile.staging ;;
production) expected_package=org.whoneedhelp.mobile ;;
*)
echo "Usage: $0 ENV_FILE development|test|production" >&2
exit 2
;;
esac
[[ -f "$env_file" ]] || {
echo "Android build environment does not exist: $env_file" >&2
exit 1
}
[[ "$(stat -c '%a' "$env_file")" == 600 ]] || {
echo "Android build environment must have mode 0600: $env_file" >&2
exit 1
}
read_unique() {
local key=$1
local output
output=$(
awk -v key="$key" '
index($0, key "=") == 1 {
count += 1
value = substr($0, length(key) + 2)
}
END {
if (count != 1) exit 1
if (value ~ /^".*"$/ || value ~ /^'\''.*'\''$/) {
value = substr(value, 2, length(value) - 2)
}
print value
}
' "$env_file"
) || {
echo "$key must occur exactly once in $env_file." >&2
exit 1
}
[[ -n "$output" ]] || {
echo "$key must not be empty in $env_file." >&2
exit 1
}
printf '%s' "$output"
}
read_optional_unique() {
local key=$1
awk -v key="$key" '
index($0, key "=") == 1 {
count += 1
value = substr($0, length(key) + 2)
}
END {
if (count != 1) exit 1
if (value ~ /^".*"$/ || value ~ /^'\''.*'\''$/) {
value = substr(value, 2, length(value) - 2)
}
print value
}
' "$env_file" || {
echo "$key must occur exactly once in $env_file." >&2
exit 1
}
}
deployment_environment=$(read_unique DEPLOYMENT_ENV)
phx_host=$(read_unique PHX_HOST)
phx_scheme=$(read_unique PHX_SCHEME)
phx_port=$(read_unique PHX_URL_PORT)
base_url=$(read_unique WNH_BASE_URL)
google_oauth_client_id=$(read_unique GOOGLE_OAUTH_CLIENT_ID)
google_oauth_authorized_party_ids=$(read_unique GOOGLE_OAUTH_AUTHORIZED_PARTY_IDS)
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_optional_unique ANDROID_PLAY_APP_SIGNING_SHA256_CERT_FINGERPRINTS
)
fi
[[ "$deployment_environment" == "$expected_environment" ]] || {
echo "Android build requires DEPLOYMENT_ENV=$expected_environment." >&2
exit 1
}
[[ "$app_links_package" == "$expected_package" ]] || {
echo "Android build for $expected_environment requires package $expected_package." >&2
exit 1
}
[[ "$phx_scheme" == https ]] || {
echo "Public Android builds require PHX_SCHEME=https." >&2
exit 1
}
[[ "$phx_host" =~ ^[a-z0-9]([a-z0-9.-]*[a-z0-9])?$ ]] || {
echo "PHX_HOST must be a lowercase public DNS hostname." >&2
exit 1
}
if ! [[ "$phx_port" =~ ^[1-9][0-9]{0,4}$ ]] ||
((phx_port > 65535)); then
echo "PHX_URL_PORT must be a valid TCP port." >&2
exit 1
fi
expected_origin="https://$phx_host"
if [[ "$phx_port" != 443 ]]; then
expected_origin="$expected_origin:$phx_port"
fi
[[ "$base_url" == "$expected_origin" ]] || {
echo "WNH_BASE_URL must equal the canonical PHX origin: $expected_origin" >&2
exit 1
}
[[ -n "$google_oauth_client_id" ]] || {
echo "Android builds require the environment's Google Web OAuth client ID." >&2
exit 1
}
[[ -n "$google_oauth_authorized_party_ids" ]] || {
echo "Android builds require at least one authorized Android Google OAuth client ID." >&2
exit 1
}
IFS=',' read -r -a google_authorized_parties <<<"$google_oauth_authorized_party_ids"
for authorized_party in "${google_authorized_parties[@]}"; do
compact_party=${authorized_party//[[:space:]]/}
[[ -n "$compact_party" ]] || {
echo "GOOGLE_OAUTH_AUTHORIZED_PARTY_IDS contains an empty value." >&2
exit 1
}
done
IFS=',' read -r -a fingerprints <<<"$app_links_fingerprints"
for fingerprint in "${fingerprints[@]}"; do
compact=${fingerprint//:/}
compact=${compact//[[:space:]]/}
[[ "$compact" =~ ^[0-9A-Fa-f]{64}$ ]] || {
echo "ANDROID_APP_LINKS_SHA256_CERT_FINGERPRINTS contains an invalid value." >&2
exit 1
}
done
if [[ "$expected_environment" == production &&
-n "$play_app_signing_fingerprints" ]]; 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."