from __future__ import annotations import base64 import concurrent.futures import datetime import functools import hashlib import importlib.util import json import os import secrets import subprocess import sys import tempfile import time from pathlib import Path REPO_ROOT = Path(__file__).resolve().parents[1] HUB = REPO_ROOT / "hub" sys.path[:0] = [str(HUB), str(HUB / "client")] CLIENT = HUB / "client" / "permission_hook.py" RUNNER = HUB / "client" / "runner.py" APPROVAL = HUB / "client" / "approval.py" SPEC = importlib.util.spec_from_file_location("kvb_hub_server", HUB / "server.py") server = importlib.util.module_from_spec(SPEC) sys.modules[SPEC.name] = server SPEC.loader.exec_module(server) RUNNER_SPEC = importlib.util.spec_from_file_location("kvb_hub_runner", RUNNER) runner = importlib.util.module_from_spec(RUNNER_SPEC) RUNNER_SPEC.loader.exec_module(runner) import hub_api # noqa: F401 import passkey import signing import verifier SCORE = "🎯 95 💥 3" GIT_ENV = { "GIT_AUTHOR_NAME": "t", "GIT_AUTHOR_EMAIL": "t@example.invalid", "GIT_COMMITTER_NAME": "t", "GIT_COMMITTER_EMAIL": "t@example.invalid", "GIT_CONFIG_GLOBAL": os.devnull, "GIT_CONFIG_NOSYSTEM": "1", } TREE = "0123456789abcdef0123456789abcdef01234567" PAGE = "diff" HOST_STATE = Path("/home/op/.local/state/kvb-hub") ASK = {"tool": "Bash", "command": "make deploy", "cwd": "/repo", "session": "s1", "agent": "", "timeout": 60} HOOK = { "session_id": "s1", "transcript_path": "/home/op/.claude/projects/-repo/s1.jsonl", "cwd": "/repo", "permission_mode": "default", "hook_event_name": "PermissionRequest", "tool_name": "Bash", "tool_input": {"command": "rm -rf node_modules", "description": "Remove node_modules"}, "permission_suggestions": [], } OPTIONS = [{"label": "Merge now", "description": "Gate is green"}, {"label": "Wait", "description": ""}] AMBIENCE = HUB / "templates" / "ambience.js" STREAMS = [ {"name": "Morgen", "url": "https://radio.example/morgen", "from": "07:00", "to": "09:00", "days": [0, 1, 2, 3, 4], "on": True}, {"name": "Nacht", "url": "http://10.0.0.5:8000/nacht", "from": "22:00", "to": "02:00", "days": [5], "on": True}, {"name": "Aus", "url": "https://other.example:8443/", "from": "00:00", "to": "24:00", "days": [0, 1, 2, 3, 4, 5, 6], "on": False}, ] VOICE = HUB / "templates" / "voice.js" SPACE = HUB / "templates" / "space.js" class FakeScripts: def __init__(self) -> None: self.calls: list[tuple[str, list[str]]] = [] self.code = 0 def run(self, script: str, args: list[str]) -> dict: self.calls.append((script, args)) return {"command": " ".join([Path(script).name, *args]), "code": self.code, "stdout": "done", "stderr": ""} def iso(ts: float) -> str: return datetime.datetime.fromtimestamp(ts, datetime.UTC).isoformat().replace("+00:00", "Z") KEYS = tempfile.TemporaryDirectory() ORIGIN = "http://localhost:8737" PRESENT = 0x05 REGISTERED = 0x45 ZERO_LED_TRIES = 4096 KEY_SPECS = { -7: ["-algorithm", "EC", "-pkeyopt", "ec_paramgen_curve:P-256"], -8: ["-algorithm", "ED25519"], -257: ["-algorithm", "RSA", "-pkeyopt", "rsa_keygen_bits:2048"], } def b64(data: bytes) -> str: return base64.urlsafe_b64encode(data).rstrip(b"=").decode("ascii") def openssl(argv: list[str], data: bytes) -> bytes: return subprocess.run(["openssl", *argv], input=data, capture_output=True, timeout=60, check=True).stdout def cbor_encode(value: object) -> bytes: def head(major: int, size: int) -> bytes: if size < 24: return bytes([major << 5 | size]) width = next(width for width in (1, 2, 4, 8) if size < 1 << (8 * width)) return bytes([major << 5 | {1: 24, 2: 25, 4: 26, 8: 27}[width]]) + size.to_bytes(width, "big") if isinstance(value, bool) or value is None: return bytes([0xE0 | {False: 20, True: 21, None: 22}[value]]) if isinstance(value, int): return head(0, value) if value >= 0 else head(1, -1 - value) if isinstance(value, bytes): return head(2, len(value)) + value if isinstance(value, str): return head(3, len(value.encode())) + value.encode() if isinstance(value, list): return head(4, len(value)) + b"".join(cbor_encode(entry) for entry in value) return head(5, len(value)) + b"".join(cbor_encode(name) + cbor_encode(entry) for name, entry in value.items()) class Key: def __init__(self, alg: int, name: str) -> None: self.alg = alg self.pem = Path(KEYS.name) / f"{name}{alg}.pem" openssl(["genpkey", *KEY_SPECS[alg], "-out", str(self.pem)], b"") self.spki = openssl(["pkey", "-in", str(self.pem), "-pubout", "-outform", "DER"], b"") self.raw_id = os.urandom(16) self.id = b64(self.raw_id) def cose(self) -> dict: if self.alg == -7: return {1: 2, 3: -7, -1: 1, -2: self.spki[-64:-32], -3: self.spki[-32:]} if self.alg == -8: return {1: 1, 3: -8, -1: 6, -2: self.spki[-32:]} modulus = openssl(["rsa", "-pubin", "-inform", "DER", "-modulus", "-noout"], self.spki).decode("ascii").strip().split("=", 1)[1] return {1: 3, 3: -257, -1: bytes.fromhex(modulus), -2: (65537).to_bytes(3, "big")} def sign(self, data: bytes) -> bytes: message = Path(KEYS.name) / f"message-{secrets.token_hex(8)}" message.write_bytes(data) if self.alg == -8: return openssl(["pkeyutl", "-sign", "-inkey", str(self.pem), "-rawin", "-in", str(message)], b"") return openssl(["dgst", "-sha256", "-sign", str(self.pem), str(message)], b"") def credential(self, origin: str, rp: str, flags: int) -> dict: return self.registration(self.cose(), origin, rp, flags) def registration(self, cose: dict, origin: str, rp: str, flags: int) -> dict: data = hashlib.sha256(rp.encode()).digest() + bytes([flags]) + bytes(4) + bytes(16) + len(self.raw_id).to_bytes(2, "big") + self.raw_id + cbor_encode(cose) client = json.dumps({"type": "webauthn.create", "challenge": b64(os.urandom(32)), "origin": origin}).encode() return {"id": self.id, "attestationObject": b64(cbor_encode({"fmt": "none", "attStmt": {}, "authData": data})), "clientDataJSON": b64(client)} def blob(self, origin: str) -> str: return b64(json.dumps(self.credential(origin, "localhost", REGISTERED)).encode()) def assertion(self, payload: dict, origin: str, rp: str, flags: int, count: int) -> dict: client = json.dumps({"type": "webauthn.get", "challenge": signing.challenge(payload), "origin": origin, "crossOrigin": False}).encode() data = hashlib.sha256(rp.encode()).digest() + bytes([flags]) + count.to_bytes(4, "big") signature = self.sign(data + hashlib.sha256(client).digest()) return {"id": self.id, "clientDataJSON": b64(client), "authenticatorData": b64(data), "signature": b64(signature), "userHandle": None} def proof(self, payload: dict, origin: str) -> dict: return {"payload": payload, "assertion": self.assertion(payload, origin, "localhost", PRESENT, 0)} def pin(self, path: Path, origin: str) -> None: verifier.pin(path, passkey.attested(self.credential(origin, "localhost", REGISTERED), origin), time.time()) @functools.cache def key(alg: int, name: str) -> Key: return Key(alg, name) @functools.cache def zero_led(label: int) -> Key: """Args: label: the COSE label of the coordinate, -2 for x or -3 for y. Returns: A fresh P-256 key whose coordinate starts with a zero byte, as about one key in 256 does. """ with concurrent.futures.ThreadPoolExecutor() as pool: for start in range(0, ZERO_LED_TRIES, 64): for signer in pool.map(lambda attempt: Key(-7, f"zero{label}-{attempt}"), range(start, start + 64)): if signer.cose()[label][0] == 0: return signer raise AssertionError(f"no P-256 key with a zero-led coordinate {label} in {ZERO_LED_TRIES} tries")