Fredrik Johansson 5a05e6e1ef Add DM support to test script; fix DM routing and JSON encoding
ipc: CmdSendMessage now routes to the named recipient only (m.SendTo) when
the "to" field is set, rather than broadcasting to all peers. Group messages
continue to use Broadcast. This is the correct privacy behaviour for DMs.

test-network.sh:
- Resolve each peer's hex id from get_state before joining the network,
  using a retry loop with timeout to handle slow daemon startup.
- Added a DM section: alice→bob, bob→alice, charlie→alice, alice→charlie.
  DMs use the "to" + "room":"dm:<peer_id>" convention.
- Fixed jq -cn (compact) instead of jq -n (pretty) so the IPC newline-
  delimited protocol receives a single JSON line per command.
- pretty() now renders DMs as 📨 DM <from→to> rather than 💬 #room.
- Persistence check now breaks down totals by group vs DM message count.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-21 18:13:27 +02:00
2026-06-21 16:14:07 +02:00

waste-go

A modern reimagining of WASTE — decentralized, friend-to-friend encrypted mesh networking with chat and file sharing. Written in Go.

Project layout

waste-go/
├── cmd/
│   ├── daemon/      The peer process — run one on each friend's machine
│   └── anchor/      WebSocket signaling server — run this on your Hetzner VPS
└── internal/
    ├── proto/       All wire types (shared by daemon and anchor)
    ├── crypto/      Ed25519 identity, nacl/box signaling, ChaCha20-Poly1305
    <20><><EFBFBD>── mesh/        Connected peer state + DataChannel helpers
    ├── anchor/      Anchor client — WebRTC signaling via the anchor server
    └── ipc/         Local JSON API (UI talks to daemon here, port 17337)

Prerequisites

On first open VS Code will prompt you to install gopls, dlv, and goimports — accept all of them.

Getting started

# Fetch dependencies
go mod tidy

# Build everything (confirms it compiles)
go build ./...

# Terminal 1 — anchor (required for peers to find each other)
go run ./cmd/anchor -bind 127.0.0.1:17339

# Terminal 2 — peer A
go run ./cmd/daemon -alias alice -data-dir /tmp/waste-alice -ipc-port 17337 -anchor ws://127.0.0.1:17339/ws

# Terminal 3 — peer B
go run ./cmd/daemon -alias bob -data-dir /tmp/waste-bob -ipc-port 17341 -anchor ws://127.0.0.1:17339/ws

Both peers join the same named network via IPC:

# Join peer A to a network called "friends"
echo '{"type":"join_network","network_name":"friends"}' | nc 127.0.0.1 17337

# Join peer B to the same network
echo '{"type":"join_network","network_name":"friends"}' | nc 127.0.0.1 17341

# Subscribe to peer A's events (in a separate terminal)
nc 127.0.0.1 17337 &

# Send a message from B
echo '{"type":"send_message","room":"general","body":"hello from bob"}' | nc 127.0.0.1 17341

On Windows — use PowerShell's built-in TCP client instead of nc:

$c = [System.Net.Sockets.TcpClient]::new('127.0.0.1', 17341)
$w = [System.IO.StreamWriter]::new($c.GetStream()); $w.AutoFlush = $true

$w.WriteLine('{"type":"join_network","network_name":"friends"}')
$w.WriteLine('{"type":"send_message","room":"general","body":"hello from bob"}')

# In a separate terminal — subscribe to peer A's events
$r = [System.Net.Sockets.TcpClient]::new('127.0.0.1', 17337)
$reader = [System.IO.StreamReader]::new($r.GetStream())
while ($true) { $reader.ReadLine() }

Deploying the anchor on your Hetzner VPS

GOOS=linux GOARCH=amd64 go build -o bin/waste-anchor ./cmd/anchor
scp bin/waste-anchor user@your-vps:~/

# On the VPS (also run coturn in STUN-only mode on port 3478)
./waste-anchor -bind 0.0.0.0:17339

Then start daemons with -anchor ws://your-vps-ip:17339/ws and they'll connect via WebRTC with ICE (STUN-assisted hole punching) through the anchor for signaling.

IPC protocol (plain JSON over TCP)

Everything is newline-delimited JSON. You can test with nc 127.0.0.1 17337.

Commands you send:

{"type":"join_network","network_name":"friends"}
{"type":"leave_network"}
{"type":"send_message","room":"general","body":"hi"}
{"type":"get_state"}

Events the daemon pushes:

{"type":"state_snapshot","local_peer":{...},"connected_peers":[...]}
{"type":"peer_connected","peer":{...}}
{"type":"session_ready","peer_id":"<hex>","nick":"alice"}
{"type":"message_received","message":{"from":"<hex>","body":"hi","room":"general"}}
{"type":"peer_disconnected","peer_id":"<hex>"}

Crypto choices

Purpose Algorithm Notes
Identity Ed25519 Fast, small keys, standard
Peer ID Hex-encoded Ed25519 pubkey 64 lowercase hex chars (YAW/2 §2)
Signaling encryption XSalsa20-Poly1305 (nacl/box) X25519 keys derived from Ed25519 identity (YAW/2 §3)
Transport WebRTC DataChannels (DTLS+SCTP) pion/webrtc — ICE, hole punching included
Hashing SHA-256 File integrity, network name hashing

Replaces WASTE's original Blowfish/PCBC (broken cipher mode) + RSA.

Peer IDs are 64-char lowercase hex (Ed25519 public key). Existing identity.json files on disk are unaffected — only the over-the-wire representation changed from base64url.

Roadmap

  • Crypto layer — hex peer IDs, nacl/box signaling, Ed25519→X25519 key derivation
  • Proto additionsmid field, signaling types, anchor wire types, hello message, FileDone
  • Anchor server (cmd/anchor) — WebSocket signaling server (replaces TCP relay)
  • WebRTC peer connections — pion/webrtc DataChannels replace raw TCP in internal/mesh
  • Anchor client (internal/anchor) — ICE offer/answer/candidate lifecycle, nacl/box sealing
  • IPC updatesjoin_network/leave_network replace connect; session_ready event added
  • File transfer — chunked binary DataChannel (f:<xid>)
  • Message persistence — SQLite via modernc.org/sqlite
  • TUI — Bubble Tea client consuming the IPC port
  • Native UI — web frontend with native packaging (Tauri-style)
Description
No description provided
Readme 1.8 MiB
v0.1.6 Latest
2026-07-02 18:35:57 +02:00
Languages
Go 52.1%
TypeScript 30.2%
Shell 12%
CSS 5.2%
HTML 0.3%
Other 0.2%