summaryrefslogtreecommitdiffstats
path: root/devel-phases-next.md
diff options
context:
space:
mode:
Diffstat (limited to 'devel-phases-next.md')
-rw-r--r--devel-phases-next.md157
1 files changed, 93 insertions, 64 deletions
diff --git a/devel-phases-next.md b/devel-phases-next.md
index ff161d6..f4793df 100644
--- a/devel-phases-next.md
+++ b/devel-phases-next.md
@@ -1,88 +1,116 @@
-# MeshBay — Phases d'implémentation suivantes
+# MeshBay — Next Implementation Phases
-> Base : Phases 1-6 terminées. demo-v2 NAT QUIC validée.
-> Référence architecture : docs/meshbay-draft-v3.md
+> Base: Phases 1-6 complete. demo-v2 NAT QUIC validated.
+> Architecture reference: docs/meshbay-draft-v3.md
+> First security review: first-review.md (2026-08-10)
---
## Phase 7 — Node v2 : production, streaming, chat
-**Objectif :** un node utilisable quotidiennement — multi-groupe, streaming fluide,
-chat intégré, reconnexion rapide.
+**Objective:** a node usable for daily operations — multi-group, smooth streaming,
+integrated chat, fast reconnection.
-### Décisions architecturales (arrêtées)
+### Prerequisites (from first security review, 2026-08-10)
-**Multi-groupe → multiplexage sur un seul port QUIC**
-Un node expose un seul port QUIC (ex. 19010). Tous les groupes hébergés
-partagent ce port. Le groupe est identifié dans le handshake MNP par le `group_id`
-contenu dans le JWT. Avantages : un seul trou NAT à maintenir, une seule redirection
-de port manuelle si nécessaire. Le serveur QUIC route chaque connexion vers
-l'IndexGroup/GEK du bon groupe après vérification du JWT.
+Before writing Phase 7 production code, two critical design gaps must be
+addressed — see `first-review.md` for full analysis:
+
+1. **[C2] JWT must carry group membership claims.** Add `"groups": [group_ids]`
+ to `issue_access_token()`. Node MNP handshake must verify the requested
+ group_id is in the JWT's groups claim before serving any content. Without
+ this, any authenticated user can access any group on the node.
+ → Implement in 7.3 (multi-group daemon) before any other milestone.
+
+2. **[C1] Chat encryption: Sender Keys, not shared Double Ratchet.** The Double
+ Ratchet is a pairwise (1:1) protocol — sharing a single ratchet state across
+ N group members causes key/nonce reuse (AEAD catastrophic failure). The
+ architecture now uses **Sender Keys** (Signal Groups approach): each member
+ has their own sending chain key, O(N) state.
+ → Implement in 7.5. The existing `ratchet.py` is kept for future 1:1 DM.
+
+### Architectural decisions (settled)
+
+**Multi-group → multiplexing on a single QUIC port**
+A node exposes a single QUIC port (e.g. 19010). All hosted groups share this
+port. The group is identified in the MNP handshake by the `group_id` in the
+JWT. Advantages: one NAT hole to maintain, one manual port forward if needed.
+The QUIC server routes each connection to the appropriate IndexGroup/GEK
+after JWT verification **and group membership authorization check**.
**Signaling punch/connect (via hub WebSocket)**
-Actuellement, le node punchs aveuglément au démarrage → 12.7s de handshake
-(trou NAT vieillit avant que le client arrive). Solution :
+Currently the node punches blindly at startup → 12.7s handshake (NAT hole ages
+before the client arrives). Solution:
```
-Client → Hub (HTTPS) : "je vais connecter node X, je viens de IP:PORT"
+Client → Hub (HTTPS) : "I'm about to connect to node X, I'm at IP:PORT"
Hub → Node (WS) : message "client_incoming: {peer_ip, peer_port}"
-Node → NAT (UDP) : punch_nat(peer_ip, peer_port) immédiat
+Node → NAT (UDP) : punch_nat(peer_ip, peer_port) immediately
Node → Hub (WS) : "punch_ready"
-Hub → Client (HTTPS) : "connecte-toi maintenant"
-Client → Node (QUIC) : < 2s après le probe → trou frais → < 200ms
+Hub → Client (HTTPS) : "connect now"
+Client → Node (QUIC) : < 2s after probe → fresh NAT entry → < 200ms
```
-Le canal hub→node WebSocket existe déjà (`hub/api/revocation.py`).
-Il suffit d'ajouter le type de message `client_incoming` / `punch_ready`.
-Ce mécanisme s'appuie sur l'ICE simplifié (Interactive Connectivity Establishment).
+The hub→node WebSocket channel already exists (`hub/api/revocation.py`).
+Just add `client_incoming` / `punch_ready` message types.
+This mechanism is a simplified ICE (Interactive Connectivity Establishment).
-**Chat — entre forum et Signal**
-Pas un chat temps-réel éphémère (Signal) ni un forum lourd.
-Modèle : **fil de discussion chiffré E2E, persistant sur le node**.
-- Messages courts + pièces jointes (comme Signal groupe)
-- Fils/topics optionnels pour structurer (comme un forum léger)
-- Historique stocké sur le node (pas éphémère)
-- Push pour membres connectés, pull pour hors-ligne
-- Double Ratchet (déjà implémenté) pour le chiffrement
-- Scope : par groupe (pas par paire d'utilisateurs)
-- Pas de suppression automatique (l'admin du groupe gère la rétention)
+The same WebSocket channel also carries **jti denylist push** (security review
+S3): when the hub revokes a token, it pushes the jti to all connected nodes.
+Nodes maintain an in-memory set and check it during MNP handshake.
+
+**Chat — between a forum and Signal**
+Not a real-time ephemeral chat (Signal) nor a heavy forum.
+Model: **E2E encrypted discussion thread, persisted on the node**.
+- Short messages + attachments (like Signal group)
+- Optional threads/topics for structure (like a light forum)
+- History stored on the node (not ephemeral)
+- Push for connected members, pull for offline
+- **Sender Keys** protocol for encryption (security review C1 — Double Ratchet
+ is pairwise only, cannot be shared across group members)
+- Scope: per group (not per user pair)
+- No automatic deletion (group admin manages retention)
### Milestones
-| # | Composant | Fichier(s) | Priorité |
+| # | Component | File(s) | Priority |
|---|---|---|---|
-| 7.1 | QUIC 0-RTT session resumption | `transport/quic_server.py` + `quic_client.py` | Haute |
-| 7.2 | Signaling `client_incoming`/`punch_ready` | `hub/api/revocation.py` + `node/hub_client.py` | Haute |
-| 7.3 | Daemon multi-groupe (multiplexage 1 port) | `node/daemon.py` — N IndexGroups, 1 QuicChunkServer | Haute |
-| 7.4 | HLS streaming via QUIC | `node/transport/hls.py` — segments en QUIC streams | Moyenne |
-| 7.5 | Chat : stockage + wire protocol MNP | `node/chat/store.py` + `common/protocol.py` | Moyenne |
-| 7.6 | Chat : UI web locale + push WS members | `node/ui/app.py` WebSocket pour notifications | Moyenne |
-| 7.7 | Calibration Argon2id CLI | `node/daemon.py` — `meshbay-node calibrate-argon2` | Basse |
+| 7.0 | JWT group claims + node authz check | `hub/auth.py` + `node/transport/quic_server.py` | **Blocker** |
+| 7.1 | QUIC 0-RTT session resumption | `transport/quic_server.py` + `quic_client.py` | High |
+| 7.2 | Signaling `client_incoming`/`punch_ready` + jti denylist push | `hub/api/revocation.py` + `node/hub_client.py` | High |
+| 7.3 | Multi-group daemon (1-port multiplexing) | `node/daemon.py` — N IndexGroups, 1 QuicChunkServer | High |
+| 7.4 | HLS streaming via QUIC | `node/transport/hls.py` — segments as QUIC streams | Medium |
+| 7.5 | Chat: Sender Keys protocol + storage + MNP wire | `common/senderkeys.py` + `node/chat/store.py` | Medium |
+| 7.6 | Chat: local web UI + WS push to members | `node/ui/app.py` WebSocket for notifications | Medium |
+| 7.7 | Argon2id calibration CLI | `node/daemon.py` — `meshbay-node calibrate-argon2` | Low |
-**Questions ouvertes restantes :**
-- Les groupes d'un même node partagent-ils la même clé Ed25519 de node ? (probable oui)
-- UI multi-groupe localhost:18000 : onglets par groupe ou liste unifiée ?
+**Remaining open questions:**
+- Do groups on the same node share the node's Ed25519 key? (likely yes)
+- Multi-group UI at localhost:18000: tabs per group or unified list?
---
-## Phase 8 — Hub v2 : admin, federation, sécurité production
+## Phase 8 — Hub v2: admin, federation, production security
-**Objectif :** hub prêt pour opération publique — rôles admin, MHP réseau,
-CSAM intégré, monitoring.
+**Objective:** hub ready for public operation — admin roles, MHP network,
+CSAM integrated, monitoring.
-| # | Composant | Fichier(s) | Priorité |
+| # | Component | File(s) | Priority |
|---|---|---|---|
-| 8.1 | Rôles admin (hub_admin flag sur User) | `hub/db/models.py` + `hub/api/admin.py` | Haute |
-| 8.2 | MHP inter-hub réseau (pas juste en mémoire) | `hub/api/federation.py` + Alembic migration | Haute |
-| 8.3 | federated_groups DB persistance | `hub/db/models.py` FederatedGroup already defined | Haute |
-| 8.4 | CSAM DB réelle (import NCMEC/IWF) | `hub/csam.py` — import CLI + API update | Haute |
-| 8.5 | Signaling endpoint WS (pour punch coordination) | `hub/api/signaling.py` | Haute |
-| 8.6 | Métriques / healthcheck | `hub/api/health.py` | Moyenne |
-| 8.7 | Cleanup IP logs (purge > 1 an) | `hub/tasks/cleanup.py` — APScheduler | Moyenne |
-| 8.8 | Alembic migration Argon2id params | Bump migration + `hub/auth.py` | Basse |
+| 8.1 | Admin roles (hub_admin flag on User) + authz on revocation | `hub/db/models.py` + `hub/api/admin.py` + `hub/api/revocation.py` | **High — S1** |
+| 8.2 | Email encryption at rest | `hub/db/models.py` — AES-256-GCM with config-derived key | **High — S2** |
+| 8.3 | Refresh token rotation (one-time use) | `hub/api/users.py` — rotate on each use, detect reuse | **High — S5** |
+| 8.4 | MHP inter-hub network (not just in-memory) | `hub/api/federation.py` + Alembic migration | High |
+| 8.5 | federated_groups DB persistence | `hub/db/models.py` FederatedGroup already defined | High |
+| 8.6 | CSAM real DB (import NCMEC/IWF) | `hub/csam.py` — import CLI + API update | High |
+| 8.7 | Rate limiting on all authenticated endpoints | `hub/api/middleware.py` — extend slowapi | Medium — M3 |
+| 8.8 | Metrics / healthcheck | `hub/api/health.py` | Medium |
+| 8.9 | Cleanup IP logs (purge > 1 year) | `hub/tasks/cleanup.py` — APScheduler | Medium |
+| 8.10 | Alembic migration Argon2id params | Bump migration + `hub/auth.py` | Low |
+
+Items 8.1-8.3 are from the first security review (S1, S2, S5).
-**Questions à clarifier :**
-- Qui peut être hub_admin ? Premier user inscrit ? Config toml ?
-- MHP : authentification inter-hubs via JWT ou mutual TLS ?
-- Signaling : hub WebSocket pour coordonner punch → connect en < 2s
+**Questions to clarify:**
+- Who can be hub_admin? First registered user? Config toml?
+- MHP: inter-hub authentication via JWT or mutual TLS?
---
@@ -123,7 +151,7 @@ des bindings JNI. La couche UI peut être Jetpack Compose.
| 10.1 | Web client : décryptage privé (AES-GCM + SubtleCrypto) | `static/crypto.js` MeshBayCrypto | Haute |
| 10.2 | Web client : groupe-type "browser" (AES-GCM GEK) | Hub : `cipher` field sur Group | Haute |
| 10.3 | Player HLS dans browser (hls.js + déchiffrement) | `static/app.js` + hls.js | Haute |
-| 10.4 | Chat browser (Double Ratchet JS via WASM ou port) | `static/ratchet.js` | Moyenne |
+| 10.4 | Chat browser (Sender Keys JS — AES-GCM via SubtleCrypto) | `static/senderkeys.js` | Moyenne |
| 10.5 | PWA / Service Worker | offline + cache | Basse |
**Question clé :** pour le streaming privé en browser, deux approches :
@@ -173,8 +201,9 @@ Phase 10 (Web v2) ← streaming privé browser
Phase 12 (Packaging) ← distribution
```
-**Prochaine décision structurante :**
-La Phase 7 nécessite de clarifier 3 points avant de coder :
-1. Architecture multi-groupe sur un node (ports partagés ou dédiés ?)
-2. Mécanisme de signaling punch/connect (nouveau endpoint WS sur le hub ?)
-3. Le chat est-il un module (Phase 7.5) ou une feature core du protocole ?
+**Next structural decisions (all resolved — see first-review.md):**
+1. Multi-group on a single QUIC port ✅ (decided Phase 7)
+2. Signaling punch/connect via existing hub WS ✅ (decided Phase 7)
+3. Chat is a core feature, not a module ✅ (decided draft v3)
+4. Chat encryption: Sender Keys ✅ (decided in security review)
+5. JWT group claims required ✅ (decided in security review)