WASTE_CONFIG.turnSecret was shipped in plaintext config.js and used to
compute coturn HMAC credentials client-side in browser.ts. Anyone reading
the PWA's JS could read the secret and mint unlimited long-lived TURN
credentials, turning the relay into an open proxy.
The anchor now mints short-lived (1h) credentials server-side via a new
GET /turn-credentials endpoint (-turn-secret flag), mirroring what the
daemon already does. The browser fetches credentials instead of holding
the secret. Daemon mode was unaffected (already server-side).
Docs updated to drop turnSecret from config.js examples, document the
new nginx route, and instruct anyone with an old config.js to rotate
the coturn secret since it was previously exposed.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Five interop issues fixed against PROTOCOL.md:
- Join signature now covers nonce_raw || net_ascii (64-char UTF-8 hex
string) as specified in §5.1, not net_raw_bytes. Both anchor server
and client updated to match.
- Chat wire fields renamed to spec names: text/ts (Unix ms int64)
replacing body/sent_at (ISO timestamp). Flat layout on PeerMessage
matches §8 exactly; store and TUI updated accordingly.
- Direct messages now use the spec "pm" type (flat {type,mid,text,ts})
instead of chat+to. Receiver reconstructs a ChatMessage with
dm:<short-id> room for IPC/storage. §8 compliant.
- File transfer message types changed to spec hyphenated names:
file-offer, file-accept, file-cancel, file-done with spec field
names (name/size not filename/size_bytes). §9 compliant.
- DataChannel open-race (§14 gotcha #3) fixed with sync.Once: doOpen
fires on OnOpen callback or immediately if the channel is already
open when WireDataChannel is called (answerer race).
Also fixes two bugs found during testing:
- mid was missing from outgoing wire messages, causing all received
messages to arrive with mid="" and collide on the UNIQUE DB
constraint. mid is now included on all sent chat/pm messages; a
random mid is generated for any received message that omits it.
- Test scripts hardened: kill -9 + active lsof polling replaces blind
sleep for port cleanup; join_network sent before peer_field queries
(local_peer is now network-scoped and nil until joined).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>