aboutsummaryrefslogtreecommitdiffstats
path: root/docs/meshbay-draft-v2-fr.md
blob: c61203eaa37eacea4b27708e790ec6ba187827b9 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
# MeshBay — Brouillon d'Architecture v2

> Statut : brouillon préliminaire — points ouverts marqués [TBD]
> Changements depuis v1 : logs IP (légal), versionnage des protocoles, dimensionnement matériel, stratégie JWT, propositions keystore, chat en core, relay déplacé en futur, miroir hub en futur, GEK clarifié, port 18000, lazy admin keystore.

---

## 1. Présentation du projet

MeshBay est une plateforme décentralisée pair-à-pair pour le partage de fichiers, le streaming vidéo et la messagerie de groupe. Elle combine une fédération d'identité (via les Mesh Hubs) avec un échange de données véritablement pair-à-pair (via les Mesh Nodes), conçue pour être résiliente, résistante à la censure et accessible aux utilisateurs.

**Principes fondamentaux :**
- Les données ne transitent jamais par un serveur central — seuls l'identité et le routage le font
- Chiffrement de bout en bout pour tout contenu privé (fichiers, index, messages)
- L'opérateur du node est l'hébergeur légal et porte l'entière responsabilité de son contenu
- Le hub est un registrar léger, pas un hébergeur ni un indexeur
- Open source, auto-hébergeable à chaque niveau

**Domaine :** meshbay.org (configurable dans tout le code source)

---

## 2. Terminologie

| Terme | Rôle |
|---|---|
| **Mesh Hub** | Serveur d'autorité d'identité et registre de groupes |
| **Mesh Node** | Programme local sur la machine de l'utilisateur hébergeur |
| **Mesh Client** | Navigateur web ou application Android (utilisateur final) |
| **Mesh Relay** | Relais TURN communautaire [futur] |
| **MNP** | Mesh Node Protocol — protocole P2P entre nodes et clients |
| **MHP** | Mesh Bay Hub Protocol — protocole de fédération inter-hubs |
| **GEK** | Group Encryption Key — clé symétrique de chiffrement des groupes privés |
| **Mesh Directory** | Registre public des groupes (niveau hub) |
| **Mesh Group Index** | Listing des fichiers d'un groupe (niveau node, chiffré pour les groupes privés) |

---

## 3. Versionnage des protocoles

Tous les protocoles (MNP, MHP, API REST du hub) portent une information de version explicite.

**Format :** `MAJOR.MINOR`
- Incrément MAJOR : changement cassant, incompatible
- Incrément MINOR : ajout rétrocompatible

**Négociation :** lors du handshake, les deux parties déclarent leur plage de versions supportées. Le MINOR le plus élevé mutuellement supporté au sein du même MAJOR est utilisé. En l'absence de version commune, la connexion est refusée avec une erreur explicite.

**Politique de support :** une version supporte le MAJOR courant et au moins les deux MINOR précédents (N-2).

**Implémentation :** champ `version` dans chaque en-tête de message msgpack. L'étape de handshake précède tous les autres échanges.

---

## 4. Composants du système

### 4.1 Mesh Hub

Serveur léger agissant comme un registrar. Intentionnellement minimal pour limiter l'exposition légale et le coût opérationnel.

**Ce que le hub stocke :**
- Comptes utilisateurs : nom d'utilisateur, email (conservé pour la récupération de compte — voir §4.1.1), numéro de téléphone optionnel, `PK_user`, ID du hub, statut, timestamp de création
- Registre de groupes : nom, `PK_group`, identifiant du node hébergeur, visibilité, politique d'adhésion, liste des membres avec bundles GEK chiffrés (groupes privés uniquement)
- Logs de connexion obligatoires (voir §4.1.2)
- Listes de révocation (utilisateurs et groupes)
- Hubs pairs enregistrés (liste d'autorisation explicite — pas de découverte automatique)

**Ce que le hub ne stocke jamais :**
- Contenu de fichiers ou métadonnées
- Index de groupes privés
- Contenu de messages
- IP courante des nodes (gérée par le signaling éphémère — voir §4.1.3)

#### 4.1.1 Données de compte

L'email est conservé en clair (non haché) pour permettre :
- La récupération de compte (réinitialisation de mot de passe)
- Les notifications légales
- Le contact en cas d'abus

Numéro de téléphone : optionnel, associable après la création du compte. Sur Android, les deux sont collectés à l'inscription. Les comptes sont fusionnables (email + téléphone pointant vers le même compte).

Email et téléphone sont stockés chiffrés au repos dans la base de données.

#### 4.1.2 Logs IP obligatoires (conformité légale)

Les cadres légaux (LCEN en France, directive e-Commerce UE, DSA) imposent aux prestataires de conserver des logs de connexion. Le hub enregistre les événements suivants avec horodatage et adresse IP :

| Événement | Rétention |
|---|---|
| Création de compte | 1 an minimum |
| Login (succès et échec) | 1 an minimum |
| Création de groupe | 1 an minimum |
| Adhésion / départ d'un groupe | 1 an minimum |
| Suppression de groupe | 1 an minimum |
| Actions de révocation | 1 an minimum |

Les logs sont stockés dans une table séparée à accès contrôlé. Ils ne sont utilisés qu'à des fins de conformité légale et ne sont pas exposés aux utilisateurs ou opérateurs sauf sur demande légale.

#### 4.1.3 Service de signaling

La coordination de la traversée NAT est gérée par un endpoint WebSocket léger, logiquement séparé de l'API principale du hub. Il est sans état : l'état de connexion est maintenu uniquement en mémoire et effacé après l'établissement de la connexion P2P (typiquement en quelques secondes). Aucun stockage persistant des IP des nodes.

**Résumé des interactions hub :**

| Événement | Charge crypto hub | Fréquence |
|---|---|---|
| Création de compte | Hash Argon2, stockage PK | Une fois |
| Login | Vérification mot de passe, émission JWT (signature Ed25519) | Par session |
| Création de groupe | Enregistrement métadonnées | Une fois par groupe |
| Ajout/suppression membre | Stockage/suppression bundle GEK | Sur action admin |
| Discovery de groupe | Retour adresse node + PK_node + bundle GEK | Par accès initial |
| Signaling NAT | Relais messages WebSocket (<1 Ko) | Par nouvelle connexion P2P |
| Recherche publique | Délégation aux nodes, cache 60s en mémoire | Sur demande |
| Sync fédération MHP | Échange Mesh Directory | Background, périodique |
| Révocation | Signature Ed25519 token de révocation | Rare |

**Le hub n'est jamais dans le chemin des données après l'établissement de la connexion. La vérification des JWT par les nodes est locale (Ed25519, aucun aller-retour hub).**

#### 4.1.4 Stratégie JWT

Deux tokens émis à la connexion :

**Access token** (JWT, signé Ed25519) :
- Validité : 1 heure
- Payload : `user_id`, `PK_user`, `hub_id`, `issued_at`, `expires_at`, claim d'appartenance aux groupes signé par le hub
- Présenté aux nodes pour authentification et vérification d'accès aux groupes
- Vérifié localement par les nodes avec la clé publique connue du hub — aucun aller-retour hub
- Fenêtre de compromission : 1 heure maximum

**Refresh token** (opaque, 256 bits aléatoires) :
- Validité : 30–90 jours [TBD durée exacte]
- Stocké de manière sécurisée côté client uniquement
- Utilisé exclusivement avec le hub pour obtenir un nouvel access token
- Révocable immédiatement par le hub (invalide tous les renouvellements futurs pour ce token)
- Stocké côté serveur sous forme de valeur hachée

**Flux de révocation :** le hub invalide le refresh token → le prochain renouvellement d'access token échoue → l'accès aux nodes expire au plus dans 1 heure.

**Stack technique :**
- Langage : Python
- Framework : FastAPI + Uvicorn
- Base de données : PostgreSQL + SQLAlchemy + Alembic
- Déploiement : reverse proxy Apache (ProxyPass + terminaison SSL)
- Authentification : système propre (JWT Ed25519, Argon2id pour le hachage des mots de passe)
- Hub accessible par domaine et par IP directe (avertissement certificat auto-signé attendu pour l'accès par IP ; documenté)

### 4.2 Mesh Node

Programme local sur la machine de l'utilisateur hébergeur. Le node est l'hébergeur effectif de tout le contenu.

**Responsabilités :**
- Surveiller et indexer les répertoires partagés (Mesh Group Index)
- Servir fichiers et flux vidéo aux membres du groupe
- Gérer toutes les clés cryptographiques localement (keystore chiffré)
- Gérer les connexions P2P et la traversée NAT
- Exécuter le protocole MNP
- Héberger le sandbox de modules Python d'extension
- Servir l'interface web locale (localhost:18000)
- Héberger le chat de groupe (fonctionnalité core)

**Plateforme :** Linux en priorité, cross-platform dès le départ (Windows/macOS). Python assure la portabilité.

#### 4.2.1 Keystore et déverrouillage

Les clés privées (identité utilisateur, identité groupe, copies GEK) sont stockées dans un fichier keystore local chiffré.

**Format :** conteneur msgpack chiffré avec AES-256-GCM, clé dérivée du mot de passe maître par Argon2id (paramétré pour ~1s de dérivation sur le matériel cible).

**Trois modes de déverrouillage :**

| Mode | Fonctionnement | Niveau de sécurité |
|---|---|---|
| **Sécurisé (défaut)** | Mot de passe saisi au démarrage via terminal ou interface web locale | Élevé |
| **Lazy (fichier)** | Mot de passe ou clé dérivée stocké dans `~/.config/meshbay/unlock.key` (chmod 600), lu automatiquement au démarrage | Moyen — acceptable pour une machine home physiquement sécurisée. Risque documenté lors de la configuration. |
| **Service (headless)** | Variable d'environnement `MESHBAY_UNLOCK_KEY`, définie via `EnvironmentFile=` systemd pointant vers un fichier chmod 600 | Moyen-élevé — pratique standard pour les déploiements serveur |

Futur : intégration keychain OS (libsecret/GNOME Keyring sur Linux, Windows Credential Manager, Keychain macOS).

#### 4.2.2 Dimensionnement matériel

La contrainte principale est la **bande passante montante**, pas le CPU ou la RAM.

| Scénario | Utilisateurs simultanés | Upload requis | CPU | RAM |
|---|---|---|---|---|
| Fichiers + chat, peu de streaming | 10 | 20–50 Mbps | 2 cœurs | 512 Mo |
| Streaming 1080p actif (5–6 flux) | 10 | 50–80 Mbps | 2–4 cœurs | 1 Go |
| Usage mixte | 50 | 200–300 Mbps | 4 cœurs | 2 Go |
| Streaming actif | 50 | 400 Mbps | 4–8 cœurs | 2–4 Go |
| Tous usages | 100 | 800 Mbps–1 Gbps | 8 cœurs | 4–8 Go |

Au-delà de 20–30 utilisateurs en streaming actif, un serveur dédié est nécessaire. Une connexion fibre domestique (100–500 Mbps symétrique) convient pour un petit groupe.

**Stack technique :**
- Langage : Python (principal). Extension Rust uniquement si un chemin critique s'avère insuffisant.
- Couche d'abstraction transport : interface `Transport` découplant QUIC du fallback TCP+TLS
- QUIC : `aioquic` (maintenu par des ingénieurs Cloudflare). Fallback : TCP + TLS 1.3 + HTTP/2 si QUIC s'avère insuffisant en production
- ICE/STUN : `aioice`
- WebRTC [futur] : `aiortc`
- Crypto : `cryptography` (PyCA, backed OpenSSL, accélération matérielle AES-NI/ChaCha)
- Sérialisation : `msgpack`
- Compression : `zstandard` (zstd)
- Surveillance fichiers : `watchdog`
- BDD locale : SQLite
- Interface web locale : servie par le node sur `localhost:18000`

### 4.3 Mesh Client

Navigateur web ou application Android. Consomme le contenu depuis les nodes ; gère le compte via le hub.

**Opérations côté hub :**
- Création de compte et login (Android : email + téléphone à l'inscription)
- Recherche et découverte de groupes publics
- Gestion de l'appartenance aux groupes

**Opérations côté node (P2P direct) :**
- Navigation dans les fichiers via Mesh Group Index
- Chat de groupe (messages + pièces jointes, façon Signal — fonctionnalité core)
- Téléchargement de fichiers
- Streaming vidéo (VOD)
- [Futur] Flux vidéo éphémère

**Modes client** [à concevoir] :
- Mode explorateur : navigateur de fichiers pour le contenu du groupe
- Mode flux : fil de chat avec pièces jointes
- Articulation UI hub/node à définir ; l'app Android se connectera directement au node rapidement après la création du compte

### 4.4 Mesh Relay

**[Fonctionnalité future]** Relais TURN opéré par la communauté. Utilisé uniquement en dernier recours quand toutes les méthodes de connexion P2P échouent (~15–20% des connexions). Le trafic est toujours chiffré E2E — le relais ne voit que des paquets QUIC opaques.

Non opéré par meshbay.org. Un protocole d'enregistrement des relais (hub-médié) sera conçu lors de l'introduction de cette fonctionnalité. N'impacte pas le design actuel.

---

## 5. Modèle de groupe

Les groupes sont l'unité organisationnelle centrale.

| Paramètre | Options |
|---|---|
| Visibilité | Public / Privé |
| Politique d'adhésion | Libre / Sur demande / Sur invitation uniquement |
| Admin | L'opérateur du node hébergeur (hébergeur légal) |

Un groupe public fonctionne comme un forum thématique : fichiers, fil de chat, liste de membres. La politique d'adhésion est indépendante de la visibilité (un groupe public peut nécessiter une approbation pour rejoindre).

Le contenu d'un groupe privé (fichiers, index, messages) est toujours chiffré E2E avec la GEK. Seuls les membres possédant la GEK peuvent déchiffrer quoi que ce soit.

**Adressage des groupes :**
```
meshbay.org/u/username/groupname    — groupe public via hub
meshbay.org/g/groupname             — groupe public (raccourci)
group://<PK_group_fingerprint>@<node_addr>  — accès direct sans hub
```
`meshbay.org` est entièrement configurable dans le code source (constante/fichier de config). Le hub est accessible par domaine ou par IP (accès par IP nécessite un certificat auto-signé ; avertissement navigateur attendu et documenté).

---

## 6. Architecture cryptographique

### 6.1 Hiérarchie de clés

```
Clé d'identité utilisateur   Ed25519     Signature, authentification
Clé d'échange utilisateur    X25519      Accord de clé
Clé d'identité groupe        Ed25519     Signature métadonnées groupe (tenue par le node admin)
Clé de chiffrement groupe    ChaCha20    Chiffrement contenu et index privés (symétrique, 256 bits)
Clés de session              X25519/HKDF Perfect forward secrecy par connexion P2P
```

Toutes les clés privées stockées exclusivement sur le node (ou l'appareil client) dans le keystore chiffré. Le hub ne voit jamais aucune clé privée.

### 6.2 Gestion de la GEK

**Périmètre :** la GEK s'applique uniquement aux groupes privés. Les groupes publics utilisent TLS uniquement (pas de chiffrement applicatif).

**Création de groupe :**
1. Le node admin génère la GEK (ChaCha20-Poly1305, 256 bits, CSPRNG)
2. GEK chiffrée pour chaque membre via accord de clé X25519 + HKDF
3. Bundles GEK chiffrés stockés sur le hub (blobs opaques — le hub ne peut pas les déchiffrer ; charge négligeable : ~200–400 octets par membre par groupe)

**Justification du stockage sur hub :** les membres peuvent récupérer leur bundle GEK même si le node est hors ligne. L'exposition du hub est minimale — il stocke du texte chiffré qu'il ne peut pas lire.

**Ajout de membre :**
- GEK chiffrée avec la `PK_user` du nouveau membre et uploadée sur le hub

**Révocation de membre :**
- Le node admin génère une nouvelle GEK
- Re-chiffrement pour tous les membres restants, upload des nouveaux bundles
- Les nouveaux contenus sont chiffrés avec la nouvelle GEK
- L'ancien membre conserve la capacité de déchiffrer le contenu précédemment reçu (compromis acceptable — re-chiffrement rétroactif complet non prévu)

### 6.3 Chiffrement à la volée pour le transfert de fichiers

Les fichiers sont stockés en clair sur le disque de l'hébergeur. Le node chiffre à la lecture.

```
Disque (clair) → compression zstd → chiffrement GEK (par chunk) → session QUIC → Client → déchiffrement QUIC → déchiffrement GEK → clair
```

**Chunking :**
- Taille de chunk : 1 Mo (amortit l'overhead AEAD ; permet le seek)
- Dérivation de clé par chunk : `chunk_key = HKDF(GEK, "file:" || blake3(fichier) || "chunk:" || index)`
- Chaque chunk déchiffrable indépendamment → permet le seek VOD
- Compresser avant chiffrer (la compression est inefficace sur du texte chiffré)

**Authentification des chunks :** chaque chunk signé avec la clé Ed25519 du node. Le client vérifie avant déchiffrement. Prévient l'injection de données par un relais compromis.

**Optimisations chiffrement :**
- `cryptography` (PyCA) utilise OpenSSL, contourne le GIL Python pour les ops crypto
- ChaCha20-Poly1305 : ~500 Mo/s sans AES-NI ; AES-256-GCM : >2 Go/s avec AES-NI
- Pour un home node (50 Mbps upload = 6 Mo/s), le chiffrement n'est pas le goulot d'étranglement
- Pipeline asyncio (lecture → compression → chiffrement → envoi) sans charger les fichiers entiers en mémoire
- Clés de chunk dérivées par batch au début du transfert, pas chunk par chunk

### 6.4 Sécurité du transport

- Principal : **QUIC** (TLS 1.3 intégré, UDP, streams multiplexés)
- Fallback : **TCP + TLS 1.3 + HTTP/2** (même protocole applicatif, performances moindres)
- Interface transport abstraite dans le code — swappable sans changer le protocole applicatif
- Clés de session par connexion via X25519 ECDH + HKDF (indépendantes de la couche GEK)

### 6.5 Chiffrement du chat

Le chat de groupe est une **fonctionnalité core** (pas un module d'extension). Utilise l'algorithme **Double Ratchet** (comme Signal) :
- Forward secrecy et break-in recovery par message
- Chaque message chiffré indépendamment
- Pièces jointes : chiffrées avec la clé de message Double Ratchet courante, hash inclus dans le message
- Implémentation Python : [TBD — évaluer les bibliothèques existantes]

---

## 7. Réseau et connectivité

### 7.1 Traversée NAT — ordre des tentatives

```
1. IPv6 disponible des deux côtés        → connexion directe
2. UPnP / NAT-PMP sur le routeur         → le node ouvre un port automatiquement
3. ICE + STUN / UDP hole punching         → ~80–85% de réussite
4. Mesh Relay (TURN)                     → [fonctionnalité future]
```

Sans l'étape 4, ~15% des connexions entre peers sous NAT symétrique échoueront. Comportement documenté jusqu'à l'implémentation du Mesh Relay.

Signaling (étape 3) : coordonné via l'endpoint WebSocket du hub, <1 Ko par tentative, sans état persistant.

### 7.2 MNP — Mesh Node Protocol

Protocole applicatif sur QUIC (ou fallback TCP+TLS). Tous les messages portent un champ `version`.

**Types de messages définis :**

| Type | Description |
|---|---|
| `handshake` | Échange de clés, présentation JWT, négociation de version |
| `index_sync` | Delta de Mesh Group Index chiffré |
| `file_request` | Demande de chunk(s) d'un fichier par hash + index de chunk |
| `file_chunk` | Données de chunk + signature |
| `stream_segment` | Segment HLS/DASH (VOD), chiffré avec clé dérivée de la GEK |
| `chat_message` | Frame de message chiffré Double Ratchet |
| `chat_attachment` | Métadonnées de pièce jointe + clé ; données transférées comme chunks de fichier |
| `ephemeral_stream` | [réservé, futur] Vidéo éphémère avec métadonnées TTL |

### 7.3 Diffusion de contenu public — Swarm

Fichiers publics identifiés par leur hash `blake3`. Plusieurs nodes peuvent servir le même fichier :

1. Tout node possédant un fichier public et choisissant de le mirrorer s'enregistre : `{ hash → adresse_node }` auprès du hub
2. Le hub maintient une table de sources : `{ blake3_hash → [node_A, node_B, ...] }`
3. Un client demande un fichier → le hub retourne la liste des sources → le client récupère des chunks en parallèle depuis plusieurs nodes
4. Intégrité vérifiée par hash blake3 sur chaque chunk

**Transport :** TLS uniquement pour le contenu public (pas de GEK). Contenu signé avec la clé Ed25519 du node original — les clients vérifient l'authenticité même depuis un miroir.

---

## 8. Index

### 8.1 Mesh Directory (niveau hub)

Registre public des groupes, échangé entre hubs via MHP.

Format : `msgpack`, signé avec la clé Ed25519 du hub, porte un champ `version`.

Champs par entrée : nom de groupe, `PK_group`, hub hébergeur, description, tags de type de contenu, politique d'adhésion, date de création.

### 8.2 Mesh Group Index (niveau node)

Listing des fichiers d'un groupe. Généré et maintenu par le node hébergeur.

Format : `msgpack` → `zstd` → chiffré GEK (groupes privés) ou signé en clair Ed25519 (groupes publics).

Structure d'une entrée :
```python
{
  "version":    1,
  "id":         "<blake3_hash>",
  "name":       "fichier.mkv",
  "path":       "Films/2024/",
  "size":       4294967296,
  "type":       "video",           # video | audio | image | document | archive | other
  "duration":   7245,              # secondes, pour les médias
  "thumb_hash": "<blake3>",        # miniature aussi chiffrée GEK
  "added_at":   1720000000
}
```

Mises à jour delta : `{ base_version, additions, deletions }` — pas de re-chiffrement complet à chaque changement.

Transit : les nodes poussent les deltas d'index aux membres connectés sur modification ; les membres tirent l'index complet à la première connexion. Le hub ne stocke aucun contenu d'index.

### 8.3 Recherche

**Groupes privés :** entièrement locale sur l'appareil du client. Le client maintient un cache local chiffré de tous les index des groupes dont il est membre. Aucun appel réseau, aucune implication du hub, résultats instantanés.

**Groupes publics :** le client interroge les nodes directement à la demande. Le hub fournit le routage uniquement.

**Interface web du hub — recherche :** délègue la requête aux nodes concernés à la demande. Le hub ne stocke rien de cette interaction. Micro-cache en mémoire des résultats : **TTL 60 secondes maximum, RAM uniquement, jamais écrit sur disque, contenu public uniquement.** Relève du caching technique (DSA UE Article 13) — pas de l'indexation.

---

## 9. Fédération inter-hubs (MHP)

### 9.1 Hiérarchie des hubs

```
Root Hub (meshbay.org)
    ├── Full Hub (auto-hébergé, CA déléguée)
    │     └── émet des credentials utilisateurs, gère ses propres groupes
    │     └── se fédère avec d'autres Full Hubs via MHP
    └── Mirror Hub
          └── héberge uniquement le Mesh Directory public (pas de comptes, pas d'émission de clés)
```

Un Full Hub reçoit un certificat signé par le Root Hub (ou un Full Hub parent). Les Mirror Hubs ne peuvent que répliquer les données publiques. Promotion/rétrogradation possible sans casser le protocole.

### 9.2 Conception MHP

- Sélection explicite des pairs : chaque hub maintient une liste d'autorisation de hubs de confiance
- Pas de découverte automatique de hubs
- Données échangées : Mesh Directory (groupes publics), listes de révocation, données d'authentification cross-hub
- Tous les messages MHP portent un champ `version`

### 9.3 Accès client cross-hub

1. Le client (utilisateur Hub A) découvre un groupe sur Hub B via le Mesh Directory ou un lien direct
2. Le client présente son JWT Hub A directement à Hub B
3. Hub B vérifie le JWT avec la clé publique de Hub A (récupérée une fois, mise en cache)
4. Hub B émet un token de session local de courte durée
5. Le client se connecte au node normalement

---

## 10. Modération

### 10.1 Contenu public

```
Signalement #1  → suspension automatique de l'accès public au contenu
                → notification à l'opérateur du node
Une republication autorisée
Signalement #2  → escalade vers les modérateurs du hub
Confirmé        → groupe révoqué sur le hub local
                → révocation propagée aux hubs fédérés via MHP
```

Mécanisme : hash `blake3` du contenu ajouté à la liste de blocage du hub. Token de révocation signé envoyé au node.

### 10.2 CSAM

Hash matching contre la base de données NCMEC/IWF sur le contenu public lors de l'enregistrement. Pas de scanning du contenu privé/chiffré. La participation est obligatoire pour les opérateurs de hub et réduit significativement l'exposition légale.

### 10.3 Copyright

Cadre de notification légale DMCA/équivalent. Takedown sur notification. Pas de blocage technique automatique (risque de faux positifs, fair use). Le hub peut révoquer sur demande légale confirmée.

### 10.4 Contenu privé

Non modérable directement (chiffré E2E par conception). Action disponible : révoquer l'utilisateur ou le groupe au niveau du hub sur demande légale formelle. Le hub émet un token de révocation signé Ed25519 vérifiable offline par les nodes de tous les membres.

---

## 11. Système de modules Python d'extension

Le node charge des modules d'extension (Python) dans un sous-processus sandbox. **Le chat est une fonctionnalité core intégrée, pas un module.**

**Manifeste de module :**
```python
{
  "name": "mon-extension",
  "version": "1.0.0",
  "mnp_version": ">=1.0",
  "permissions": ["read_index", "send_message", "receive_events"]
}
```

**APIs disponibles :**
- `read_index()` — lecture de l'index courant du groupe (lecture seule)
- `send_message(content)` — poster dans le fil du groupe
- `receive_events(handler)` — s'abonner aux événements du groupe

**Non disponible :** accès réseau arbitraire, accès au système de fichiers hors du contexte du groupe, appels système.

---

## 12. Cadre légal

**Opérateur du node :** hébergeur légal principal du contenu. Entièrement responsable de ce qu'il partage. Le logiciel node communique cela explicitement lors de l'installation.

**Opérateur du hub (meshbay.org) :** registrar, pas hébergeur de contenu. Stocke un minimum de données. Opère le mécanisme de takedown. Participe au hash matching CSAM. Exposition légale analogue à celle d'un bureau d'enregistrement de domaines.

**Auteur du protocole/logiciel :** protégé par les usages non-contrefaisants substantiels.

**Données du hub :**
- Email et téléphone optionnel : conservés pour la récupération de compte et la conformité légale
- Mot de passe : haché Argon2id, jamais stocké en clair
- Logs de connexion : conservés selon les obligations légales (1 an minimum)
- Métadonnées de contenu : jamais stockées
- IP courante des nodes : non persistée (signaling éphémère)

---

## 13. Fonctionnalités futures

- **Mesh Relay :** relais TURN communautaires, protocole d'enregistrement via hub, trafic E2E chiffré
- **Réplication de contenu entre nodes :** node-à-node, autorisée par l'admin, sans implication du hub
- **Miroir de hub (répartition de charge) :** réplication complète du hub (BDD users, registre de groupes, bundles GEK) pour distribuer la charge. Nécessite une stratégie de BDD distribuée (streaming replication PostgreSQL ou équivalent). Complexe — à concevoir quand nécessaire.
- **Push vidéo depuis mobile → node :** mobile filme → pousse vers le node hébergeur → flux éphémère avec TTL distribué aux membres du groupe. Type MNP `ephemeral_stream` réservé.
- **Appairage node–mobile :** QR code depuis l'interface web locale
- **Téléchargement multi-sources :** récupération de chunks en parallèle depuis le swarm pour les fichiers publics
- **Client iOS**
- **Chiffrement at-rest sur le node :** optionnel pour les nodes déployés sur des serveurs distants
- **Intégration keychain OS pour le déverrouillage du keystore**

---

## 14. Questions ouvertes [TBD]

1. **Durée de validité du refresh token :** 30 ou 90 jours ?
2. **Schéma d'adressage des groupes :** confirmation du format URL final
3. **Bibliothèque Double Ratchet :** identifier la meilleure implémentation Python
4. **Emplacement des bundles GEK pour les groupes à accès mixte** (public restreint aux inscrits) : hub ou node ?
5. **Fréquence de sync fédération MHP et résolution de conflits**
6. **Stratégie de réplication pour le miroir de hub** (quand implémenté)
7. **Stockage des pièces jointes du chat :** stockées sur le node comme des fichiers ordinaires, ou store séparé ?
8. **Conception du protocole d'enregistrement des relais** (quand implémenté)
9. **Claims du payload JWT :** champs exacts à inclure pour la vérification d'accès aux groupes par le node
10. **Paramètres Argon2id :** calibrage pour le matériel cible (home server vs VPS)