Files
featherChat/warzone/docs/SERVER.md
Siavash Sameni 60a7006ed9 Add documentation: protocol spec, server admin, client guide
docs/PROTOCOL.md (520 lines):
- Identity model (seed → Ed25519 + X25519 via HKDF)
- X3DH key exchange (4 DH operations, ASCII flow diagram)
- Double Ratchet (chain/DH ratchet, skipped keys, state machine)
- KDF chains with domain separation strings
- AEAD (ChaCha20-Poly1305)
- Wire format (WireMessage enum, bincode serialization)
- Pre-key bundle format and lifecycle

docs/SERVER.md (429 lines):
- Build and run instructions
- Full API reference with request/response examples
- Database structure (sled trees)
- Deployment (nginx reverse proxy, systemd unit)
- Security considerations
- Backup and recovery

docs/CLIENT.md (507 lines):
- Quick start guide
- All CLI commands with examples
- Identity management and mnemonic backup
- Web client usage and limitations
- Session and pre-key management
- Threat model table
- Troubleshooting guide

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 21:59:19 +04:00

430 lines
10 KiB
Markdown

# Warzone Server -- Operation & Administration
---
## 1. Building
The server is part of the Cargo workspace. From the workspace root:
```bash
# Debug build
cargo build -p warzone-server
# Release build (recommended for deployment)
cargo build -p warzone-server --release
```
The resulting binary is at `target/release/warzone-server` (or
`target/debug/warzone-server`). It is a single statically-linked binary with
no runtime dependencies beyond libc.
### Minimum Rust Version
Rust 1.75 or later (set via `rust-version = "1.75"` in `Cargo.toml`).
---
## 2. Running
```bash
# Default: bind 0.0.0.0:7700, data in ./warzone-data
./warzone-server
# Custom bind address and data directory
./warzone-server --bind 127.0.0.1:8080 --data-dir /var/lib/warzone
```
### CLI Flags
| Flag | Short | Default | Description |
|------|-------|---------|-------------|
| `--bind` | `-b` | `0.0.0.0:7700` | Address and port to listen on |
| `--data-dir` | `-d` | `./warzone-data` | Directory for sled database files |
### Logging
The server uses `tracing-subscriber`. Control log level with the `RUST_LOG`
environment variable:
```bash
RUST_LOG=info ./warzone-server
RUST_LOG=warzone_server=debug ./warzone-server
RUST_LOG=trace ./warzone-server # very verbose
```
---
## 3. API Reference
All API endpoints are under the `/v1` prefix. The web UI is served at `/`.
### Health Check
```
GET /v1/health
```
**Response:**
```json
{
"status": "ok",
"version": "0.1.0"
}
```
Use this for monitoring, load balancer health probes, and uptime checks.
---
### Register Key Bundle
```
POST /v1/keys/register
Content-Type: application/json
```
**Request body:**
```json
{
"fingerprint": "a3f8:c912:44be:7d01",
"bundle": [/* bincode-serialized PreKeyBundle as byte array */]
}
```
The `bundle` field is a JSON array of unsigned bytes (the raw bincode
serialization of a `PreKeyBundle`).
**Response:**
```json
{
"ok": true
}
```
**Behavior:** stores the bundle in the `keys` sled tree, keyed by the
fingerprint string. Overwrites any existing bundle for the same fingerprint.
---
### Fetch Key Bundle
```
GET /v1/keys/{fingerprint}
```
**Path parameter:** the fingerprint string, e.g. `a3f8:c912:44be:7d01`.
**Response (200):**
```json
{
"fingerprint": "a3f8:c912:44be:7d01",
"bundle": "base64-encoded-bincode-bytes..."
}
```
The `bundle` value is standard base64-encoded bincode. The client decodes
base64, then deserializes with bincode to recover the `PreKeyBundle`.
**Response (404):** returned if no bundle is registered for the fingerprint.
---
### Send Message
```
POST /v1/messages/send
Content-Type: application/json
```
**Request body:**
```json
{
"to": "b7d1:e845:0022:9f3a",
"message": [/* bincode-serialized WireMessage as byte array */]
}
```
**Response:**
```json
{
"ok": true
}
```
**Behavior:** the message bytes are stored in the `messages` sled tree under
the key `queue:{recipient_fingerprint}:{uuid}`. The UUID is generated
server-side to ensure unique keys.
The server does NOT parse, validate, or inspect the message contents. It is an
opaque blob.
---
### Poll Messages
```
GET /v1/messages/poll/{fingerprint}
```
**Response (200):**
```json
[
"base64-encoded-message-1",
"base64-encoded-message-2"
]
```
Returns a JSON array of base64-encoded message blobs. Each blob is a
bincode-serialized `WireMessage`. An empty array means no messages.
**Behavior:** scans the `messages` sled tree for all keys prefixed with
`queue:{fingerprint}`. Messages are NOT deleted by polling; they remain until
explicitly acknowledged.
---
### Acknowledge Message
```
DELETE /v1/messages/{id}/ack
```
**Path parameter:** the message storage key (currently the full sled key
including the `queue:` prefix and UUID).
**Response:**
```json
{
"ok": true
}
```
**Behavior:** removes the message from the `messages` tree.
**Note:** the current implementation requires knowing the exact sled key to
acknowledge. A proper message-ID-based index is planned for Phase 2.
---
## 4. Web UI
The server serves a single-page web client at the root path `/`.
```
GET /
```
Returns an HTML page with embedded CSS and JavaScript. The web client provides:
- **Identity generation:** generates a random 32-byte seed in the browser
using `crypto.getRandomValues()`.
- **Identity recovery:** paste a hex-encoded seed to recover.
- **Fingerprint display:** shows the user's fingerprint in the header.
- **Key registration:** automatically registers a public key with the server
on entry.
- **Message polling:** polls `/v1/messages/poll/{fingerprint}` every 5 seconds.
- **Slash commands:** `/help`, `/info`, `/seed`.
### Web Client Limitations
- Uses ECDH P-256 (Web Crypto API) instead of X25519. Cross-client
compatibility with the CLI is not yet implemented. (Phase 2)
- Does not use BIP39 mnemonics; seed is displayed as hex.
- Message decryption is not yet wired (Double Ratchet in JS is TODO).
- The seed is stored in `localStorage` (unencrypted).
---
## 5. Database
The server uses **sled** (embedded key-value store). All data lives under the
directory specified by `--data-dir`.
### Trees (Tables)
| Tree | Key format | Value | Purpose |
|------|-----------|-------|---------|
| `keys` | fingerprint string (UTF-8 bytes) | bincode `PreKeyBundle` | Pre-key bundle storage |
| `messages` | `queue:{fingerprint}:{uuid}` (UTF-8 bytes) | bincode `WireMessage` | Message queue |
| `otpks` | (reserved) | (reserved) | One-time pre-key tracking (not yet used server-side) |
### Data Directory Structure
```
warzone-data/
db # sled database file
conf # sled config
blobs/ # sled blob storage (if any)
snap.*/ # sled snapshots
```
The exact file layout is managed by sled internally. The entire directory
should be treated as a unit for backup.
### What the Server Stores
- **Pre-key bundles:** public keys only. The server never holds private keys.
- **Encrypted message blobs:** opaque binary data. The server cannot read
message contents.
- **Metadata visible to server:** sender fingerprint, recipient fingerprint,
message size, timestamps (implicit from storage order).
---
## 6. Deployment
### Single Binary
The recommended deployment is a single `warzone-server` binary behind a
reverse proxy for TLS termination.
### Reverse Proxy (nginx)
```nginx
server {
listen 443 ssl http2;
server_name wz.example.com;
ssl_certificate /etc/letsencrypt/live/wz.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/wz.example.com/privkey.pem;
location / {
proxy_pass http://127.0.0.1:7700;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# WebSocket support (for future real-time push)
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
```
When using a reverse proxy, bind the server to localhost only:
```bash
./warzone-server --bind 127.0.0.1:7700
```
### systemd Service
```ini
[Unit]
Description=Warzone Messenger Server
After=network.target
[Service]
Type=simple
User=warzone
ExecStart=/usr/local/bin/warzone-server --bind 127.0.0.1:7700 --data-dir /var/lib/warzone
Restart=always
RestartSec=5
Environment=RUST_LOG=info
[Install]
WantedBy=multi-user.target
```
---
## 7. Monitoring
### Health Endpoint
```bash
curl http://localhost:7700/v1/health
# {"status":"ok","version":"0.1.0"}
```
Use this for:
- Load balancer health checks
- Uptime monitoring (e.g., with `uptime-kuma`, Prometheus blackbox exporter)
- Deployment verification
### Logs
All request activity is logged via `tracing`. In production, pipe to a log
aggregator or use `journalctl -u warzone-server`.
---
## 8. Security Considerations
### The Server Is a Dumb Relay
The server never sees plaintext message content. It stores and forwards
opaque encrypted blobs. Even if the server is fully compromised, an attacker
gains:
- **Encrypted message blobs** (useless without recipient's private keys)
- **Public pre-key bundles** (public by design)
- **Metadata:** who is messaging whom, when, and how often
### What the Server CAN See
| Data | Visible to server |
|------|-------------------|
| Message plaintext | No |
| Sender fingerprint | Yes (in `WireMessage`) |
| Recipient fingerprint | Yes (used for routing) |
| Message size | Yes |
| Timing | Yes |
| IP addresses | Yes (from HTTP) |
| Pre-key bundles (public keys) | Yes |
### Mitigations for Metadata (Future)
- **Sealed sender** (Phase 6): hide sender identity from the server.
- **Padding:** fixed-size messages to prevent size-based analysis.
- **Onion routing** (Phase 6): hide IP addresses via relay chains.
### Access Control
The current server has **no authentication**. Anyone can:
- Register a key bundle for any fingerprint
- Poll messages for any fingerprint
- Send messages to any fingerprint
**TODO (Phase 2):** authentication via Ed25519 challenge-response. Clients
sign requests to prove they own the fingerprint they claim.
---
## 9. Backup and Recovery
### Database Backup
The sled database can be backed up by copying the entire data directory while
the server is stopped:
```bash
systemctl stop warzone-server
cp -r /var/lib/warzone /backup/warzone-$(date +%Y%m%d)
systemctl start warzone-server
```
**Warning:** copying the sled directory while the server is running may
produce an inconsistent snapshot. Stop the server first or use filesystem-level
snapshots (LVM, ZFS, btrfs).
### Recovery
1. Stop the server.
2. Replace the data directory with the backup.
3. Start the server.
Messages queued after the backup was taken will be lost. Since all messages
are E2E encrypted, there is no way to recover them from any other source.
### Data Loss Impact
- **Lost key bundles:** users must re-register. No security impact (public
data).
- **Lost message queue:** undelivered messages are permanently lost. Senders
will not know delivery failed (no delivery receipts yet).
- **Corrupted database:** sled includes crash recovery. If the database is
corrupt beyond recovery, delete it and start fresh. Users re-register.