#!/usr/bin/env bash set -euo pipefail ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" LOCAL_KEY="${RENDEZVOUS_SMOKE_LOCAL_KEY:-$ROOT/deploy/compose/secrets/signing-key}" GAME_ID="${RENDEZVOUS_LOCAL_CREDENTIAL_GAME_ID:-space-game}" case "$GAME_ID" in space-game) KEY_ID="local-smoke-1" SUBJECT="local-smoke-host" ;; unscouted) KEY_ID="local-smoke-unscouted-1" SUBJECT="local-smoke-unscouted-host" ;; *) printf 'RENDEZVOUS_LOCAL_CREDENTIAL_GAME_ID must be space-game or unscouted.\n' >&2 exit 2 ;; esac if (( $# != 0 )); then printf 'This helper accepts no arguments; select only a provisioned local game through RENDEZVOUS_LOCAL_CREDENTIAL_GAME_ID.\n' >&2 exit 2 fi command -v python3 >/dev/null || { printf 'Missing required command: python3\n' >&2 exit 2 } # This is deliberately a local-fixture tool, not a general credential issuer. # Python reads the raw key from the protected file; key material never appears in # a child process argument, environment value, temporary file, or command output. python3 - "$LOCAL_KEY" "$GAME_ID" "$KEY_ID" "$SUBJECT" <<'PY' import base64 import hashlib import hmac import json import os import secrets import stat import sys import time key_path = sys.argv[1] game_id = sys.argv[2] key_id = sys.argv[3] subject = sys.argv[4] try: metadata = os.lstat(key_path) except FileNotFoundError: raise SystemExit(f"Local Compose smoke key does not exist: {key_path}") if stat.S_ISLNK(metadata.st_mode) or not stat.S_ISREG(metadata.st_mode): raise SystemExit(f"Local Compose smoke key must be a regular non-symlink file: {key_path}") parent_path = os.path.dirname(os.path.abspath(key_path)) parent = os.lstat(parent_path) if stat.S_ISLNK(parent.st_mode) or not stat.S_ISDIR(parent.st_mode): raise SystemExit(f"Local Compose secret directory must be a non-symlink directory: {parent_path}") if parent.st_uid != os.geteuid() or parent.st_mode & 0o077: raise SystemExit(f"Local Compose secret directory must be owned by this user with mode 0700: {parent_path}") if metadata.st_uid != os.geteuid() or metadata.st_mode & 0o077 or metadata.st_nlink != 1: raise SystemExit(f"Local Compose smoke key must be owned by this user, single-linked, and private to its owner: {key_path}") with open(key_path, "rb") as key_file: key = key_file.read(33) if len(key) != 32: raise SystemExit(f"Local Compose smoke key must be exactly 32 bytes: {key_path}") now = int(time.time()) payload = { "version": 1, "issuer": "final-factory-rendezvous-smoke", "audience": "rendezvous-service", "subject": subject, "kind": "dedicatedPublisher", "gameId": game_id, "environmentId": "smoke", "regions": ["local"], "permissions": [], "issuedAtUnixSeconds": now, "notBeforeUnixSeconds": now, "expiresAtUnixSeconds": now + 600, "nonce": secrets.token_hex(16), } def base64url(value: bytes) -> str: return base64.urlsafe_b64encode(value).rstrip(b"=").decode("ascii") encoded = base64url(json.dumps(payload, separators=(",", ":")).encode("utf-8")) signed = f"rv1.{key_id}.{encoded}" signature = base64url(hmac.new(key, signed.encode("ascii"), hashlib.sha256).digest()) print(f"{signed}.{signature}") PY