UAT/PHASE1.md — 20 test scenarios, 80+ checkboxes Identity, encryption, messaging, TUI, web, groups, aliases, auth, OTP replenishment, session persistence, cross-client UAT/PHASE2.md — 7 scenarios (WASM, receipts, files, multi-device, HW wallet, groups, history) UAT/PHASE3.md — 6 scenarios (DNS discovery, key transparency, federation, mutual TLS, gossip) UAT/PHASE4.md — 10 scenarios (mule identity, pickup, delivery, receipts, dedup, expiry, compression) UAT/PHASE5.md — 6 scenarios (Bluetooth, LoRa, mDNS, Wi-Fi Direct, USB export, fallback chain) UAT/PHASE6.md — 3 scenarios (sealed sender, traffic analysis resistance, onion routing) UAT/PHASE7.md — 8 scenarios (ntfy, DoH, DB encryption, admin CLI, rate limiting, audit, CI, monitoring) Each test has exact commands to run and checkboxes for pass/fail. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
12 KiB
Phase 1 — User Acceptance Testing
Prerequisites
cd warzone
cargo build
rm -rf warzone-data # clean server DB
Open 3 terminals:
- T1: Server
- T2: Alice (default
~/.warzone) - T3: Bob (
WARZONE_HOME=/tmp/bob)
1. Server Startup
T1:
cargo run --bin warzone-server
- Server prints "Listening on 0.0.0.0:7700"
curl http://localhost:7700/v1/healthreturns{"status":"ok","version":"0.1.0"}http://localhost:7700/loads the web UI in a browser
2. Identity Generation
T2 (Alice):
cargo run --bin warzone-client -- init
- Prompted "Set passphrase (empty for no encryption):"
- Input is hidden (no echo)
- Prompted "Confirm passphrase:"
- Fingerprint displayed in format
xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx - 24-word BIP39 mnemonic displayed
- Seed path shown (e.g.
/Users/you/.warzone/identity.seed) - "Generated 1 signed pre-key + 10 one-time pre-keys" shown
- File
~/.warzone/identity.seedexists - File
~/.warzone/bundle.binexists - File permissions on identity.seed are 600 (Unix):
ls -la ~/.warzone/identity.seed
T3 (Bob):
WARZONE_HOME=/tmp/bob cargo run --bin warzone-client -- init
- Bob gets a different fingerprint than Alice
- Seed saved to
/tmp/bob/identity.seed - Bob's mnemonic is different from Alice's
3. Seed Encryption
T2 (Alice):
cargo run --bin warzone-client -- info
- Prompted for passphrase (if one was set during init)
- Fingerprint, signing key, and encryption key displayed
- Same fingerprint as during init
- Wrong passphrase shows "Wrong passphrase" error
Test plaintext seed (empty passphrase):
WARZONE_HOME=/tmp/test cargo run --bin warzone-client -- init
# press Enter twice for empty passphrase
xxd /tmp/test/identity.seed | head -1
- File is exactly 32 bytes (raw seed, no encryption header)
Test encrypted seed:
xxd ~/.warzone/identity.seed | head -1
- File starts with
575a 5331(hex for "WZS1" magic bytes) - File is larger than 32 bytes (salt + nonce + ciphertext)
4. Mnemonic Recovery
WARZONE_HOME=/tmp/recovered cargo run --bin warzone-client -- recover <paste 24 words from Alice's init>
- "Identity recovered!" shown
- Fingerprint matches Alice's original fingerprint
WARZONE_HOME=/tmp/recovered cargo run --bin warzone-client -- infoshows same keys
5. Key Registration
T2 (Alice):
cargo run --bin warzone-client -- register -s http://localhost:7700
- "Bundle registered with http://localhost:7700"
T3 (Bob):
WARZONE_HOME=/tmp/bob cargo run --bin warzone-client -- register -s http://localhost:7700
- "Bundle registered with http://localhost:7700"
Verify on server:
curl http://localhost:7700/v1/keys/list
- JSON shows 2 keys with Alice's and Bob's fingerprints (hex, no colons)
Verify lookup works:
curl http://localhost:7700/v1/keys/<bob-fingerprint-no-colons>
- Returns JSON with
fingerprintandbundle(base64 string) - Does NOT return 404
6. 1:1 E2E Encrypted Messaging (CLI)
T2 (Alice sends to Bob):
cargo run --bin warzone-client -- send "<bob-fingerprint>" "Hello from Alice" -s http://localhost:7700
- "No existing session. Fetching key bundle for ..."
- "Message sent to "
T3 (Bob receives):
WARZONE_HOME=/tmp/bob cargo run --bin warzone-client -- recv -s http://localhost:7700
- "Received 1 message(s):"
[new session] <alice-fingerprint>: Hello from Alice
Bob sends reply:
WARZONE_HOME=/tmp/bob cargo run --bin warzone-client -- send "<alice-fingerprint>" "Hi Alice, Bob here" -s http://localhost:7700
- "Message sent to ..." (no "new session" — reuses existing ratchet)
Alice receives:
cargo run --bin warzone-client -- recv -s http://localhost:7700
[new session] <bob-fingerprint>: Hi Alice, Bob here
7. Fetch-and-Delete (No Duplicate Delivery)
T3 (Bob polls again):
WARZONE_HOME=/tmp/bob cargo run --bin warzone-client -- recv -s http://localhost:7700
- "No new messages." (Alice's message was deleted on first poll)
8. TUI Chat (CLI)
T2 (Alice):
cargo run --bin warzone-client -- chat "<bob-fingerprint>" -s http://localhost:7700
T3 (Bob):
WARZONE_HOME=/tmp/bob cargo run --bin warzone-client -- chat "<alice-fingerprint>" -s http://localhost:7700
- Both TUIs launch with header showing fingerprints
- Alice types "hello from TUI" → Enter
- Message appears in green on Alice's screen
- Within 2 seconds, message appears in yellow on Bob's screen
- Bob types "reply from Bob" → Enter
- Message appears on both screens
/infoshows fingerprint/quitexits TUI cleanly (terminal restored)- Ctrl+C also exits cleanly
- Esc also exits cleanly
9. Groups (CLI TUI)
T2 (Alice, in TUI):
/g ops
- "Joined 'ops'" or "Group 'ops' auto-created"
- "Switched to group #ops"
T3 (Bob, in TUI):
/g ops
- "Joined 'ops'"
- "Switched to group #ops"
Alice types a message:
hello team
- Message appears on Alice's screen with
[#ops]tag - Message appears on Bob's screen within 2 seconds
Bob replies:
hey alice!
- Appears on both screens
Test group list:
/glist
- Shows
#ops (2 members)
Switch back to DM:
/dm
- "Switched to DM mode"
10. Aliases (CLI TUI)
T2 (Alice, in TUI):
/alias alice
- "Alias @alice registered"
T3 (Bob, in TUI):
/alias bob
- "Alias @bob registered"
Alice sets peer by alias:
/peer @bob
- "@bob → " resolved
- "Peer set to "
List aliases:
/aliases
- Shows
@alice → <fp>and@bob → <fp>
11. Web UI — Identity
Open http://localhost:7700/ in a browser.
- "WARZONE" title and "Generate Identity" button shown
- Click "Generate Identity"
- Fingerprint displayed in green
- Hex seed displayed in orange
- "Enter Chat" button shown
- Click "Enter Chat"
- Chat screen loads with header showing fingerprint
- "Key registered with server" message appears
- Refresh page → auto-loads identity (no setup screen)
12. Web UI — DM
Open TWO browser tabs/windows (or incognito for second identity).
Tab 1: Generate identity → Enter Chat Tab 2: Generate identity → Enter Chat
Tab 1: Paste Tab 2's fingerprint in peer input field. Type "hello from tab 1". Enter.
- Message appears in green on Tab 1
- Message appears with lock icon on Tab 2 within 2 seconds
Tab 2: Paste Tab 1's fingerprint. Type "hello back". Enter.
- Message appears on both tabs
13. Web UI — Groups
Tab 1:
/g webteam
- "Joined group" and "Switched to group" messages
Tab 2:
/g webteam
- Also joined
Tab 1: Type "hello webteam" → Enter
- Message appears on Tab 1 with
[webteam]tag - Message appears on Tab 2 within 2 seconds
14. Web UI — Aliases
Tab 1:
/alias webuser1
- "Alias @webuser1 registered"
Tab 1:
/info
- Shows fingerprint with
(@webuser1)suffix
Tab 2: Set peer input to @webuser1. Type message. Enter.
- Message delivered (alias resolved to fingerprint)
15. Alias TTL & Recovery
Register alias via curl:
curl -X POST http://localhost:7700/v1/alias/register \
-H 'Content-Type: application/json' \
-d '{"alias":"testuser","fingerprint":"<alice-fp-no-colons>"}'
- Response includes
recovery_key(32-char hex) - Response includes
expires_in_days: 365 - SAVE THE RECOVERY KEY
Check alias:
curl http://localhost:7700/v1/alias/resolve/testuser
- Returns fingerprint +
expires_in_days
Recover alias to new fingerprint:
curl -X POST http://localhost:7700/v1/alias/recover \
-H 'Content-Type: application/json' \
-d '{"alias":"testuser","recovery_key":"<saved-key>","new_fingerprint":"<bob-fp-no-colons>"}'
- "ok: true"
new_recovery_keyreturned (rotated)
Verify transfer:
curl http://localhost:7700/v1/alias/resolve/testuser
- Now points to Bob's fingerprint
Wrong recovery key:
curl -X POST http://localhost:7700/v1/alias/recover \
-H 'Content-Type: application/json' \
-d '{"alias":"testuser","recovery_key":"wrong","new_fingerprint":"aaaa"}'
- "error: invalid recovery key"
16. Server Auth (Challenge-Response)
Request challenge:
curl -X POST http://localhost:7700/v1/auth/challenge \
-H 'Content-Type: application/json' \
-d '{"fingerprint":"<alice-fp-no-colons>"}'
- Returns
challenge(64-char hex) andexpires_at(unix timestamp) - Challenge expires in ~60 seconds
17. OTP Key Replenishment
Check count:
curl http://localhost:7700/v1/keys/<alice-fp-no-colons>/otpk-count
- Returns
otpk_count(number, may be 0 if not yet stored separately)
Replenish:
curl -X POST http://localhost:7700/v1/keys/replenish \
-H 'Content-Type: application/json' \
-d '{"fingerprint":"<alice-fp-no-colons>","otpks":[{"id":100,"public_key":"aa"},{"id":101,"public_key":"bb"}]}'
- Returns
stored: 2andtotalcount
Verify count increased:
curl http://localhost:7700/v1/keys/<alice-fp-no-colons>/otpk-count
otpk_countincreased by 2
18. Protocol Unit Tests
cargo test -p warzone-protocol
identity::tests::deterministic_derivation— PASSidentity::tests::mnemonic_roundtrip— PASSidentity::tests::fingerprint_display— PASSmnemonic::tests::roundtrip— PASScrypto::tests::aead_roundtrip— PASScrypto::tests::aead_wrong_key_fails— PASScrypto::tests::aead_wrong_aad_fails— PASScrypto::tests::hkdf_deterministic— PASSprekey::tests::signed_pre_key_verify— PASSprekey::tests::signed_pre_key_reject_tampered— PASSprekey::tests::generate_otpks— PASSx3dh::tests::x3dh_shared_secret_matches— PASSratchet::tests::basic_exchange— PASSratchet::tests::bidirectional— PASSratchet::tests::multiple_messages_same_direction— PASSratchet::tests::out_of_order— PASSratchet::tests::many_messages— PASS
Total: 17/17 PASS
19. Session Persistence
T2 (Alice, send then quit):
cargo run --bin warzone-client -- send "<bob-fp>" "message 1" -s http://localhost:7700
cargo run --bin warzone-client -- send "<bob-fp>" "message 2" -s http://localhost:7700
- First send says "No existing session" (X3DH)
- Second send does NOT say "No existing session" (reuses saved ratchet)
ls ~/.warzone/db/shows sled database files
T3 (Bob receives both):
WARZONE_HOME=/tmp/bob cargo run --bin warzone-client -- recv -s http://localhost:7700
- Both messages decrypted correctly
- Messages in order
20. Cross-Client Compatibility
Web → CLI:
Web Tab sends message to CLI Alice's fingerprint.
- CLI
recvshows[encrypted message from CLI client — use CLI to read]OR fails gracefully - No crash on either side
CLI → Web:
CLI Alice sends to Web Tab's fingerprint.
- Web shows graceful error (different crypto) or ignores silently
- No crash on either side
Note: Web↔CLI interop requires WASM bridge (Phase 2). Currently incompatible crypto is expected.
Summary
| # | Feature | Result |
|---|---|---|
| 1 | Server startup | ☐ |
| 2 | Identity generation | ☐ |
| 3 | Seed encryption | ☐ |
| 4 | Mnemonic recovery | ☐ |
| 5 | Key registration | ☐ |
| 6 | 1:1 E2E messaging | ☐ |
| 7 | Fetch-and-delete | ☐ |
| 8 | TUI chat | ☐ |
| 9 | Groups (CLI) | ☐ |
| 10 | Aliases (CLI) | ☐ |
| 11 | Web UI identity | ☐ |
| 12 | Web UI DM | ☐ |
| 13 | Web UI groups | ☐ |
| 14 | Web UI aliases | ☐ |
| 15 | Alias TTL & recovery | ☐ |
| 16 | Server auth | ☐ |
| 17 | OTP replenishment | ☐ |
| 18 | Protocol tests (17/17) | ☐ |
| 19 | Session persistence | ☐ |
| 20 | Cross-client compat | ☐ |
Tester: _______________
Date: _______________
Build: cargo build commit hash: _______________