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

10 KiB

Warzone Server -- Operation & Administration


1. Building

The server is part of the Cargo workspace. From the workspace root:

# 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

# 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:

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:

{
  "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:

{
  "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:

{
  "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):

{
  "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:

{
  "to": "b7d1:e845:0022:9f3a",
  "message": [/* bincode-serialized WireMessage as byte array */]
}

Response:

{
  "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):

[
  "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:

{
  "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)

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:

./warzone-server --bind 127.0.0.1:7700

systemd Service

[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

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:

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.