#!/usr/bin/env zsh # scripts/validate-livekit-token.sh # Reinicia/arranca livekit-server con la clave API/SECRET adecuada, redirige logs y realiza checks básicos. # Uso: # ./scripts/validate-livekit-token.sh --api-key KEY --api-secret SECRET --server https://example.com --room test_room --identity test_user set -euo pipefail API_KEY="${LIVEKIT_API_KEY:-}" API_SECRET="${LIVEKIT_API_SECRET:-}" SERVER_URL="${LIVEKIT_SERVER_URL:-https://livekit-server.bfzqqk.easypanel.host}" ROOM="test_room" IDENTITY="test_user" usage(){ cat <, try a WebSocket handshake to wss:///rtc?access_token= (if wscat/websocat available), and print decoded JWT payload. EOF } while [[ $# -gt 0 ]]; do case "$1" in --api-key) API_KEY="$2"; shift 2;; --api-secret) API_SECRET="$2"; shift 2;; --server) SERVER_URL="$2"; shift 2;; --room) ROOM="$2"; shift 2;; --identity) IDENTITY="$2"; shift 2;; -h|--help) usage; exit 0;; *) echo "Unknown arg: $1"; usage; exit 1;; esac done if [ -z "$API_KEY" ] || [ -z "$API_SECRET" ]; then echo "ERROR: API_KEY and API_SECRET must be set (via args or env)." >&2 usage exit 2 fi echo "[validate-livekit-token] api_key=${API_KEY} server=${SERVER_URL} room=${ROOM} identity=${IDENTITY}" # Temp files for outputs OUT_DIR="/tmp/validate-livekit" mkdir -p "$OUT_DIR" TOKEN_FILE="$OUT_DIR/token.txt" CURL_FILE="$OUT_DIR/curl_strict.txt" CURLK_FILE="$OUT_DIR/curl_insecure.txt" WS_FILE="$OUT_DIR/ws_attempt.txt" PAYLOAD_FILE="$OUT_DIR/payload.json" # Generar token via Node inline # Pass credentials and params via environment to avoid issues with heredoc args TOKEN=$(API_KEY="$API_KEY" API_SECRET="$API_SECRET" IDENTITY="$IDENTITY" ROOM="$ROOM" node - <<'NODE' try{ const sdk = require('livekit-server-sdk'); const AccessToken = sdk.AccessToken || (sdk.default && sdk.default.AccessToken); const VideoGrant = sdk.VideoGrant || (sdk.default && sdk.default.VideoGrant); const identity = process.env.IDENTITY || 'anon'; const room = process.env.ROOM || 'default'; const apiKey = process.env.API_KEY; const apiSecret = process.env.API_SECRET; if (!apiKey || !apiSecret) { console.error('missing API_KEY/API_SECRET in env'); process.exit(2); } const at = new AccessToken(apiKey, apiSecret, { identity: identity, name: identity }); if (VideoGrant) at.addGrant(new VideoGrant({ room: room })); else if (typeof at.addGrant === 'function') at.addGrant({ room: room, roomJoin: true, canPublish: true, canSubscribe: true }); (async ()=>{ const t = (typeof at.toJwt === 'function') ? await at.toJwt() : at.jwt; console.log(t); })(); }catch(e){ console.error('ERRGEN', e && e.stack ? e.stack : e); process.exit(2); } NODE ) || { echo "[error] token generation failed" >&2; exit 3; } if [ -z "$TOKEN" ]; then echo "[error] empty token" >&2; exit 4 fi # Save token echo "$TOKEN" > "$TOKEN_FILE" chmod 600 "$TOKEN_FILE" echo; echo "=== Token generated and saved to: $TOKEN_FILE ===" echo "Token preview: ${TOKEN:0:140}..." VALIDATE_URL="$SERVER_URL/rtc/validate" echo; echo "=== CURL validate (strict TLS) -> $CURL_FILE ===" # store headers and body set +e curl -i -sS --max-time 15 -H "Authorization: Bearer $TOKEN" "$VALIDATE_URL" > "$CURL_FILE" 2>&1 CURL_EXIT=$? set -e if [ $CURL_EXIT -ne 0 ]; then echo "[warn] curl strict failed (exit $CURL_EXIT). See $CURL_FILE" else echo "[ok] curl strict completed. See $CURL_FILE" fi # insecure curl (diagnostic) echo; echo "=== CURL validate (insecure -k) -> $CURLK_FILE ===" set +e curl -i -sS -k --max-time 15 -H "Authorization: Bearer $TOKEN" "$VALIDATE_URL" > "$CURLK_FILE" 2>&1 CURLK_EXIT=$? set -e if [ $CURLK_EXIT -ne 0 ]; then echo "[warn] curl -k failed (exit $CURLK_EXIT). See $CURLK_FILE" else echo "[ok] curl -k completed. See $CURLK_FILE" fi # 2) WebSocket handshake attempt WS_HOST=$(echo "$SERVER_URL" | sed -E 's#https?://##' | sed -E 's#/$##') WS_URL="wss://$WS_HOST/rtc?access_token=$TOKEN" echo; echo "=== WS handshake attempt to: $WS_URL (output -> $WS_FILE) ===" if command -v wscat >/dev/null 2>&1; then if command -v timeout >/dev/null 2>&1; then timeout 10s wscat -c "$WS_URL" > "$WS_FILE" 2>&1 || true else wscat -c "$WS_URL" > "$WS_FILE" 2>&1 || true fi echo "[info] wscat output saved to $WS_FILE" elif command -v websocat >/dev/null 2>&1; then if command -v timeout >/dev/null 2>&1; then timeout 10s websocat "$WS_URL" > "$WS_FILE" 2>&1 || true else websocat "$WS_URL" > "$WS_FILE" 2>&1 || true fi echo "[info] websocat output saved to $WS_FILE" else echo "[info] wscat/websocat not installed; skipping WS handshake test" fi # 3) decode payload (no signature verification) echo "$TOKEN" | awk '{print $0}' > /dev/null node -e 'try{const t=process.argv[1]; const p=t.split(".")[1]; const b=Buffer.from(p.replace(/-/g,"+").replace(/_/g,"/"),"base64").toString(); console.log(b);}catch(e){console.error("failed decode",e);} ' "$TOKEN" > "$PAYLOAD_FILE" 2>&1 || true echo; echo "=== DECODED PAYLOAD SAVED TO: $PAYLOAD_FILE ===" # Print short summary and file locations for user to copy cat <