130 lines
4.1 KiB
Markdown
130 lines
4.1 KiB
Markdown
|
|
# waste-go
|
||
|
|
|
||
|
|
A modern reimagining of [WASTE](https://en.wikipedia.org/wiki/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
|
||
|
|
│ └── relay/ Bootstrap/relay server — run this on your Hetzner VPS
|
||
|
|
└── internal/
|
||
|
|
├── proto/ All wire types (shared by daemon and relay)
|
||
|
|
├── crypto/ Ed25519 identity, X25519 ECDH, ChaCha20-Poly1305
|
||
|
|
├── mesh/ Connected peer state + per-connection handler
|
||
|
|
├── ipc/ Local JSON API (UI talks to daemon here, port 17337)
|
||
|
|
└── nat/ Relay client (hole-punching lives here later)
|
||
|
|
```
|
||
|
|
|
||
|
|
## Prerequisites
|
||
|
|
|
||
|
|
- Go 1.22+ → https://go.dev/dl/
|
||
|
|
- VS Code with the Go extension (`golang.go`)
|
||
|
|
|
||
|
|
On first open VS Code will prompt you to install `gopls`, `dlv`, and `goimports` — accept all of them.
|
||
|
|
|
||
|
|
## Getting started
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Fetch dependencies
|
||
|
|
go mod tidy
|
||
|
|
|
||
|
|
# Build everything (confirms it compiles)
|
||
|
|
go build ./...
|
||
|
|
|
||
|
|
# Terminal 1 — relay (optional for LAN testing, required across internet)
|
||
|
|
go run ./cmd/relay -bind 127.0.0.1:17339
|
||
|
|
|
||
|
|
# Terminal 2 — peer A
|
||
|
|
go run ./cmd/daemon -alias alice -data-dir /tmp/waste-alice -peer-port 17338 -ipc-port 17337
|
||
|
|
|
||
|
|
# Terminal 3 — peer B
|
||
|
|
go run ./cmd/daemon -alias bob -data-dir /tmp/waste-bob -peer-port 17340 -ipc-port 17341
|
||
|
|
```
|
||
|
|
|
||
|
|
Then connect B → A and send a message (netcat works fine as a quick test):
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Tell peer B to connect to peer A
|
||
|
|
echo '{"type":"connect","addr":"127.0.0.1:17338"}' | nc 127.0.0.1 17341
|
||
|
|
|
||
|
|
# In another terminal — subscribe to peer A's events, then send a message from B
|
||
|
|
nc 127.0.0.1 17337 &
|
||
|
|
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`:
|
||
|
|
|
||
|
|
```powershell
|
||
|
|
# Open a connection to peer B's IPC port and keep it open
|
||
|
|
$c = [System.Net.Sockets.TcpClient]::new('127.0.0.1', 17341)
|
||
|
|
$w = [System.IO.StreamWriter]::new($c.GetStream()); $w.AutoFlush = $true
|
||
|
|
|
||
|
|
# Tell peer B to connect to peer A
|
||
|
|
$w.WriteLine('{"type":"connect","addr":"127.0.0.1:17338"}')
|
||
|
|
|
||
|
|
# Send a chat message from B
|
||
|
|
$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() }
|
||
|
|
```
|
||
|
|
|
||
|
|
Keep `$c` / `$w` in scope for the session; closing them disconnects the peer.
|
||
|
|
|
||
|
|
## Deploying the relay on your Hetzner VPS
|
||
|
|
|
||
|
|
```bash
|
||
|
|
GOOS=linux GOARCH=amd64 go build -o bin/waste-relay ./cmd/relay
|
||
|
|
scp bin/waste-relay user@your-vps:~/
|
||
|
|
|
||
|
|
# On the VPS
|
||
|
|
./waste-relay -bind 0.0.0.0:17339
|
||
|
|
```
|
||
|
|
|
||
|
|
Then start daemons with `-relay your-vps-ip:17339` and they'll register and
|
||
|
|
be able to find each other across NAT.
|
||
|
|
|
||
|
|
## IPC protocol (plain JSON over TCP)
|
||
|
|
|
||
|
|
Everything is newline-delimited JSON. You can test with `nc 127.0.0.1 17337`.
|
||
|
|
|
||
|
|
**Commands you send:**
|
||
|
|
```jsonc
|
||
|
|
{"type":"connect","addr":"1.2.3.4:17338"}
|
||
|
|
{"type":"send_message","room":"general","body":"hi"}
|
||
|
|
{"type":"get_state"}
|
||
|
|
```
|
||
|
|
|
||
|
|
**Events the daemon pushes:**
|
||
|
|
```jsonc
|
||
|
|
{"type":"state_snapshot","local_peer":{...},"connected_peers":[...]}
|
||
|
|
{"type":"peer_connected","peer":{...}}
|
||
|
|
{"type":"message_received","message":{"from":"...","body":"hi","room":"general"}}
|
||
|
|
{"type":"peer_disconnected","peer_id":"..."}
|
||
|
|
```
|
||
|
|
|
||
|
|
## Crypto choices
|
||
|
|
|
||
|
|
| Purpose | Algorithm | Notes |
|
||
|
|
|---|---|---|
|
||
|
|
| Identity | Ed25519 | Fast, small keys, standard |
|
||
|
|
| Key exchange | X25519 ECDH | Per-session ephemeral keys |
|
||
|
|
| Symmetric | ChaCha20-Poly1305 | No AES-NI needed, authenticated |
|
||
|
|
| Hashing | SHA-256 | File integrity |
|
||
|
|
|
||
|
|
Replaces WASTE's original Blowfish/PCBC (broken cipher mode) + RSA.
|
||
|
|
|
||
|
|
## Roadmap
|
||
|
|
|
||
|
|
- [ ] UDP hole-punching (STUN) in `internal/nat`
|
||
|
|
- [ ] Invite file format (`.waste-invite`) — share a keypair + address hint
|
||
|
|
- [ ] Peer gossip → auto-connect to friends-of-friends
|
||
|
|
- [ ] File transfer
|
||
|
|
- [ ] Message persistence (SQLite via `modernc.org/sqlite`)
|
||
|
|
- [ ] Tauri or simple web UI consuming the IPC port
|