Files
hermes-config/skills/gaming/game-streaming/references/pairing-bypass-inject-cert.py
T
2026-07-12 10:17:17 -04:00

121 lines
4.2 KiB
Python

#!/usr/bin/env python3
"""Emergency Sunshine pairing bypass — extract client cert from log and inject into state file.
Sunshine v2026.516.143833 has a broken PIN validation pipeline. The /api/pin endpoint
deadlocks internally even when IP addresses match. This script:
1. Reads the most recent /pair request's clientcert from sunshine.log
2. Decodes the hex-encoded PEM cert
3. Injects it directly into sunshine_state.json as a pre-paired named_device
4. Restarts Sunshine
After running, Moonlight must be FULLY CLOSED AND REOPENED — it will see the pre-paired
cert and skip the PIN screen.
Usage:
python3 pairing-bypass-inject-cert.py [--restart]
Requirements:
- Root not needed (Sunshine runs as the same user)
- sunshine_state.json must be writable
- Moonlight must have sent at least one /pair request (visible in sunshine.log)
"""
import json
import re
import uuid
import sys
import os
import subprocess
import time
SUNSHINE_LOG = os.path.expanduser("~/.config/sunshine/sunshine.log")
SUNSHINE_STATE = os.path.expanduser("~/.config/sunshine/sunshine_state.json")
SUNSHINE_CONF = os.path.expanduser("~/.config/sunshine/sunshine.conf")
def extract_latest_cert():
with open(SUNSHINE_LOG, "r", encoding="utf-8", errors="replace") as f:
content = f.read()
matches = re.findall(r'clientcert -- ([0-9a-fA-F]+)', content)
if not matches:
print("ERROR: No clientcert found in sunshine.log")
print("Make sure Moonlight has tried to pair (it should show a PIN screen)")
sys.exit(1)
hex_cert = matches[-1]
pem_cert = bytes.fromhex(hex_cert).decode("utf-8")
print(f"Extracted certificate ({len(pem_cert)} bytes)")
print(f"Preview: {pem_cert[:60]}...")
return pem_cert
def inject_cert(pem_cert, client_name="RE-PC"):
try:
with open(SUNSHINE_STATE, "r") as f:
state = json.load(f)
except (FileNotFoundError, json.JSONDecodeError):
state = {}
if "root" not in state:
state["root"] = {"uniqueid": "0123456789ABCDEF", "named_devices": []}
if "named_devices" not in state["root"]:
state["root"]["named_devices"] = []
# Check if client already exists — update cert
updated = False
for dev in state["root"]["named_devices"]:
if dev.get("name") == client_name:
dev["cert"] = pem_cert
dev["enabled"] = "true"
updated = True
print(f"Updated existing client '{client_name}'")
break
if not updated:
state["root"]["named_devices"].append({
"name": client_name,
"cert": pem_cert,
"uuid": str(uuid.uuid4()).upper(),
"enabled": "true"
})
print(f"Added new client '{client_name}'")
# Ensure origin_pin_allowed = pc for easier future pairing
try:
with open(SUNSHINE_CONF, "r") as f:
conf = f.read()
if "origin_pin_allowed" not in conf:
with open(SUNSHINE_CONF, "a") as f:
f.write("\norigin_pin_allowed = pc\n")
print("Added origin_pin_allowed = pc to sunshine.conf")
except FileNotFoundError:
pass
with open(SUNSHINE_STATE, "w") as f:
json.dump(state, f, indent=4)
print(f"Injected into {SUNSHINE_STATE}")
def restart_sunshine():
print("Restarting Sunshine...")
subprocess.run(["systemctl", "--user", "restart", "sunshine"], check=False)
time.sleep(3)
result = subprocess.run(
["systemctl", "--user", "status", "sunshine", "--no-pager"],
capture_output=True, text=True
)
if "active (running)" in result.stdout:
print("Sunshine is running.")
else:
print("WARNING: Sunshine may not have started. Check: systemctl --user status sunshine")
def main():
restore = "--restart" in sys.argv
cert = extract_latest_cert()
inject_cert(cert, client_name=os.environ.get("MOONLIGHT_CLIENT_NAME", "RE-PC"))
if restore:
restart_sunshine()
else:
print("\nNow restart Sunshine: systemctl --user restart sunshine")
print("\nIMPORTANT: Fully CLOSE Moonlight on the client, then reopen it.")
print("It should connect directly to apps without asking for a PIN.")
if __name__ == "__main__":
main()