Add safe Play signing identity import
This commit is contained in:
parent
897a943815
commit
38e297f83b
|
|
@ -26,6 +26,9 @@
|
||||||
- [ ] Publish and verify
|
- [ ] Publish and verify
|
||||||
`https://whoneedhelp.com/.well-known/assetlinks.json` for the Play
|
`https://whoneedhelp.com/.well-known/assetlinks.json` for the Play
|
||||||
certificate identities used to sign delivered APKs.
|
certificate identities used to sign delivered APKs.
|
||||||
|
Use `scripts/import-play-android-config.sh` in plan mode first, then
|
||||||
|
`--apply`; it must match every Play SHA-1 to the production Firebase
|
||||||
|
Android OAuth client and preserve the upload identity.
|
||||||
|
|
||||||
## Build
|
## Build
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -257,6 +257,50 @@ chmod 600 /secure/downloads/fcm-service-account.json
|
||||||
.env /secure/downloads/fcm-service-account.json
|
.env /secure/downloads/fcm-service-account.json
|
||||||
```
|
```
|
||||||
|
|
||||||
|
After the first AAB has made Google Play generate its delivery identities,
|
||||||
|
download a fresh production `google-services.json` after registering every
|
||||||
|
Play App Signing SHA-1 in the production Firebase Android application. Record
|
||||||
|
the SHA-1/SHA-256 pairs shown by Play in a protected temporary JSON document:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"package_name": "org.whoneedhelp.mobile",
|
||||||
|
"identities": [
|
||||||
|
{"sha1": "PLAY_SHA1", "sha256": "PLAY_SHA256"}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Keep both provider downloads at mode `0400` or `0600`. First run the importer
|
||||||
|
without `--apply`: this validates the package, every SHA-1-to-Android-OAuth
|
||||||
|
client match, Firebase/FCM project consistency, the resulting App Links set,
|
||||||
|
and the production Android environment while leaving `.env` byte-for-byte
|
||||||
|
unchanged. Apply the same validated candidate only after reviewing the counts:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
chmod 600 /secure/downloads/google-services.json \
|
||||||
|
/secure/downloads/play-identities.json
|
||||||
|
|
||||||
|
./scripts/import-play-android-config.sh \
|
||||||
|
.env \
|
||||||
|
/secure/downloads/google-services.json \
|
||||||
|
/secure/downloads/play-identities.json
|
||||||
|
|
||||||
|
./scripts/import-play-android-config.sh \
|
||||||
|
.env \
|
||||||
|
/secure/downloads/google-services.json \
|
||||||
|
/secure/downloads/play-identities.json \
|
||||||
|
--apply
|
||||||
|
```
|
||||||
|
|
||||||
|
The apply step is atomic. It preserves the existing upload certificate and
|
||||||
|
Android OAuth client, adds every Play delivery identity, refreshes the four
|
||||||
|
public Firebase Android values, and never prints OAuth client IDs or the
|
||||||
|
Firebase API key. It refuses a test/development environment, another package,
|
||||||
|
an unmatched or duplicate certificate, and a Firebase project inconsistent
|
||||||
|
with the configured FCM service account. Provider files remain on disk after
|
||||||
|
the import and must be stored or removed deliberately.
|
||||||
|
|
||||||
The VAPID helper runs the exact locked `web_push_elixir` generator in an
|
The VAPID helper runs the exact locked `web_push_elixir` generator in an
|
||||||
isolated, network-disabled container, imports the result atomically, removes
|
isolated, network-disabled container, imports the result atomically, removes
|
||||||
its one-run image tag and temporary files, and never prints either key. It
|
its one-run image tag and temporary files, and never prints either key. It
|
||||||
|
|
|
||||||
327
scripts/import-play-android-config.sh
Executable file
327
scripts/import-play-android-config.sh
Executable file
|
|
@ -0,0 +1,327 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
ROOT=$(CDPATH='' cd -- "$(dirname -- "$0")/.." && pwd)
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
cat >&2 <<'EOF'
|
||||||
|
Usage: import-play-android-config.sh ENV_FILE GOOGLE_SERVICES_JSON PLAY_IDENTITIES_JSON [--apply]
|
||||||
|
|
||||||
|
The command validates a production Google/Firebase Android client against the
|
||||||
|
Play App Signing certificate identities without changing ENV_FILE by default.
|
||||||
|
Use --apply only after reviewing the plan. PLAY_IDENTITIES_JSON must contain:
|
||||||
|
|
||||||
|
{
|
||||||
|
"package_name": "org.whoneedhelp.mobile",
|
||||||
|
"identities": [
|
||||||
|
{"sha1": "AA:...", "sha256": "BB:..."}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
if [[ $# -lt 3 || $# -gt 4 ]]; then
|
||||||
|
usage
|
||||||
|
exit 2
|
||||||
|
fi
|
||||||
|
|
||||||
|
env_file=$1
|
||||||
|
google_services_file=$2
|
||||||
|
identities_file=$3
|
||||||
|
mode=${4:-}
|
||||||
|
|
||||||
|
if [[ -n "$mode" && "$mode" != --apply ]]; then
|
||||||
|
usage
|
||||||
|
exit 2
|
||||||
|
fi
|
||||||
|
|
||||||
|
for path_variable in env_file google_services_file identities_file; do
|
||||||
|
path=${!path_variable}
|
||||||
|
if [[ "$path" != /* ]]; then
|
||||||
|
printf -v "$path_variable" '%s/%s' "$ROOT" "$path"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
for command in awk jq mktemp stat; do
|
||||||
|
command -v "$command" >/dev/null 2>&1 || {
|
||||||
|
echo "Required command is unavailable: $command" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
done
|
||||||
|
|
||||||
|
[[ -f "$env_file" ]] || {
|
||||||
|
echo "Production environment does not exist: $env_file" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
[[ "$(stat -c '%a' "$env_file")" == 600 ]] || {
|
||||||
|
echo "Production environment must have mode 0600: $env_file" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
for provider_file in "$google_services_file" "$identities_file"; do
|
||||||
|
[[ -f "$provider_file" ]] || {
|
||||||
|
echo "Required provider input does not exist: $provider_file" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
case "$(stat -c '%a' "$provider_file")" in
|
||||||
|
400 | 600) ;;
|
||||||
|
*)
|
||||||
|
echo "Provider inputs must have mode 0400 or 0600: $provider_file" >&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
read_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
|
||||||
|
print value
|
||||||
|
}
|
||||||
|
' "$env_file" || {
|
||||||
|
echo "$key must occur exactly once in $env_file." >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
deployment_env=$(read_unique DEPLOYMENT_ENV)
|
||||||
|
package_name=$(read_unique ANDROID_APP_LINKS_PACKAGE_NAME)
|
||||||
|
existing_app_links=$(read_unique ANDROID_APP_LINKS_SHA256_CERT_FINGERPRINTS)
|
||||||
|
existing_play_fingerprints=$(read_unique ANDROID_PLAY_APP_SIGNING_SHA256_CERT_FINGERPRINTS)
|
||||||
|
existing_authorized_parties=$(read_unique GOOGLE_OAUTH_AUTHORIZED_PARTY_IDS)
|
||||||
|
existing_firebase_project=$(read_unique WNH_FIREBASE_PROJECT_ID)
|
||||||
|
existing_fcm_project=$(read_unique FCM_PROJECT_ID)
|
||||||
|
|
||||||
|
[[ "$deployment_env" == production ]] || {
|
||||||
|
echo "Play App Signing identities may only be imported into DEPLOYMENT_ENV=production." >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
[[ "$package_name" == org.whoneedhelp.mobile ]] || {
|
||||||
|
echo "The production Android package must be org.whoneedhelp.mobile." >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
[[ -n "$existing_app_links" ]] || {
|
||||||
|
echo "The production App Links list must already contain the measured upload certificate." >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
[[ -n "$existing_authorized_parties" ]] || {
|
||||||
|
echo "The production environment must already contain its Android OAuth authorized party." >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
normalized_identities=$(mktemp "${TMPDIR:-/tmp}/wnh-play-identities.XXXXXX")
|
||||||
|
matched_oauth_ids=$(mktemp "${TMPDIR:-/tmp}/wnh-play-oauth-ids.XXXXXX")
|
||||||
|
values_file=$(mktemp "${TMPDIR:-/tmp}/wnh-play-values.XXXXXX")
|
||||||
|
env_dir=$(CDPATH='' cd -- "$(dirname -- "$env_file")" && pwd)
|
||||||
|
env_name=$(basename -- "$env_file")
|
||||||
|
candidate_env=$(mktemp "$env_dir/$env_name.play-candidate.XXXXXX")
|
||||||
|
cleanup() {
|
||||||
|
rm -f "$normalized_identities" "$matched_oauth_ids" "$values_file" "$candidate_env"
|
||||||
|
}
|
||||||
|
trap cleanup EXIT HUP INT TERM
|
||||||
|
chmod 600 "$normalized_identities" "$matched_oauth_ids" "$values_file" "$candidate_env"
|
||||||
|
|
||||||
|
if ! jq --exit-status --arg package "$package_name" '
|
||||||
|
def normalize_sha1:
|
||||||
|
ascii_upcase | gsub(":"; "");
|
||||||
|
def normalize_sha256:
|
||||||
|
ascii_upcase | gsub(":"; "");
|
||||||
|
def valid_sha1:
|
||||||
|
test("^[0-9A-Fa-f]{40}$|^([0-9A-Fa-f]{2}:){19}[0-9A-Fa-f]{2}$");
|
||||||
|
def valid_sha256:
|
||||||
|
test("^[0-9A-Fa-f]{64}$|^([0-9A-Fa-f]{2}:){31}[0-9A-Fa-f]{2}$");
|
||||||
|
|
||||||
|
(.package_name == $package)
|
||||||
|
and (.identities | type == "array" and length > 0)
|
||||||
|
and all(
|
||||||
|
.identities[];
|
||||||
|
(.sha1 | type == "string" and valid_sha1)
|
||||||
|
and (.sha256 | type == "string" and valid_sha256)
|
||||||
|
)
|
||||||
|
and (([.identities[].sha1 | normalize_sha1] | unique | length) == (.identities | length))
|
||||||
|
and (([.identities[].sha256 | normalize_sha256] | unique | length) == (.identities | length))
|
||||||
|
' "$identities_file" >/dev/null; then
|
||||||
|
echo "Play identities are incomplete, malformed, duplicated, or belong to another package." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
jq --compact-output '
|
||||||
|
{
|
||||||
|
package_name,
|
||||||
|
identities: [
|
||||||
|
.identities[]
|
||||||
|
| {
|
||||||
|
sha1: (.sha1 | ascii_upcase | gsub(":"; "")),
|
||||||
|
sha256: (.sha256 | ascii_upcase | gsub(":"; ""))
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
' "$identities_file" >"$normalized_identities"
|
||||||
|
|
||||||
|
if ! jq --exit-status --arg package "$package_name" '
|
||||||
|
(.project_info.project_number) as $project_number
|
||||||
|
| [
|
||||||
|
.client[]?
|
||||||
|
| select(.client_info.android_client_info.package_name == $package)
|
||||||
|
] as $clients
|
||||||
|
| ($clients | length == 1)
|
||||||
|
and (.project_info.project_id
|
||||||
|
| type == "string" and length > 0 and test("^[^\r\n]+$"))
|
||||||
|
and (.project_info.project_number
|
||||||
|
| type == "string" and length > 0 and test("^[0-9]+$"))
|
||||||
|
and ($clients[0].client_info.mobilesdk_app_id
|
||||||
|
| type == "string" and length > 0
|
||||||
|
and startswith("1:" + $project_number + ":android:"))
|
||||||
|
and ($clients[0].api_key[0].current_key
|
||||||
|
| type == "string" and length > 0 and test("^[^\r\n]+$"))
|
||||||
|
' "$google_services_file" >/dev/null; then
|
||||||
|
echo "Firebase configuration does not contain exactly one complete production Android client." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! jq --exit-status --raw-output \
|
||||||
|
--slurpfile identity_documents "$normalized_identities" \
|
||||||
|
--arg package "$package_name" '
|
||||||
|
def normalize_sha1:
|
||||||
|
ascii_upcase | gsub(":"; "");
|
||||||
|
$identity_documents[0] as $identities
|
||||||
|
|
|
||||||
|
[
|
||||||
|
.client[]
|
||||||
|
| select(.client_info.android_client_info.package_name == $package)
|
||||||
|
| .oauth_client[]?
|
||||||
|
| select(.client_type == 1)
|
||||||
|
| select(.android_info.package_name == $package)
|
||||||
|
| {
|
||||||
|
client_id,
|
||||||
|
sha1: (.android_info.certificate_hash | normalize_sha1)
|
||||||
|
}
|
||||||
|
] as $android_clients
|
||||||
|
| [
|
||||||
|
$identities.identities[]
|
||||||
|
| . as $identity
|
||||||
|
| [$android_clients[] | select(.sha1 == $identity.sha1)] as $matches
|
||||||
|
| if ($matches | length) == 1
|
||||||
|
then $matches[0].client_id
|
||||||
|
else error("each Play SHA-1 must match exactly one Android OAuth client")
|
||||||
|
end
|
||||||
|
] as $matched
|
||||||
|
| if (($matched | length) == ($identities.identities | length))
|
||||||
|
and (($matched | unique | length) == ($matched | length))
|
||||||
|
then $matched[]
|
||||||
|
else error("Play Android OAuth clients are incomplete or duplicated")
|
||||||
|
end
|
||||||
|
' "$google_services_file" >"$matched_oauth_ids"; then
|
||||||
|
echo "Firebase configuration does not contain one distinct Android OAuth client for every Play SHA-1." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
firebase_project=$(jq --raw-output '.project_info.project_id' "$google_services_file")
|
||||||
|
if [[ -n "$existing_firebase_project" && "$existing_firebase_project" != "$firebase_project" ]]; then
|
||||||
|
echo "Firebase download belongs to a different project than WNH_FIREBASE_PROJECT_ID." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if [[ -n "$existing_fcm_project" && "$existing_fcm_project" != "$firebase_project" ]]; then
|
||||||
|
echo "Firebase download belongs to a different project than FCM_PROJECT_ID." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
jq --null-input --raw-output \
|
||||||
|
--arg existing_app_links "$existing_app_links" \
|
||||||
|
--arg existing_play "$existing_play_fingerprints" \
|
||||||
|
--arg existing_authorized "$existing_authorized_parties" \
|
||||||
|
--slurpfile identity_documents "$normalized_identities" \
|
||||||
|
--rawfile matched_oauth "$matched_oauth_ids" \
|
||||||
|
--slurpfile firebase_documents "$google_services_file" '
|
||||||
|
def stable_unique:
|
||||||
|
reduce .[] as $item ([]; if index($item) then . else . + [$item] end);
|
||||||
|
def compact_fingerprint:
|
||||||
|
ascii_upcase | gsub(":"; "");
|
||||||
|
def colonize:
|
||||||
|
[range(0; length; 2) as $offset | .[$offset:$offset + 2]] | join(":");
|
||||||
|
def trim:
|
||||||
|
gsub("^[[:space:]]+|[[:space:]]+$"; "");
|
||||||
|
|
||||||
|
$identity_documents[0] as $identities
|
||||||
|
| $firebase_documents[0] as $firebase
|
||||||
|
| ($existing_app_links
|
||||||
|
| split(",")
|
||||||
|
| map(trim | compact_fingerprint)
|
||||||
|
) as $published
|
||||||
|
| if all($published[]; test("^[0-9A-F]{64}$"))
|
||||||
|
then .
|
||||||
|
else error("existing App Links fingerprints are malformed")
|
||||||
|
end
|
||||||
|
| ($existing_play
|
||||||
|
| if length == 0 then [] else split(",") | map(trim | compact_fingerprint) end
|
||||||
|
) as $existing_play_values
|
||||||
|
| if all($existing_play_values[]; test("^[0-9A-F]{64}$"))
|
||||||
|
then .
|
||||||
|
else error("existing Play fingerprints are malformed")
|
||||||
|
end
|
||||||
|
| ($existing_authorized | split(",") | map(trim)) as $authorized
|
||||||
|
| if all($authorized[]; length > 0 and test("^[^\r\n,]+$"))
|
||||||
|
then .
|
||||||
|
else error("existing Android OAuth clients are malformed")
|
||||||
|
end
|
||||||
|
| ($identities.identities | map(.sha256)) as $new_play
|
||||||
|
| ($matched_oauth | split("\n") | map(select(length > 0))) as $new_oauth
|
||||||
|
| (($published + $new_play) | stable_unique | map(colonize)) as $all_published
|
||||||
|
| (($existing_play_values + $new_play) | stable_unique | map(colonize)) as $all_play
|
||||||
|
| (($authorized + $new_oauth) | stable_unique) as $all_authorized
|
||||||
|
| ($firebase.client[]
|
||||||
|
| select(.client_info.android_client_info.package_name == "org.whoneedhelp.mobile")) as $client
|
||||||
|
| "ANDROID_APP_LINKS_SHA256_CERT_FINGERPRINTS=\($all_published | join(","))",
|
||||||
|
"ANDROID_PLAY_APP_SIGNING_SHA256_CERT_FINGERPRINTS=\($all_play | join(","))",
|
||||||
|
"GOOGLE_OAUTH_AUTHORIZED_PARTY_IDS=\($all_authorized | join(","))",
|
||||||
|
"WNH_FIREBASE_APPLICATION_ID=\($client.client_info.mobilesdk_app_id)",
|
||||||
|
"WNH_FIREBASE_API_KEY=\($client.api_key[0].current_key)",
|
||||||
|
"WNH_FIREBASE_PROJECT_ID=\($firebase.project_info.project_id)",
|
||||||
|
"WNH_FIREBASE_GCM_SENDER_ID=\($firebase.project_info.project_number)"
|
||||||
|
' >"$values_file"
|
||||||
|
|
||||||
|
cp "$env_file" "$candidate_env"
|
||||||
|
chmod 600 "$candidate_env"
|
||||||
|
"$ROOT/scripts/set-env-values.sh" "$candidate_env" "$values_file" >/dev/null
|
||||||
|
"$ROOT/scripts/validate-android-environment.sh" "$candidate_env" production >/dev/null
|
||||||
|
|
||||||
|
identity_count=$(jq '.identities | length' "$normalized_identities")
|
||||||
|
published_count=$(
|
||||||
|
awk -F= '
|
||||||
|
$1 == "ANDROID_APP_LINKS_SHA256_CERT_FINGERPRINTS" {
|
||||||
|
value = substr($0, index($0, "=") + 1)
|
||||||
|
print split(value, fingerprints, ",")
|
||||||
|
exit
|
||||||
|
}
|
||||||
|
' "$candidate_env"
|
||||||
|
)
|
||||||
|
authorized_count=$(
|
||||||
|
awk -F= '
|
||||||
|
$1 == "GOOGLE_OAUTH_AUTHORIZED_PARTY_IDS" {
|
||||||
|
value = substr($0, index($0, "=") + 1)
|
||||||
|
print split(value, clients, ",")
|
||||||
|
exit
|
||||||
|
}
|
||||||
|
' "$candidate_env"
|
||||||
|
)
|
||||||
|
|
||||||
|
echo "Validated production Play Android identity import."
|
||||||
|
echo "Target environment: $env_file"
|
||||||
|
echo "Package: $package_name"
|
||||||
|
echo "Play signing identities supplied: $identity_count"
|
||||||
|
echo "Published App Links identities after import: $published_count"
|
||||||
|
echo "Authorized Android OAuth clients after import: $authorized_count"
|
||||||
|
echo "Firebase/FCM project relationship: verified"
|
||||||
|
|
||||||
|
if [[ "$mode" == --apply ]]; then
|
||||||
|
mv "$candidate_env" "$env_file"
|
||||||
|
echo "Applied the validated values atomically without printing credentials."
|
||||||
|
else
|
||||||
|
echo "Plan only: no files were changed. Re-run with --apply after reviewing these counts."
|
||||||
|
fi
|
||||||
|
|
@ -399,6 +399,135 @@ if ./scripts/import-firebase-android-config.sh \
|
||||||
fi
|
fi
|
||||||
test "$(sha256sum "$credential_env" | awk '{print $1}')" = "$credential_hash"
|
test "$(sha256sum "$credential_env" | awk '{print $1}')" = "$credential_hash"
|
||||||
|
|
||||||
|
echo "Checking production Play Android identity import"
|
||||||
|
play_env="$scan_dir/play-production.env"
|
||||||
|
cp .env.example "$play_env"
|
||||||
|
chmod 600 "$play_env"
|
||||||
|
play_upload_sha256=BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
|
||||||
|
play_sha1_one=1111111111111111111111111111111111111111
|
||||||
|
play_sha1_two=2222222222222222222222222222222222222222
|
||||||
|
play_sha256_one=D7C4F1124DF468E5B354DED896E801512941F18A710C18B0E798AA2B81DA11DF
|
||||||
|
play_sha256_two=A5742BAE70C6D034E37544B62E37A375C0E005647450F40F29B2A984F9FDB8FB
|
||||||
|
play_upload_colon=$(printf '%s' "$play_upload_sha256" | sed 's/../&:/g; s/:$//')
|
||||||
|
play_sha256_one_colon=$(printf '%s' "$play_sha256_one" | sed 's/../&:/g; s/:$//')
|
||||||
|
play_sha256_two_colon=$(printf '%s' "$play_sha256_two" | sed 's/../&:/g; s/:$//')
|
||||||
|
sed -i \
|
||||||
|
-e 's|^DEPLOYMENT_ENV=.*|DEPLOYMENT_ENV=production|' \
|
||||||
|
-e 's|^PHX_HOST=.*|PHX_HOST=help.test|' \
|
||||||
|
-e 's|^PHX_SCHEME=.*|PHX_SCHEME=https|' \
|
||||||
|
-e 's|^PHX_URL_PORT=.*|PHX_URL_PORT=443|' \
|
||||||
|
-e 's|^WNH_BASE_URL=.*|WNH_BASE_URL=https://help.test|' \
|
||||||
|
-e 's|^GOOGLE_OAUTH_CLIENT_ID=.*|GOOGLE_OAUTH_CLIENT_ID=quality-production-web-client|' \
|
||||||
|
-e 's|^GOOGLE_OAUTH_AUTHORIZED_PARTY_IDS=.*|GOOGLE_OAUTH_AUTHORIZED_PARTY_IDS=quality-upload-android-client|' \
|
||||||
|
-e 's|^ANDROID_APP_LINKS_PACKAGE_NAME=.*|ANDROID_APP_LINKS_PACKAGE_NAME=org.whoneedhelp.mobile|' \
|
||||||
|
-e "s|^ANDROID_APP_LINKS_SHA256_CERT_FINGERPRINTS=.*|ANDROID_APP_LINKS_SHA256_CERT_FINGERPRINTS=$play_upload_colon|" \
|
||||||
|
-e 's|^ANDROID_PLAY_APP_SIGNING_SHA256_CERT_FINGERPRINTS=.*|ANDROID_PLAY_APP_SIGNING_SHA256_CERT_FINGERPRINTS=|' \
|
||||||
|
-e 's|^WNH_FIREBASE_PROJECT_ID=.*|WNH_FIREBASE_PROJECT_ID=quality-production|' \
|
||||||
|
-e 's|^FCM_PROJECT_ID=.*|FCM_PROJECT_ID=quality-production|' \
|
||||||
|
"$play_env"
|
||||||
|
|
||||||
|
play_google_services="$scan_dir/play-google-services.json"
|
||||||
|
jq --null-input \
|
||||||
|
--arg sha1_one "$play_sha1_one" \
|
||||||
|
--arg sha1_two "$play_sha1_two" \
|
||||||
|
'{
|
||||||
|
project_info: {
|
||||||
|
project_number: "987654321",
|
||||||
|
project_id: "quality-production"
|
||||||
|
},
|
||||||
|
client: [
|
||||||
|
{
|
||||||
|
client_info: {
|
||||||
|
mobilesdk_app_id: "1:987654321:android:quality-production",
|
||||||
|
android_client_info: {package_name: "org.whoneedhelp.mobile"}
|
||||||
|
},
|
||||||
|
oauth_client: [
|
||||||
|
{
|
||||||
|
client_id: "quality-play-android-client-one",
|
||||||
|
client_type: 1,
|
||||||
|
android_info: {
|
||||||
|
package_name: "org.whoneedhelp.mobile",
|
||||||
|
certificate_hash: $sha1_one
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
client_id: "quality-play-android-client-two",
|
||||||
|
client_type: 1,
|
||||||
|
android_info: {
|
||||||
|
package_name: "org.whoneedhelp.mobile",
|
||||||
|
certificate_hash: $sha1_two
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
api_key: [{current_key: "quality-production-firebase-api-key"}]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}' >"$play_google_services"
|
||||||
|
chmod 600 "$play_google_services"
|
||||||
|
|
||||||
|
play_identities="$scan_dir/play-identities.json"
|
||||||
|
jq --null-input \
|
||||||
|
--arg sha1_one "$play_sha1_one" \
|
||||||
|
--arg sha1_two "$play_sha1_two" \
|
||||||
|
--arg sha256_one "$play_sha256_one" \
|
||||||
|
--arg sha256_two "$play_sha256_two" \
|
||||||
|
'{
|
||||||
|
package_name: "org.whoneedhelp.mobile",
|
||||||
|
identities: [
|
||||||
|
{sha1: $sha1_one, sha256: $sha256_one},
|
||||||
|
{sha1: $sha1_two, sha256: $sha256_two}
|
||||||
|
]
|
||||||
|
}' >"$play_identities"
|
||||||
|
chmod 600 "$play_identities"
|
||||||
|
|
||||||
|
play_hash_before=$(sha256sum "$play_env" | awk '{print $1}')
|
||||||
|
play_plan_output=$(
|
||||||
|
./scripts/import-play-android-config.sh \
|
||||||
|
"$play_env" "$play_google_services" "$play_identities"
|
||||||
|
)
|
||||||
|
test "$(sha256sum "$play_env" | awk '{print $1}')" = "$play_hash_before"
|
||||||
|
printf '%s' "$play_plan_output" | grep -F 'Plan only: no files were changed.' >/dev/null
|
||||||
|
if printf '%s' "$play_plan_output" |
|
||||||
|
grep -E 'quality-production-firebase-api-key|quality-play-android-client' >/dev/null; then
|
||||||
|
echo "Play Android identity plan printed a provider value." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
./scripts/import-play-android-config.sh \
|
||||||
|
"$play_env" "$play_google_services" "$play_identities" --apply >/dev/null
|
||||||
|
grep -Fx \
|
||||||
|
"ANDROID_APP_LINKS_SHA256_CERT_FINGERPRINTS=$play_upload_colon,$play_sha256_one_colon,$play_sha256_two_colon" \
|
||||||
|
"$play_env" >/dev/null
|
||||||
|
grep -Fx \
|
||||||
|
"ANDROID_PLAY_APP_SIGNING_SHA256_CERT_FINGERPRINTS=$play_sha256_one_colon,$play_sha256_two_colon" \
|
||||||
|
"$play_env" >/dev/null
|
||||||
|
grep -Fx \
|
||||||
|
'GOOGLE_OAUTH_AUTHORIZED_PARTY_IDS=quality-upload-android-client,quality-play-android-client-one,quality-play-android-client-two' \
|
||||||
|
"$play_env" >/dev/null
|
||||||
|
grep -Fx 'WNH_FIREBASE_APPLICATION_ID=1:987654321:android:quality-production' \
|
||||||
|
"$play_env" >/dev/null
|
||||||
|
grep -Fx 'WNH_FIREBASE_API_KEY=quality-production-firebase-api-key' \
|
||||||
|
"$play_env" >/dev/null
|
||||||
|
grep -Fx 'WNH_FIREBASE_PROJECT_ID=quality-production' "$play_env" >/dev/null
|
||||||
|
grep -Fx 'WNH_FIREBASE_GCM_SENDER_ID=987654321' "$play_env" >/dev/null
|
||||||
|
|
||||||
|
play_hash_after=$(sha256sum "$play_env" | awk '{print $1}')
|
||||||
|
./scripts/import-play-android-config.sh \
|
||||||
|
"$play_env" "$play_google_services" "$play_identities" --apply >/dev/null
|
||||||
|
test "$(sha256sum "$play_env" | awk '{print $1}')" = "$play_hash_after"
|
||||||
|
|
||||||
|
play_bad_identities="$scan_dir/play-identities-unmatched.json"
|
||||||
|
jq '.identities[0].sha1 = "3333333333333333333333333333333333333333"' \
|
||||||
|
"$play_identities" >"$play_bad_identities"
|
||||||
|
chmod 600 "$play_bad_identities"
|
||||||
|
if ./scripts/import-play-android-config.sh \
|
||||||
|
"$play_env" "$play_google_services" "$play_bad_identities" --apply \
|
||||||
|
>/dev/null 2>&1; then
|
||||||
|
echo "Play Android identity import accepted an unmatched Play SHA-1." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
test "$(sha256sum "$play_env" | awk '{print $1}')" = "$play_hash_after"
|
||||||
|
|
||||||
echo "Checking Android environment isolation"
|
echo "Checking Android environment isolation"
|
||||||
./scripts/android-play-policy-check.sh >/dev/null
|
./scripts/android-play-policy-check.sh >/dev/null
|
||||||
android_fingerprint=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
|
android_fingerprint=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
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user