#!/usr/bin/env bash # Get email verification token via Admin API (multi-stand). # Usage: get-verification-token.sh # Env: STAND=local|dev|ift|stage|calentiq [ADMIN_API_HOST] [ENV_FILE] [ADMIN_*|SMOKE_ADMIN_*] # stdout: token only; stderr: stand / user_id / expires_at set -euo pipefail ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" TARGET_EMAIL="${1:-}" STAND="${STAND:-local}" if [[ -z "${TARGET_EMAIL}" ]]; then echo "Usage: STAND=ift get-verification-token.sh user@example.com" >&2 exit 1 fi # Make may pass empty ADMIN_API_HOST= / ENV_FILE= — treat as unset. [[ -z "${ADMIN_API_HOST:-}" ]] && unset ADMIN_API_HOST || true [[ -z "${ENV_FILE:-}" ]] && unset ENV_FILE || true # Preserve explicit creds so ENV_FILE does not override CLI/make env. _PRE_SMOKE_ADMIN_EMAIL="${SMOKE_ADMIN_EMAIL:-}" _PRE_SMOKE_ADMIN_PASSWORD="${SMOKE_ADMIN_PASSWORD:-}" _PRE_ADMIN_SUPER_EMAIL="${ADMIN_SUPER_EMAIL:-}" _PRE_ADMIN_SUPER_PASSWORD="${ADMIN_SUPER_PASSWORD:-}" _PRE_ADMIN_EMAIL="${ADMIN_EMAIL:-}" _PRE_ADMIN_PASSWORD="${ADMIN_PASSWORD:-}" case "${STAND}" in local) DEFAULT_ADMIN_API="http://localhost:8445" ENV_CANDIDATES=( "${ROOT}/docker/.env" "${ROOT}/.env.development" ) ALLOW_FALLBACK_CREDS=1 ;; dev) DEFAULT_ADMIN_API="https://admin-api.dev.eventhub.local" ENV_CANDIDATES=( "${ROOT}/docker/.env" ) ALLOW_FALLBACK_CREDS=1 ;; ift) DEFAULT_ADMIN_API="https://admin-api.ift.eventhub.local" ENV_CANDIDATES=( "${ROOT}/docker/.env.ift" ) ALLOW_FALLBACK_CREDS=0 ;; stage) DEFAULT_ADMIN_API="https://admin-api.stage.eventhub.local" ENV_CANDIDATES=( "${ROOT}/docker/.env.stage" "${HOME}/.cursor/secrets/eventhub-stage.env" "/mnt/c/Users/alexc/.cursor/secrets/eventhub-stage.env" ) ALLOW_FALLBACK_CREDS=0 ;; calentiq) DEFAULT_ADMIN_API="https://admin-api.stage.calentiq.com" ENV_CANDIDATES=( "${ROOT}/docker/.env.stage" "${HOME}/.cursor/secrets/eventhub-stage.env" "/mnt/c/Users/alexc/.cursor/secrets/eventhub-stage.env" ) ALLOW_FALLBACK_CREDS=0 ;; *) echo "Unknown STAND=${STAND} (expected: local|dev|ift|stage|calentiq)" >&2 exit 1 ;; esac ADMIN_API="${ADMIN_API_HOST:-$DEFAULT_ADMIN_API}" ADMIN_API="${ADMIN_API%/}" resolve_env_file() { if [[ -n "${ENV_FILE:-}" ]]; then if [[ ! -f "${ENV_FILE}" ]]; then echo "ENV_FILE not found: ${ENV_FILE}" >&2 exit 1 fi printf '%s\n' "${ENV_FILE}" return fi local f for f in "${ENV_CANDIDATES[@]}"; do if [[ -f "${f}" ]]; then printf '%s\n' "${f}" return fi done printf '\n' } load_admin_creds_from_file() { local file="$1" [[ -n "${file}" ]] || return 0 set -a # shellcheck disable=SC1091 source <(sed $'s/\xEF\xBB\xBF//' "${file}" | tr -d '\r' | grep -E '^(ADMIN_SUPER_|ADMIN_EMAIL=|ADMIN_PASSWORD=|SMOKE_ADMIN_)' || true) set +a } ENV_RESOLVED="$(resolve_env_file)" if [[ -n "${ENV_RESOLVED}" ]]; then load_admin_creds_from_file "${ENV_RESOLVED}" fi # Restore CLI/make overrides [[ -n "${_PRE_SMOKE_ADMIN_EMAIL}" ]] && SMOKE_ADMIN_EMAIL="${_PRE_SMOKE_ADMIN_EMAIL}" [[ -n "${_PRE_SMOKE_ADMIN_PASSWORD}" ]] && SMOKE_ADMIN_PASSWORD="${_PRE_SMOKE_ADMIN_PASSWORD}" [[ -n "${_PRE_ADMIN_SUPER_EMAIL}" ]] && ADMIN_SUPER_EMAIL="${_PRE_ADMIN_SUPER_EMAIL}" [[ -n "${_PRE_ADMIN_SUPER_PASSWORD}" ]] && ADMIN_SUPER_PASSWORD="${_PRE_ADMIN_SUPER_PASSWORD}" [[ -n "${_PRE_ADMIN_EMAIL}" ]] && ADMIN_EMAIL="${_PRE_ADMIN_EMAIL}" [[ -n "${_PRE_ADMIN_PASSWORD}" ]] && ADMIN_PASSWORD="${_PRE_ADMIN_PASSWORD}" ADMIN_LOGIN_EMAIL="${SMOKE_ADMIN_EMAIL:-${ADMIN_SUPER_EMAIL:-${ADMIN_EMAIL:-}}}" ADMIN_LOGIN_PASS="${SMOKE_ADMIN_PASSWORD:-${ADMIN_SUPER_PASSWORD:-${ADMIN_PASSWORD:-}}}" if [[ -z "${ADMIN_LOGIN_EMAIL}" || -z "${ADMIN_LOGIN_PASS}" ]]; then if [[ "${ALLOW_FALLBACK_CREDS}" -eq 1 ]]; then ADMIN_LOGIN_EMAIL="${ADMIN_LOGIN_EMAIL:-superadmin@eventhub.local}" ADMIN_LOGIN_PASS="${ADMIN_LOGIN_PASS:-123456}" else echo "No admin credentials for STAND=${STAND}." >&2 echo "Set ADMIN_* / SMOKE_ADMIN_* or provide ENV_FILE (tried: ${ENV_CANDIDATES[*]})." >&2 exit 1 fi fi echo "stand=${STAND} admin_api=${ADMIN_API} env_file=${ENV_RESOLVED:-none}" >&2 LOGIN=$(curl -sk --connect-timeout 15 -X POST "${ADMIN_API}/v1/admin/login" \ -H 'Content-Type: application/json' \ -d "{\"email\":\"${ADMIN_LOGIN_EMAIL}\",\"password\":\"${ADMIN_LOGIN_PASS}\"}") || { echo "admin login request failed: ${ADMIN_API}/v1/admin/login" >&2 exit 1 } ADMIN_TOKEN=$(printf '%s' "${LOGIN}" | python3 -c ' import json,sys try: d=json.load(sys.stdin) except Exception as e: print("", end="") sys.exit(0) print(d.get("token") or d.get("access_token") or "", end="") ') || true if [[ -z "${ADMIN_TOKEN}" ]]; then echo "admin login failed: ${LOGIN}" >&2 exit 1 fi ENC=$(python3 -c 'import urllib.parse,sys; print(urllib.parse.quote(sys.argv[1]))' "${TARGET_EMAIL}") USERS_JSON=$(curl -sk --connect-timeout 15 \ "${ADMIN_API}/v1/admin/users?q=${ENC}&limit=50" \ -H "Authorization: Bearer ${ADMIN_TOKEN}") USER_ID=$(printf '%s' "${USERS_JSON}" | python3 -c ' import json,sys raw=sys.stdin.read() try: items=json.loads(raw) except Exception: print("") raise SystemExit if isinstance(items, dict): items=items.get("users") or items.get("items") or items.get("data") or [] target=sys.argv[1].lower() for u in items: if str(u.get("email","")).lower()==target: print(u.get("id") or "") raise SystemExit print("") ' "${TARGET_EMAIL}") if [[ -z "${USER_ID}" ]]; then echo "USER_NOT_FOUND=${TARGET_EMAIL}" >&2 exit 2 fi VT=$(curl -sk --connect-timeout 15 \ "${ADMIN_API}/v1/admin/users/${USER_ID}/verification-token" \ -H "Authorization: Bearer ${ADMIN_TOKEN}") TOKEN=$(printf '%s' "${VT}" | python3 -c ' import json,sys try: d=json.load(sys.stdin) except Exception: print("") raise SystemExit print(d.get("token") or "", end="") ') EXPIRES=$(printf '%s' "${VT}" | python3 -c ' import json,sys try: d=json.load(sys.stdin) except Exception: print("") raise SystemExit print(d.get("expires_at") or "", end="") ') if [[ -z "${TOKEN}" ]]; then echo "verification-token failed for user_id=${USER_ID}: ${VT}" >&2 exit 1 fi echo "user_id=${USER_ID} expires_at=${EXPIRES}" >&2 printf '%s\n' "${TOKEN}"