#!/bin/bash # ============================================================================== # ACTION REPLAY - CLIENT DOWNLOADER (In-Folder Edition) # ============================================================================== set -e VPS_HOST="actionreplay.mekadata.fr" AR_SCHEME="${AR_SCHEME:-https}" AR_BASE="${AR_SCHEME}://${VPS_HOST}" OPS_URL="${AR_BASE}/ops/approvals.html" echo "================================================" echo " ACTION REPLAY - INSTALLATION" echo "================================================" # 0. Token : DOWNLOADER_PWD (bypass lab) OU challenge console /ops obtain_token() { local action="${1:-cold}" local pass="${DOWNLOADER_PWD:-}" local json tok cid status i hostname hwid if [ -n "$pass" ]; then echo "Demande de token (DOWNLOADER_PWD)..." json=$(curl -sSf --connect-timeout 8 \ -X POST "${AR_BASE}/api/v1/downloader-pwd" \ -H "Content-Type: application/json" \ -d "{\"password\":\"${pass}\"}") || { echo "DOWNLOADER_PWD refuse ou VPS injoignable." exit 1 } tok=$(printf '%s' "$json" | sed -n 's/.*"token"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p') [ -n "$tok" ] || { echo "Reponse downloader-pwd invalide."; exit 1; } AR_DL_TOKEN="$tok" return 0 fi # Challenge sans HWID final encore : on cree apres selection cart/env. # Ici placeholder — obtain_token_after_hwid pour le vrai cold. echo "Pas de DOWNLOADER_PWD : approve console requis apres calcul HWID." AR_DL_TOKEN="" } obtain_token_with_hwid() { local cart="$1" local env="$2" local hwid="$3" local action="${4:-cold}" local hostname cid status tok i json if [ -n "${DOWNLOADER_PWD:-}" ] && [ -n "${AR_DL_TOKEN:-}" ]; then return 0 fi if [ -n "${DOWNLOADER_PWD:-}" ]; then obtain_token cold return 0 fi hostname=$(hostname -f 2>/dev/null || hostname) echo "Demande d'approve ops (${action})..." json=$(curl -sSf --connect-timeout 8 \ -X POST "${AR_BASE}/api/v1/install-challenge" \ -H "Content-Type: application/json" \ -d "{\"hwid\":\"${hwid}\",\"cartridge\":\"${cart}\",\"env\":\"${env}\",\"action\":\"${action}\",\"hostname\":\"${hostname}\"}") || { echo "Echec creation challenge." exit 1 } cid=$(printf '%s' "$json" | sed -n 's/.*"id"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p') [ -n "$cid" ] || { echo "Challenge id manquant."; exit 1; } echo "Valide dans la console AR :" echo " ${OPS_URL}" echo " Challenge : ${cid}" for i in $(seq 1 150); do sleep 2 status=$(curl -sSf --connect-timeout 8 \ "${AR_BASE}/api/v1/install-challenge?id=${cid}" 2>/dev/null || true) case "$status" in *'"status":"approved"'*|*'"status": "approved"'*) tok=$(printf '%s' "$status" | sed -n 's/.*"token"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p') [ -n "$tok" ] || { echo "Token manquant apres approve."; exit 1; } AR_DL_TOKEN="$tok" echo "Approve OK — token obtenu." return 0 ;; *'"status":"denied"'*|*'"status": "denied"'*) echo "Refuse par l'operateur." exit 1 ;; *'"status":"expired"'*|*'"status": "expired"'*) echo "Challenge expire — relancer." exit 1 ;; esac done echo "Timeout approve (5 min)." exit 1 } # Bootstrap client public? No — need token. For HWID we need /client first. # Chicken-egg: need token to get client to compute HWID to create challenge. # Solution: DOWNLOADER_PWD bypass OR temporary public bootstrap endpoint OR # challenge without hwid for bootstrap-only. # # Plan: cold challenge allows empty-ish bootstrap — we use a pre-hwid challenge # with hwid="pending" then... licence check for repair needs real hwid. # # Better cold flow without pwd: # 1) Minimal unauthenticated bootstrap is BAD. # 2) Challenge with hwid computed from local formula without binary — duplicate logic BAD. # 3) Two-step: ops approve "bootstrap" with cartridge+env+hostname only, token # scoped... we don't have scoped tokens. # 4) Practical: first GET /client still needs token. Create challenge with # hwid=bootstrap--- hash for step1, then after real HWID # if unlicensed stop; if need tar, second approve with real HWID. # # Simpler V1 cold without pwd: # - Challenge action=cold with hwid placeholder = sha of hostname+cart+env+path # computed in bash (not same as real HWID!) — WRONG for licence. # # Correct approach matching existing binary: # - Keep requiring token for /client. # - For cold without DOWNLOADER_PWD: create challenge with action=cold and # hwid="BOOTSTRAP" + hostname/cart/env in fields — API allows cold without licence. # - After approve, download client, compute real HWID, verify licence. # - If licence missing: print HWID and exit (pense-bete) — token already used for client only. # - User adds licence, re-runs: challenge cold with REAL hwid, approve, client+tar. bootstrap_hwid_placeholder() { local cart="$1" env="$2" local host host=$(hostname -f 2>/dev/null || hostname) printf 'BOOTSTRAP:%s:%s:%s' "$cart" "$env" "$host" } if [ -z "${DOWNLOADER_PWD:-}" ]; then echo "Mode console ops (pas de DOWNLOADER_PWD)." else obtain_token cold fi # 1. Scan cartouches — need token. If none yet, pick cart/env first then challenge. if [ -z "${AR_DL_TOKEN:-}" ]; then echo "Cartouche (nom exact sous /cartridges/) :" printf "> " read -r CART_NAME < /dev/tty echo "Environnement [TEST/PROD] (DEV rare sur cold) :" select TARGET_ENV in "TEST" "PROD" "DEV"; do case $TARGET_ENV in TEST|PROD|DEV) break ;; *) echo "Invalide." ;; esac done < /dev/tty TARGET_ENV_LOWER=$(echo "$TARGET_ENV" | tr '[:upper:]' '[:lower:]') EXPECTED_DIR="${CART_NAME}-${TARGET_ENV_LOWER}" CURRENT_DIR=$(basename "$PWD") if [ "$CURRENT_DIR" != "$EXPECTED_DIR" ]; then echo "Dossier attendu : $EXPECTED_DIR (actuel: $CURRENT_DIR)" exit 1 fi PH=$(bootstrap_hwid_placeholder "$CART_NAME" "$TARGET_ENV") obtain_token_with_hwid "$CART_NAME" "$TARGET_ENV" "$PH" cold else AR_Q="token=${AR_DL_TOKEN}" AVAILABLE_CARTS=($(curl -sSf --connect-timeout 2 --max-time 3 "${AR_BASE}/cartridges/?${AR_Q}" 2>/dev/null | grep -o 'href="[^"/]*/"' | sed 's/href="//;s/\/"//' | grep -v '^\.\.' || true)) if [ ${#AVAILABLE_CARTS[@]} -eq 0 ]; then echo "Aucune cartouche listee." exit 1 fi echo "Cartouches disponibles :" select CART_NAME in "${AVAILABLE_CARTS[@]}"; do if [ -n "$CART_NAME" ]; then break; fi echo "Choix invalide." done < /dev/tty echo "" echo "Environnement pour [$CART_NAME] :" select TARGET_ENV in "DEV" "TEST" "PROD"; do case $TARGET_ENV in DEV|TEST|PROD) break ;; *) echo "Choix invalide." ;; esac done < /dev/tty fi AR_Q="token=${AR_DL_TOKEN}" TARGET_ENV_LOWER=$(echo "$TARGET_ENV" | tr '[:upper:]' '[:lower:]') EXPECTED_DIR="${CART_NAME}-${TARGET_ENV_LOWER}" CURRENT_DIR=$(basename "$PWD") if [ "$CURRENT_DIR" != "$EXPECTED_DIR" ]; then echo "" echo "[ERREUR] Emplacement invalide." echo "Cartouche : $CART_NAME" echo "Environnement : $TARGET_ENV" echo "Dossier attendu : $EXPECTED_DIR" echo "Dossier actuel : $CURRENT_DIR" exit 1 fi echo "================================================" echo "Cartouche : $CART_NAME" echo "Environnement : $TARGET_ENV" echo "Dossier : $PWD" echo "================================================" echo "Telechargement du client (bootstrap HWID)..." curl -sSf --connect-timeout 5 "${AR_BASE}/client?${AR_Q}" -o ./client.hwid chmod +x ./client.hwid HWID=$(./client.hwid hwid "$CART_NAME" "$TARGET_ENV" "$PWD") echo "Verification licence Control Plane..." AUTH_URL="${AR_BASE}/api/v1/auth/verify?hwid=${HWID}&cartridge=${CART_NAME}&env=${TARGET_ENV}&actor=downloader" HTTP_STATUS=$(curl -s -o /dev/null -w "%{http_code}" --connect-timeout 3 "$AUTH_URL" || echo "000") if [ "$HTTP_STATUS" != "200" ]; then rm -f ./client.hwid echo "" echo "ACCES REFUSE (HTTP $HTTP_STATUS) — ajoute la licence puis relance." echo "HWID calcule : $HWID" echo "Fichier : action-replay/config/licenses.jsonl" echo "" exit 1 fi echo "Autorisation OK." rm -f ./client.hwid # Si token bootstrap (placeholder), demander un nouveau grant avec HWID reel pour le tar. if [ -z "${DOWNLOADER_PWD:-}" ]; then echo "Approve pour extract cartouche (HWID licence)..." unset AR_DL_TOKEN obtain_token_with_hwid "$CART_NAME" "$TARGET_ENV" "$HWID" cold AR_Q="token=${AR_DL_TOKEN}" fi echo "Telechargement archive [$CART_NAME]..." curl -sSf --connect-timeout 5 "${AR_BASE}/cartridges/${CART_NAME}/${CART_NAME}.tar.gz?${AR_Q}" | tar -xz --no-same-owner if [ ! -x console/sidecars/client/client ]; then echo "Client scelle absent dans la cartouche." exit 1 fi chmod +x console/deploy/*.sh game/etl_custom/*.sh console/build/*.sh 2>/dev/null || true echo "Lancement installation ($TARGET_ENV)..." # Evite un second challenge immediat dans install.sh si token encore valide. export AR_DL_TOKEN export DOWNLOADER_PWD="${DOWNLOADER_PWD:-}" ./console/deploy/install.sh