AvanzaCast/scripts/validate-livekit-token.sh

172 lines
6.0 KiB
Bash
Executable File

#!/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 <<EOF
Usage: $0 [options]
Options:
--api-key KEY LiveKit API key (or set LIVEKIT_API_KEY env)
--api-secret SECRET LiveKit API secret (or set LIVEKIT_API_SECRET env)
--server URL Base server URL (default: $SERVER_URL)
--room NAME Room name (default: test_room)
--identity ID Participant identity (default: test_user)
-h, --help Show this help
This script requires node and livekit-server-sdk installed (npm i livekit-server-sdk).
It will: generate a token, call $SERVER_URL/rtc/validate with Authorization: Bearer <token>,
try a WebSocket handshake to wss://<host>/rtc?access_token=<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 <<EOF
SUMMARY (files saved):
Token: $TOKEN_FILE
Curl (strict TLS): $CURL_FILE
Curl (insecure -k): $CURLK_FILE
WS attempt: $WS_FILE
Decoded payload: $PAYLOAD_FILE
Commands to view outputs:
cat $TOKEN_FILE
sed -n '1,200p' $CURL_FILE
sed -n '1,200p' $CURLK_FILE
sed -n '1,200p' $WS_FILE
sed -n '1,200p' $PAYLOAD_FILE
Paste the contents of those files here and I will interpret the results and guide next steps.
EOF
echo; echo "=== DONE ==="