summaryrefslogtreecommitdiffstats
path: root/tmp-decisions.md
blob: 97a27eafa86f632b3227eb3939ebd1c7417ff6f8 (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
# Open decisions — client architecture

> Working note, not a spec. Created 2026-08-13 after the second security review.
> Delete or fold into `docs/meshbay-draft-v5.md` once decided.

---

## Status

| # | Decision | State |
|---|---|---|
| D1 | Does the hub keep serving the web UI? | **Open** — leaning yes |
| D2 | Browser extension, native desktop client, or both? | **Open** — needs time |
| D3 | Transport: aiortc primary, QUIC at parity, TCP+HTTP removed | ✅ Decided 2026-08-13 |

**Neither D1 nor D2 blocks anything right now.** Phase 11.5 (security remediation),
Phase 12 (hub minimization), Phase 14 (node CLI) and Phase 15 (Sender Keys) are entirely
client-agnostic — every finding they close is node-side or hub-side. Phase 11.5 is in
progress on that basis.

---

## Why these are open

The second review recommended a native client and claimed *"T3 disappears — code integrity
stops depending on the hub."* **That claim was wrong and has been corrected** in
`second-review.md` §9.

If the hub operator is the adversary, a native client downloaded from `meshbay.org` and
signed with a key that operator holds does not remove the trust — it relocates it from "the
JS they serve" to "the binary they serve." What actually changes is **detectability**:

- **Browser:** an attack is one HTTP response, targeted at one user, leaving no artifact.
  Undetectable in principle.
- **Native:** an attack requires shipping a build. That build is an artifact — hashable,
  archivable, comparable between users, reversible. Targeting one user means giving them a
  different binary, which reproducible builds and published hashes make detectable.

That is a real improvement, but **the value lives in the verification machinery
(reproducible builds, published hashes, independent rebuilds — Phase 18.7), not in the
packaging format.** Without it, a native client from meshbay.org is only marginally more
trustworthy than the SPA from meshbay.org.

Native also has real costs that were under-weighted: loss of the browser sandbox (a Python
process with full user privileges vs a seccomp-confined renderer), ownership of patch
velocity for WebKitGTK and every bundled dependency, and new attack surface (loopback media
server, IPC bridge, update client).

**Conclusion recorded:** the native client is justified on *product* grounds — durable keys,
no browser tab, background connectivity, better video, hub-less `group://` access over QUIC.
It should not be justified as the fix for T3 unless 18.7 ships with it.

---

## D1 — Should the hub keep serving the UI?

Keeping it is defensible. It is how anyone tries the platform without installing anything,
and it stays the fallback when a device has no client installed.

What must be true if it stays (all already scheduled in Phase 12.6):

- strict CSP and Subresource Integrity on the bundle
- the hub publishes a **signed digest** of the served bundle, so any third party — an
  extension, a native client, a curious user — can verify it
- `/app/` carries an explicit, visible "reduced trust: this hub serves this code" notice
- the docs never claim end-to-end integrity for the hub-served SPA path

The honest framing: hub-served SPA is a **convenience tier**, not the secure tier.

---

## D2 — Extension vs native: what each actually covers

Three shapes, cheapest first:

**Option A — Extension as a verifier (hub still serves the UI)**
The extension does not ship the UI. It hashes the bundle the hub served and compares it
against a digest signed by the project. Mismatch → visible alarm, optionally block.
Converts a silent targeted injection into a loud one. Small effort, keeps today's
architecture, compatible with D1 = yes.

**Option B — Extension ships the UI (hub serves the API only)**
The UI lives in the extension, distributed and signed by Mozilla/Chrome — a channel **the
hub operator does not control**. Manifest V3 forbids remote code, which works in our favour:
the structure enforces exactly what we want. Keys live in extension storage, isolated from
page JS. Moderate effort.

**Option C — Native desktop client (pywebview + aiortc)**
Phase 13. Full control, durable keys in an OS keystore, QUIC, hub-less access, best UX.
Highest effort, and the security argument depends on 18.7.

### Comparison

| | Hub-served SPA (today) | A: extension verifies | B: extension ships UI | C: native desktop |
|---|---|---|---|---|
| Code distribution channel | Hub (the adversary) | Hub, but **verified** | Store (independent) | Hub download + own signing key |
| Silent targeted injection | Undetectable | **Detected** | Not possible | Detectable *if* 18.7 |
| Browser sandbox | ✅ Full | ✅ Full | ✅ Full | ❌ None (partial under Flatpak) |
| Patch velocity | Browser auto-updates | Browser auto-updates | Browser + store review latency | **You own it** (WebKitGTK, Python deps) |
| Key storage | IndexedDB, page-reachable | unchanged | Extension storage, page-isolated | **OS keystore** |
| Crypto available | WebCrypto only (no ChaCha20/Argon2id) | unchanged | unchanged | **Full** (ChaCha20, Argon2id 256 MB) |
| Transport | WebRTC | WebRTC | WebRTC | WebRTC **+ QUIC** |
| Large file → disk | Chrome only (FS Access API) | unchanged | unchanged | **Native, unlimited** |
| Hub-less `group://` | ❌ | ❌ | ❌ | ✅ |
| New attack surface | — | negligible | negligible | loopback server, IPC, updater |
| Platforms to maintain | 0 | 2 stores | 2 stores | 3 OSes |
| Effort | 0 | Low | Moderate | High |

### Observations for the decision

- **A and B are not exclusive with C.** A/B protect browser users; C serves users who want a
  real application. "Both" is coherent — just sequence them.
- **B gives most of C's security benefit at a fraction of the cost**, because the win was
  never the packaging format — it was getting the code off the adversary's distribution
  channel — and the extension keeps the browser sandbox while doing it.
- **Store review latency is the one place B is worse than C**: a critical fix waits on
  Mozilla/Google. Mitigate with a version-pinned kill switch.
- **For node operators specifically, Phase 14 (CLI) beats all three.** The operator is the
  highest-value target — holds the GEK, is the content authority — and today must use
  hub-served JS to initialize GEKs and invite members. The CLI removes that dependency at a
  fraction of any client's cost. If only one thing gets built for T3, it should be the CLI.
- If **D1 = yes** (hub keeps serving the UI), Option A is the natural companion and is nearly
  free once 12.6 publishes the signed digest.

### Not yet investigated

- Whether AMO/Chrome Web Store policy accepts an extension whose purpose is P2P file sharing
- Whether MV3 service-worker lifetimes can hold a long-lived WebRTC DataChannel (may need an
  offscreen document — worth a spike before committing to B)
- Safari/iOS: no extension route comparable to AMO; likely out of scope either way

---

## Impact on the roadmap

| Decision | If yes | If no |
|---|---|---|
| D1 hub serves UI | Phase 12.6 as written (CSP, SRI, signed digest, reduced-trust notice) | 12.6 shrinks to removing `/app/`; hub becomes API-only |
| D2 = A | Small new phase; 12.6 is a prerequisite | — |
| D2 = B | New phase, ~Phase 13-sized; 13.1 platform split is reused directly | — |
| D2 = C | Phase 13 as written (13.2–13.11), + 18.7 for the security claim to hold | Phase 13 reduces to 13.1 only |

**13.1 (platform adapter split) is worth doing regardless of D2.** It is pure refactoring
whose acceptance criterion is "the browser SPA behaves identically," and it is the
prerequisite for A, B and C alike.