Files
featherChat/warzone/docs/CLIENT.md
Siavash Sameni 7b72f7cba5 feat: friend list, bot API, ETH addressing, deep links, docs overhaul
Tier 1 — New features:
- E2E encrypted friend list: server stores opaque blob (POST/GET /v1/friends),
  protocol-level encrypt/decrypt with HKDF-derived key, 4 tests
- Telegram Bot API compatibility: /bot/register, /bot/:token/getUpdates,
  sendMessage, getMe — TG-style Update objects with proper message mapping
- ETH address resolution: GET /v1/resolve/:address (0x.../alias/@.../fp),
  bidirectional ETH↔fp mapping stored on key registration
- Seed recovery: /seed command in TUI + web client
- URL deep links: /message/@alias, /message/0xABC, /group/#ops
- Group members with online status in GET /groups/:name/members

Tier 2 — UX polish:
- TUI: /friend, /friend <addr>, /unfriend <addr> with presence checking
- Web: friend commands, showGroupMembers() on group join
- Web: ETH address in header, clickable addresses (click→peer or copy)
- Bot: full WireMessage→TG Update mapping (encrypted base64, CallSignal,
  FileHeader, bot_message JSON)

Documentation:
- USAGE.md rewritten: complete user guide with all commands
- SERVER.md rewritten: full admin guide with all 50+ endpoints
- CLIENT.md rewritten: architecture, commands, keyboard, storage
- LLM_HELP.md created: 1083-word token-optimized reference for helper LLM

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 07:31:54 +04:00

20 KiB

Warzone Client -- Operation Guide

Version: 0.0.21


1. Installation

Build from Source

Requires Rust 1.75+.

cd warzone/
cargo build -p warzone-client --release

The binary is at target/release/warzone. You can copy it anywhere or add target/release to your PATH.

# Optional: install to ~/.cargo/bin
cargo install --path crates/warzone-client

Build the WASM Module (Web Client)

Requires wasm-pack.

cd crates/warzone-wasm
wasm-pack build --target web
# Output in pkg/ — copy to web client directory

2. TUI Architecture

The interactive client is built on ratatui (rendering) and crossterm (terminal I/O). The event loop polls at 100 ms intervals, giving a responsive feel without busy-waiting.

Module Layout

The TUI lives in crates/warzone-client/src/tui/ and is split into seven modules:

Module Responsibility
types Core data structures: App, ChatLine, ReceiptStatus, PendingFileTransfer, constants (MAX_FILE_SIZE, CHUNK_SIZE)
draw Rendering: header bar, message list with timestamps and receipt indicators, input box with unread badge, scroll windowing
commands All /-prefixed command handlers (peer, alias, group, file, history, friends, devices, etc.) and message send logic
input Key event dispatch: text editing, cursor movement, scroll, quit
file_transfer Chunked file send: reads file, SHA-256 hash, splits into 64 KB encrypted chunks
network WebSocket receive loop (with HTTP polling fallback), incoming message decryption, receipt handling, session auto-recovery
mod Public entry point run_tui(): sets up terminal, spawns network task, runs the 100 ms event loop

Event Loop

loop {
    terminal.draw(app)           // ratatui render pass
    if event::poll(100ms) {      // crossterm poll
        handle key event         // Enter → send; everything else → input.rs
    }
    if app.should_quit { break }
}

Messages arrive asynchronously on a background tokio task (network::poll_loop) and are pushed into a shared Arc<Mutex<Vec<ChatLine>>>.


3. CLI Subcommands

warzone init

Generate a new identity (seed, keypair, pre-keys).

$ warzone init
Set passphrase (empty for no encryption): ****
Confirm passphrase: ****

Your identity:
  Fingerprint: a3f8:c912:44be:7d01:9e5a:3b2c:7f80:12d4
  Mnemonic: abandon ability able about above absent absorb abstract ...

SAVE YOUR MNEMONIC — it is the ONLY way to recover your identity.

What happens:

  1. Generates 32 random bytes (seed) from OsRng.
  2. Derives Ed25519 signing key and X25519 encryption key from the seed.
  3. Converts seed to a 24-word BIP39 mnemonic and displays it.
  4. Prompts for a passphrase. Encrypts the seed with Argon2id + ChaCha20-Poly1305 and saves to ~/.warzone/identity.seed (mode 0600 on Unix). An empty passphrase stores the seed in plaintext.
  5. Generates 1 signed pre-key (id=1) and 10 one-time pre-keys (ids 0-9).
  6. Stores pre-key secrets in the local sled database at ~/.warzone/db/.
  7. Saves the public pre-key bundle to ~/.warzone/bundle.bin.

warzone recover <words...>

Recover an identity from a 24-word BIP39 mnemonic.

$ warzone recover abandon ability able about above absent absorb abstract \
    absurd abuse access accident account accuse achieve acid \
    acoustic acquire across act action actor actress actual
Set passphrase (empty for no encryption): ****
Confirm passphrase: ****
Identity recovered. Fingerprint: a3f8:c912:44be:7d01:9e5a:3b2c:7f80:12d4

Recovery restores the seed and keypair. Pre-keys and sessions are NOT restored; contacts will need to re-establish sessions.


warzone info

Display your fingerprint and public keys.

$ warzone info
Fingerprint: a3f8:c912:44be:7d01:9e5a:3b2c:7f80:12d4
Signing key: 3a7b...  (64 hex chars)
Encryption key: 9f2c...  (64 hex chars)

Requires a saved identity (~/.warzone/identity.seed).


warzone tui / warzone chat [peer]

Launch the interactive TUI client.

$ warzone chat --server http://wz.example.com:7700
$ warzone chat a3f8:c912:44be:7d01:... --server http://wz.example.com:7700
$ warzone chat @alice --server http://wz.example.com:7700

An optional peer argument (fingerprint or @alias) pre-sets the active DM target.

Flags:

Flag Short Default Description
--server -s http://localhost:7700 Server URL

warzone send <recipient> <message>

Send an encrypted message. Recipient can be a fingerprint or @alias.

$ warzone send a3f8:c912:44be:7d01:... "Hello!" --server http://wz.example.com:7700
$ warzone send @alice "Hello!" --server http://wz.example.com:7700

Behavior:

  1. Auto-registers your bundle with the server if needed.
  2. Checks for an existing Double Ratchet session with the recipient.
  3. If no session: fetches the recipient's pre-key bundle, verifies the signed pre-key signature, performs X3DH, initializes the ratchet as Alice, and sends a WireMessage::KeyExchange containing the X3DH parameters and the first encrypted message.
  4. If a session exists: encrypts with the existing ratchet and sends a WireMessage::Message.
  5. Updates the local session state.

warzone recv

Poll for and decrypt incoming messages.

$ warzone recv --server http://wz.example.com:7700

Fetches messages from /v1/messages/poll/{fingerprint}, deserializes each WireMessage, performs X3DH respond or ratchet decrypt as appropriate, and prints plaintext to stdout.


warzone backup [output]

Export an encrypted backup of local data (sessions, pre-keys).

$ warzone backup my-backup.wzb
Backup saved to my-backup.wzb (4096 bytes encrypted)

The backup is encrypted with HKDF(seed, info="warzone-history") + ChaCha20-Poly1305.

Backup file format:

WZH1 (4 bytes) + nonce (12) + ciphertext

Plaintext: JSON {
  "version": 1,
  "sessions": { "<fp>": "base64_bincode", ... },
  "pre_keys": { "spk:1": "base64_bytes", "otpk:1": "base64_bytes", ... }
}

warzone restore <input>

Restore from an encrypted backup. Requires the same seed (passphrase prompt).

$ warzone restore my-backup.wzb
Restored 12 entries from my-backup.wzb

Merges data without overwriting existing entries.


4. TUI Features

Message Timestamps

Every message is rendered with a [HH:MM] prefix in dark gray, derived from chrono::Local::now() at receive/send time.

Message Scrolling

The message area supports scrolling with a "pinned to bottom" model:

  • scroll_offset = 0 means the newest messages are visible.
  • Scrolling up increases the offset; scrolling down decreases it.
  • The visible window is computed as items[total - offset - height .. total - offset].

Connection Status Indicator

The header bar displays a colored dot after the server URL:

  • Green dot: WebSocket connection active.
  • Red dot: disconnected (HTTP polling fallback or reconnecting).

Unread Badge

When scroll_offset > 0, the input box title changes from " message " to " [N new] " showing how many messages are below the current scroll position. This makes it obvious that new content has arrived while reading history.

Terminal Bell

A terminal bell (\x07) is emitted on every incoming DM (both KeyExchange and Message wire types). This triggers a system notification in most terminal emulators.

Receipt Indicators

Sent messages display delivery status after the message text:

Indicator Meaning
Single tick Sent (no confirmation yet)
Double tick Delivered (decrypted by recipient)
Double tick blue Read (viewed by recipient)

Session Auto-Recovery

When decryption fails on an incoming message, the TUI automatically:

  1. Deletes the corrupted session from the local database.
  2. Displays a system message: [session reset] Decryption failed for <fp>. Session cleared -- next message will re-establish.

The next incoming KeyExchange from that peer will create a fresh session without manual intervention.


5. Full Command Reference

All commands start with / and are entered in the TUI input box.

Peer and Navigation

Command Short Description
/peer <fp_or_alias> /p Set the active DM peer (fingerprint or @alias)
/dm Switch to DM mode (clear group context)
/reply /r Switch to the last person who DM'd you
/info Display your fingerprint
/eth Display your Ethereum address (derived from seed)
/seed Display your 24-word recovery mnemonic
/quit /q Exit the TUI
/help /? Show the built-in help text

Alias Management

Command Description
/alias <name> Register an alias for your fingerprint. Returns a recovery key -- save it.
/unalias Remove your alias from the server
/aliases List all registered aliases on the server

Alias rules: 1-32 alphanumeric characters (plus _ and -), case-insensitive, normalized to lowercase. TTL is 365 days of inactivity with a 30-day grace period before reclamation.

Contacts and History

Command Short Description
/contacts /c List all contacts with message counts
/history [peer] /h Show message history (last 50 messages). Uses current peer if set.

Group Commands

Command Description
/g <name> Switch to group (auto-join if needed)
/gcreate <name> Create a new group (you become creator)
/gjoin <name> Join an existing group
/gleave Leave the current group
/gkick <fp_or_alias> Kick a member (creator only)
/gmembers List members of the current group
/glist List all groups on the server

Group messages use Sender Keys for O(1) encryption per message. Each member generates a SenderKey distributed via 1:1 encrypted channels. Keys rotate on member join/leave.

File Transfer

Command Description
/file <path> Send a file to the current peer or group

Constraints:

  • Maximum file size: 10 MB
  • Chunk size: 64 KB
  • Files are sent as FileHeader + encrypted FileChunk wire messages
  • SHA-256 verification on receipt
  • Received files are saved to ~/.warzone/downloads/

Device Management

Command Description
/devices List your active device sessions
/kick <device_id> Kick a specific device session

6. Keyboard Shortcuts

Text Editing

Key Action
Left / Right Move cursor one character
Home / Ctrl+A Move to beginning of line
End / Ctrl+E Move to end of line
Backspace Delete character before cursor
Delete Delete character at cursor
Ctrl+U Clear entire input line
Ctrl+K Kill from cursor to end of line
Ctrl+W Delete word before cursor
Alt+Backspace Delete word before cursor
Alt+Left Jump one word left
Alt+Right Jump one word right

Scrolling

Key Action
PageUp Scroll up 10 messages
PageDown Scroll down 10 messages
Up Scroll up 1 message (when input is empty)
Down Scroll down 1 message (when input is empty)
End Snap to bottom (when input is empty)
Ctrl+End Snap to bottom (always)

Quit

Key Action
Ctrl+C Quit
Esc Quit

7. Friend List

The friend list is an E2E encrypted contact list stored on the server as an opaque blob. The server never sees the plaintext.

Encryption

  • Key derivation: HKDF(seed, info="warzone-friends") produces a 32-byte key.
  • Encryption: ChaCha20-Poly1305 with AAD "warzone-friends-aad".
  • Plaintext format: JSON-serialized FriendList containing address, alias, and added_at timestamp per friend.

Commands

Command Description
/friend List all friends with online/offline presence
/friend <address> Add a friend (fingerprint or ETH address)
/unfriend <address> Remove a friend

When listing friends, the TUI queries the server's presence endpoint for each friend to show real-time online/offline status.

How It Works

  1. On /friend <address>: the client fetches the current encrypted blob from the server, decrypts it, adds the entry, re-encrypts, and uploads.
  2. On /unfriend <address>: same fetch-decrypt-modify-encrypt-upload cycle.
  3. On /friend (no argument): fetches and decrypts the blob, then checks /v1/presence/<fp> for each friend.

The server stores the blob at POST /v1/friends and returns it at GET /v1/friends. It has no knowledge of the contents.


8. Local Storage

Directory Layout

~/.warzone/
  identity.seed        # Encrypted seed (Argon2id + ChaCha20-Poly1305)
  bundle.bin           # bincode-serialized PreKeyBundle (public data)
  db/                  # sled database directory
    sessions/          # Double Ratchet state per peer (keyed by hex fingerprint)
    pre_keys/          # Signed and one-time pre-key secrets
    contacts/          # Contact metadata and message counts
    history/           # Message history per peer
    sender_keys/       # Sender Key state for group encryption
  downloads/           # Received files from /file transfers

Seed Encryption

The seed file uses a fixed format:

WZS1 (4 bytes magic) + salt (16) + nonce (12) + ciphertext (48)

Encryption: Argon2id(passphrase, salt) -> 32-byte key
            ChaCha20-Poly1305(key, nonce, seed) -> ciphertext

An empty passphrase at init time stores the seed in plaintext (for testing only). The seed file is created with mode 0600 (owner read/write) on Unix.

Mnemonic Backup

The 24-word BIP39 mnemonic shown during init is the only way to recover your identity if you lose ~/.warzone/. Write it down on paper. You can also view it later with /seed in the TUI.


9. Web Client

The web client is served by the server at / and uses a WASM bridge (warzone-wasm) that exposes the exact same cryptographic primitives as the CLI: X25519, ChaCha20-Poly1305, X3DH, Double Ratchet.

Features

  • Same crypto as TUI: the WASM module wraps warzone-protocol directly, so web-to-CLI interoperability is fully supported.
  • URL deep links: paths like /message/@alias, /message/0xABC, and /group/#ops auto-navigate to the corresponding conversation.
  • Clickable addresses: fingerprints and aliases in the chat are rendered as interactive links.
  • Service worker cache: all shell assets (/, WASM JS, WASM binary, manifest, icon) are cached by a versioned service worker (wz-v2). The cache name is bumped on updates to force refresh.
  • PWA support: includes a manifest and install prompt (/install command).
  • BIP39 mnemonic: seed is displayed as 24 words via the WASM bridge (not hex).

Web-Only Commands

Command Description
/selftest Run WASM crypto self-test (X3DH + ratchet cycle)
/bundleinfo Debug: show bundle details (keys, sizes)
/debug Toggle debug mode (verbose output)
/reset Clear identity and all local data
/install Show PWA installation instructions
/sessions List active ratchet sessions
/admin-unalias Admin: remove any alias (requires admin password)

Web Client Storage

Data is stored in localStorage:

Key Value Purpose
wz_seed hex seed (64 chars) Identity seed
wz_spk_secret hex SPK secret (64 chars) Signed pre-key secret
wz_session:<fp> base64 ratchet state Per-peer session
wz_contacts JSON contact list Contact metadata

10. Session Management

How Sessions Work

A "session" is a Double Ratchet state between you and one peer, identified by their fingerprint.

  1. First message to a peer: X3DH key exchange establishes a shared secret. The ratchet is initialized. The session is saved in ~/.warzone/db/ under the sessions tree, keyed by the peer's hex fingerprint.

  2. Subsequent messages: the ratchet state is loaded, used to encrypt or decrypt, then saved back.

  3. Bidirectional: when Bob receives Alice's KeyExchange, he initializes his side. From then on, both use WireMessage::Message.

Session Auto-Recovery

On decrypt failure, the TUI deletes the corrupted session and displays a warning. The next incoming KeyExchange from that peer re-establishes the session automatically. No manual intervention required.

Multi-Device

The server stores per-device bundles (device:<fp>:<device_id>). Multiple WebSocket connections per fingerprint are supported -- all connected devices receive messages. Ratchet sessions are per-device and not synchronized; use warzone backup / warzone restore to transfer session state.


11. Troubleshooting

"No identity found. Run warzone init first."

~/.warzone/identity.seed is missing. Run warzone init.

"No bundle found. Run warzone init first."

~/.warzone/bundle.bin is missing. This happens if you ran recover without regenerating pre-keys. Re-run warzone init (generates a new identity).

"failed to fetch recipient's bundle. Are they registered?"

The recipient has not registered with the server, or the fingerprint / alias is wrong, or the server URL is incorrect. Verify with warzone info and warzone register.

"X3DH respond failed" / "missing signed pre-key"

Signed pre-key secret missing from local database. Database may have been deleted or corrupted. Re-initialize with warzone init.

"[session reset] Decryption failed"

The TUI auto-recovery has cleared the corrupted session. Ask the other party to send a new message -- a fresh KeyExchange will re-establish the session.

Corrupted Database

# Back up your seed first
cp ~/.warzone/identity.seed ~/identity.seed.bak
rm -rf ~/.warzone/db/
warzone init   # regenerate pre-keys (NOTE: generates a new identity)
# To keep your old identity, recover from mnemonic after:
warzone recover <24 words>