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