Files
featherChat/warzone/docs/CLIENT.md
Siavash Sameni c2be68ca20 docs: comprehensive update all docs to v0.0.46
11 files updated to reflect current state (v0.0.22 → v0.0.46):

ARCHITECTURE.md:
- Ring tones, group calls, read receipts, markdown rendering sections
- Bot API expanded (BotFather, numeric IDs, Telegram compat)
- Admin commands, known issues, 155 tests

TASK_PLAN.md:
- All P1-P4 marked DONE with version numbers
- Additional completed work section (bots, ETH, ring tones, group calls)
- New FC-P7 (Voice & Transport): cpal, Sender Keys, WebTransport
- FC-P6-T9/T10 added

PROGRESS.md:
- Full version history table v0.0.22 through v0.0.46
- Known issues section

README.md:
- Voice calls, ring tones, group calls, read receipts, markdown, 155 tests

SECURITY.md:
- Bot API security, voice call security, admin commands sections
- Updated protection tables

USAGE.md:
- Group calls, read receipts, markdown formatting, admin commands

CLIENT.md:
- Call commands, read receipts, markdown rendering

LLM_HELP.md + LLM_BOT_DEV.md:
- Call/group call/admin commands, ring tones, per-bot numeric IDs

TESTING_E2E.md:
- Tests 16-18: ring tones, group calls, admin commands

CLAUDE.md:
- Ring tone notes, group signal endpoint, MLS roadmap

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 09:47:13 +04:00

22 KiB

Warzone Client -- Operation Guide

Version: 0.0.46


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.

Voice Calls

The TUI supports DM and group call commands:

Command Description
/call [peer] Initiate a voice call with the current or specified peer
/accept Accept an incoming call
/reject Reject an incoming call
/hangup End the current call

Call state display: The TUI header bar shows call status with color coding:

  • Yellow "CALLING..." — outgoing call ringing, waiting for peer to accept
  • Green "IN CALL" + timer — active call with elapsed duration (MM:SS)
  • No indicator when idle

Note: TUI audio requires the web client. When a call is active in the TUI, a hint is displayed directing the user to open the web client for actual audio. The TUI handles signaling (offer/answer/ICE) but does not capture or play audio.

Read Receipts

Read receipts track message delivery through three states: sent, delivered, and read.

  • Sender fingerprint tracking: Each outgoing message records the sender's fingerprint so the system can match incoming receipts to the correct message.
  • Dedup set: A per-conversation set prevents sending duplicate read receipts for the same message. Once a read receipt is sent for a message ID, it is not sent again.
  • Viewport-based: Read receipts are triggered when a message scrolls into the visible area of the chat. Messages that are never scrolled into view do not generate read receipts.

Markdown Rendering

Messages support inline markdown formatting via the md_to_spans function, which converts markdown syntax into ratatui Span elements with appropriate styling:

Syntax TUI Rendering
**bold** Bold attribute
*italic* Italic attribute
`code` Dark gray background, monospace feel
# Header Bold + uppercase (line start only)
> quote Italic + gray foreground (line start only)
- list item Bullet prefix (line start only)

Markdown is parsed per-message at render time. The web client renders the same syntax as HTML elements.


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>