"""One-time ops recovery: decrypt and print the server's master xprv. This is the single secret the entire custodial wallet derives from (every user address, the pool address) — treat the output like a root password. Not exposed via any API endpoint or the admin panel, by design; run manually, locally, only when you actually need it (e.g. disaster-recovery backup). Usage: python scripts/decrypt_master_key.py Requires XPRV_ENCRYPTION_KEY to already be set (.env), same as the running server. Looks for the encrypted key at MASTER_KEY_PATH (.env) — if that path doesn't exist, falls back to ./data/keys/master.xprv.enc, the location docker-compose.yml bind-mounts it to, since .env's default (./master.xprv.enc) often doesn't match wherever the running server actually reads it from. """ import os from app.config import settings from app.wallet.keystore import decrypt_xprv _DOCKER_COMPOSE_PATH = "./data/keys/master.xprv.enc" def _resolve_key_path() -> str: if os.path.exists(settings.master_key_path): return settings.master_key_path if os.path.exists(_DOCKER_COMPOSE_PATH): print(f"{settings.master_key_path} not found — using {_DOCKER_COMPOSE_PATH} instead.") return _DOCKER_COMPOSE_PATH raise SystemExit(f"No master key found at {settings.master_key_path} or {_DOCKER_COMPOSE_PATH}") if __name__ == "__main__": if not settings.xprv_encryption_key: raise SystemExit("XPRV_ENCRYPTION_KEY is not set") key_path = _resolve_key_path() print(f"About to decrypt and print the master xprv from {key_path}.") print("This key controls every user's funds and the pool. Make sure this") print("terminal isn't logged/recorded and no one is watching your screen.") confirm = input("Type 'yes' to continue: ") if confirm.strip().lower() != "yes": raise SystemExit("Aborted.") with open(key_path, "rb") as f: token = f.read() print(decrypt_xprv(token))