wzp-web connects to relay via QUIC and does crypto handshake directly,
but relay with --auth-url expects AuthToken first → handshake fails.
Auth at relay level will be re-added when wzp-web learns to forward tokens.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The 'full' variant sends a key exchange as first WS message, not auth.
The 'pure' variant sends raw PCM immediately, no auth.
Only ws/ws-fec/ws-full variants send auth JSON.
With auth removed, wzp-web accepts all WS connections. Auth is
still enforced on the relay (--auth-url) for direct connections.
Caddy provides access control at the TLS layer.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
startAudio() now dynamically loads the selected WZP client variant:
- /audio-variant [pure|hybrid|full|ws|ws-fec|ws-full]
- Loads variant JS from wzp-web's /audio/js/ path via Caddy
- Falls back to inline pure implementation if variant fails to load
- Variant persisted in localStorage across sessions
- Call bar shows active variant: "In call [ws-fec] with 0x..."
Variants:
pure — raw PCM over WS (bridge needed, no WASM)
hybrid — raw PCM + WASM FEC over WS (bridge needed)
full — WebTransport + FEC + crypto (no bridge, future)
ws — WZP protocol over WS (relay direct)
ws-fec — WZP + WASM FEC over WS (relay direct)
ws-full — WZP + FEC + E2E crypto over WS (relay direct)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- v1-v6.voip.manko.yoga → each maps to a WZP client variant
- Caddyfile.test: wildcard *.voip.manko.yoga with CF DNS cert
- scripts/test-variants.sh: --setup creates DNS + swaps Caddyfile
- --teardown cleans up DNS + restores original
- --check verifies all 6 respond HTTP 200
- All variants join same room for cross-variant audio testing
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- wzp-web runs plain HTTP behind Caddy (no --tls)
- deploy-chat.sh clones feature/wzp-web-variants for warzone-phone
- Three audio variants: ?variant=pure|hybrid|full
- Auth kept on both wzp-relay and wzp-web
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Removed dns-updater Docker sidecar (curl not available in alpine)
- scripts/start-voip.sh: updates DNS then docker compose up
- update-dns.sh: supports --once flag, runs locally with curl
- All CF API calls forced to IPv4 (-4 flag)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- update-dns.sh: detects public IPv4/IPv6, upserts CF records
- Runs on container start + every 5 minutes
- Only updates if IP actually changed (skips if unchanged)
- python:3-alpine container with curl
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Caddy now uses network_mode: host (sees real IPv4/IPv6)
- All backend services on fixed IPs (172.28.0.10/20/30)
- Caddyfile uses IPs instead of Docker DNS names
- /myip now returns actual client IP, not Docker gateway
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
wzp-web --relay only accepts IP:port, not Docker hostnames.
Fixed IP 172.28.0.10 on backend network with explicit subnet.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
WASM fix (critical):
- encrypt_key_exchange_with_id was calling x3dh::initiate a second time,
generating a new ephemeral key that didn't match the ratchet — receiver
always failed to decrypt. Now stores X3DH result from initiate() and
reuses it. Added 2 protocol tests confirming the fix + the bug.
- Bumped service worker cache to wz-v2 to force browsers to re-fetch.
- Disabled wasm-opt for Hetzner builds (libc compat issue).
Federation — alias support:
- resolve_alias falls back to federation peer if not found locally
- register_alias checks peer server before allowing — globally unique aliases
- Added resolve_remote_alias() and is_alias_taken_remote() to FederationHandle
Federation — key proxy fix:
- Remote bundles no longer cached locally (stale cache caused decrypt failures)
- Local vs remote determined by device: prefix in keys DB
Client fixes:
- Self-messaging blocked ("Cannot send messages to yourself")
- /peer <self> blocked
- last_dm_peer never set to self
- /r <message> sends reply inline (switches peer + sends in one command)
Deploy tooling:
- scripts/build-linux.sh with --ship (build + deploy + destroy)
- --update-all, --status, --logs commands
- WASM rebuilt on Hetzner VM before server binary
- deploy/ directory: systemd service, federation configs, setup script
- Journald log cap (50MB, 7-day retention)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>