feat(apple): adapt the macOS client to ABI v2 — client identity + SPAKE2 PIN pairing
ci / rust (push) Has been cancelled
ci / rust (push) Has been cancelled
The pairing/renegotiation batch bumped the punktfunk/1 ABI to v2 and the host now hard-rejects v1 Hellos (m3.rs), so streaming from the Mac was dead until the bundled PunktfunkCore.xcframework is rebuilt — it is gitignored, so that is a per-checkout step: bash scripts/build-xcframework.sh. The Swift wrapper itself was already adapted upstream; this lands the app on top of it. - ClientIdentityStore: persistent client identity in the login Keychain, presented on every connect so paired hosts recognize this Mac. Keychain access failure throws instead of regenerating (a fresh identity would silently un-pair this Mac from every --require-pairing host); a lost first-run race resolves toward the stored identity; pairing uses the strict loadForPairing() so a memory-only identity can't strand a ceremony. - PairSheet: the SPAKE2 PIN ceremony, reachable from a host card's context menu and from the trust prompt's "Pair with PIN instead…" (which drops the live session first — the host's accept loop is sequential). Success pins the verified fingerprint and connects; an in-flight ceremony self-discards when the sheet is dismissed, so a late success can't pin + auto-connect behind the user's back. Wrong PIN and Keychain failures get distinct, actionable error text. - Tests: identity unit tests; the full pairing ceremony + --require-pairing gate on loopback (test-loopback.sh arms a second host, parses its PIN from the log, and gives both hosts throwaway config homes — no more writes to the real ~/.config/punktfunk); remote pairing + pinned stream over the LAN (PUNKTFUNK_REMOTE_PIN, _PORT). Validated live against the box: SPAKE2 ceremony with the host's arming PIN → verified fingerprint → pinned + identified 720p60 session (host persisted the client identity); first light 60/60 AUs decoded to pixels; vkcube on glass through the app. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,17 +1,44 @@
|
||||
#!/usr/bin/env bash
|
||||
# Loopback integration: a real punktfunk/1 host (synthetic source — pure protocol, runs fine on
|
||||
# macOS) on 127.0.0.1, then the Swift integration tests against it through the xcframework.
|
||||
# The m3 host serves exactly one session and exits; the trap is just for failure paths.
|
||||
# Loopback integration: real punktfunk/1 hosts (synthetic source — pure protocol, runs fine on
|
||||
# macOS) on 127.0.0.1, then the Swift integration tests against them through the xcframework.
|
||||
# Two hosts: an open one (stream round trip) and one armed with --require-pairing (the PIN
|
||||
# ceremony + pairing gate — its random PIN is parsed out of its log).
|
||||
set -euo pipefail
|
||||
cd "$(dirname "$0")/../.."
|
||||
|
||||
PORT="${PUNKTFUNK_LOOPBACK_PORT:-19778}"
|
||||
PAIR_PORT="${PUNKTFUNK_PAIRING_PORT:-19779}"
|
||||
|
||||
cargo build --release -p punktfunk-host
|
||||
target/release/punktfunk-host m3-host --port "$PORT" --source synthetic --frames 300 &
|
||||
|
||||
# Each host gets a throwaway config home: the pairing host persists a trust store
|
||||
# (punktfunk1-paired.json, resolved from $HOME) and both mint an identity cert on first
|
||||
# run — none of that belongs in the user's real ~/.config/punktfunk, and separate homes
|
||||
# also keep the two first runs from racing on the same cert.pem.
|
||||
CFG="$(mktemp -d "${TMPDIR:-/tmp}/punktfunk-loopback.XXXXXX")"
|
||||
PAIR_LOG="$CFG/pairing-host.log"
|
||||
mkdir -p "$CFG/open" "$CFG/paired"
|
||||
trap 'kill "${HOST_PID:-}" "${PAIR_PID:-}" 2>/dev/null || true' EXIT
|
||||
HOME="$CFG/open" XDG_CONFIG_HOME="$CFG/open/.config" \
|
||||
target/release/punktfunk-host m3-host --port "$PORT" --source synthetic --frames 300 &
|
||||
HOST_PID=$!
|
||||
trap 'kill "$HOST_PID" 2>/dev/null || true' EXIT
|
||||
HOME="$CFG/paired" XDG_CONFIG_HOME="$CFG/paired/.config" \
|
||||
target/release/punktfunk-host m3-host --port "$PAIR_PORT" --source synthetic --frames 300 \
|
||||
--require-pairing >"$PAIR_LOG" 2>&1 &
|
||||
PAIR_PID=$!
|
||||
sleep 1
|
||||
|
||||
PIN=""
|
||||
for _ in $(seq 50); do
|
||||
PIN="$(grep -oE 'pair: [0-9]+' "$PAIR_LOG" | head -1 | cut -d' ' -f2 || true)"
|
||||
[ -n "$PIN" ] && break
|
||||
sleep 0.2
|
||||
done
|
||||
if [ -z "$PIN" ]; then
|
||||
echo "no arming PIN in the pairing host's log ($PAIR_LOG)" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cd clients/apple
|
||||
PUNKTFUNK_LOOPBACK_PORT="$PORT" swift test --filter LoopbackIntegrationTests
|
||||
PUNKTFUNK_LOOPBACK_PORT="$PORT" PUNKTFUNK_PAIRING_PORT="$PAIR_PORT" PUNKTFUNK_PAIRING_PIN="$PIN" \
|
||||
swift test --filter LoopbackIntegrationTests
|
||||
|
||||
Reference in New Issue
Block a user