From 76548e578b5455b2efd96f631fc9bd0050839cbc Mon Sep 17 00:00:00 2001 From: Aleksey Sabilin Date: Tue, 28 Jul 2026 22:26:44 +0300 Subject: [PATCH] chore(make): add verification-token target for multi-stand email lookup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit make verification-token EMAIL=… STAND=local|dev|ift|stage|calentiq fetches admin verification token via Admin API. [skip ci] --- Makefile | 8 +- scripts/get-verification-token.sh | 215 ++++++++++++++++++++++++++++++ 2 files changed, 222 insertions(+), 1 deletion(-) create mode 100644 scripts/get-verification-token.sh diff --git a/Makefile b/Makefile index 8ac3b7f..78bf4ec 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ .PHONY: help clean compile shell test eunit test-api test-all \ - dialyzer xref cover docs release run stop logs + dialyzer xref cover docs release run stop logs verification-token # Цвета для вывода (только для команд, где нужны) GREEN := \033[0;32m @@ -352,6 +352,12 @@ docker-swarm-shell: # ============================================================================ # UTILITIES # ============================================================================ +# STAND=local|dev|ift|stage|calentiq (default local). Overrides: ADMIN_API_HOST, ENV_FILE, ADMIN_*/SMOKE_ADMIN_* +verification-token: ## Token: make verification-token EMAIL=u@x STAND=ift|stage|dev|local|calentiq + @test -n "$(EMAIL)" || (echo "Usage: make verification-token EMAIL=user@x STAND=ift" >&2; exit 1) + @STAND="$(STAND)" ADMIN_API_HOST="$(ADMIN_API_HOST)" ENV_FILE="$(ENV_FILE)" \ + bash scripts/get-verification-token.sh "$(EMAIL)" + status: ## Проверить статус сервера @echo "Проверка статуса сервера..." @if curl -s http://localhost:8080/health > /dev/null 2>&1; then \ diff --git a/scripts/get-verification-token.sh b/scripts/get-verification-token.sh new file mode 100644 index 0000000..b8dcc66 --- /dev/null +++ b/scripts/get-verification-token.sh @@ -0,0 +1,215 @@ +#!/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}"