- Signed invites: waste: URI gains inviter+sig fields (Ed25519); hello carries the invite so receiving peers can verify against known keys - RequireInvite per-network flag: rejects peers without valid signed invite - Hash-based hang links: #waste:base64 fragment pre-fills join form without server-side leakage of network name - Multi-share: shares.json (daemon) + waste_shares localStorage (browser); IPC add_share/remove_share/list_shares commands - EXTENSIONS.md: addendum documenting all waste-go protocol deviations from YAW/2; all extensions are additive and backward compatible Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
8.4 KiB
Future Vision
WASTE's design philosophy is still sound: small trusted groups, no central server, encrypted everything, equal nodes. That's essentially what Signal's sealed sender and private groups do today, just without a self-hosted option. This gap is worth filling.
Architecture
Two clean layers, connected by the IPC port.
Daemon
The real application. A long-running background process that handles everything:
- Peer mesh and connection management (WebRTC DataChannels, DTLS, ICE)
- Cryptography and handshake (Ed25519 identity, nacl/box signaling, YAW/2.1 FS)
- NAT traversal (ICE/STUN via pion/webrtc — no custom relay needed)
- File transfer (dedicated binary DataChannels per transfer)
Exposes a local JSON API over TCP (127.0.0.1:17337). Can run headlessly — SSH into a box and the mesh stays alive even with no UI attached.
UI Layer
Talks to the daemon over the IPC port. The separation means the UI is replaceable without touching the core.
Target: a web frontend (React or similar) wrapped in a native binary using a Tauri-style approach — native packaging, OS webview, no Electron weight. Avoids the wxWidgets ugliness of the old wxWASTE fork and the Qt licensing headaches of the VIA fork.
TUI ✅ (shipped)
A terminal UI (cmd/tui) using Bubble Tea. Three-pane layout: rooms, messages, peers. Supports group chat, DMs, room switching, invite generation. Works over SSH.
Web UI ✅ (shipped)
React + Vite frontend. Two modes:
- Browser mode — runs entirely in-browser, connects directly to the anchor via WebSocket. No daemon required. Identity persists in
localStorage. File sharing, file push, per-peer ICE/NAT status. - Daemon mode — web UI connects to a local daemon over WebSocket IPC. Same UI, different adapter.
Protocol
NAT Traversal ✅ (WebRTC ICE/STUN)
Solved by using WebRTC DataChannels via pion. ICE gathers host + server-reflexive (STUN) candidates and performs UDP hole punching automatically. The anchor (cmd/anchor) doubles as a STUN server on UDP/3478.
TURN relay ✅ (shipped, browser mode)
Browser mode now supports TURN relay. iceServers() in browser.ts reads WASTE_CONFIG.turnURL and WASTE_CONFIG.turnSecret, generates time-limited HMAC-SHA1 credentials (compatible with coturn use-auth-secret), and adds the TURN server to the ICE candidate list. Mobile/CGNAT peers that fail STUN hole-punching automatically fall back to TURN relay.
The peer dot in the sidebar turns yellow for relayed connections (candidate_type: relay).
Daemon mode: not yet wired. Add -turn-url / -turn-secret flags to cmd/daemon/main.go and pass them into the ICEServers slice in internal/anchor/client.go.
Signaling ✅ YAW/2.1 (shipped)
Forward-secret signaling via per-session ephemeral X25519 keys. Falls back transparently to 2.0 static-key sealing for peers that don't speak 2.1.
Multi-Network Support ✅ (shipped)
One daemon, multiple simultaneously-joined networks. Per-network HKDF-derived identities prevent cross-network correlation. Network-scoped SQLite stores.
Invite System ✅ (shipped)
waste:<base64> URIs encoding anchor URL + network name. --join flag on daemon and TUI. Ctrl+I in TUI or generate_invite via IPC.
File Transfer ✅ (shipped)
Dedicated binary DataChannel per transfer (f:<xid>). SHA-256 integrity verification. 64 KiB chunks with backpressure. Auto-accept. In browser mode: both pull (browse peer's shared folder) and push (📎 send directly to a peer).
Peer Gossip ✅ (shipped)
When a new peer connects, the mesh immediately gossips the full peer list to them (peer_gossip wire message). New arrivals discover existing peers without needing the anchor to re-introduce them. The anchor becomes optional once the first handshake has happened — the mesh self-heals around anchor downtime.
Remaining Work
Session Persistence ✅ (shipped)
Browser mode now auto-rejoins on reload. The last-used network name, alias, and anchor URL are saved to localStorage on join and restored on load. A ⏻ logout button in the sidebar clears session state (optionally including the identity keypair) and reloads the page.
Per-Network Share Directories ✅ (shipped)
Share state is tracked per network_id in the store (sharedFilesByNetwork). Switching networks switches the active share.
Persistent Multi-Share Configuration ✅ (shipped)
Multiple share roots per network, with global (all networks) or scoped visibility.
- Daemon:
shares.jsonnext toidentity.jsonin the data dir.add_share/remove_share/list_sharesIPC commands. File listing recursively walks all share roots, returning relative paths. Backward compatible with the existingset_share_dirsingle-dir mechanism. - Browser:
waste_sharesinlocalStoragestores named share records (folder name, global flag). TheShareManagersidebar component shows the list with re-pick (↺) and remove (✕) buttons. ActualFileobjects live in memory — the record persists across reloads so the user can restore with one click.
Additional Channels / Rooms ✅ (shipped, web UI)
The + button in the Rooms sidebar section creates custom rooms, stored in customRooms keyed by network_id. Room names are slugified strings — any peer that sends to a room name causes it to appear on the recipient automatically. DM rooms (dm:<peerId>) appear automatically when messages arrive.
Not yet done: TUI room creation, daemon-side SQLite persistence of room lists across restarts.
File Transfer UX ✅ (shipped)
- Manual accept/reject via the Transfers panel in the sidebar
- Transfer cancellation (
file-cancelmessage, closes DataChannel) - Live progress bar per active transfer
- Push (📎) sends directly to a peer without them needing to share a folder
Not yet done: resume after disconnection, daemon-side download directory.
TURN Relay for Daemon Mode
The daemon doesn't yet support TURN. Add -turn-url and -turn-secret flags to cmd/daemon/main.go and wire them into the ICE server list in internal/anchor/client.go. The credential generation is the same HMAC-SHA1 scheme already implemented in browser mode.
Native UI
Web frontend (React, already built) + Tauri shell for native packaging. The IPC protocol is the full boundary — the UI is already a pure consumer. Main work: Tauri setup, system tray, OS notifications.
Roadmap
| Status | Item |
|---|---|
| ✅ shipped | Daemon + anchor server |
| ✅ shipped | WebRTC DataChannels (ICE/STUN hole punching) |
| ✅ shipped | Ed25519 identity, nacl/box signaling (YAW/2.0 + 2.1) |
| ✅ shipped | IPC protocol — join/leave/chat/DM/state |
| ✅ shipped | Message persistence (SQLite, per-network) |
| ✅ shipped | TUI (cmd/tui, Bubble Tea) |
| ✅ shipped | Invite system (waste: URI, --join flag) |
| ✅ shipped | Multi-network support (HKDF derived identities) |
| ✅ shipped | File transfer (binary DataChannels, pull + push) |
| ✅ shipped | Forward-secret signaling (YAW/2.1 ephemeral X25519) |
| ✅ shipped | Peer gossip (anchor-free mesh reconnection) |
| ✅ shipped | Web UI — browser mode + daemon mode |
| ✅ shipped | Per-peer NAT/ICE status, identity backup/restore |
| ✅ shipped | Per-network share directories |
| ✅ shipped | Additional channels/rooms per network |
| ✅ shipped | TURN relay (browser mode, coturn use-auth-secret) |
| ✅ shipped | File transfer UX (progress, cancel, manual accept) |
| ✅ shipped | Session persistence + logout (browser mode) |
| ✅ shipped | Persistent multi-share config (shares.json + localStorage) |
| ✅ shipped | Subfolder support + directory browser UI in file browser |
| ✅ shipped | Signed invites + invite-only networks (RequireInvite) |
| ✅ shipped | Hash-based "come hang" links (#waste:...) |
| ✅ shipped | Protocol extensions documented in EXTENSIONS.md |
| next | TURN relay for daemon mode |
| next | TUI room creation + daemon-side room persistence |
| next | File transfer resume after disconnection |
| future | Native UI (React + Tauri) |
What to Keep from WASTE
- Small group — not a public network, not federated, not discoverable
- No registration — no phone number, no email, no central service
- Encrypted everything — at rest and in transit, end to end
- Equal nodes — no peer is "the server"; the anchor is dumb infrastructure
- The soul — a private overlay for people you actually trust