V3.1 → V3.12 consolidated and tagged for the first GA release. Wire format unchanged from 0.4.x — 4.0 peers interoperate with 0.4.x peers byte-for-byte. The version bump is semantic: audit-cycle complete, opt-in surface fully exposed, threat model refreshed for every new surface. Highlights: - All 24 @shade/* packages bumped to 4.0.0 in lockstep. - CHANGELOG 4.0.0 section is the canonical manifest of what landed. - THREAT-MODEL extended (§10 fingerprint gates, §11 WebRTC P2P, §12 Web-Worker boundary) + residual-risks table refreshed. - OpenAPI now covers all 27 routes: prekey, transfer, KT, inbox, bridge, observer, /metrics, /healthz, /ready. - MIGRATION 0.3.x → 4.0 documented + smoke-tested against shade migrate-storage on a real SQLite DB. - docs/audit/REVIEW-BUNDLE.md + SCOPE.md ready for external reviewer. - scripts/soak.ts harness for the GA-stable 2-week soak window. - All V*.md plans archived under docs/archive/ with Status: Done. - Voice/Video carved out into V5.0; 4.0 audit focuses on the frozen non-realtime stack. Tests: TS 1000/1000 + Kotlin 11/11 cross-platform vectors green. Docker: gt.zyon.no/stian/shade-prekey:4.0.0 builds and reports version 4.0.0 on /health. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
4.2 KiB
Shade V3.3 — Fingerprint Gates & Trust UX
Status: Done
Effort: M (2–4 uker)
Forrige: V3.1
Adresserer: V2.3 §1B
Implementert: se docs/trust-ux.md
Mål
Gjør safety numbers handlingspålagte — ikke bare synlige — i flyt der
MITM-risikoen er reell. I dag finnes FingerprintCompare-widget og
requireFingerprintVerifiedFor i @shade/files, men hovedkjernen
(Shade.send, first-large-file, backup-import) har ingen automatisk gate.
Resultat: alert-fatigue-fri, men også gate-fri.
Dette legger inn eksplisitt blokkerende verifisering på et lite antall kritiske hendelser, plus widget-støtte for å eksponere det i UI.
Scope
Inn — kritiske hendelser
- Før første store fil —
Shade.uploadover en bytes-terskel uten verifisert peer. - Før backup-import —
Shade.importBackupblokkerer til peer (eller egen identitet) er bekreftet. - Ny enhet med rotert identitet —
acceptIdentityChangeblokkerer på første bruk inntil verifisert. - Før
@shade/inboxfan-out (V3.6) — gate per mottaker.
Inn — APIer
Shade.beforeFirstLargeFile(threshold, handler)— appen får mulighet til å vise modal og returnere bekreftelse.Shade.beforeBackupImport(handler)— samme mønster.Shade.beforeNewDeviceTrust(handler)— ditto.Shade.markPeerVerified(address)/Shade.isPeerVerified(address)— persistent state.
Inn — widgets
<FingerprintGate />— render-prop wrapper som blokkerer barn til verifisert.<FingerprintCompare />utvides med "kopier OOB-tekst" + "jeg har verifisert".
Ut
- "Tving alle peers verifisert før hver melding" — alert fatigue.
- Cross-device sync av verified-state (kommer evt. via V3.6 inbox).
Design
Persistent verified-state
Ny tabell peer_verifications:
CREATE TABLE peer_verifications (
peer_address TEXT PRIMARY KEY,
fingerprint TEXT NOT NULL,
verified_at INTEGER NOT NULL,
verified_by TEXT, -- "user" | "transitive" | "tofu-after-warning"
identity_version INTEGER NOT NULL -- knytter verifikasjon til identity-rotasjon
);
Når peer roterer identitet → identity_version bumper → verifikasjon "ugyldig"
til ny verifisering.
Hook-flyt
shade.upload(peer, file)
│
├─ if !verified(peer) AND file.size > threshold
│ │
│ └─ await beforeFirstLargeFileHandler(peer, fingerprint)
│ ├─ true → markPeerVerified(peer); proceed
│ └─ false → throw FingerprintNotVerifiedError
│
└─ proceed
Leveranser
Kode
@shade/core—peer_verifications-tabell + storage methods.@shade/sdk— gate-hooks +markPeerVerified/isPeerVerified.@shade/widgets—<FingerprintGate />, utvidet<FingerprintCompare />.
Tester
- Unit: gate kalles, ikke kalles, retur false → throw, retur true → proceed.
- Integration: fil < threshold går gjennom uten gate; fil > threshold blokkerer.
- Identity-rotasjon ugyldiggjør verifikasjon.
- Backup-import blokkerer.
Dokumentasjon
docs/trust-ux.md— guide til hvilke gates som finnes og når de bør tunes.
Akseptansekriterier
- Gate kan ikke bypasses ved å nulle
thresholdut — minimum gate finnes alltid for backup-import og new-device. - App uten registrerte gates får sane defaults (logger en warning, men kjører — ikke krasj).
- Identity-rotasjon resetter verifikasjon i en testet ende-til-ende-flow.
- Widget kan rendres SSR uten å trigge runtime-gate.
Avhengigheter
- V3.1 — threat-matrise oppdatert til å vise hvilke gates som dekker hvilke rader.
Risiko
- Alert fatigue. Hvis terskler er for lave → bruker klikker blindt. Mitiger ved å sette default-terskler høyt (10 MiB for first-large-file) og dokumenter justerings-guide.
- DX-friksjon. Apper som ikke vet om gates får uventede prompts. Mitiger ved å logge tydelig ved første aktivering: "Shade.beforeFirstLargeFile not configured — using default modal".
Migrasjon
0.3.x apps får defaults aktivert med warning. Ingen breaking change.