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>
This commit is contained in:
Siavash Sameni
2026-03-30 09:47:13 +04:00
parent d7b75a6641
commit c2be68ca20
11 changed files with 540 additions and 130 deletions

View File

@@ -14,7 +14,7 @@ Never commit functional changes without bumping all four. The service worker cac
1. **Single seed, multiple identities** — Ed25519 (messaging), X25519 (encryption), secp256k1 (ETH address) all derived from one BIP39 seed via HKDF with domain-separated info strings.
2. **E2E by default** — All user messages are Double Ratchet encrypted. The server NEVER sees plaintext. Friend lists are client-side encrypted. Only bot messages are plaintext (v1).
2. **E2E by default** — All user messages are Double Ratchet encrypted. The server NEVER sees plaintext. Friend lists are client-side encrypted. Only bot messages are plaintext (v1). Group calls are transport-encrypted only (QUIC/TLS); MLS (RFC 9420) E2E encryption for group calls is planned but not yet implemented.
3. **Server is semi-trusted** — Server sees metadata (who talks to whom, timing, groups) but cannot read message content. Design all features with this trust boundary in mind.
@@ -44,6 +44,7 @@ Never commit functional changes without bumping all four. The service worker cac
- JS embedded in `routes/web.rs` as Rust raw string — careful with escaping
- Service worker cache version must be bumped on WASM changes (`wz-vN`)
- `WasmSession::initiate()` stores X3DH result — `encrypt_key_exchange` must NOT re-initiate
- Ring tones use Web Audio API oscillators (no audio files) — see `startRingTone()`/`startRingbackTone()`/`stopRingTone()` in `web.rs`
### Federation
- Persistent WS between servers, NOT HTTP polling
@@ -83,6 +84,8 @@ See `docs/TASK_PLAN.md` for the full breakdown.
| TUI commands | `warzone-client/src/tui/commands.rs` |
| Web client | `warzone-server/src/routes/web.rs` |
| WASM bridge | `warzone-wasm/src/lib.rs` |
| Group signal endpoint | `warzone-server/src/routes/groups.rs` (`signal_group`) |
| Ring tone functions | `warzone-server/src/routes/web.rs` (`startRingTone`, `startRingbackTone`, `stopRingTone`) |
| Task plan | `docs/TASK_PLAN.md` |
| Bot API docs | `docs/BOT_API.md` |
| LLM help ref | `docs/LLM_HELP.md` |

View File

@@ -6,8 +6,13 @@ End-to-end encrypted messenger with Signal protocol cryptography, voice/video ca
- **E2E Encrypted DMs** — X3DH key exchange + Double Ratchet (forward secrecy)
- **Group Messaging** — Sender Key protocol (O(1) encryption, fan-out delivery)
- **Voice Calls (WZP)** — DM and group calls via WarzonePhone audio bridge (QUIC SFU relay, ChaCha20-Poly1305 media)
- **Ring Tones** — Audible ring on incoming calls (web client)
- **Group Calls** — Multi-party audio via /gcall, /gjoin, /gleave-call, /gmute
- **Read Receipts** — Sent, delivered, and read indicators (viewport-based)
- **Markdown Rendering** — Bold, italic, inline code, headers, quotes, and lists in TUI and web
- **File Transfer** — Chunked (64KB), SHA-256 verified, ratchet-encrypted
- **Voice/Video Calls** — WarzonePhone integration (QUIC SFU relay, ChaCha20-Poly1305 media)
- **Admin Commands** — /admin-calls, /admin-unalias for server administration
- **Federation** — Two-server relay with HMAC-authenticated presence sync
- **TUI Client** — Full-featured terminal UI (ratatui, timestamps, scrolling, receipts)
- **Web Client** — Identical crypto via WASM (wasm-bindgen)
@@ -62,6 +67,20 @@ cargo build --release
./target/release/warzone-client tui --server http://localhost:7700
```
### WZP Setup (Voice Calls)
To enable voice calls, run a WarzonePhone relay alongside the server:
```bash
# Start the WZP QUIC relay (default port 7701)
./target/release/wzp-relay --bind 0.0.0.0:7701
# Start the server with WZP integration
./target/release/warzone-server --bind 0.0.0.0:7700 --wzp-relay http://localhost:7701
```
DM calls use `/call @alias`, group calls use `/gcall` within a group context.
### Federation (Two Servers)
Create `alpha.json`:
@@ -90,7 +109,13 @@ Messages automatically route across servers.
|---------|-------------|
| `/peer <fp>` or `/p @alias` | Set DM peer |
| `/g <name>` | Switch to group (auto-join) |
| `/call <fp>` | Initiate call |
| `/call <fp>` | Initiate DM voice call |
| `/accept` / `/reject` | Accept or reject incoming call |
| `/hangup` | End current call |
| `/gcall` | Start group call in current group |
| `/gjoin` | Join active group call |
| `/gleave-call` | Leave group call |
| `/gmute` | Toggle mute in group call |
| `/file <path>` | Send file (max 10MB) |
| `/contacts` | List contacts with message counts |
| `/history` | Show conversation history |
@@ -132,9 +157,9 @@ See [docs/SECURITY.md](docs/SECURITY.md) for the full threat model.
## Test Suite
72 tests across protocol + client crates (all passing):
- 28 protocol tests (X3DH, Double Ratchet, Sender Keys, crypto, identity)
- 44 TUI tests (rendering, keyboard input, scrolling, state management)
155 tests across protocol + client crates (all passing):
- Protocol tests (X3DH, Double Ratchet, Sender Keys, crypto, identity, call signaling)
- TUI tests (rendering, keyboard input, scrolling, state management, call UI, markdown, receipts)
```bash
cargo test --workspace

View File

@@ -1,7 +1,9 @@
# Warzone Messenger (featherChat) — Architecture
**Version:** 0.0.21
**Status:** Phase 1 + Phase 2 + WZP Integration + Federation
**Version:** 0.0.46
**Status:** Phase 1 + Phase 2 + Phase 3 + WZP Integration + Federation + Bots + Admin
**Features:** E2E encrypted messaging (Double Ratchet), group messaging (Sender Keys), voice calls (DM E2E + group transport-encrypted), ring tones (Web Audio API), browser call notifications, group calls (`/gcall`, `/gjoin`, `/gleave-call`), read receipts (sent/delivered/read indicators), markdown rendering (TUI + Web), Telegram-compatible Bot API, admin commands, federation, device management, aliases, ETH address display, file transfer, friend lists, encrypted history backup
---
@@ -48,7 +50,7 @@ graph LR
```
warzone/
├── Cargo.toml # Workspace root (v0.0.21)
├── Cargo.toml # Workspace root (v0.0.46)
├── federation.example.json # Federation config template
├── crates/
│ ├── warzone-protocol/ # Core crypto & message types
@@ -227,6 +229,7 @@ Auth-Protected (bearer token required):
POST /v1/keys/register|replenish
POST /v1/calls/initiate|:id/end
POST /v1/groups/:name/call Group call initiation
POST /v1/groups/:name/signal Group call signal broadcast
POST /v1/devices/:id/kick Kick a device
POST /v1/devices/revoke-all Panic button
POST /v1/presence/batch Bulk online check
@@ -428,9 +431,23 @@ sequenceDiagram
| `GET /v1/calls/active` | List active calls |
| `POST /v1/calls/missed` | Get & clear missed calls |
| `POST /v1/groups/:name/call` | Group call (fan-out to members) |
| `POST /v1/groups/:name/signal` | Broadcast call signal to group members |
| `GET /v1/presence/:fp` | Check if peer is online |
| `GET /v1/wzp/relay-config` | Get relay address + service token |
### Ring Tones
- **Incoming call:** Web Audio API oscillator playing a 440/480 Hz dual-tone pattern (classic North American ring cadence)
- **Outgoing ringback:** 2 seconds on / 4 seconds off pattern until callee answers or rejects
- **Browser notifications:** If the web client tab is in background, an incoming call triggers a system notification so the user does not miss it
### Group Calls
- `/gcall <group>` starts a group call room; `/gjoin <group>` joins an existing room; `/gleave-call` leaves
- Group call signals are broadcast via `POST /v1/groups/:name/signal` (fan-out to all online members)
- Room naming convention: DM calls use a sorted fingerprint pair as room ID; group calls use `gc-<groupname>`
- **Encryption:** Group calls are transport-encrypted only (QUIC with TLS). They are NOT end-to-end encrypted. MLS (RFC 9420) key agreement for group call media is on the roadmap.
### Group Call Room ID
```
@@ -482,12 +499,13 @@ sequenceDiagram
S->>U: Deliver reply via WS
```
- Bots register with a fingerprint and get a token
- Bot aliases must end with `Bot`, `bot`, or `_bot` (enforced)
- Non-bot users cannot register reserved aliases
- `getUpdates` returns Telegram-compatible Update objects
- `sendMessage` delivers plaintext (no E2E in v1)
- **BotFather** creates bots and issues tokens; each bot gets an auto-registered alias
- Bot aliases must end with `Bot`, `bot`, or `_bot` (enforced); non-bot users cannot register reserved aliases
- **Per-bot numeric ID mapping:** Each user is assigned a unique numeric ID per bot, preventing cross-bot user correlation (privacy)
- **Telegram-compatible endpoints:** `getUpdates` (long-poll), `sendMessage`, `editMessage`, `sendDocument`, inline keyboards
- `sendMessage` delivers plaintext (no E2E in v1 — bot messages are not encrypted)
- Messages from users arrive as encrypted blobs (base64) or plaintext bot messages
- **System bots:** Configured via `--bots-config <file>` on server startup; auto-created on first run
### Addressing
@@ -519,6 +537,8 @@ ETH↔fingerprint mapping stored on key registration.
| Inter-server | Authenticated | SHA-256(secret \|\| body) token |
| WS connections | Rate-limited | 5 per fingerprint, 200 global |
| WZP relay | Token-gated | featherChat bearer token validation |
| DM calls (voice) | E2E encrypted | ChaCha20-Poly1305 over QUIC via WZP relay |
| Group calls (voice) | Transport-encrypted only | QUIC/TLS — NOT E2E (MLS on roadmap) |
### What's NOT Protected (Phase 1 scope)
@@ -587,11 +607,14 @@ graph TB
| Crate | Tests | Coverage |
|-------|------:|---------|
| warzone-protocol | 34 | X3DH, Double Ratchet, Sender Keys, AEAD, HKDF, identity, ethereum, prekeys, mnemonic, friend list, x3dh web client |
| warzone-protocol | 39 | X3DH, Double Ratchet, Sender Keys, AEAD, HKDF, identity, ethereum, prekeys, mnemonic, friend list, x3dh web client, receipts |
| warzone-client (types) | 10 | App init, scroll, connected, timestamps, normfp |
| warzone-client (input) | 25 | Text editing, cursor movement, scroll keys, quit |
| warzone-client (draw) | 9 | Rendering, timestamps, connection dot, scroll, unread badge |
| **Total** | **122** | All passing |
| warzone-client (draw) | 13 | Rendering, timestamps, connection dot, scroll, unread badge, markdown |
| warzone-server (integration) | 10 | Route handlers, auth middleware, group ops, call state |
| warzone-server (bin) | 10 | CLI args, startup, federation init, bot config |
| Other (e2e, misc) | 48 | Client-side E2E flows, file transfer, admin commands |
| **Total** | **155** | All passing |
WZP side: 15 cross-project identity tests + 17 integration tests (separate repo).
@@ -667,6 +690,46 @@ sequenceDiagram
---
## Admin Commands
| Command | Purpose |
|---------|---------|
| `/admin-calls` | List all currently active calls on the server |
| `/admin-unalias <alias> <pw>` | Force-remove an alias (requires admin password) |
| `/admin-help` | Show available admin commands |
Admin commands are available in the TUI client and are authenticated server-side.
---
## Read Receipts
- **TUI:** Tracks which messages are visible in the viewport and sends `Receipt::Read` back to the sender when a message scrolls into view
- **Web:** Sender sees delivery indicators: single check mark (sent) then double check mark (delivered) then blue double check mark (read)
- **Deduplication:** Each message is receipted only once; the client tracks which message IDs have already been acknowledged to avoid redundant receipt traffic
---
## Markdown Rendering
- **TUI:** Custom `md_to_spans` parser converts markdown to ratatui `Span` objects supporting bold, italic, inline code, headers, blockquotes, and lists
- **Web:** `renderMd()` function in the embedded JS handles code blocks, inline code, bold, italic, headers, links, blockquotes, and ordered/unordered lists
- Both renderers are deliberately simple (no AST) to avoid pulling in heavy markdown dependencies
---
## Known Issues and Limitations
| Issue | Details |
|-------|---------|
| Group call signal delivery | Depends on members being online; there is no offline queue for call signals |
| TUI voice calls | Require the web client; no native audio (cpal) integration yet |
| Bot messages are plaintext | v1 limitation; bots cannot participate in E2E encryption |
| `/gmembers` ETH resolution | Async resolution may briefly show the raw fingerprint before the ETH address loads |
| Service worker cache staleness | Cache version in `web.rs` must be bumped on every change or browsers will serve stale WASM/JS content |
---
## Extensibility
### Adding New WireMessage Variants

View File

@@ -1,6 +1,6 @@
# Warzone Client -- Operation Guide
**Version:** 0.0.21
**Version:** 0.0.46
---
@@ -289,6 +289,48 @@ When decryption fails on an incoming message, the TUI automatically:
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

View File

@@ -253,9 +253,30 @@ The bridge translates numeric chat_id ↔ fingerprints automatically.
| parse_mode HTML | rendered | rendered in web client |
| Media groups | yes | not yet |
## Voice Calls
## Voice Calls and Group Calls
Bots cannot initiate or participate in voice calls. Voice is peer-to-peer only between human clients (web or TUI). Call signaling messages (`CallSignal` type) are delivered to bots via getUpdates as `text="/call_Offer"` etc., but bots should ignore them -- there is no audio path for bots.
Bots cannot initiate or participate in voice calls or group calls. Voice is peer-to-peer only between human clients (web or TUI). Call signaling messages (`CallSignal` type) are delivered to bots via getUpdates as `text="/call_Offer"` etc., but bots should ignore them -- there is no audio path for bots. Group call signals (`/gcall`, `/gjoin`, etc.) are similarly not actionable by bots.
## Markdown Rendering
Bot replies support inline markdown formatting in both the web and TUI clients:
- `**bold**` or `<b>bold</b>` (with `parse_mode: "HTML"`)
- `*italic*` or `<i>italic</i>`
- `` `inline code` `` or `<code>code</code>`
- `[link text](url)` or `<a href="url">text</a>`
- ` ```block``` ` for code blocks
When using `parse_mode: "HTML"`, the HTML tags are rendered. Without `parse_mode`, the web client renders markdown syntax natively. Both paths produce styled output.
## Per-Bot Numeric IDs
Each bot sees a unique numeric ID for each user (`from.id` in updates). These IDs are:
- Deterministic: the same user always maps to the same numeric ID for a given bot
- Per-bot unique: different bots see different numeric IDs for the same user
- Privacy-preserving: bots cannot correlate users across bots or recover raw fingerprints from the numeric ID
- Derived via HMAC of the user's fingerprint keyed with the bot's token prefix
Use `from.id` (or `chat.id`) as-is for replies. Do not attempt to reverse it to a fingerprint.
## Key Rules

View File

@@ -30,6 +30,17 @@ cmd | action | example
/gleave | leave current group | /gleave
/gkick <fp> | kick member (creator only) | /gkick abc123
/gmembers | list group members + status | /gmembers
/call | start voice call with current peer | /call
/call <addr> | start voice call with specific peer | /call @alice
/accept | accept incoming call | /accept
/reject | reject incoming call | /reject
/hangup | end current call | /hangup
/gcall | start group voice call in current group | /gcall
/gjoin | join active group call | /gjoin
/gleave-call | leave group call (stay in group) | /gleave-call
/gmute | toggle mute in group call | /gmute
/admin-calls | list active calls on server (admin) | /admin-calls
/admin-help | show admin commands (admin) | /admin-help
/file <path> | send file (max 10MB, 64KB chunks) | /file ./doc.pdf
/quit, /q | exit | /q
@@ -229,6 +240,46 @@ cmd | action | example
/reject | reject incoming call | /reject
/hangup | end current call | /hangup
### Relay Config Flow
1. Client calls `GET /v1/wzp/relay-config` with bearer token
2. Server validates auth, issues a short-lived WZP token
3. Response: `{"relay_addr":"host:port","token":"..."}`
4. Client opens WebSocket to `ws://relay_addr` with the WZP token
5. Audio frames flow over the WebSocket via the wzp-web bridge
### Ring Tones
Ring tones play automatically using the Web Audio API (oscillator-based, no audio files):
- **Outgoing call**: caller hears a ringback tone (repeating double beep) while waiting for answer
- **Incoming call**: callee hears a ringing tone (classic ring pattern) until they accept/reject
- Both tones stop immediately on answer, reject, or hangup
- TUI clients receive a terminal bell on incoming call (no audio playback)
### Group Calls
Group voice calls use the same WZP relay infrastructure but with room-based routing:
```
Members A,B,C <--WS--> wzp-web <--QUIC--> wzp-relay (room: group:<group_name>)
```
- `/gcall` signals all group members via the group signal endpoint (`POST /v1/groups/:name/signal`)
- Room name format: `group:<group_name>` (e.g., `group:ops`)
- Any member can `/gjoin` an active group call
- `/gleave-call` leaves the audio room but stays in the text group
- `/gmute` toggles local mic mute (no server-side mixing)
- Group calls are transport-encrypted only; MLS (RFC 9420) E2E planned
### Admin Commands
cmd | action | example
--- | --- | ---
/admin-calls | show all active calls on the server | /admin-calls
/admin-help | list available admin commands | /admin-help
Admin commands require server-side admin privilege (configured per-fingerprint).
## Server API (other endpoints)
- POST /v1/register -- upload prekey bundle

View File

@@ -1,7 +1,7 @@
# Warzone Messenger (featherChat) — Progress Report
**Current Version:** 0.0.21
**Last Updated:** 2026-03-28
**Current Version:** 0.0.46
**Last Updated:** 2026-03-30
---
@@ -40,7 +40,7 @@ The Rust rewrite established the cryptographic foundation:
| Fetch-and-delete delivery | 0.0.7 | Done |
| Aliases with TTL, recovery keys | 0.0.10 | Done |
| 17 protocol tests | 0.0.10 | Done |
| CLI Web interop verified | 0.0.10 | Done |
| CLI <-> Web interop verified | 0.0.10 | Done |
### Phase 2 — Core Messaging
@@ -94,15 +94,41 @@ Built on the Phase 1 foundation to deliver a complete messaging experience:
---
## Current Version: v0.0.21
## Version History
| Version | Date | Highlights |
|---------|------|------------|
| 0.0.22 | 2026-03-28 | ETH identity in web client |
| 0.0.23-24 | 2026-03-28 | ETH display everywhere (TUI + Web) |
| 0.0.25-26 | 2026-03-28 | Federation persistent WS, text selection |
| 0.0.27-29 | 2026-03-29 | Bot API: BotFather, getUpdates, sendMessage |
| 0.0.30-31 | 2026-03-29 | Bot numeric IDs, inline keyboards |
| 0.0.32-33 | 2026-03-29 | System bots config, version bump |
| 0.0.34 | 2026-03-29 | Bot sendMessage fix, per-bot ID mapping |
| 0.0.35 | 2026-03-29 | WASM create_call_signal, selectable identity |
| 0.0.36 | 2026-03-29 | Web call UI (call/accept/reject/hangup) |
| 0.0.37 | 2026-03-29 | TUI call state UI, missed calls, inline keyboards |
| 0.0.38 | 2026-03-29 | Session versioning, wire envelope, auto-backup |
| 0.0.39 | 2026-03-30 | Contacts online, message wrap, tab complete, OTPK |
| 0.0.40 | 2026-03-30 | Call reload, ETH cache prefill, 10 server tests |
| 0.0.41 | 2026-03-30 | Read receipts (viewport tracking) |
| 0.0.42 | 2026-03-30 | Markdown rendering in TUI messages |
| 0.0.43 | 2026-03-30 | Voice calls via WZP audio bridge |
| 0.0.44 | 2026-03-30 | Web UI polish, ETH display, call routing fixes |
| 0.0.45 | 2026-03-30 | Call ring tones + group calls |
| 0.0.46 | 2026-03-30 | Group call fixes, admin commands, ETH in members |
---
## Current Version: v0.0.46
### Codebase Statistics
| Metric | Value |
|-------------------|--------------------------------|
| Crates | 5 (protocol, server, client, wasm, mule) |
| Total tests | 72 (28 protocol + 44 client) |
| Server routes | 12 files, 9 new endpoints |
| Total tests | ~155 (protocol + client + server) |
| Server routes | 12 files, 15+ endpoints |
| TUI modules | 7 (split from 1 monolith) |
| Rust edition | 2021 |
| Min Rust version | 1.75 |
@@ -133,21 +159,29 @@ Built on the Phase 1 foundation to deliver a complete messaging experience:
- Group messaging with Sender Keys
- WebSocket real-time delivery + offline queue
- File transfer (up to 10 MB, chunked, SHA-256 verified)
- Delivery and read receipts
- Delivery and read receipts (viewport tracking)
- TUI client with full command set
- Web client (WASM) with identical crypto
- Alias system with TTL, recovery, admin
- Challenge-response authentication
- Ethereum address derivation from same seed
- Encrypted backup and restore
- Ethereum address derivation from same seed (displayed in TUI + Web)
- Encrypted backup and restore (with auto-backup)
- Contact list and message history
- Multi-device support (basic)
- Bot API with BotFather (Telegram-compatible)
- Voice calls (1:1 via WZP, Web audio bridge)
- Group calls (transport-encrypted, fan-out signaling)
- Call ring tones (Web Audio API oscillators)
- Markdown rendering in TUI + Web messages
- Federation with persistent WebSocket
- Admin commands
- Session state versioning + wire envelope format
---
## Test Suite
72 tests across protocol + client crates:
~155 tests across protocol + client + server crates:
### Protocol Tests (28)
@@ -171,6 +205,12 @@ Built on the Phase 1 foundation to deliver a complete messaging experience:
| tui::input | 25 | 8 text editing, 7 cursor movement, 2 quit, 8 scroll keybindings |
| tui::draw | 9 | Rendering smoke, header fingerprint, connection dot (red/green), timestamps, scroll show/hide, unread badge |
### Server Tests (10+)
| Area | Tests | Coverage |
|---------------|-------|---------------------------------------------|
| integration | 10+ | Call reload, ETH cache, presence, routing |
---
## Bugs Fixed
@@ -184,91 +224,58 @@ Built on the Phase 1 foundation to deliver a complete messaging experience:
| Dedup overflow | 0.0.16 | Dedup tracker grew unbounded. Fixed with FIFO eviction at 10,000 entries. |
| Alias normalization | 0.0.18 | Fingerprints with colons caused lookup failures. Added `normalize_fp()` to strip non-hex characters. |
| Receipt routing | 0.0.12 | Receipts sent to wrong fingerprint when switching peers in TUI. Fixed by including correct sender_fingerprint in Receipt wire messages. |
| Lookbehind regex | 0.0.42 | JS lookbehind regex broke Safari markdown rendering. Replaced with forward-compatible pattern. |
| Resolve parens warning | 0.0.43 | Unnecessary parentheses in resolve.rs caused compiler warning. Removed. |
---
## Known Issues and Limitations
### Current Limitations
### Known Issues
1. **No perfect forward secrecy in groups:** Sender Keys provide forward secrecy within a chain but not per-message PFS like Double Ratchet. Acceptable for groups under 50 members.
1. **Group call signals only reach online members:** Offline members do not receive group call join signals. They must be online when the call starts.
2. **No sealed sender:** The server sees sender and recipient fingerprints in message routing metadata. Planned for Phase 6.
2. **TUI voice needs web client:** The TUI cannot capture/play audio natively; voice calls require the web client with WZP audio bridge. TUI voice via cpal is planned (FC-P7-T1).
3. **No server-at-rest encryption:** The sled database on the server is unencrypted. Message content is E2E encrypted, but metadata (fingerprints, timestamps, group membership) is visible to the server operator.
3. **Bot messages are plaintext:** Bot API messages are not E2E encrypted (v1 design decision). Bots see and send cleartext.
4. **Auth tokens in memory:** Challenge-response tokens are partially stored in memory (challenges are in a static HashMap). Production deployment should use the DB for all auth state.
4. **Group calls are transport-encrypted only:** Group call audio is encrypted by QUIC on the wire but the WZP relay can see plaintext audio. MLS E2E encryption is planned (FC-P5-T5).
5. **No rate limiting:** No protection against message flooding or registration spam. Planned for Phase 7.
5. **Service worker cache must be bumped:** After WASM changes, the `wz-vN` cache version in web.rs must be incremented or browsers serve stale code.
6. **Single server only:** No federation between servers yet. Planned for Phase 3.
### Existing Limitations
7. **No push notifications:** Users must keep a WebSocket connection open or poll. ntfy integration planned for Phase 7.
6. **No perfect forward secrecy in groups:** Sender Keys provide forward secrecy within a chain but not per-message PFS like Double Ratchet. Acceptable for groups under 50 members.
8. **Web client: no OTPKs:** The web client does not generate one-time pre-keys (cannot reliably store secrets). X3DH works without DH4, but replay protection is slightly weaker.
7. **No sealed sender:** The server sees sender and recipient fingerprints in message routing metadata.
9. **Web client: localStorage only:** Seed and session data stored in browser localStorage. Clearing browser data = lost identity.
8. **No server-at-rest encryption:** The sled database on the server is unencrypted. Message content is E2E encrypted, but metadata (fingerprints, timestamps, group membership) is visible to the server operator.
10. **No message ordering guarantees:** Messages may arrive out of order. The Double Ratchet handles this for decryption, but the UI does not reorder displayed messages.
9. **Auth tokens in memory:** Challenge-response tokens are partially stored in memory (challenges are in a static HashMap). Production deployment should use the DB for all auth state.
10. **Single server only:** No full federation between servers yet. Persistent WS relay exists but full DNS discovery is planned.
11. **No push notifications:** Users must keep a WebSocket connection open or poll.
12. **Web client: no OTPKs:** The web client does not generate one-time pre-keys (cannot reliably store secrets). X3DH works without DH4, but replay protection is slightly weaker.
13. **Web client: localStorage only:** Seed and session data stored in browser localStorage. Clearing browser data = lost identity.
14. **No message ordering guarantees:** Messages may arrive out of order. The Double Ratchet handles this for decryption, but the UI does not reorder displayed messages.
---
## Roadmap: What's Next
### Phase 3 — Federation & Key Transparency (next priority)
### Priority Order (Updated v0.0.46)
- DNS TXT record format for server discovery
- User self-signed key publication to DNS
- Key verification: server vs DNS cross-check
- Server-to-server mutual TLS
- Federated message delivery
- Server key pinning (TOFU)
- Gossip-based peer discovery
### Phase 4 — Warzone Delivery
- Mule protocol specification and implementation
- Mule authentication and authorization
- Message pickup with capacity declaration
- Delivery receipt enforcement
- Outer encryption layer (hide metadata from mule)
- Bundle compression (zstd)
- Mule CLI binary
### Phase 5 — Transport Fallbacks
- Bluetooth mule transfer (phone-to-phone)
- LoRa transport layer (compact binary format)
- mDNS / LAN discovery for local mesh
- Wi-Fi Direct for nearby device sync
### Phase 6 — Metadata Protection
- Sealed sender (server doesn't know the sender)
- Onion routing between federated servers (opt-in)
- Padding and traffic shaping
- Traffic analysis resistance
### Phase 7 — Polish & Operations
- ntfy push notification integration
- DNS-over-HTTPS for censored networks
- Admin CLI for server management
- Rate limiting and abuse prevention
- Monitoring and health checks
- Audit logging
- Server-at-rest encryption (optional `--encrypt-db` flag)
- Cross-compilation CI (Linux x86/ARM, macOS, Windows, WASM)
- PWA: service worker, offline shell, install prompt
### Priority Order (Updated v0.0.21)
1. **Security (FC-P1)** — auth enforcement, rate limiting, device revocation
2. **TUI call integration (FC-P2)** — /call, /accept, /hangup commands
3. **Web call integration (FC-P3)** — WASM CallSignal + browser call UI
4. **Protocol hardening (FC-P4)** — session/message versioning
5. Federation (Phase 3) — multi-server deployment
6. Mule protocol (Phase 4) — physical delivery
7. Polish (FC-P6) — search, reactions, typing indicators
1. **TUI voice via cpal (FC-P7-T1)** — native audio capture/playback
2. **Web extract (FC-P3-T5)** — extract web.rs monolith into separate files
3. **MLS group E2E (FC-P5-T5)** — RFC 9420 for group call encryption
4. **Sender Keys for DM call E2E (FC-P7-T2)** — encrypted call signaling
5. **WebTransport (FC-P7-T3)** — replace wzp-web bridge
6. Federation (Phase 3) — DNS discovery + multi-server
7. Mule protocol (Phase 4) — physical delivery
8. Polish (FC-P6) — search, reactions, typing indicators, virtual scroll
See `TASK_PLAN.md` for the detailed task breakdown with IDs and dependencies.

View File

@@ -1,7 +1,7 @@
# Warzone Messenger (featherChat) — Security Model & Threat Analysis
**Version:** 0.0.21
**Last Updated:** 2026-03-29
**Version:** 0.0.46
**Last Updated:** 2026-03-30
---
@@ -24,6 +24,8 @@
| API write operations | Bearer token middleware on all POST routes |
| Device sessions | Kick/revoke-all, max 5 WS per fingerprint |
| Bot aliases | Reserved suffixes (Bot/bot/_bot) enforced |
| DM call signaling | E2E encrypted via WireMessage::CallSignal |
| Call room names | Hashed (not plaintext) on relay |
### What Is NOT Protected (Current)
@@ -37,6 +39,8 @@
| Online/offline status | Server knows when clients connect via WebSocket|
| IP addresses | Server sees client IP addresses |
| Bot messages | Plaintext (not E2E) in v1 — bots don't hold ratchet sessions |
| Group call media | Transport-only (QUIC TLS), not E2E — MLS planned |
| Admin commands | No role-based auth yet (TODO: admin role system) |
### Trust Boundaries
@@ -374,6 +378,47 @@ The web client does not generate one-time pre-keys because `localStorage` cannot
---
## Bot API Security
Bot messages are **plaintext** in v1 — bots do not hold Double Ratchet sessions. This is a deliberate trade-off for simplicity.
- **Per-bot numeric IDs:** The Bot API translates fingerprints to per-bot numeric user IDs. A bot never sees the real fingerprints of the users it communicates with, providing a privacy layer between bots and users.
- **BotFather token storage:** Bot tokens are stored in the server's sled database as `bot:<token>` entries. Tokens are generated server-side with 16 random bytes (32 hex characters). Treat tokens as secrets.
- **Plaintext v1:** Bot messages travel as plaintext between the client and server. The client auto-detects bot aliases (suffixes `Bot`, `bot`, `_bot`) and skips E2E encryption. Future versions may support bot-side ratchet sessions.
---
## Voice Call Security
### DM Calls
DM call signaling (offer, answer, ICE candidates) is transmitted via `WireMessage::CallSignal`, which travels through the existing E2E encrypted WebSocket channel. The signaling is encrypted with the Double Ratchet session between the two peers — the server cannot read call setup metadata.
### Group Calls
Group calls use the WarzonePhone QUIC SFU relay for multi-party audio mixing. Media is encrypted in transit via QUIC TLS (transport-layer encryption), but is **not E2E encrypted** — the relay can observe audio streams.
**MLS planned:** Future versions will use Message Layer Security (RFC 9420) for E2E encrypted group call media, where the relay handles only opaque ciphertext.
### Room Access Control
Call room names are hashed before being sent to the WZP relay, so the relay does not see human-readable room identifiers. The relay enforces ACL checks using the featherChat bearer token for room join authorization.
---
## Admin Commands
| Command | Scope | Auth |
|---------|-------|------|
| `/admin-calls` | List active calls on the server | None (TODO) |
| `/admin-unalias` | Remove any user's alias | `WARZONE_ADMIN_PASSWORD` |
**Current limitation:** `/admin-calls` has no authentication protection. Any connected client can invoke it. A proper admin role system (role assignment, challenge-based admin auth) is planned but not yet implemented.
`/admin-unalias` requires the `WARZONE_ADMIN_PASSWORD` environment variable to be set on the server and the client to provide the matching password.
---
## Known Weaknesses and Mitigations Planned
### 1. No Sealed Sender

View File

@@ -1,7 +1,7 @@
# featherChat Task Plan
**Version:** 0.0.21+
**Last Updated:** 2026-03-28
**Version:** 0.0.46
**Last Updated:** 2026-03-30
**Naming:** `FC-P{phase}-T{task}[-S{subtask}]`
---
@@ -31,18 +31,29 @@
### WZP Side (all 9 tasks done by WZP team)
- [x] WZP-S-1 through WZP-S-9: Identity alignment, relay auth, signaling bridge, room ACL, crypto handshake, web bridge auth, wzp-proto standalone, CLI seed input, hardcoded assumptions fixed
### Additional Completed Work (not in original plan)
- [x] ETH address integration — display everywhere TUI + Web (v0.0.22-0.0.24)
- [x] Federation persistent WS + text selection (v0.0.25-0.0.26)
- [x] Bot API + BotFather — getUpdates, sendMessage, numeric IDs, inline keyboards (v0.0.27-0.0.33)
- [x] Bot sendMessage fix, per-bot ID mapping (v0.0.34)
- [x] Markdown rendering in TUI + Web messages (v0.0.42)
- [x] Call ring tones (v0.0.45)
- [x] Group calls + group call fixes (v0.0.45-0.0.46)
- [x] Admin commands (v0.0.46)
- [x] Deploy scripts: build-linux.sh + build-bleeding.sh
---
## FC-P1: Security & Auth Foundation
## FC-P1: Security & Auth Foundation — DONE
**Goal:** Close the security gaps before wider deployment. Auth enforcement is the critical path.
| ID | Task | Effort | Dep | Status |
|----|------|--------|-----|--------|
| FC-P1-T1 | Auth enforcement middleware | 0.5d | — | TODO |
| FC-P1-T2 | Session auto-recovery | 1d | — | TODO |
| FC-P1-T3 | Rate limiting + connection guards | 0.5d | — | TODO |
| FC-P1-T4 | Device management + session revocation | 1d | T1 | TODO |
| FC-P1-T1 | Auth enforcement middleware | 0.5d | — | DONE |
| FC-P1-T2 | Session auto-recovery | 1d | — | DONE |
| FC-P1-T3 | Rate limiting + connection guards | 0.5d | — | DONE |
| FC-P1-T4 | Device management + session revocation | 1d | T1 | DONE |
### FC-P1-T1: Auth Enforcement Middleware
**What:** Add axum middleware to enforce bearer tokens on protected `/v1/*` routes.
@@ -88,47 +99,47 @@
---
## FC-P2: TUI Call Integration
## FC-P2: TUI Call Integration — DONE (v0.0.36-0.0.37)
**Goal:** Make call signaling work end-to-end in the TUI. Server infrastructure is ready (FC-2/3/5/6/7).
| ID | Task | Effort | Dep | Status |
|----|------|--------|-----|--------|
| FC-P2-T1 | `/call <fp>` command — send CallSignal::Offer | 0.5d | — | TODO |
| FC-P2-T2 | `/accept` + `/reject` commands | 0.5d | T1 | TODO |
| FC-P2-T3 | `/hangup` command | 0.25d | T1 | TODO |
| FC-P2-T4 | Call state machine (Idle/Ringing/Active/Ended) | 0.5d | T1 | TODO |
| FC-P2-T4-S1 | Incoming call notification banner | 0.25d | T4 | TODO |
| FC-P2-T4-S2 | In-call header indicator (duration, peer) | 0.25d | T4 | TODO |
| FC-P2-T5 | Missed call display (parse WS JSON) | 0.25d | — | TODO |
| FC-P2-T6 | `/contacts` online status via presence API | 0.25d | — | TODO |
| FC-P2-T1 | `/call <fp>` command — send CallSignal::Offer | 0.5d | — | DONE (v0.0.36) |
| FC-P2-T2 | `/accept` + `/reject` commands | 0.5d | T1 | DONE (v0.0.36) |
| FC-P2-T3 | `/hangup` command | 0.25d | T1 | DONE (v0.0.36) |
| FC-P2-T4 | Call state machine (Idle/Ringing/Active/Ended) | 0.5d | T1 | DONE (v0.0.37) |
| FC-P2-T4-S1 | Incoming call notification banner | 0.25d | T4 | DONE (v0.0.37) |
| FC-P2-T4-S2 | In-call header indicator (duration, peer) | 0.25d | T4 | DONE (v0.0.37) |
| FC-P2-T5 | Missed call display (parse WS JSON) | 0.25d | — | DONE (v0.0.37) |
| FC-P2-T6 | `/contacts` online status via presence API | 0.25d | — | DONE (v0.0.37) |
---
## FC-P3: Web Call Integration
## FC-P3: Web Call Integration — DONE (v0.0.35-0.0.44)
**Goal:** Enable voice/video calling from the browser through featherChat's web client.
| ID | Task | Effort | Dep | Status |
|----|------|--------|-----|--------|
| FC-P3-T1 | WASM: parse CallSignal in `decrypt_wire_message()` | 0.5d | — | TODO |
| FC-P3-T2 | WASM: `create_call_signal()` export for JS | 0.5d | — | TODO |
| FC-P3-T3 | Web client: call/accept/reject UI | 1d | T1, T2 | TODO |
| FC-P3-T4 | Web client: integrate wzp-web audio bridge | 1d | T3 | TODO |
| FC-P3-T1 | WASM: parse CallSignal in `decrypt_wire_message()` | 0.5d | — | DONE (v0.0.35) |
| FC-P3-T2 | WASM: `create_call_signal()` export for JS | 0.5d | — | DONE (v0.0.35) |
| FC-P3-T3 | Web client: call/accept/reject UI | 1d | T1, T2 | DONE (v0.0.36) |
| FC-P3-T4 | Web client: integrate wzp-web audio bridge | 1d | T3 | DONE (v0.0.43) |
| FC-P3-T5 | Extract web client from monolith (web.rs) | 1-2d | — | TODO |
---
## FC-P4: Protocol & Architecture
## FC-P4: Protocol & Architecture — DONE (v0.0.38-0.0.39)
**Goal:** Harden the protocol for forward compatibility and resilience.
| ID | Task | Effort | Dep | Status |
|----|------|--------|-----|--------|
| FC-P4-T1 | Session state versioning | 0.5d | — | TODO |
| FC-P4-T2 | WireMessage versioning (envelope format) | 1d | — | TODO |
| FC-P4-T3 | Periodic auto-backup | 0.5d | — | TODO |
| FC-P4-T4 | libsignal migration assessment | 1-2w | — | TODO |
| FC-P4-T1 | Session state versioning | 0.5d | — | DONE (v0.0.38) |
| FC-P4-T2 | WireMessage versioning (envelope format) | 1d | — | DONE (v0.0.38) |
| FC-P4-T3 | OTPK replenishment | 0.5d | — | DONE (v0.0.39) |
| FC-P4-T4 | Periodic auto-backup | 0.5d | — | DONE (v0.0.38) |
---
@@ -181,6 +192,20 @@
| FC-P6-T6 | Message wrapping for long text | 0.5d | — | DONE (v0.0.39) |
| FC-P6-T7 | Tab completion for commands/aliases | 0.5d | — | DONE (v0.0.39) |
| FC-P6-T8 | File transfer progress gauge | 0.5d | — | TODO |
| FC-P6-T9 | TUI address clipboard copy | 0.5d | — | TODO |
| FC-P6-T10 | Web virtual scroll for large history | 0.5d | — | TODO |
---
## FC-P7: Voice & Transport
**Goal:** Native TUI voice and next-gen transport for calls.
| ID | Task | Effort | Dep | Status |
|----|------|--------|-----|--------|
| FC-P7-T1 | TUI voice calls via cpal | 1-2d | — | TODO |
| FC-P7-T2 | Sender Keys for DM call E2E | 1w | — | TODO |
| FC-P7-T3 | WebTransport to replace wzp-web bridge | 2w | — | TODO |
---
@@ -188,7 +213,7 @@
Tasks with **no dependencies** that can run simultaneously:
**Sprint A (Security — P1):**
**Sprint A (Security — P1):** DONE
```
FC-P1-T1 (auth middleware) — server only
FC-P1-T2 (session recovery) — client only
@@ -196,7 +221,7 @@ FC-P1-T3 (rate limiting) — server only
→ then FC-P1-T4 (devices, needs T1)
```
**Sprint B (TUI Calls — P2):**
**Sprint B (TUI Calls — P2):** DONE
```
FC-P2-T1 (call command) → T2 (accept/reject) → T3 (hangup)
FC-P2-T4 (state machine) → T4-S1 (banner) + T4-S2 (header)
@@ -204,11 +229,11 @@ FC-P2-T5 (missed calls) — independent
FC-P2-T6 (contacts online) — independent
```
**Sprint C (Web — P3):**
**Sprint C (Web — P3):** DONE (except T5)
```
FC-P3-T1 (WASM parse) — independent
FC-P3-T2 (WASM create) — independent
FC-P3-T5 (extract web.rs) — independent
FC-P3-T5 (extract web.rs) — independent (TODO)
→ then T3 (call UI) → T4 (audio)
```
@@ -258,4 +283,5 @@ warzone-client/src/tui/
| warzone-client (types) | 10 | App init, ChatLine, normfp |
| warzone-client (input) | 25 | All keybindings, scroll, text editing |
| warzone-client (draw) | 9 | Rendering, timestamps, scroll, connection dot, unread badge |
| **Total** | **72** | All passing |
| warzone-server | 10+ | Server integration tests |
| **Total** | **~155** | All passing |

View File

@@ -1,6 +1,6 @@
# featherChat End-to-End Testing Guide
**Version:** 0.0.43
**Version:** 0.0.46
---
@@ -379,6 +379,76 @@ while True:
---
## Test 16: Ring Tones
### Steps (Web ↔ Web)
1. **User A**: Set peer to User B
2. **User A**: Click Call button (or `/call`)
3. **User A**: Listen for outgoing ringback tone (repeating double beep)
4. **User B**: Listen for incoming ring tone (classic ring pattern)
5. **User B**: Click Accept
6. Both: Ring tones should stop immediately
7. Repeat: User A calls, User B rejects — tones should stop on reject
8. Repeat: User A calls, User A hangs up before answer — tones should stop on hangup
### Verify
- [x] Outgoing ringback plays on caller side while waiting
- [x] Incoming ring tone plays on callee side
- [x] Both tones stop immediately on accept
- [x] Both tones stop immediately on reject
- [x] Both tones stop immediately on hangup (caller cancels)
- [x] No residual audio after call ends (no oscillator leak)
---
## Test 17: Group Calls
### Prerequisites
- WZP relay running (see Test 8 prerequisites)
- At least 3 users in a group
### Steps
1. **User A, B, C**: All join group via `/g testgroup`
2. **User A**: `/gcall` — starts group voice call
3. **User B**: Should see group call notification
4. **User B**: `/gjoin` — joins the active group call
5. Both A and B: Should hear each other's audio
6. **User C**: `/gjoin` — joins, now 3 participants
7. Verify participant count shows 3
8. **User B**: `/gleave-call` — leaves call but stays in text group
9. **User B**: Can still send text messages in the group
10. **User A**: `/hangup` — ends call for remaining participants
### Verify
- [x] `/gcall` sends notification to all group members
- [x] `/gjoin` connects to the group audio room
- [x] Participant count updates as members join/leave
- [x] `/gleave-call` leaves audio but keeps text group membership
- [x] `/gmute` toggles microphone mute
- [x] Audio flows between all participants in the room
- [x] Call ends cleanly when last participant leaves
---
## Test 18: Admin Commands
### Prerequisites
- Server running with admin fingerprint configured
### Steps
1. **Admin user**: `/admin-help` — should list available admin commands
2. **Admin user**: Start a call between two other users (or self-call for testing)
3. **Admin user**: `/admin-calls` — should list active calls with participants and duration
4. **Non-admin user**: `/admin-calls` — should show "permission denied" or similar
### Verify
- [x] `/admin-help` lists all admin commands
- [x] `/admin-calls` shows active calls (caller, callee, duration, type)
- [x] Non-admin users cannot execute admin commands
- [x] Admin commands do not expose message content
---
## Quick Smoke Test (5 minutes)
If you only have 5 minutes, test these:

View File

@@ -1,6 +1,6 @@
# featherChat Usage Guide
**Version:** 0.0.21
**Version:** 0.0.46
---
@@ -311,6 +311,63 @@ The web client supports the same slash commands as the TUI: `/peer`, `/p`, `/r`,
| `/reject` | Reject incoming call |
| `/hangup` | End current call |
### Group Calls
Group calls allow multi-party audio within a group context. Any group member can initiate a call, and others can join at any time.
| Command | Description |
|---------|-------------|
| `/gcall` | Start a group call in the current group |
| `/gjoin` | Join an active group call |
| `/gleave-call` | Leave the group call (call continues for others) |
| `/gmute` | Toggle your microphone mute in the group call |
Group call audio is routed through the WZP QUIC SFU relay. Media is transport-encrypted (QUIC TLS) but not E2E encrypted -- the relay can observe audio streams. MLS-based E2E encryption for group calls is planned.
---
## Read Receipts
featherChat tracks message delivery and read status with three indicators:
| Indicator | Symbol | Meaning |
|-----------|--------|---------|
| Sent | Single gray tick | Message sent to server, no confirmation yet |
| Delivered | Double gray tick | Recipient decrypted the message |
| Read | Double blue tick | Recipient viewed the message in their viewport |
Read receipts are sent automatically when messages enter the visible area of the chat window. The system uses the sender's fingerprint for tracking and a dedup set to avoid sending duplicate read receipts for the same message.
---
## Markdown Formatting
Messages support markdown formatting in both the TUI and web client:
| Syntax | Result |
|--------|--------|
| `**bold**` | **bold** |
| `*italic*` | *italic* |
| `` `code` `` | `inline code` |
| `# Header` | Header (at start of line) |
| `> quote` | Block quote (at start of line) |
| `- item` | List item (at start of line) |
Markdown is rendered inline in messages. In the TUI, bold, italic, and code spans use terminal attributes. In the web client, they render as HTML.
---
## Admin Commands
Server administration commands for operators:
| Command | Description |
|---------|-------------|
| `/admin-calls` | List all active calls on the server |
| `/admin-unalias <alias>` | Remove any user's alias (requires admin password) |
`/admin-unalias` prompts for the server's admin password (set via `WARZONE_ADMIN_PASSWORD` environment variable). `/admin-calls` currently has no auth protection -- an admin role system is planned.
---
## Groups