docs: CLAUDE.md design principles, update ARCHITECTURE + SECURITY
- CLAUDE.md: design principles (E2E by default, semi-trusted server, federation transparency, TG bot compat), coding conventions for Rust/TUI/ WASM/federation/bots, task naming, key files reference - ARCHITECTURE.md: added bots to high-level diagram, friends/bot/resolve modules, 9 sled trees (was 7), bot API sequence diagram, addressing table, federated features table, test count 72→122 - SECURITY.md: v0.0.21, added friend list/API auth/device/bot alias to protected assets, auth & authorization section, rate limiting, session recovery Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
78
warzone/CLAUDE.md
Normal file
78
warzone/CLAUDE.md
Normal file
@@ -0,0 +1,78 @@
|
||||
# featherChat — Design Principles & Conventions
|
||||
|
||||
## Architecture Principles
|
||||
|
||||
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).
|
||||
|
||||
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.
|
||||
|
||||
4. **Federation is transparent** — Users don't need to know which server their peer is on. Key lookup, alias resolution, and message delivery automatically proxy through federation.
|
||||
|
||||
5. **Telegram Bot API compatibility** — Bot API follows Telegram conventions (getUpdates, sendMessage, token-in-URL). Bot aliases must end with Bot/bot/_bot.
|
||||
|
||||
6. **Auth on writes, open reads** — All POST/write endpoints require bearer tokens. GET/read endpoints are public (needed for key exchange before auth is possible).
|
||||
|
||||
## Coding Conventions
|
||||
|
||||
### Rust
|
||||
- Workspace crates: protocol (no I/O), server (axum), client (ratatui), wasm (wasm-bindgen), mule (future)
|
||||
- Error handling: `AppResult<T>` in server, `anyhow::Result` in client, `ProtocolError` in protocol
|
||||
- State: `AppState` with `Arc<Mutex<>>` for shared state, `Arc<Database>` for sled
|
||||
- Auth: `AuthFingerprint` extractor as first handler param for protected routes
|
||||
- Fingerprints: always normalize with `normfp()` (strip non-hex, lowercase)
|
||||
- New routes: create `routes/<name>.rs`, add `pub fn routes() -> Router<AppState>`, merge in `routes/mod.rs`
|
||||
|
||||
### TUI
|
||||
- 7 modules in `tui/`: types, draw, commands, input, file_transfer, network, mod
|
||||
- All ChatLine must include `timestamp: Local::now()`
|
||||
- Add new commands to both the handler chain AND `/help` text
|
||||
- Self-messaging prevention: check `normfp(&peer) != normfp(&self.our_fp)`
|
||||
|
||||
### Web (WASM)
|
||||
- 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
|
||||
|
||||
### Federation
|
||||
- Persistent WS between servers, NOT HTTP polling
|
||||
- Presence re-pushed every 10s + on connect
|
||||
- Key lookup: proxy to peer for non-local fingerprints (never cache remote bundles)
|
||||
- Alias resolution: fall back to peer if not found locally
|
||||
- Registration: check peer to enforce global uniqueness
|
||||
|
||||
### Bot API
|
||||
- Token stored as `bot:<token>` in tokens tree
|
||||
- Reverse lookup: `bot_fp:<fingerprint>` → token
|
||||
- Alias auto-registered on bot creation with `_bot` suffix
|
||||
- Reserved aliases: `*Bot`, `*bot`, `*_bot` blocked for non-bots
|
||||
|
||||
## Task Naming
|
||||
|
||||
`FC-P{phase}-T{task}[-S{subtask}]`
|
||||
|
||||
See `docs/TASK_PLAN.md` for the full breakdown.
|
||||
|
||||
## Testing
|
||||
|
||||
- Protocol: unit tests in each module's `#[cfg(test)]`
|
||||
- TUI: unit tests for types, input, draw (using ratatui TestBackend)
|
||||
- WASM: can't test natively (js-sys dependency) — test equivalent logic in protocol crate
|
||||
- Server: no integration tests yet (planned)
|
||||
|
||||
## Key Files
|
||||
|
||||
| What | Where |
|
||||
|------|-------|
|
||||
| Wire format | `warzone-protocol/src/message.rs` |
|
||||
| Crypto primitives | `warzone-protocol/src/crypto.rs` |
|
||||
| Server state | `warzone-server/src/state.rs` |
|
||||
| All routes | `warzone-server/src/routes/mod.rs` |
|
||||
| Federation | `warzone-server/src/federation.rs` |
|
||||
| TUI commands | `warzone-client/src/tui/commands.rs` |
|
||||
| Web client | `warzone-server/src/routes/web.rs` |
|
||||
| WASM bridge | `warzone-wasm/src/lib.rs` |
|
||||
| Task plan | `docs/TASK_PLAN.md` |
|
||||
| Bot API docs | `docs/BOT_API.md` |
|
||||
| LLM help ref | `docs/LLM_HELP.md` |
|
||||
@@ -12,11 +12,11 @@ graph TB
|
||||
CLI[CLI Client] --> PROTO[warzone-protocol]
|
||||
TUI[TUI Client] --> PROTO
|
||||
WEB[Web Client WASM] --> PROTO
|
||||
BOT[Bots TG API] -->|HTTP| SRVA
|
||||
PROTO -->|HTTP / WS| SRVA[Server Alpha]
|
||||
PROTO -->|HTTP / WS| SRVB[Server Bravo]
|
||||
SRVA <-->|Federation WS| SRVB
|
||||
SRVA -->|Call Signaling| WZP[WarzonePhone Relay]
|
||||
SRVB -->|Call Signaling| WZP
|
||||
```
|
||||
|
||||
---
|
||||
@@ -78,6 +78,7 @@ warzone/
|
||||
| `sender_keys` | Sender Key protocol for group encryption |
|
||||
| `history` | Encrypted backup/restore |
|
||||
| `ethereum` | secp256k1, Keccak-256, Ethereum address derivation |
|
||||
| `friends` | E2E encrypted friend list (encrypt/decrypt with HKDF key) |
|
||||
| `types` | Fingerprint, DeviceId, SessionId, MessageId |
|
||||
|
||||
### warzone-server
|
||||
@@ -86,7 +87,7 @@ warzone/
|
||||
|----------------------|---------------------------------------------------|
|
||||
| `main` | CLI args, startup, federation init |
|
||||
| `state` | AppState, Connections, CallState, DedupTracker |
|
||||
| `db` | 7 sled trees: keys, messages, groups, aliases, tokens, calls, missed_calls |
|
||||
| `db` | 9 sled trees: keys, messages, groups, aliases, tokens, calls, missed_calls, friends, eth_addresses |
|
||||
| `federation` | Peer config, presence sync, message forwarding |
|
||||
| `auth_middleware` | Bearer token extractor (401 on protected routes) |
|
||||
| `routes/auth` | Challenge-response authentication |
|
||||
@@ -100,6 +101,9 @@ warzone/
|
||||
| `routes/wzp` | WZP relay config + service token |
|
||||
| `routes/aliases` | Alias CRUD with TTL + recovery keys |
|
||||
| `routes/keys` | Pre-key bundle registration & retrieval |
|
||||
| `routes/friends` | Encrypted friend list blob storage (GET/POST) |
|
||||
| `routes/bot` | Telegram Bot API compatibility layer |
|
||||
| `routes/resolve` | Address resolution (ETH/alias/fingerprint → fp) |
|
||||
|
||||
### warzone-client (TUI)
|
||||
|
||||
@@ -238,6 +242,13 @@ Public (no auth):
|
||||
GET /v1/wzp/relay-config WZP relay address + token
|
||||
GET /v1/federation/status Federation health
|
||||
GET /v1/ws/:fp WebSocket upgrade
|
||||
GET /v1/friends Encrypted friend list (auth)
|
||||
POST /v1/friends Save friend list (auth)
|
||||
GET /v1/resolve/:address ETH/alias/fp resolution
|
||||
POST /v1/bot/register Register a bot
|
||||
GET /v1/bot/:token/getMe Bot identity
|
||||
POST /v1/bot/:token/getUpdates Long-poll for messages
|
||||
POST /v1/bot/:token/sendMessage Send message as bot
|
||||
POST /v1/auth/challenge|verify|validate
|
||||
|
||||
Federation (HMAC-authenticated, server-to-server):
|
||||
@@ -366,6 +377,16 @@ sequenceDiagram
|
||||
| Peer restarts | Presence repopulates on WS reconnect |
|
||||
| HMAC mismatch | Request rejected with 401 |
|
||||
|
||||
### Federated Features
|
||||
|
||||
| Feature | How it works |
|
||||
|---------|-------------|
|
||||
| Message forwarding | deliver_or_queue() checks remote presence, forwards via WS |
|
||||
| Key lookup | get_bundle() proxies to peer if fingerprint is not local |
|
||||
| Alias resolution | resolve_alias() falls back to peer server |
|
||||
| ETH resolution | resolve endpoint checks peer via HTTP |
|
||||
| Presence | Bidirectional sync every 10s + on-connect |
|
||||
|
||||
---
|
||||
|
||||
## Call Infrastructure (WZP Integration)
|
||||
@@ -438,6 +459,51 @@ flowchart LR
|
||||
|
||||
---
|
||||
|
||||
## Bot API (Telegram-Compatible)
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Dev as Bot Developer
|
||||
participant S as featherChat Server
|
||||
participant U as User
|
||||
|
||||
Dev->>S: POST /v1/bot/register {name, fp}
|
||||
S->>Dev: {token, alias: "@mybot_bot"}
|
||||
|
||||
loop Long-poll
|
||||
Dev->>S: POST /bot/:token/getUpdates
|
||||
S->>Dev: [updates...]
|
||||
end
|
||||
|
||||
U->>S: Message to @mybot_bot
|
||||
S->>S: Queue for bot fp
|
||||
Dev->>S: getUpdates → receives message
|
||||
Dev->>S: POST /bot/:token/sendMessage
|
||||
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)
|
||||
- Messages from users arrive as encrypted blobs (base64) or plaintext bot messages
|
||||
|
||||
### Addressing
|
||||
|
||||
Three address formats, all interchangeable:
|
||||
|
||||
| Format | Example | Usage |
|
||||
|--------|---------|-------|
|
||||
| Fingerprint | `522d:4d6e:a8ee:588a:...` | Internal routing, crypto |
|
||||
| ETH address | `0x742d35Cc6634C0532...` | User-facing display |
|
||||
| Alias | `@alice`, `@weatherbot` | Human-friendly |
|
||||
|
||||
Resolution: `GET /v1/resolve/:address` accepts any format, returns fingerprint.
|
||||
ETH↔fingerprint mapping stored on key registration.
|
||||
|
||||
---
|
||||
|
||||
## Security Model
|
||||
|
||||
### What's Protected
|
||||
@@ -491,7 +557,7 @@ graph TB
|
||||
|
||||
## Storage Model
|
||||
|
||||
### Server sled Trees (7)
|
||||
### Server sled Trees (9)
|
||||
|
||||
| Tree | Key Format | Value |
|
||||
|----------------|---------------------------|--------------------------|
|
||||
@@ -502,6 +568,8 @@ graph TB
|
||||
| `tokens` | `<token_hex>` | JSON {fp, expires_at} |
|
||||
| `calls` | `<call_id>` | JSON CallState |
|
||||
| `missed_calls` | `missed:<fp>:<call_id>` | JSON {caller, timestamp} |
|
||||
| `friends` | `<fingerprint>` | Encrypted blob (ChaCha20) |
|
||||
| `eth_addresses` | `0x...` or `rev:<fp>` | ETH↔fingerprint mapping |
|
||||
|
||||
### Client sled Trees (5)
|
||||
|
||||
@@ -519,11 +587,11 @@ graph TB
|
||||
|
||||
| Crate | Tests | Coverage |
|
||||
|-------|------:|---------|
|
||||
| warzone-protocol | 28 | X3DH, Double Ratchet, Sender Keys, AEAD, HKDF, identity, ethereum, prekeys, mnemonic |
|
||||
| warzone-protocol | 34 | X3DH, Double Ratchet, Sender Keys, AEAD, HKDF, identity, ethereum, prekeys, mnemonic, friend list, x3dh web client |
|
||||
| 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** | **72** | All passing |
|
||||
| **Total** | **122** | All passing |
|
||||
|
||||
WZP side: 15 cross-project identity tests + 17 integration tests (separate repo).
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Warzone Messenger (featherChat) — Security Model & Threat Analysis
|
||||
|
||||
**Version:** 0.0.20
|
||||
**Last Updated:** 2026-03-28
|
||||
**Version:** 0.0.21
|
||||
**Last Updated:** 2026-03-29
|
||||
|
||||
---
|
||||
|
||||
@@ -20,6 +20,10 @@
|
||||
| Session state | Encrypted backup (HKDF + ChaCha20-Poly1305) |
|
||||
| Pre-key authenticity | Ed25519 signature on signed pre-keys |
|
||||
| Key exchange integrity | X3DH with 3-4 DH operations |
|
||||
| Friend list | E2E encrypted blob (ChaCha20 + HKDF-derived key) |
|
||||
| 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 |
|
||||
|
||||
### What Is NOT Protected (Current)
|
||||
|
||||
@@ -32,6 +36,7 @@
|
||||
| Message sizes | Server sees encrypted message sizes |
|
||||
| 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 |
|
||||
|
||||
### Trust Boundaries
|
||||
|
||||
@@ -63,6 +68,34 @@
|
||||
└─────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### Authentication & Authorization
|
||||
|
||||
- Challenge-response: Ed25519 signature over random challenge
|
||||
- Bearer tokens: 7-day TTL, required on all write endpoints
|
||||
- Auth middleware: `AuthFingerprint` extractor returns 401 on invalid/missing token
|
||||
- Bot tokens: separate namespace (`bot:<token>`), validated per-request
|
||||
- Federation: shared secret compared on WS auth frame
|
||||
|
||||
Protected endpoints (require bearer token):
|
||||
- messages/send, groups/*, aliases/*, calls/*, devices/*, friends, presence/batch
|
||||
|
||||
Public endpoints (no auth):
|
||||
- keys/:fp, messages/poll, groups GET, alias/resolve, resolve/:address, bot/*
|
||||
|
||||
### Rate Limiting & Abuse Prevention
|
||||
|
||||
- Global: 200 concurrent requests (tower ConcurrencyLimitLayer)
|
||||
- Per-fingerprint: max 5 WebSocket connections
|
||||
- Stale connections auto-cleaned on new registrations
|
||||
- Federation: auto-reconnect with 3s backoff (no amplification)
|
||||
|
||||
### Session Recovery
|
||||
|
||||
On ratchet decryption failure:
|
||||
1. Corrupted session deleted from local DB
|
||||
2. Warning shown: "[session reset]"
|
||||
3. Next KeyExchange re-establishes the session automatically
|
||||
|
||||
---
|
||||
|
||||
## Cryptographic Primitives
|
||||
|
||||
Reference in New Issue
Block a user