aboutsummaryrefslogtreecommitdiffstats
path: root/CLAUDE.md
blob: dd816ef49b18bc71956ac8c5c7ed68ba599697a3 (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
# MeshBay — Project Conventions

## What this project is

MeshBay is a decentralized peer-to-peer platform for file sharing, video streaming, and group messaging.
See `docs/meshbay-draft-v3.md` for the architecture specification.

## Repository structure

```
meshbay/
├── packages/
│   ├── meshbay-common/   # Shared crypto + protocol — python3-meshbay-common RPM
│   ├── meshbay-hub/      # Hub server (FastAPI + PostgreSQL) — meshbay-hub RPM
│   └── meshbay-node/     # Node daemon + local UI — meshbay-node RPM
├── poc/                  # POC spike scripts (reference, not production)
├── docs/                 # Architecture drafts and POC plans
├── packaging/            # RPM spec files, DEB control files, systemd units
└── QE/                   # NOT versioned (.gitignore) — test artefacts, credentials, demos
    ├── demo-v1/          #   Scripts démo opérationnels (setup_demo.py, run_node.py, download.py)
    ├── spikes/           #   Expérimentations futures (remplace ~/draft/)
    └── server-state/     #   Inventaire de ce qui tourne sur meshbay.org
```

**Règle QE/** : tout test sur meshbay.org doit ouvrir le port UFW, tester, et
fermer le port + tuer les processus dans le MÊME bloc de commandes.
Jamais de processus orphelins ni de ports ouverts après un test.

## Python environment

- **Minimum Python:** 3.12
- **Build backend:** hatchling (per package `pyproject.toml`)

```bash
# Créer le venv (--clear si recréation sur une autre machine/OS)
python3 -m venv .venv --clear
source .venv/bin/activate

# Toutes les dépendances sont déclarées dans les pyproject.toml — un seul pip install suffit
pip install -e packages/meshbay-common -e packages/meshbay-hub -e packages/meshbay-node
pip install pytest pytest-asyncio aiosqlite   # extras dev
```

Les deps clés (aioquic, watchdog, fastapi, blake3, etc.) sont dans les `pyproject.toml`
et installées automatiquement. Ne pas ajouter manuellement des packages sans les déclarer
dans le bon `pyproject.toml`.

> **Ne jamais copier `.venv/` entre machines d'OS différents.** Si rsync depuis Fedora vers Ubuntu,
> exclure `.venv/` et recréer sur la cible avec `python3 -m venv .venv --clear`.
> Sans `--clear`, `certifi.where()` pointe vers un chemin Fedora inexistant sur Ubuntu → `FileNotFoundError`.

```bash
# Lancer les tests
.venv/bin/pytest
```

## Code conventions

- **Linter/formatter:** ruff (`uv run ruff check .` / `uv run ruff format .`)
- **Line length:** 100
- **Type hints:** required on all public functions
- **Comments:** only when the WHY is non-obvious; no docstrings restating the function name
- **No prints in library code** — use `logging` module

## Versioning

### Package versions (SemVer)
- Format: `MAJOR.MINOR.PATCH`
- Pre-1.0: breaking changes bump MINOR, not MAJOR
- All three packages share the same version number (released together)

### Protocol versions (independent)
- MNP: `0.1` → bumped independently of package version
- MHP: `0.1` → bumped independently of package version
- Every wire message carries a `v` field
- Breaking change → MAJOR bump; backward-compatible → MINOR bump
- N-2 MINOR backward compatibility guaranteed

## Commit messages (Conventional Commits)

```
feat(node): add directory watcher with watchdog
fix(hub): include jti in all JWT tokens
chore(common): add Argon2id calibration to crypto.py
docs: update draft v3 with POC findings
test(common): add wrap/unwrap GEK round-trip test
```

Types: `feat`, `fix`, `chore`, `docs`, `test`, `refactor`, `perf`
Scope: `hub`, `node`, `common`, or omitted for cross-cutting

## Security rules

- **Never commit private keys** (hub_private.pem, *.key, unlock.key, keystore.enc)
- **Never commit QE/** — credentials, test keys, demo data go there
- **Never log GEK, private keys, or plaintext passwords** — even at DEBUG level
- **meshbay.org is internet-facing** — open port → test → close port + kill processes in same block

## First security review (2026-08-10) — see `first-review.md`

**Critical (before Phase 7):**
- **C1** Chat: Sender Keys protocol, NOT shared Double Ratchet (pairwise protocol
  would cause key/nonce reuse in group context). `ratchet.py` kept for future 1:1 DM.
- **C2** JWT must carry `"groups": [group_ids]` claim. Node MNP handshake must verify
  group membership before serving content. Without this, any authenticated user
  accesses any group.

**Significant (Phase 7-8):**
- **S1** Admin revocation endpoint has no authz check ✅ DONE (Phase 8.1 — config-based require_admin)
- **S2** Email stored in plaintext (spec says encrypted at rest) ✅ DONE (Phase 8.2 — AES-256-GCM, HKDF from hub key)
- **S3** jti denylist push via hub→node WebSocket → Phase 7.2
- **S4** AES-GCM keystore IV fixed: 128-bit → 96-bit (NIST SP 800-38D) ✅ DONE
- **S5** Refresh token rotation (one-time use) ✅ DONE (Phase 8.3 — family-based reuse detection)

**Architecture validated:** crypto primitives, GEK wrapping (ECIES), trust model,
key hierarchy, on-the-fly encryption, transport abstraction.

## Known calibration TODOs

- Argon2id `memory_cost`: ✅ DONE — bumped to 262144 (256 MB) in pw_version=2.
  Existing v1 users (64 MB) are transparently rehashed on next successful login.
  CLI `calibrate` command still TODO for per-hardware tuning.

## NAT traversal — empirical results

### QUIC native clients (demo-v2)

SFR residential Fedora 44 → meshbay.org OVH VPS:
- **NAT type**: Port-Restricted Cone
- **Mechanism**: `QuicChunkServer.punch_nat()` sends probe from QUIC server socket
- **Scripts**: `QE/demo-v2/`

### WebRTC browser clients (Phase 9 spike, 2026-08-10)

**SFR residential NAT** — Mobile 4G SFR → node behind SFR residential (Port-Restricted Cone + CGNAT 4G):

| Test | ICE path | Result |
|---|---|---|
| WiFi LAN | IPv6 direct | OK, ~100ms |
| 4G + IPv6 | IPv6 inter-network | OK, ~600ms |
| 4G + IPv4 only (IPv6 disabled) | STUN hole-punch IPv4 | OK, ~650ms |

**Orange Livebox NAT** — Firefox/Chrome laptop (SFR) → node behind Orange residential NAT:

| Test | ICE path | Result |
|---|---|---|
| Chrome laptop → Orange node | IPv6 inter-network | OK, ~7000ms |
| Firefox laptop → Orange node | IPv6 inter-network | OK, ~6700ms |
| Firefox laptop → Orange node (IPv6 disabled) | STUN hole-punch IPv4 | OK, ~6900ms |

- **Two ISPs validated** — SFR + Orange residential NAT, both work without TURN
- **No TURN relay needed** — ICE/STUN handles both NAT types automatically
- **Hub role**: signaling only (SDP/ICE relay via WebSocket, <1 KB)
- **Data path**: browser ↔ node P2P via WebRTC DataChannel
- **Scripts**: `QE/demo-v3/run_node_webrtc.py`, test page at `/webrtc-test.html`

## Key modules — où trouver quoi

| Need | Module | File |
|---|---|---|
| Chunk encryption (prod) | `meshbay_common.crypto` | `crypto.py` |
| Key derivation from password | `meshbay_common.keyderive` | `keyderive.py` |
| Key bundle (web) | `meshbay_common.keyderive` | `keyderive.py` + `static/keyderive.js` |
| GEK wrap/unwrap (ECIES) | `meshbay_common.crypto` | `crypto.py` |
| Double Ratchet (1:1 DM, future) | `meshbay_common.ratchet` | `ratchet.py` |
| Sender Keys (group chat) | `meshbay_common.senderkeys` | `senderkeys.py` (Phase 7.5) |
| AES-GCM (browser) | `meshbay_common.webcrypto` | `webcrypto.py` + `static/crypto.js` |
| Node keystore | `meshbay_node.keystore` | `keystore.py` |
| QUIC NAT punch (native) | `meshbay_node.transport.quic_server` | `QuicChunkServer.punch_nat()` |
| WebRTC transport (browser) | `meshbay_node.transport.webrtc_server` | Phase 9.3 — `aiortc` DataChannel |
| WebRTC signaling (hub) | `meshbay_hub.api.signaling` | Phase 9.2 — SDP/ICE relay |
| Browser transport client | `static/transport.js` | Phase 9.4 — WebRTC DataChannel |
| Web SPA | `static/app.js` | Phase 9.6 — Preact + preact-router |
| File download (large) | `static/app.js` | File System Access API (`showSaveFilePicker`) — stream to disk |
| i18n (browser) | `static/i18n.js` | `t()` lookup, ESM, localStorage lang selection |
| Admin API (hub) | `meshbay_hub.api.admin` | Phase 10.2 — user/group mgmt, audit logs, stats |
| Admin UI (browser) | `static/app.js` | Phase 10.3–10.4 — AdminPage component, 5 tabs |
| Auth dependencies | `meshbay_hub.api.deps` | `require_admin`, `require_moderator`, `get_current_user` |
| Site overlay | `site/` | Phase 10.1 — landing, about, downloads (meshbay.org-specific) |
| Notifications (hub) | `meshbay_hub.api.notifications` | Phase 10.5 — CRUD, per-user, triggered by admin/group actions |
| Version check (hub) | `meshbay_hub.api.hub` | Phase 10.10 — `GET /v1/hub/version` |
| Group self-service (hub) | `meshbay_hub.api.groups` | Phase 10b — create, join, members, GEK bundle store |
| File upload (node) | `meshbay_node.transport.webrtc_server` | Phase 10b.4 — FILE_UPLOAD MNP handler |
| GEK wrap AES (browser) | `static/crypto.js` | Phase 10b.2 — AES-256-GCM ECIES for WebCrypto |
| GEK wrap AES (Python) | `meshbay_common.crypto` | Phase 10b.2 — `wrap_gek_aes()` / `unwrap_gek_aes()` |
| IndexedDB cache (browser) | `static/app.js` | Phase 10b.5 — group index caching |
| Cross-group search (browser) | `static/app.js` | Phase 10b.6 — SearchPage, client-side |
| Demo scripts | — | `QE/demo-v1/*.py`, `QE/demo-v2/*.py`, `QE/demo-v3/*.py` (not versioned) |

## meshbay.org server (état cible)

- OS: Ubuntu 26.04 LTS, Python 3.14.4
- SSH: `ssh cbesson@meshbay.org`
- Caddy : reverse proxy HTTPS sur 80/443
- UFW rules: **22/tcp, 80/tcp, 443/tcp uniquement**
- Services légitimes : `meshbay-hub.service`, Caddy, PostgreSQL (local)
- Inventaire détaillé : `QE/server-state/meshbay.org.md`
- Deploy hub : voir `QE/server-state/meshbay.org.md`

## new rules, from now
Documents and demo/comments are written in english unless requested in french.