feat(notes): notekroppe forsegles, og søgningen åbner dem selv
CI / OpenAPI is valid (push) Successful in 38s
CI / Go (push) Failing after 18m36s
CI / End-to-end (push) Failing after 18m54s
CI / Docker image builds (push) Successful in 7m27s
Documentation / build (push) Failing after 7m7s
Documentation / deploy (push) Skipped
Release / Build and publish image (push) Failing after 9m59s
CI / OpenAPI is valid (push) Successful in 38s
CI / Go (push) Failing after 18m36s
CI / End-to-end (push) Failing after 18m54s
CI / Docker image builds (push) Successful in 7m27s
Documentation / build (push) Failing after 7m7s
Documentation / deploy (push) Skipped
Release / Build and publish image (push) Failing after 9m59s
Grunden er den samme som for postkassers kodeord og OAuth-tokens: en sikkerhedskopi kan hentes gennem fladen, og indtil nu bar hver eneste af dem hver eneste note i klartekst. Noter er dér, folk skriver kodeord og API-nøgler ned — det ved vi, fordi der ligger sådan nogle i den installation, det her blev bygget til. **Både titel og krop.** Titlen *er* første linje, så en forseglet krop ved siden af en læselig titel ville efterlade begyndelsen af hver eneste note i klartekst. **Og de to kopier gik med.** Det var derfor det ikke var gjort for længe siden: `notes_fts` indekserede kroppen, og den genererede `fold`-søjle bar en translittereret kopi af den. At forsegle kroppen og lade dem stå ville have været teater — en angriber med filen kunne læse hver note ud af indekset. Begge er væk, og tabellen er bygget om, fordi SQLite ikke kan fjerne en genereret søjle på plads. **Søgningen åbner teksten i Go.** Målt frem for gættet: tolv hundrede noter à 3,3 kB koster 33–43 ms pr. søgning, og fladen venter 250 ms efter sidste tastetryk, før den spørger — så det ligger inde i pausen. Tiden går ikke med at åbne konvolutterne; fire megabyte AES-GCM er få millisekunder. Den går med at folde og småskrive hver krop, og det er lineært: regn med omtrent 350 ms ved ti tusind noter. Dér er det den forkerte form, og svaret er da et nøglet indeks — hvis pris er, at præfiks- og delordssøgningen falder bort. bm25 forsvandt med indekset. Det, der er beholdt, er den halvdel, der betød mest: titlen vejer ti gange kroppen. Med et loft pr. ord, så en note, der nævner ordet fyrre gange, ikke slår en, der nævner alle ordene én gang — det er den fejl, en ren optælling laver, og den er let at lave og svær at få øje på. **En bagudfyldning ved opstart, ikke efterhånden.** Instansens indstillinger forsegles, når de skrives, og det er rigtigt for dem. For et arkiv på tolv hundrede importerede noter, som ingen redigerer igen, betyder "når de skrives" aldrig — og det er præcis dét arkiv, der er værd at forsegle. Idempotent, så den koster et gennemløb af id'er hver anden gang, og `updated_at` røres ikke: at lukke en konvolut om en note er ikke at skrive den, og et stempel med i aften ville kaste den rækkefølge væk, importen brugte en dag på at hente hjem. En fejl under bagudfyldningen stopper opstarten. Halvdelen af noterne lukket er ikke i stykker — `v1:`-præfikset gør, at begge slags kan læses — men en instans, der starter og lader som om den beskytter noget, den ikke gør, er værre end en, der siger fra. Hvad der stadig ligger åbent, står i SECURITY.md og på dokumentationssiden: opgavetitler, beskrivelser, kommentarer, og `note_links`, som røber hvilke projekter og opgaver en note peger på, men ikke hvad der står. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
23bd784b07
commit
c8d67dd07d
+12
-7
@@ -39,13 +39,18 @@ reply within a week.
|
||||
- **The CSP** is computed at startup by hashing the inline scripts in the built
|
||||
page, rather than allowing `unsafe-inline`.
|
||||
|
||||
- **Note bodies, task titles, descriptions and comments are not encrypted.** The
|
||||
sealing above covers credentials — mailbox passwords, OAuth tokens, TOTP secrets,
|
||||
AI keys — and nothing else. A note holding a password is holding it in plain text
|
||||
in every backup that can be downloaded. Encrypting note bodies is on the list and
|
||||
is larger than it sounds: the full-text index and the folded search column are
|
||||
both derived from the body, so both would have to go and search would have to be
|
||||
rewritten to decrypt in application code.
|
||||
- **Note titles and bodies are sealed** under the same key, since 0027. Both, not
|
||||
only the body: a note's title *is* its first line, so a readable title beside a
|
||||
sealed body would leave the beginning of every note in the clear.
|
||||
|
||||
The two plaintext copies went with it. `notes_fts` indexed the body and the
|
||||
generated `fold` column held a transliterated copy of it — sealing the body while
|
||||
leaving those would have been theatre, since a stolen file could be read straight
|
||||
out of the index. Search opens the text in Go instead, which costs 33–43 ms
|
||||
across twelve hundred notes and is the wrong shape somewhere around ten thousand.
|
||||
- **Task titles, descriptions and comments are still in the clear**, and so is
|
||||
`note_links` — ids derived from a note's body, so a stolen file still shows which
|
||||
projects and tasks a note points at, though not what it says.
|
||||
|
||||
## What it does not do
|
||||
|
||||
|
||||
Reference in New Issue
Block a user