archy/docs/MASTER_PLAN.md
2026-03-18 09:56:40 +00:00

187 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# MASTER PLAN
> Archipelago project task tracking and roadmap.
## Roadmap
| ID | Title | Priority | Status | Dependencies |
|----|-------|----------|--------|--------------|
| **BUG-1** | **Random logout / CSRF mismatch** | **P0** | PLANNED | - |
| **TASK-2** | **Roll incoming-tx into deploy & ISO** | **P2** | PLANNED | - |
| **BUG-3** | **IndeedHub WebSocket spam in console** | **P2** | PLANNED | - |
| **FEATURE-4** | **Onboarding loading screen with progress** | **P1** | IN PROGRESS | - |
| **INQUIRY-5** | **Offline balance check via mesh relay** | **P2** | PLANNED | - |
| **FEATURE-6** | **Watch-only wallet architecture** | **P1** | PLANNED | - |
| **TASK-7** | **Mesh Bitcoin security hardening** | **P1** | PLANNED | FEATURE-6 |
## Active Work
### BUG-1: Random logout / CSRF mismatch (PLANNED)
**Priority**: P0 — Critical
**Status**: PLANNED (2026-03-15)
Sessions expire unexpectedly during normal use. Backend sessions now persist to disk (`/var/lib/archipelago/sessions.json`) but CSRF token mismatch (403) still causes logouts. Need to investigate CSRF token lifecycle and fix the mismatch between cookie and header values.
**Root cause analysis so far**:
- Sessions were purely in-memory — fixed with disk persistence
- CSRF validation compares cookie value vs `X-CSRF-Token` header — both present but don't match
- Log: `403 CSRF mismatch — rejecting RPC call ... has_cookie=true has_header=true`
- Possible cause: cookie value rotated (e.g., new login in another tab) but frontend cached old value
**Key files**:
- `core/archipelago/src/session.rs` — session store (now persisted)
- `core/archipelago/src/api/rpc/mod.rs:273-307` — CSRF validation
- `neode-ui/src/api/rpc-client.ts:18-45` — frontend CSRF extraction from cookie
**Tasks**:
- [ ] Investigate CSRF token rotation — when/why cookie and header diverge
- [ ] Add logging to CSRF validation to capture actual cookie vs header values
- [ ] Consider returning CSRF token in response body (not just cookie) for explicit client storage
- [ ] Test multi-tab scenario where one tab's login rotates the CSRF token
- [ ] Verify session persistence survives deploys (second deploy test)
### TASK-2: Roll incoming-tx into deploy & ISO (PLANNED)
**Priority**: P2 — Medium
**Status**: PLANNED (2026-03-16)
The incoming transactions feature (lnd.gettransactions RPC + wallet badge UI + auto-refresh) is working on .228. Roll changes into deploy-to-target.sh and build-auto-installer-iso.sh so fresh installs and deploys get it automatically. Do not break existing changes.
**Key files changed**:
- `core/archipelago/src/api/rpc/lnd.rs` — new `handle_lnd_gettransactions` method
- `core/archipelago/src/api/rpc/mod.rs` — registered `lnd.gettransactions` route
- `neode-ui/src/views/Web5.vue` — incoming tx badge, panel, auto-refresh polling
- `neode-ui/src/style.css` — incoming-tx-badge, incoming-tx-row, incoming-tx-slide classes
**Tasks**:
- [ ] Verify changes are already captured by existing deploy (backend build + frontend build)
- [ ] Ensure ISO build captures the updated Rust binary and frontend dist
- [ ] Test that no existing deploy/build logic is broken
### BUG-3: IndeedHub WebSocket spam in console (PLANNED)
**Priority**: P2 — Medium
**Status**: PLANNED (2026-03-16)
`ws://localhost:7777/` connection refused fills browser console endlessly when IndeedHub is loaded in iframe. IndeedHub's compiled frontend bundle hardcodes `localhost` for WebSocket connections. When loaded from a remote host, `localhost` resolves to the user's machine, not the server.
**Root cause**: IndeedHub's Next.js build bakes `localhost:7777` into the WebSocket URL. The nginx WebSocket proxy at `/app/indeedhub/ws/` exists but is unused because IndeedHub loads via direct port 7777, not through the proxy path.
**Tasks**:
- [ ] Rebuild IndeedHub with `NEXT_PUBLIC_WS_URL` env var pointing to relative URL or actual server address
- [ ] Alternatively, configure IndeedHub to use relative WebSocket URLs (`/ws/` instead of `ws://localhost:7777/`)
- [ ] Test that WebSocket reconnection works after the fix
### FEATURE-4: Onboarding loading screen with progress (IN PROGRESS)
**Priority**: P1 — High
**Status**: IN PROGRESS (2026-03-17)
Users hit the onboarding screen before the backend is ready, resulting in "Server is still starting up" errors that block identity creation. The onboarding flow should not begin until the server is fully operational.
**Solution**: Show the existing screensaver as a loading/boot screen with server startup progress. Swap the inner logo for animated pixel art icons (smiley face, Bitcoin logo, etc.) that cycle while services come online. Show progress indicators for each backend service (identity store, container runtime, LND, etc.). Only transition to onboarding once `/health` returns ready.
**Key considerations**:
- Reuse the existing screensaver component as the boot screen
- Animated pixel art icons rotate in the center (smiley, BTC, lightning bolt, etc.)
- Progress bar or status checklist showing which services are ready
- Poll `/health` endpoint for service readiness
- Smooth transition from boot screen → onboarding once all critical services are up
- First-boot vs normal boot: first boot shows onboarding after, normal boot goes to dashboard
**Key files**:
- `neode-ui/src/views/Onboarding.vue` — current onboarding flow
- `neode-ui/src/components/Screensaver.vue` — existing screensaver to repurpose
- `core/archipelago/src/api/rpc/mod.rs` — health endpoint
- `core/archipelago/src/server.rs` — startup sequence and service initialization
**Tasks**:
- [ ] Investigate current health endpoint — what services does it check, what's missing
- [ ] Design boot screen component: screensaver background + animated pixel icons + progress
- [ ] Create pixel art icon set (smiley, BTC, lightning, shield, etc.) as SVG/CSS animations
- [ ] Implement service readiness polling (health check with granular service status)
- [ ] Add backend support for granular startup progress (which services are ready)
- [ ] Build boot screen component with smooth transition to onboarding/dashboard
- [ ] Handle edge cases: very slow starts, partial service failures, timeout fallback
- [ ] Test on fresh ISO install (first-boot scenario)
### INQUIRY-5: Offline balance check via mesh relay (PLANNED)
**Priority**: P2
**Status**: PLANNED (2026-03-17)
Design how to query wallet balance (LND/Bitcoin Core) from an off-grid node by relaying the request through mesh peers to an internet-connected Archy node that responds with the balance. Uses the same E2E encrypted relay infrastructure as TX relay.
**Approach options**:
- New typed message pair: `BalanceRequest` (type 13) / `BalanceResponse` (type 14)
- Off-grid node sends `BalanceRequest` to Archy peers
- Internet-connected peer queries its own LND `walletbalance` or the requesting node's LND (if accessible)
- Challenge: the relay peer doesn't have access to the requesting node's wallet — need to either trust the relay peer's balance report, or have the relay peer proxy the RPC to the requesting node's LND over Tor/LAN
- Simplest: relay peer reports its OWN balance (useful for checking if your remote node has funds)
- Advanced: relay peer forwards the LND RPC call to the off-grid node's LND via reverse mesh tunnel
**Tasks**:
- [ ] Define `BalanceRequest` / `BalanceResponse` typed messages
- [ ] Implement balance relay handler on internet-connected node
- [ ] Add "Check Balance" button to Off-Grid Bitcoin panel
- [ ] Consider trust model — relay peer could lie about balance
- [ ] Explore UTXO set proof (SPV-style) for trustless verification
### FEATURE-6: Watch-only wallet architecture (PLANNED)
**Priority**: P1 — High
**Status**: PLANNED (2026-03-18)
Archipelago should never hold private keys or seeds. Users create wallets on companion devices (Coldcard, SeedSigner, phone) and import xpubs to the node for watch-only tracking. The node creates unsigned PSBTs, the companion signs, and the node broadcasts.
**Security rationale**: If the node is compromised (physical theft, remote exploit), no funds can be stolen — only xpubs are present, which reveal balances but cannot sign transactions. This is the standard for Bitcoin node OS security (see: Specter Desktop, Sparrow Wallet).
**Design considerations**:
- xpub import: QR scan, USB file, manual paste
- PSBT workflow: create unsigned on node → transfer to companion → sign → return → broadcast
- Hardware wallet compatibility: Coldcard (USB/SD), SeedSigner (QR), Passport (QR/USB)
- Bitcoin Knots `importdescriptors` for watch-only wallet setup
- Derive receive addresses from xpub (BIP84 native segwit, BIP86 taproot)
- UTXO/balance tracking via watch-only wallet RPC
- UI: receive address display, UTXO list, PSBT generation, transaction history
**Key files**:
- `core/archipelago/src/api/rpc/package.rs` — Bitcoin Knots container config
- `neode-ui/src/views/Web5.vue` — Bitcoin/wallet UI
- Bitcoin Knots RPC: `createwallet`, `importdescriptors`, `listunspent`, `walletcreatefundedpsbt`
**Tasks**:
- [ ] Research Bitcoin Knots watch-only wallet RPC workflow (createwallet, importdescriptors)
- [ ] Design xpub import UI flow (QR scan, paste, file upload)
- [ ] Implement watch-only wallet creation via RPC on first xpub import
- [ ] Implement PSBT creation flow (select UTXOs → build unsigned PSBT → export)
- [ ] Design PSBT transfer UX (QR animated export, file download, USB)
- [ ] Implement signed PSBT import and broadcast
- [ ] Build receive address derivation and display (BIP84/BIP86)
- [ ] Add balance/UTXO tracking dashboard
- [ ] Ensure no private key material ever touches the node (audit all wallet RPC calls)
- [ ] Hardware wallet compatibility testing (Coldcard, SeedSigner)
- [ ] Document the companion device setup guide
### TASK-7: Mesh Bitcoin security hardening (PLANNED)
**Priority**: P1 — High
**Status**: PLANNED (2026-03-18)
Implement the security gaps identified in the off-grid Bitcoin security analysis (`docs/mesh-bitcoin.md`, Section 12). These harden the existing mesh Bitcoin relay infrastructure against the most impactful attack vectors.
**Reference**: `docs/mesh-bitcoin.md` — full analysis with severity ratings and effort estimates.
**Tasks (ordered by severity × effort)**:
- [ ] **G1**: Validate block header chain continuity — reject headers where `prev_hash` doesn't match stored header at height-1 (`BlockHeaderCache::store_header`)
- [ ] **G5**: RBF detection — check nSequence on `TxRelayPayload`, warn/reject if RBF-signaled in off-grid context
- [ ] **G9**: Timestamp sanity checking — reject headers with timestamps >2 hours in future or suspiciously old
- [ ] **G3**: Sign `TxRelayResponse` with relay's Ed25519 key (`TypedEnvelope::new_signed`)
- [ ] **G6**: BOLT11 invoice expiry validation — reject relay payment if invoice expires in <10 minutes
- [ ] **G11**: Random broadcast delay jitter relay adds 0-30s random delay before `sendrawtransaction` to resist timing analysis
- [ ] **G2**: Validate proof-of-work on received block headers (check hash meets difficulty target)
- [ ] **G4**: Encrypt dead man alerts to emergency contacts individually (not cleartext broadcast)
- [ ] **G7**: Multi-relay header comparison track headers by source, flag divergence between relays
- [ ] **G8**: Merkle proof relay new message type for SPV transaction inclusion verification
- [ ] **G10**: Payment intent message type signed envelope (destination, amount, timestamp) for non-repudiable records
- [ ] **G12**: Evaluate Cashu/ecash integration for low-value off-grid payments (spike/prototype)
- [ ] **G13**: Watch-only wallet integration with mesh relay (balance queries use local watch-only, not relay trust)
## Completed
<!-- Done tasks are moved here -->