You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
## Appendix: Berichten cachen en doorzoeken in de client (Proton Mail-model)
208
+
209
+
### Aanleiding
210
+
211
+
In het blauwe-knop-model ligt de aggregatie bij de burger-app en niet bij een uitvraagsysteem. Daarmee verschuift ook de vraag waar opgehaalde berichten blijven staan en hoe je erin zoekt. Browseropslag leek daarvoor eerder te krap — zeker in Safari, waar de opslag bovendien tijdelijk bleek.
212
+
213
+
Proton Mail doet het wel. Hun server kan de berichten niet lezen (client-side encryptie), dus zoeken op inhoud kán alleen lokaal. Dat maakt hun ontwerp interessant als referentie: het is een werkend voorbeeld van een aggregaat dat volledig in de client leeft.
214
+
215
+
### Hoe Proton het oplost
216
+
217
+
De index is een **versleutelde forward index in IndexedDB** — geen inverted index.
218
+
219
+
1. Bericht van de server halen en lokaal OpenPGP-decrypten
220
+
2. HTML-markup strippen tot platte tekst (scheelt fors in volume)
221
+
3. Opnieuw versleutelen met **AES-GCM** via de Web Crypto API
222
+
4. Wegschrijven in IndexedDB, met het message-ID als key
223
+
224
+
De symmetrische indexsleutel is zelf versleuteld onder de sleutel van de gebruiker. De index verlaat de browser nooit en moet per browser per apparaat opnieuw worden opgebouwd.
225
+
226
+
**Zoeken is een lineaire scan**: alle berichten worden in het geheugen ontsleuteld en op substring gematcht, met resultaten die incrementeel binnenkomen. Geen tokenisatie, geen postings-lijsten.
227
+
228
+
Proton motiveert die keuze met eenvoud en met exacte frase-matching, die in een inverted index extra structuur vereist. Veelzeggend is dat hun losse bibliotheek `ProtonMail/encrypted-search` — een getokeniseerde inverted index mét `AND`/`OR`/`PHRASE`/`PROXIMITY`/`WILDCARD` — in november 2021 is gearchiveerd. Dat is de weg die ze niet zijn ingeslagen.
229
+
230
+
### De opslaggrens wordt niet opgelost, maar toegegeven
231
+
232
+
Proton omzeilt de beperking niet; ze degraderen zichtbaar:
233
+
234
+
> "In rare cases, the contents of a large inbox may require more storage capacity than your browser offers."
235
+
236
+
Past de mailbox niet, dan indexeren ze **partieel en nieuwste-eerst**, en toont de UI een datum die aangeeft hoe ver terug het zoeken op inhoud reikt. Die datum schuift mee als er nieuwe berichten binnenkomen. In private/incognito-modus werkt de functie niet. Raakt de index corrupt, dan is het advies: browserdata wissen en opnieuw opbouwen.
237
+
238
+
De index is bij hen dus een **wegwerpbare cache** die altijd herbouwbaar is uit de server — nooit een bron van waarheid.
239
+
240
+
### Wat er sinds de eerdere analyse veranderd is (Safari)
241
+
242
+
| Aspect | Stand van zaken |
243
+
|--------|-----------------|
244
+
|**Quota per origin**| WebKit staat een origin tot **60% van de totale schijfruimte** toe (browser-apps), met 80% als totaal over alle origins. Voor niet-browser-apps is dat 15%/20%. Ruimte is daarmee niet meer de knellende factor. |
245
+
|**Eviction**| De ITP-regel blijft: een origin zonder user-interaction binnen zeven dagen browsergebruik verliest **alle** script-writable storage — in één keer, niet gedeeltelijk. |
246
+
|**Ontsnapping**| Safari 17+ ondersteunt de Storage API volledig. `navigator.storage.persist()` kan persistent mode geven, maar WebKit kent die toe op heuristiek; het genoemde voorbeeld is een site die als Home Screen Web App is geopend. Als gewoon tabblad is het geen garantie. |
247
+
248
+
De conclusie verschuift daarmee van "er is te weinig ruimte" naar "de ruimte is er, maar de bewaartermijn is niet gegarandeerd".
249
+
250
+
### Waarom het model niet zomaar overdraagbaar is
251
+
252
+
De drijfveer verschilt fundamenteel, en dat bepaalt de kosten van een verloren cache.
|**Waarom in de client?**| Cryptografisch — de server *kan* niet lezen | Architectonisch — er *mag* geen intermediair een kopie houden | Niet in de client; sessiecache in Redis, server-side |
257
+
|**Herstel na verlies**| Eén server opnieuw bevragen | Fan-out naar álle bronorganisaties, mét sessie-opzet per organisatie | Opnieuw ophalen bij de magazijnen via de uitvraag |
258
+
|**Kosten van eviction**| Laag | Hoog | N.v.t. — TTL-gestuurd en bedoeld |
259
+
260
+
Voor Proton is een weggegooide index een vervelende, maar goedkope her-synchronisatie. Bij blauwe knop is opnieuw opbouwen precies de dure operatie: een fan-out over alle bronorganisaties, waarbij elke organisatie een eigen challenge/response en credential-presentatie vereist. Eviction na zeven dagen betekent dan dat de hele keten wekelijks opnieuw wordt aangeslingerd.
261
+
262
+
Daar staat tegenover dat **VoRijk een native mobiele app is, geen browser**. Dan gelden er geen IndexedDB-quota en geen ITP: je hebt gewone bestandsopslag plus Keychain/Keystore voor de sleutels. Het Safari-vraagstuk is in dat geval een browser-probleem, geen blauwe-knop-probleem. Het speelt alleen als je blauwe knop óók in een webcontext wil aanbieden — en dan is een PWA op het beginscherm de enige route naar opslag die blijft staan.
263
+
264
+
### Wat wél overneembaar is
265
+
266
+
1.**Behandel de client-cache als wegwerpbaar.** De cache is een prestatie-optimalisatie, nooit de bron van waarheid. Dat is dezelfde keuze als bij de FBS-sessiecache, die met een sliding TTL in Redis staat en altijd opnieuw gevuld kan worden uit de magazijnen.
267
+
268
+
2.**Partiële index, nieuwste-eerst, met een expliciete grens in de UI.** Een zichtbare melding "zoeken in inhoud vanaf <datum>" is eerlijker dan stilzwijgend onvolledige resultaten tonen. Dit patroon is bruikbaar ongeacht welke opslagstrategie verder gekozen wordt.
269
+
270
+
3.**Lineaire scan volstaat ruimschoots.** Proton doet dit over mailboxen met tienduizenden berichten. Hier zijn berichten enkele kilobytes groot — `Bericht.MAX_INHOUD_BYTES` (1 MiB) is een validatieplafond, geen werkpunt. Een inverted index bouwen zou over-engineering zijn; neem hun conclusie over, niet hun gearchiveerde bibliotheek.
271
+
272
+
4.**Versleutel de lokale opslag alsnog.** Ook als de inhoud onderweg niet end-to-end versleuteld is, beschermt een AES-GCM-laag over de lokale index tegen een aanvaller met toegang tot het apparaat of het browserprofiel.
273
+
274
+
### Open punten
275
+
276
+
- De exacte opslaglimiet die Proton in de client hanteert is niet uit de openbare bronnen te halen; ze noemen wel het gedrag bij overschrijding, niet de drempel.
277
+
- Hoe hun **native** clients (iOS/Android) dit doen is niet gedocumenteerd in de engineering-post — die gaat uitsluitend over de webclient. Juist dat is voor een app-gebaseerd blauwe-knop-model de relevantere vraag.
278
+
- Of `navigator.storage.persist()` in Safari buiten de Home Screen Web App betrouwbaar wordt toegekend, is niet gespecificeerd; WebKit noemt alleen "heuristics".
279
+
280
+
### Bronnen
281
+
282
+
-[Behind the scenes of Proton Mail's message content search](https://proton.me/blog/engineering-message-content-search)
283
+
-[Search message content in Proton Mail (support)](https://proton.me/support/search-message-content)
0 commit comments