summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristophe Besson <cbesson@gmail.com>2026-08-10 01:24:40 +0200
committerChristophe Besson <cbesson@gmail.com>2026-08-10 01:24:40 +0200
commit8ccbe262ecf4a8f7545cbf1e9f1cc5a485acae67 (patch)
treee8e09526f8794c666b5f2fce87ed161c2589c35b
parent2b69da8aeab7d940a9ae4e2ca8eef9995ab2a6d1 (diff)
downloadmeshbay-8ccbe262ecf4a8f7545cbf1e9f1cc5a485acae67.tar.gz
docs: update draft v3 + phases-next with Phase 7 decisions
Multi-group: single QUIC port (multiplexing), group_id from JWT. Signaling punch/connect: hub WS client_incoming/punch_ready protocol, reduces handshake 12.7s → < 200ms. SFR Port-Restricted findings added. Chat model: between forum and Signal — persistent, threaded, E2E, per-group scope, push for online / pull for offline members. Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
-rw-r--r--devel-phases-next.md57
-rw-r--r--docs/meshbay-draft-v3.md54
2 files changed, 87 insertions, 24 deletions
diff --git a/devel-phases-next.md b/devel-phases-next.md
index 96526a1..ff161d6 100644
--- a/devel-phases-next.md
+++ b/devel-phases-next.md
@@ -10,25 +10,56 @@
**Objectif :** un node utilisable quotidiennement — multi-groupe, streaming fluide,
chat intégré, reconnexion rapide.
-**Débloqueurs techniques :**
-- 0-RTT QUIC (aioquic le supporte) → handshake < 50ms en reconnexion
-- Coordination punch/connect via hub WebSocket (réduire le gap)
-- HLS via QUIC (pas seulement via HTTP)
+### Décisions architecturales (arrêtées)
+
+**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.
+
+**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 :
+```
+Client → Hub (HTTPS) : "je vais connecter node X, je viens de IP:PORT"
+Hub → Node (WS) : message "client_incoming: {peer_ip, peer_port}"
+Node → NAT (UDP) : punch_nat(peer_ip, peer_port) immédiat
+Node → Hub (WS) : "punch_ready"
+Hub → Client (HTTPS) : "connecte-toi maintenant"
+Client → Node (QUIC) : < 2s après le probe → trou frais → < 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).
+
+**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)
+
+### Milestones
| # | Composant | Fichier(s) | Priorité |
|---|---|---|---|
| 7.1 | QUIC 0-RTT session resumption | `transport/quic_server.py` + `quic_client.py` | Haute |
-| 7.2 | Signaling punch/connect via hub WS | `hub/api/signaling.py` + `node/hub_client.py` | Haute |
-| 7.3 | Daemon multi-groupe | `node/daemon.py` — N DirectoryIndexers + N servers | Haute |
-| 7.4 | HLS streaming via QUIC | `node/transport/hls.py` — segments via QUIC stream | Moyenne |
-| 7.5 | Chat wire protocol (MNP) | `common/protocol.py` MNP.CHAT_* + `node/chat/` | Moyenne |
-| 7.6 | Chat UI (node web UI) | `node/ui/app.py` — fil de messages temps réel | Moyenne |
+| 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 |
-**Questions à clarifier avant 7.3 (multi-groupe) :**
-- Un groupe = un port dédié, ou multiplexage sur un port unique ?
-- Les groupes d'un même node partagent-ils la même clé Ed25519 de node ?
-- Interface UI : comment présenter plusieurs groupes dans localhost:18000 ?
+**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 ?
---
diff --git a/docs/meshbay-draft-v3.md b/docs/meshbay-draft-v3.md
index 6983191..e11200c 100644
--- a/docs/meshbay-draft-v3.md
+++ b/docs/meshbay-draft-v3.md
@@ -222,14 +222,20 @@ Complete table of validated and planned hub REST API endpoints. Endpoints marked
A local program running on the host user's machine. The node is the actual host of all content.
**Responsibilities:**
-- Watch and index shared directories (Mesh Group Index)
-- Serve files and video streams to group members
+- Watch and index shared directories (Mesh Group Index) — one directory per group
+- Serve files, video streams, and group chat to members
- Manage all cryptographic keys locally (encrypted keystore)
-- Handle P2P connections and NAT traversal
-- Run the MNP protocol
+- Handle P2P connections and NAT traversal (STUN + QUIC hole punching)
+- Run the MNP protocol (QUIC v2, TCP+TLS v1)
- Host the Python extension module sandbox
- Serve the local web UI (localhost:18000)
-- Host the group chat (core feature)
+
+**Multi-group architecture (decided Phase 7):**
+A node exposes **one QUIC port** for all groups it hosts. Groups are not isolated
+by port — the MNP handshake identifies the target group via the `group_id` claim
+in the client JWT. The server routes each connection to the appropriate
+DirectoryIndexer and GEK after JWT verification.
+Rationale: one NAT hole to maintain, one port to forward manually if needed.
**Platform:** Linux primary, cross-platform from the start (Windows/macOS). Python ensures portability.
@@ -582,13 +588,23 @@ Node → Client: session established
- `18001/tcp` — MNP P2P listener (exposed externally, TLS required)
- Configurable via `~/.config/meshbay/node.toml`
-### 6.6 Chat Encryption
+### 6.6 Chat Encryption and Model
+
+Group chat is a **core feature** (not an extension module).
+
+**Model (decided):** between a forum and Signal.
+- **Persistent:** messages stored on the node (not ephemeral like Signal by default)
+- **Structured:** optional threads/topics for longer discussions, flat stream for quick messages
+- **Scope:** per group (not per user pair)
+- **Attachments:** files and images, shared like regular group files
+- **Push/pull:** connected members get real-time push (WebSocket); offline members pull history on reconnect
+- **Retention:** managed by the group admin (no automatic expiry)
-Group chat is a **core feature** (not an extension module). Uses the **Double Ratchet algorithm** (as in Signal):
+**Encryption:** Double Ratchet algorithm (implemented in `meshbay_common.ratchet`):
- Forward secrecy and break-in recovery per message
-- Each message independently encrypted
-- Attachment files: encrypted with the current Double Ratchet message key, hash included in message
-- Python implementation: [TBD — evaluate existing libraries]
+- Each message independently encrypted, out-of-order delivery handled
+- Attachment files: encrypted with GEK-derived key (same as file chunks), hash in message
+- Group scope: all members share the same ratchet state seeded from the group GEK
---
@@ -613,7 +629,23 @@ Group chat is a **core feature** (not an extension module). Uses the **Double Ra
Without step 4 (Mesh Relay), approximately 15% of connections between symmetric-NAT peers will fail. This is documented behavior until Mesh Relay is implemented.
-Signaling for hole punching: coordinated via hub WebSocket endpoint, <1 KB per attempt, no persistent state.
+**Signaling punch/connect (Phase 7.2 — reduces handshake from 12.7s to < 200ms):**
+Currently the node punches blindly at startup; the client may connect 10-20s later
+on an aging NAT entry, causing retransmissions. The coordinated flow uses the
+existing hub→node WebSocket (revocation channel):
+```
+Client → Hub : POST /v1/nodes/{id}/incoming {peer_ip, peer_port}
+Hub → Node (WS) : {type: "client_incoming", peer_ip, peer_port}
+Node : punch_nat(peer_ip, peer_port) immediately
+Node → Hub (WS) : {type: "punch_ready"}
+Hub → Client: 200 OK "connect now"
+Client → QUIC: first packet < 2s after probe → fresh NAT entry
+```
+demo-v2 finding: SFR residential is **Port-Restricted Cone NAT**.
+The probe must come from the QUIC server's own socket (`punch_nat()` via
+`_transport.sendto()`). The QUIC client must connect from the same port
+as the probe's destination (`local_port=QUIC_PORT`). Handshake time
+with proper signaling: < 200ms (vs 12.7s without).
### 7.2 MNP — Mesh Node Protocol