#!/usr/bin/env bash set -euo pipefail readonly GRAPH_API_BASE_URL="https://graph.facebook.com" readonly GRAPH_API_VERSION="v25.0" readonly PSID="27511427698460020" readonly ASID="122111097783118257" readonly PAGE_ID="TODO_PAGE_ID" readonly APP_ID="TODO_APP_ID" readonly PAGE_ACCESS_TOKEN="TODO_PAGE_ACCESS_TOKEN" readonly ACCESS_TOKEN="$PAGE_ACCESS_TOKEN" readonly APP_SECRET="TODO_APP_SECRET" usage() { cat <<'EOF' Verify Meta PSID / ASID matching in both directions. Usage: bash scripts/tools/verify-meta-id-match.sh Built-in IDs: PSID 27511427698460020 ASID 122111097783118257 Before running: Fill PAGE_ID, APP_ID, PAGE_ACCESS_TOKEN, and APP_SECRET constants at the top of this script. Exit code: 0 Both directions matched. 1 API call succeeded, but one or both directions did not match. 2 Missing required input. EOF } if [ "${1:-}" = "-h" ] || [ "${1:-}" = "--help" ]; then usage exit 0 fi if [ "$#" -gt 0 ]; then echo "This script does not accept runtime parameters. Edit constants in the script instead." >&2 usage >&2 exit 2 fi require_value() { local name="$1" local value="$2" if [ -n "$value" ]; then return fi echo "Missing required value: $name" >&2 exit 2 } require_command() { local name="$1" if command -v "$name" >/dev/null 2>&1; then return fi echo "Missing required command: $name" >&2 exit 2 } require_configured() { local name="$1" local value="$2" require_value "$name" "$value" if [[ "$value" == TODO_* ]]; then echo "Please fill script constant: $name" >&2 exit 2 fi } require_configured "PAGE_ID" "$PAGE_ID" require_configured "APP_ID" "$APP_ID" require_configured "PAGE_ACCESS_TOKEN" "$PAGE_ACCESS_TOKEN" require_configured "ACCESS_TOKEN" "$ACCESS_TOKEN" require_configured "APP_SECRET" "$APP_SECRET" require_command curl require_command node urlencode() { node -e 'process.stdout.write(encodeURIComponent(process.argv[1] ?? ""))' "$1" } appsecret_proof() { local token="$1" if [ -z "$APP_SECRET" ]; then return fi node -e ' const crypto = require("crypto"); const token = process.argv[1] ?? ""; const secret = process.argv[2] ?? ""; process.stdout.write( crypto.createHmac("sha256", secret).update(token).digest("hex") ); ' "$token" "$APP_SECRET" } json_ids() { local file="$1" node -e ' const fs = require("fs"); const payload = JSON.parse(fs.readFileSync(process.argv[1], "utf8")); const ids = Array.isArray(payload.data) ? payload.data.map((item) => item && item.id).filter(Boolean) : []; process.stdout.write(ids.join("\n")); ' "$file" } json_has_id() { local file="$1" local expected="$2" node -e ' const fs = require("fs"); const payload = JSON.parse(fs.readFileSync(process.argv[1], "utf8")); const expected = process.argv[2]; const matched = Array.isArray(payload.data) && payload.data.some((item) => item && String(item.id) === expected); process.exit(matched ? 0 : 1); ' "$file" "$expected" } print_ids() { local file="$1" local ids ids="$(json_ids "$file")" if [ -z "$ids" ]; then echo "Returned IDs: " return fi echo "Returned IDs:" while IFS= read -r id; do echo " - $id" done <<<"$ids" } request_graph() { local output_file="$1" local endpoint="$2" shift 2 local http_code if ! http_code="$( curl -sS -w '%{http_code}' -o "$output_file" -G "$endpoint" "$@" )"; then echo "Graph API request failed before receiving a response." >&2 return 1 fi if [ "$http_code" -lt 200 ] || [ "$http_code" -ge 300 ]; then echo "Graph API returned HTTP $http_code:" >&2 cat "$output_file" >&2 echo >&2 return 1 fi } tmp_psid_to_asid="$(mktemp)" tmp_asid_to_psid="$(mktemp)" cleanup() { rm -f "$tmp_psid_to_asid" "$tmp_asid_to_psid" } trap cleanup EXIT encoded_psid="$(urlencode "$PSID")" encoded_asid="$(urlencode "$ASID")" psid_to_asid_endpoint="${GRAPH_API_BASE_URL}/${GRAPH_API_VERSION}/${encoded_psid}/ids_for_apps" asid_to_psid_endpoint="${GRAPH_API_BASE_URL}/${GRAPH_API_VERSION}/${encoded_asid}/ids_for_pages" psid_proof="$(appsecret_proof "$PAGE_ACCESS_TOKEN")" asid_proof="$(appsecret_proof "$ACCESS_TOKEN")" echo "=== PSID -> ASID ===" echo "GET ${psid_to_asid_endpoint}?app=${APP_ID}&access_token=&appsecret_proof=" psid_args=( --data-urlencode "app=${APP_ID}" --data-urlencode "access_token=${PAGE_ACCESS_TOKEN}" ) if [ -n "$psid_proof" ]; then psid_args+=(--data-urlencode "appsecret_proof=${psid_proof}") fi request_graph "$tmp_psid_to_asid" "$psid_to_asid_endpoint" "${psid_args[@]}" print_ids "$tmp_psid_to_asid" psid_to_asid_matched=0 if json_has_id "$tmp_psid_to_asid" "$ASID"; then echo "Match: yes, ASID was found from PSID." else echo "Match: no, ASID was not found from PSID." psid_to_asid_matched=1 fi echo echo "=== ASID -> PSID ===" echo "GET ${asid_to_psid_endpoint}?page=${PAGE_ID}&access_token=" asid_args=( --data-urlencode "page=${PAGE_ID}" --data-urlencode "access_token=${ACCESS_TOKEN}" ) if [ -n "$asid_proof" ]; then asid_args+=(--data-urlencode "appsecret_proof=${asid_proof}") fi request_graph "$tmp_asid_to_psid" "$asid_to_psid_endpoint" "${asid_args[@]}" print_ids "$tmp_asid_to_psid" asid_to_psid_matched=0 if json_has_id "$tmp_asid_to_psid" "$PSID"; then echo "Match: yes, PSID was found from ASID." else echo "Match: no, PSID was not found from ASID." asid_to_psid_matched=1 fi echo if [ "$psid_to_asid_matched" -eq 0 ] && [ "$asid_to_psid_matched" -eq 0 ]; then echo "Result: matched in both directions." exit 0 fi echo "Result: not matched in both directions." exit 1