release(v4.0.0): Shade GA — V3.x consolidation + audit prep
Some checks failed
Test / test (push) Has been cancelled
Cross-platform vectors / TypeScript vectors (bun) (push) Has been cancelled
Cross-platform vectors / Kotlin vectors (gradle) (push) Has been cancelled
Docker build and publish / docker (push) Has been cancelled
Publish / publish (push) Has been cancelled
Some checks failed
Test / test (push) Has been cancelled
Cross-platform vectors / TypeScript vectors (bun) (push) Has been cancelled
Cross-platform vectors / Kotlin vectors (gradle) (push) Has been cancelled
Docker build and publish / docker (push) Has been cancelled
Publish / publish (push) Has been cancelled
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>
This commit is contained in:
151
docs/archive/V2.1.md
Normal file
151
docs/archive/V2.1.md
Normal file
@@ -0,0 +1,151 @@
|
||||
# Shade V2.1 — Improvements (infrastructure, storage, operations, security)
|
||||
|
||||
This document describes **improvements** agreed for next-generation work on Shade: clearer product story, stronger storage, mobile parity, operational hardening, transfer abuse, and a formal security narrative.
|
||||
|
||||
**Audience:** **Maintainers and contributors** implementing the changes. Add status fields as items land in code/docs.
|
||||
|
||||
---
|
||||
|
||||
## 1. Clear “who is the server?” and data flow
|
||||
|
||||
**Problem:** New users may think the prekey server is a message hub or that all E2EE traffic goes through the Shade container.
|
||||
|
||||
**Goal:** One consistent explanation across the root README, package READMEs, and optional onboarding: **the prekey server distributes public keys and bundles**; **actual messages and (typically) file chunks go through your app’s own channel** (your transport, your backend, your URLs).
|
||||
|
||||
**Deliverables (proposal):**
|
||||
|
||||
- Diagram + short “keys vs payloads” text in the root README and in `@shade/server` README.
|
||||
- Link to `THREAT-MODEL.md` from the same section (MITM on first contact ↔ safety numbers).
|
||||
- Optionally one “concept page” (or extend `MIGRATION.md`) with typical architecture: *A ↔ B via app; both talk to the prekey host for X3DH material*.
|
||||
|
||||
**Acceptance criteria:** A new developer without domain background understands in one reading *what* goes to the Shade server and *what* does not.
|
||||
|
||||
---
|
||||
|
||||
## 2. Optional encryption of storage (at-rest)
|
||||
|
||||
**Problem:** `THREAT-MODEL.md` states that a stolen DB + filesystem can expose private keys because Shade does not encrypt the storage layer by default.
|
||||
|
||||
**Goal:** **Opt-in** protection for sensitive state (identity, session, optional stream resume secrets) with keys that **do not** live in plaintext in the DB — e.g. OS keychain/Keystore, passphrase + KDF, or an explicit device key injected by the app.
|
||||
|
||||
**Design principles:**
|
||||
|
||||
- Default developer experience (dev, simple demos) stays unchanged or includes a clear “insecure mode” warning in docs.
|
||||
- APIs implementable per platform (Bun/SQLite, Postgres, web/IndexedDB, Android).
|
||||
- Document limitations: what remains uncovered (e.g. active memory compromise).
|
||||
|
||||
**Acceptance criteria:** Threat model updated for “when encrypted storage is enabled”; at least one reference implementation + migration note.
|
||||
|
||||
---
|
||||
|
||||
## 3. Android parity and a published roadmap
|
||||
|
||||
**Problem:** `shade-android` is under development; drift from the TS SDK undermines the “byte-compatible” promise.
|
||||
|
||||
**Goal:** A **published roadmap** (milestones + what counts as parity vs TS-only) and **CI running shared test vectors** as a merge gate before release.
|
||||
|
||||
**Deliverables:**
|
||||
|
||||
- Roadmap section in `android/shade-android/README.md` or dedicated `ROADMAP-ANDROID.md` with explicit cross-checkpoints: wire format, fingerprints, rotations, streams (`0x11`) where applicable, resume semantics.
|
||||
- CI job that fails on Kotlin vs TS vector mismatch.
|
||||
|
||||
**Acceptance criteria:** Parity coverage is visible and enforceable; the first critical cross-surface (e.g. core ratchet + proto) is green before a “production” label.
|
||||
|
||||
---
|
||||
|
||||
## 4. Operational hardening — prekey container and production
|
||||
|
||||
**Problem:** Many teams deploy the Docker image quickly; mistakes around TLS, backups, and secrets add avoidable risk.
|
||||
|
||||
**Goal:** A **production checklist**: TLS termination, volume backup (`/data`), rotation of `SHADE_OBSERVER_TOKEN`, use of `SHADE_PREKEY_PG_URL` vs SQLite, observability hooks, logging levels, meaning of stale cleanup parameters.
|
||||
|
||||
**Deliverables:**
|
||||
|
||||
- Extend `docs/DEPLOYMENT.md` or add short `docs/PRODUCTION-CHECKLIST.md` with bullet defaults.
|
||||
- Link from the main README under “Deployment”.
|
||||
|
||||
**Acceptance criteria:** A checklist operators can follow without reading the whole codebase first.
|
||||
|
||||
---
|
||||
|
||||
## 5. Abuse and resource limits on the transfer plane
|
||||
|
||||
**Problem:** Parallel lanes and large uploads can be abused for resource or storage if consumer mounts of `createTransferRoutes()` share no coherent policy.
|
||||
|
||||
**Goal:** Documented **limits and patterns**: authentication (already an active SDK topic), max stream size, TTL for temporary chunk storage, quotas per identity or IP where sensible.
|
||||
|
||||
**Deliverables:**
|
||||
|
||||
- Guidelines in `docs/streams.md` or a dedicated “Transfer hardening” section.
|
||||
- Optional helpers or middleware examples in `@shade/transfer` / server routes for common limits (without forcing every deployment into one DB model).
|
||||
|
||||
**Acceptance criteria:** A clear “recommended minimum” for production that teams can copy.
|
||||
|
||||
---
|
||||
|
||||
## 6. Security review and formal test / narrative
|
||||
|
||||
**Problem:** Enterprises and security-conscious users often ask for independent review and a traceable test matrix.
|
||||
|
||||
**Goal:** Plan for **independent crypto review** (timing, scope, deliverables) and a **published test / threat matrix** linking `THREAT-MODEL.md` to concrete automated tests (replay, tamper, out-of-order, resume, etc.).
|
||||
|
||||
**Deliverables:**
|
||||
|
||||
- Internal checklist “preparing for external review” (which files, assumptions, known limits).
|
||||
- Short section in `SECURITY.md` on review status and how to report findings.
|
||||
|
||||
**Acceptance criteria:** One authoritative source for “what is tested automatically” vs “what needs manual/MITM/out-of-band process”.
|
||||
|
||||
---
|
||||
|
||||
## Dependencies and order (proposal)
|
||||
|
||||
| Priority | Topic | Note |
|
||||
|---------|-------|------|
|
||||
| Low friction | §1, §4 | Documentation and checklists only |
|
||||
| Medium | §5 | Design + docs + possibly small API helpers |
|
||||
| High effort | §2, §3 | Platform work and long-term maintenance |
|
||||
| Coordinated | §6 | Parallel with maturity in §2–§5 |
|
||||
|
||||
---
|
||||
|
||||
## Document versioning
|
||||
|
||||
- **V2.1** — first consolidated plan for the six improvement areas above. Update with dates and short per-section status lines as work starts and completes.
|
||||
|
||||
Gitt der du er nå (post-streams 0.2.0), ville jeg prioritert:
|
||||
|
||||
1. Sosial nøkkel-recovery — løser "hva skjer hvis jeg mister telefonen?" som er det store hullet i alle
|
||||
E2EE-systemer
|
||||
2. P2P WebRTC transport — naturlig kompletterende til streams; gir massiv throughput-gevinst gratis
|
||||
3. E2EE Pub/Sub — lavt scope, høy nytte, og passer perfekt med din "magic drop-in"-filosofi
|
||||
|
||||
Disse tre har alle samme egenskap: de er infrastruktur-features som hver app du bygger fremover vil dra nytte av,
|
||||
ikke bare Dispatch. Helt i tråd med "Shade som komponent som dras inn i hvilket som helst prosjekt".
|
||||
|
||||
|
||||
/btw Hva med Shade videostreaming, VOIP streaming, og lignende?
|
||||
|
||||
Magic drop-in-tilnærming (din filosofi)
|
||||
|
||||
Tenk deg at i en Dispatch-app kan du bare gjøre:
|
||||
|
||||
<ShadeVideoCall to="device:server-admin" />
|
||||
<ShadeVoiceButton to={peerAddress} />
|
||||
<ShadeBroadcaster streamKey="game-stream-1" />
|
||||
<ShadeViewer streamKey="game-stream-1" />
|
||||
|
||||
…og det bare fungerer, E2EE, P2P når mulig, fallback til relay automatisk. Det er det samme mønsteret som streams
|
||||
0.2.0, bare for sanntid.
|
||||
|
||||
Realisme-sjekk
|
||||
|
||||
Video/VOIP er det vanskeligste i hele E2EE-verdenen. Signal brukte år på å få det riktig. Du bør:
|
||||
1. Ferdigstille streams 0.2.0 først (verifiserer crypto-fundamentet)
|
||||
2. Bygge P2P WebRTC-transport som separat milestone
|
||||
3. Da har du alle byggeklossene og Voice 0.4.0 blir 70% gjenbruk
|
||||
|
||||
Men ja — dette hører absolutt hjemme i Shade. Shade som "alt-i-ett E2EE-platform" er en mye sterkere posisjon enn
|
||||
"bare messaging + filer". Du kan bli til E2EE hva Twilio er til vanlig kommunikasjon.
|
||||
|
||||
|
||||
126
docs/archive/V2.2.md
Normal file
126
docs/archive/V2.2.md
Normal file
@@ -0,0 +1,126 @@
|
||||
# Shade V2.2 — Feature plan: product, platform, and developer experience
|
||||
|
||||
This document gathers **planned features** that extend Shade beyond today’s core (X3DH + Double Ratchet + Streams/transfer): groups, asynchronous delivery, richer file UX, web workers, CLI, API docs, and scaffolding.
|
||||
|
||||
Add optional per-feature status (Idea / Design / IMP / Done).
|
||||
|
||||
---
|
||||
|
||||
## 1. Groups / multiple participants
|
||||
|
||||
**Vision:** Beyond strict 1:1 — multiple identities in the same “conversation” or shared context (messages and possibly shared file/stream policy).
|
||||
|
||||
**Challenges:**
|
||||
|
||||
- Today’s Signal-like core is naturally 1:1; groups need either **pairwise sessions per member**, **sender keys / fan-out**, or a **dedicated group protocol** (larger architectural step).
|
||||
- Lifecycle: invites, member removal, compromised device, history, and group PCS.
|
||||
|
||||
**Goals for early milestones (proposal):**
|
||||
|
||||
1. **Document** a recommended pattern for “group-lite” (e.g. coordinator relays ciphertext without decrypting + clients encrypt per-recipient).
|
||||
2. **Optional** minimal API making fan-out easier in the SDK (without promising full MLS).
|
||||
|
||||
**Acceptance criteria (MVP definition):** Explicit scope in docs + one reference architecture; no ambiguous “group is done” without an updated threat model.
|
||||
|
||||
---
|
||||
|
||||
## 2. Async store-and-forward messaging
|
||||
|
||||
**Vision:** Recipient need not be online; **ciphertext** is stored temporarily and fetched when the recipient returns — the server never sees plaintext.
|
||||
|
||||
**Distinction from the prekey server:**
|
||||
|
||||
- Prekey stays **public keys only** (or extended only under strict policy).
|
||||
- A **dedicated relay/inbox service** (or app-owned backend) holds **encrypted blobs only** with TTL, idempotency, and authorization (who may list/fetch).
|
||||
|
||||
**Deliverables (proposal):**
|
||||
|
||||
- Protocol sketch: address registration, `PUT` blob, `GET`/`DELETE` or lease, replay protection at the application layer.
|
||||
- SDK helpers: outgoing queue, poll/pull, or push-notification hook (without dictating mobile platform).
|
||||
|
||||
**Acceptance criteria:** Threat-model section “what the relay sees” + reference implementation or example app.
|
||||
|
||||
---
|
||||
|
||||
## 3. File metadata and preview
|
||||
|
||||
**Vision:** Richer UX **without** leaking sensitive content to the server: filename, MIME type, length where known; **optional** client-generated thumbnails or previews encrypted as separate blocks or small payloads on the control init path.
|
||||
|
||||
**Technical considerations:**
|
||||
|
||||
- Anything sent must be **E2EE** or omitted; plaintext metadata on the server must be deliberate and minimal.
|
||||
- Thumbnails should use **format hardening** on the client (size limits, sandboxing in UI).
|
||||
|
||||
**Acceptance criteria:** Extended `stream-init` (or sidecar envelope) with optional fields + widget support for “preview when available”.
|
||||
|
||||
---
|
||||
|
||||
## 4. Web: worker-based crypto and streaming
|
||||
|
||||
**Vision:** Large files in the browser without blocking the main thread or blowing RAM — **Web Crypto / noble** inside a **Worker**, **ReadableStream/WritableStream** end-to-end chunk pipeline aligned with `@shade/streams` / transfer.
|
||||
|
||||
**Deliverables:**
|
||||
|
||||
- `@shade/crypto-web` (or companion) patterns: transferable buffers, lifecycle, errors surfaced to the UI.
|
||||
- Documented constraints (Safari, chunk sizing, Service Worker vs dedicated worker).
|
||||
|
||||
**Acceptance criteria:** E2E demo or test that sends multi‑MiB through a worker without a blocking UI.
|
||||
|
||||
---
|
||||
|
||||
## 5. CLI: `shade doctor`
|
||||
|
||||
**Vision:** One command that **diagnoses the environment** before production debugging.
|
||||
|
||||
**Typical checks (proposal):**
|
||||
|
||||
- Reachability of `prekeyServer` (`/health`, optional OpenAPI).
|
||||
- Local config: storage path, rotation headers, clock skew (relevant for signed requests).
|
||||
- **Streams:** transfer routes mounted, auth matches expected key, `GET .../state` behaves as expected in test mode.
|
||||
- CLI / Node/Bun runtime versions and `@shade/*` packages where readable from `package.json`.
|
||||
|
||||
**Acceptance criteria:** `shade doctor` with exit codes suitable for CI (warn vs fail).
|
||||
|
||||
---
|
||||
|
||||
## 6. OpenAPI / docs
|
||||
|
||||
**Vision:** All HTTP contracts teams are expected to implement (prekey **and** transfer) appear in **one** OpenAPI story or clearly linked specs — not only README examples.
|
||||
|
||||
**Deliverables:**
|
||||
|
||||
- Consolidate or cross-reference `openapi.yaml` with transfer endpoints (`/v1/transfer/*`) and security schemes for chunk upload.
|
||||
- `/docs` (Redoc or similar) or published static artifacts for versioned specs.
|
||||
|
||||
**Acceptance criteria:** Generated client (e.g. Python/Go) from spec without manual fixes for the happy path.
|
||||
|
||||
---
|
||||
|
||||
## 7. `shade init`
|
||||
|
||||
**Vision:** Scaffolding from **empty repo** to a **minimal runnable** app with Shade and optional streams.
|
||||
|
||||
**Extensions:**
|
||||
|
||||
- New or extended template: **minimal Hono/Fastify** app with `Shade.transferRoute()` mounted, auth example matching the SDK authenticator, `.env` template.
|
||||
- Optional: demo `shade doctor` after init.
|
||||
|
||||
**Acceptance criteria:** `shade init …` produces a project that `bun install && bun run start` runs with documented env vars.
|
||||
|
||||
---
|
||||
|
||||
## Dependencies between items
|
||||
|
||||
```text
|
||||
shade init ─────► doctor (same conventions for URLs and secrets)
|
||||
openapi/docs ◄── transfer + prekey (single source)
|
||||
web workers ───► streams UX (large file in browser)
|
||||
groups ◄──────── store-and-forward (often related socially/technically)
|
||||
metadata/preview► widgets + proto/control plane
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Document versioning
|
||||
|
||||
- **V2.2** — feature backlog as described. Split into issues/ADR per feature when implementation starts.
|
||||
102
docs/archive/V2.3.md
Normal file
102
docs/archive/V2.3.md
Normal file
@@ -0,0 +1,102 @@
|
||||
# Shade V2.3 — Tillit, retention, integrasjon og observability
|
||||
|
||||
Dette dokumentet beskriver **høyere ambisjonsnivå** og **plattformkryssende** arbeid: brukertilfeller der tillit må være **eksplisitt**, data må **utkrympes**/ryddes automatisk, apper må **enkelt koble seg på** kjente transportmønstre, og drift må **observere** uten å lekke innhold.
|
||||
|
||||
---
|
||||
|
||||
## 1. Key transparency / bundle-attestasjon **eller** kritiske fingerprint-øyeblikk i UI
|
||||
|
||||
Dette kan sees som **to spor** samme mål: redusere tillit til én korrumperbar prekey-server uten brukerens merknad.
|
||||
|
||||
### Spor A — Key transparency / bundle-attestasjon (ambisiøst)
|
||||
|
||||
**Idé:** Logging av **hvilket bundle som ble utlevert når**, kryptografisk forankret og **verifiserbar av klienter** eller tredjeparts-audit (inspirert av KT-litteratur, tilpasset Shade sin trusselmodell).
|
||||
|
||||
**Leveranser (målpris høyt):**
|
||||
|
||||
- Trusselmodell-oppdatering: *hva* CT/attest løser vs *fortsatt MITM før første verifisering*.
|
||||
- Designnotat: datastruktur, friskhetsbevis, klient-verifikasjonssteg, operatørkost.
|
||||
|
||||
**Risiko:** Kompleks drift og kryptodesign — bør være **valgfritt** lag for motiverte deploys.
|
||||
|
||||
### Spor B — Fingerprints i app-UI på kritiske hendelser (pragmatisk)
|
||||
|
||||
**Idé:** Gjør **safety numbers** synlige og **handlingspålagte** i presiserte flyt:
|
||||
|
||||
- **Før første stor fil** (eller før første stream over terskel i bytes).
|
||||
- **Før «trust this device»** / backup-importer / ny enhet som gjenbruker identitet.
|
||||
|
||||
**Leveranser:**
|
||||
|
||||
- `@shade/widgets` + SDK-hooks: modal/sheet med fingerprint, kopier-OOB-tekst, «jeg har verifisert».
|
||||
- Dokumenterte UX-retningslinjer (unngå «alert fatigue» kun på lave risiko-events).
|
||||
|
||||
### Felles akseptansekriterier
|
||||
|
||||
Enten spor A eller B må ha **eksplisitt testcoverage** på «blokkerer/handhever verifisering» der det er lovet, og trusselmodellen må nevne kombinasjonen av OOB + tekniske grep.
|
||||
|
||||
---
|
||||
|
||||
## 2. Retention policies
|
||||
|
||||
**Vision:** Standardiserte **TTL- og oppryddingsregler** for data Shade-økosystemet etterlater på server eller i klient-lagring — spesielt:
|
||||
|
||||
- **Stream-state** og midlertidige chunk-referanser etter fullførte/avbrutte transfers.
|
||||
- **Eventuell** inbox/relay-ciphertext (`V2.2`).
|
||||
- Prekey-server: kobling til eksisterende `SHADE_STALE_DAYS` / cleanup, plus **policy-dokumentasjon** for operatører.
|
||||
|
||||
**Leveranser:**
|
||||
|
||||
- Default-anbefalinger (f.eks. «ferdige streams: prune etter N dager») i `@shade/storage-*` helpers eller server-factory.
|
||||
- Konfigurerbare hooks: `maxAge`, `maxBytesPerIdentity`, cron vs on-access prune.
|
||||
|
||||
**Akseptansekriterier:** Ingen «uendelig vekst» som default i nye templates; dokumentert adferd i `streams.md` / deployment.
|
||||
|
||||
---
|
||||
|
||||
## 3. Ferdig «bridge» (transport)
|
||||
|
||||
**Vision:** Apper som ikke kan eller vil bruke WebSocket, får **ferdig mønster** for mottak av små meldinger eller kontroll-signaler.
|
||||
|
||||
**Eksempler:**
|
||||
|
||||
- **Server-Sent Events (SSE)** som **ren ciphertext-pipe** eller som signal «hent fra inbox» uten plaintext på server (kombinasjon med `V2.2`).
|
||||
- **Lang-poll fallback** dokumentert ved siden av WS i `@shade/transport`.
|
||||
|
||||
**Leveranser:**
|
||||
|
||||
- Modulær `bridge`-pakke eller tydelig undermodul med få eksponerte typer og én felles `IncomingMessage`-modell på klient.
|
||||
|
||||
**Akseptansekriterier:** Ett fungende eksempel + test som viser dekryptering likt eksisterende transport.
|
||||
|
||||
---
|
||||
|
||||
## 4. Observability
|
||||
|
||||
**Vision:** Produksjonsteam får **målepunkter og spor** uten **innholdslekkasjer** eller kryptomatrise i logger.
|
||||
|
||||
**Forslag til innhold:**
|
||||
|
||||
- **Metrics (Prometheus-stil eller vendor-nøytralt):** opplastings-/nedlastings-varighet, lane-telling, retry counts, abort vs complete rates, HTTP/WS-feilkoder (aggregert).
|
||||
- **OpenTelemetry:** spans rundt `TransferEngine` og prekey-endepunkter (uten payload-lengde i klartekst som PII — bruk binære størrelser eller binning).
|
||||
- **Sampling og PII-policy** dokumentert (ikke logg adresser i full hvis compliance krever maskering).
|
||||
|
||||
**Akseptansekriterier:** Opt-in flags (default av i lib, på i server-container der det gir mening), og `docs/` avsnitt om hva som **aldri** skal logges.
|
||||
|
||||
---
|
||||
|
||||
## Prioritering mot V2.1 / V2.2
|
||||
|
||||
| Dette dokument (V2.3) | Naturlig forutsetning |
|
||||
|----------------------|------------------------|
|
||||
| Retention | Streams/transfer i bruk (`V2.1` §5, `V2.2` metadata) |
|
||||
| Bridge | `V2.2` store-and-forward eller egen meldingskanal |
|
||||
| UI fingerprints | Widgets/SDK allerede i bruk |
|
||||
| KT / attest | Moden trusselmodell + juridisk/operativ vilje |
|
||||
| Observability | Stabil nok intern API for hooks |
|
||||
|
||||
---
|
||||
|
||||
## Versjonering
|
||||
|
||||
- **V2.3** — første samlet plan for tillit, retention, bridge og observability. Splitt i ADR-er når konkret design er valgt.
|
||||
100
docs/archive/V3.1.md
Normal file
100
docs/archive/V3.1.md
Normal file
@@ -0,0 +1,100 @@
|
||||
# Shade V3.1 — Documentation & Hardening Foundation
|
||||
|
||||
**Status:** Done
|
||||
**Effort:** S (1–2 uker)
|
||||
**Forrige:** V2.3
|
||||
**Neste:** V3.2 / V3.3 / V3.4 (kan kjøres parallelt)
|
||||
|
||||
---
|
||||
|
||||
## Mål
|
||||
|
||||
Lukke "lav-friksjon"-gjelden fra V2.1, V2.2 og V2.3 før vi tar fatt på de tunge
|
||||
sikkerhetsløftene. Dette er pre-arbeidet som låser opp resten av roadmapen:
|
||||
operatører skal kunne deploye trygt, transfer-konsumenter skal ha klare grenser,
|
||||
og OpenAPI skal dekke hele HTTP-flaten.
|
||||
|
||||
Ingen ny kjernekode — kun docs, OpenAPI-utvidelser, retention-defaults og en
|
||||
test-/threat-matrise.
|
||||
|
||||
---
|
||||
|
||||
## Scope
|
||||
|
||||
### Inn
|
||||
|
||||
- README + `@shade/server`-README: eksplisitt "keys vs payloads"-narrativ med
|
||||
diagram + lenke til `THREAT-MODEL.md`.
|
||||
- Ny `docs/PRODUCTION-CHECKLIST.md`: TLS, backup, observer-token-rotering,
|
||||
SQLite vs PG, log-nivå, stale-params, secret-rotering.
|
||||
- Hardening-seksjon i `docs/streams.md`: max stream-size, TTL, quota-mønstre —
|
||||
peker mot `@shade/files`-hooks som referanse.
|
||||
- `openapi.yaml` utvidet med `/v1/transfer/*` (`chunk`, `state`, `health`) +
|
||||
sikkerhetsskjema for `ShadeTransferAuthenticator`.
|
||||
- Retention-defaults i `docs/streams.md` + SDK-template:
|
||||
`pruneStreamStates`-cron som default — "ferdige streams ryddes etter N
|
||||
dager".
|
||||
- `SECURITY.md`-utvidelse: review-status, "hvordan rapportere", lenking fra
|
||||
`THREAT-MODEL.md`-rader → `tests/security/*` (test-/threat-matrise).
|
||||
|
||||
### Ut
|
||||
|
||||
- Faktisk crypto-review (det er V4.0).
|
||||
- Endringer i krypto- eller wire-format.
|
||||
- Ny kode utenfor SDK-templates.
|
||||
|
||||
---
|
||||
|
||||
## Leveranser
|
||||
|
||||
### Dokumentasjon
|
||||
|
||||
- `docs/PRODUCTION-CHECKLIST.md` — ny.
|
||||
- `docs/streams.md` — utvidet med "Hardening" og "Retention".
|
||||
- `README.md` — diagram-justering + "Hva som ikke går via Shade-server".
|
||||
- `packages/shade-server/README.md` — speile narrativet.
|
||||
- `SECURITY.md` — review-status + threat-/test-matrise.
|
||||
- `THREAT-MODEL.md` — krysslenker til konkrete tester.
|
||||
|
||||
### Kode (kun konfig + templates)
|
||||
|
||||
- `packages/shade-server/openapi.yaml` — `/v1/transfer/*`-paths,
|
||||
`ShadeTransferAuthenticator` securityScheme.
|
||||
- `packages/shade-cli/templates/bun-server` — default
|
||||
`pruneStreamStates`-cron.
|
||||
|
||||
### Tester
|
||||
|
||||
- Lint-test: OpenAPI-spec validerer fortsatt mot OpenAPI 3.1-skjema.
|
||||
- Smoke-test for cron i template.
|
||||
|
||||
---
|
||||
|
||||
## Akseptansekriterier
|
||||
|
||||
- [ ] Ny utvikler kan lese README + `PRODUCTION-CHECKLIST.md` og deploye
|
||||
prod-klar Shade uten å lese hele kodebasen.
|
||||
- [ ] Generert klient (Python eller Go) fra `openapi.yaml` dekker både
|
||||
prekey- og transfer-flate uten manuelle fixes for happy path.
|
||||
- [ ] `THREAT-MODEL.md` linker hver "Mitigations"-rad til minst én test-fil.
|
||||
- [ ] Default SDK-template `bun-server` prune'r resumable streams uten
|
||||
manuell konfig.
|
||||
|
||||
---
|
||||
|
||||
## Avhengigheter
|
||||
|
||||
Ingen.
|
||||
|
||||
---
|
||||
|
||||
## Risiko
|
||||
|
||||
Lav. Verste utfall er foreldet docs hvis V3.2+ endrer overflater. Mitiger ved
|
||||
å skrive små, oppdaterbare seksjoner heller enn lange narrative kapitler.
|
||||
|
||||
---
|
||||
|
||||
## Migrasjon
|
||||
|
||||
Ingen — alt er additivt.
|
||||
134
docs/archive/V3.10.md
Normal file
134
docs/archive/V3.10.md
Normal file
@@ -0,0 +1,134 @@
|
||||
# Shade V3.10 — Social Key Recovery
|
||||
|
||||
**Status:** Done — landet i `@shade/recovery` 0.4.0, frosset i 4.0 GA.
|
||||
**Effort:** L (4–8 uker)
|
||||
**Forrige:** V3.2 + V3.3
|
||||
**Adresserer:** V2.1-tillegg "sosial nøkkel-recovery"
|
||||
|
||||
---
|
||||
|
||||
## Mål
|
||||
|
||||
Løs det største UX-hullet i alle E2EE-systemer: **"Hva skjer hvis jeg
|
||||
mister telefonen?"**. Bruker velger N "guardians" (familie / venner /
|
||||
jobb-partnere); når bruker mister enheten, kan en threshold-andel av
|
||||
guardians sammen returnere identity-nøkkelen — uten at noen enkelt guardian
|
||||
kan gjøre det alene, og uten at server lærer noe.
|
||||
|
||||
---
|
||||
|
||||
## Scope
|
||||
|
||||
### Inn
|
||||
|
||||
- Shamir Secret Sharing (k-of-n) over identity private key (eller en
|
||||
backup-encryption-key).
|
||||
- Distribusjon av shares via eksisterende 1:1 Shade-sesjoner — guardians
|
||||
lagrer share lokalt.
|
||||
- Recovery-flow: ny enhet ber threshold guardians sende sine shares;
|
||||
rekonstruerer på ny enhet.
|
||||
- Verifikasjons-step: ny enhet beviser identitet til hver guardian via OOB
|
||||
safety-number-sammenligning **før** guardian frigjør share.
|
||||
- UX-guide: hvor mange guardians, hvilken threshold, hvordan rotere når en
|
||||
guardian mister enhet.
|
||||
|
||||
### Ut
|
||||
|
||||
- "Cloud guardian" / Shade-driftet recovery — vi tillater ingen sentralisert
|
||||
komponent som kan gjøre det alene.
|
||||
- Auto-distribusjon (vi krever eksplisitt valg av guardians).
|
||||
|
||||
---
|
||||
|
||||
## Design
|
||||
|
||||
### Hva deles
|
||||
|
||||
```text
|
||||
shareSecret = AES-256-GCM-encrypt(identityState, recoveryKey)
|
||||
recoveryKey is Shamir-split(k, n) → shares[i]
|
||||
shareSecret stored locally + on each guardian
|
||||
each guardian receives one share via Shade.send
|
||||
```
|
||||
|
||||
`identityState` er det samme som `Shade.exportBackup` (eksisterer i 0.3.x),
|
||||
men her gjenbrukes formatet.
|
||||
|
||||
### Recovery-flow
|
||||
|
||||
1. Ny enhet genererer **temporary** identity + safety number.
|
||||
2. Ny enhet kontakter guardians via prekey-server (OOB verifisering først).
|
||||
3. Hver guardian godkjenner manuelt og returnerer sin share via
|
||||
`Shade.send`.
|
||||
4. Ny enhet rekonstruerer `recoveryKey`, dekrypterer `shareSecret`,
|
||||
gjenoppretter identity.
|
||||
5. Original identity roterer (gammel identitet markeres som
|
||||
"compromised — used for recovery").
|
||||
|
||||
### Guardian-UX
|
||||
|
||||
- Guardian-app/widget viser:
|
||||
*"Alice (din venn) har mistet sin enhet og ber om recovery share.
|
||||
Bekreft fingerprint før du sender."*
|
||||
- Guardian kan **avslå** uten konsekvens.
|
||||
|
||||
---
|
||||
|
||||
## Leveranser
|
||||
|
||||
### Pakker
|
||||
|
||||
- `@shade/recovery` — Shamir + share-distribusjon.
|
||||
- `@shade/widgets` — `<RecoverySetup />` (velg guardians) +
|
||||
`<RecoveryRequest />` (ny enhet ber) + `<RecoveryApprove />` (guardian
|
||||
godkjenner).
|
||||
|
||||
### Tester
|
||||
|
||||
- Unit: Shamir split/combine roundtrip; threshold-håndhevelse.
|
||||
- Integration: full 3-of-5 recovery med 5 mock-guardians.
|
||||
- Adversarial: 2 guardians koluderer (under threshold) → kan ikke
|
||||
rekonstruere.
|
||||
- Adversarial: ondsinnet ny enhet uten safety-number-bekreftelse → ingen
|
||||
guardian skal frigjøre share.
|
||||
|
||||
### Dokumentasjon
|
||||
|
||||
- `docs/recovery.md` — full UX + threat model.
|
||||
- Trusselmodell-utvidelse: kollusjon ≤ k-1, identitetsforfalskning, social
|
||||
engineering.
|
||||
|
||||
---
|
||||
|
||||
## Akseptansekriterier
|
||||
|
||||
- [ ] 3-of-5 recovery fungerer end-to-end på 2 separate enheter.
|
||||
- [ ] Ingen koalisjon av (k-1) guardians kan rekonstruere `shareSecret`
|
||||
(verifisert med fast-check property test).
|
||||
- [ ] Guardian-side widget krever fingerprint-bekreftelse før send (gate
|
||||
fra V3.3 forsterket).
|
||||
|
||||
---
|
||||
|
||||
## Avhengigheter
|
||||
|
||||
- V3.2 — nøkkelmateriale at-rest hos guardian skal være kryptert.
|
||||
- V3.3 — fingerprint-gate på recovery-handshake.
|
||||
|
||||
---
|
||||
|
||||
## Risiko
|
||||
|
||||
- **UX er det vanskeligste.** "Hvem er min guardian?" er sosialt komplekst;
|
||||
bruker kan velge dårlig.
|
||||
- **Social engineering.** Angriper imiterer offer over telefon → guardian
|
||||
gir share. Mitiger med harde fingerprint-gates + cool-down.
|
||||
- **Dead guardians.** Hvis guardian dør / mister sin enhet uten å være
|
||||
erstattet, threshold synker. Periodisk "guardian health check"-prompt
|
||||
anbefales.
|
||||
|
||||
---
|
||||
|
||||
## Migrasjon
|
||||
|
||||
Ny pakke. Apper kan legge til recovery-widget i innstillinger.
|
||||
124
docs/archive/V3.11.md
Normal file
124
docs/archive/V3.11.md
Normal file
@@ -0,0 +1,124 @@
|
||||
# Shade V3.11 — WebRTC P2P Transport
|
||||
|
||||
**Status:** Done — landet med `@shade/transport-webrtc` 0.4.0,
|
||||
`MultiTransportFallback` i `@shade/transfer`, og
|
||||
`shade.configureWebRTC()` i `@shade/sdk`. Se [docs/webrtc.md](../webrtc.md).
|
||||
**Effort:** XL (2–4 måneder)
|
||||
**Forrige:** V3.7
|
||||
**Adresserer:** V2.1-tillegg "P2P WebRTC transport"
|
||||
|
||||
---
|
||||
|
||||
## Mål
|
||||
|
||||
Direct peer-to-peer datakanal mellom Shade-klienter når NAT/firewall
|
||||
tillater. Primær gevinst: massiv throughput for `@shade/transfer`
|
||||
(filer, store payloads) og lav-latens for messaging når begge peere
|
||||
er online samtidig. E2EE bevart: WebRTC DTLS-SRTP er **transport** —
|
||||
payload er fortsatt Shade ratchet-krypto.
|
||||
|
||||
V3.11 lander i V4.0-vinduet og er foundation-only — sanntidsbruken
|
||||
(voice, video, broadcast) ligger i [V5.0](../V5.0.md) som downstream
|
||||
konsumer av denne datakanalen.
|
||||
|
||||
---
|
||||
|
||||
## Scope
|
||||
|
||||
### Inn
|
||||
|
||||
- Ny pakke `@shade/transport-webrtc`.
|
||||
- Signaling via Shade control plane (eksisterende kanal — `Shade.send`).
|
||||
- ICE/STUN: bruk offentlige STUN-servere som default.
|
||||
- TURN: konfigurerbar TURN-relay som fallback.
|
||||
- DataChannel for `@shade/transfer`-chunks.
|
||||
- Auto-fallback: P2P → HTTP (eksisterende stack).
|
||||
|
||||
### Ut
|
||||
|
||||
- SFU/MCU (mange-til-mange topologi) — broadcast/video er V5.0.
|
||||
- Voice/video media-tracks — V3.11 er ren datakanal (DataChannel);
|
||||
audio/video over RTP er V5.0.
|
||||
- DTLS-fingerprint-binding til Shade-fingerprint (vurderes som hardening,
|
||||
men ikke krav).
|
||||
|
||||
---
|
||||
|
||||
## Design
|
||||
|
||||
### Connection-flow
|
||||
|
||||
```text
|
||||
A initierer:
|
||||
1. createOffer() → SDP
|
||||
2. shade.send(B, { kind: "webrtc-offer", sdp })
|
||||
3. B mottar over Shade-kanal, createAnswer()
|
||||
4. shade.send(A, { kind: "webrtc-answer", sdp })
|
||||
5. ICE-candidates exchange (samme kanal)
|
||||
6. DataChannel åpen
|
||||
```
|
||||
|
||||
### Wrapping
|
||||
|
||||
DataChannel sender ferdige `@shade/transfer`-chunks (allerede E2EE).
|
||||
WebRTC's egen DTLS-SRTP fungerer som transport-secrecy lag.
|
||||
|
||||
### Topologi
|
||||
|
||||
- 1:1 P2P direkte når mulig.
|
||||
- TURN-relay når NAT'er er for strenge (transport-only, ser ikke plaintext).
|
||||
|
||||
---
|
||||
|
||||
## Leveranser
|
||||
|
||||
### Pakker
|
||||
|
||||
- `@shade/transport-webrtc` — Connection, DataChannel-wrapper, ICE-config.
|
||||
- `@shade/transfer` utvides: `WebRTCTransferTransport` som drop-in.
|
||||
- `FallbackTransferTransport` får ny ledd: P2P → WS → HTTP.
|
||||
|
||||
### Tester
|
||||
|
||||
- Loopback unit: offer/answer/ICE i Bun via `node-datachannel` eller
|
||||
`wrtc`.
|
||||
- Integration: 100 MB transfer over P2P vs HTTP — P2P skal vinne på samme
|
||||
nettverk.
|
||||
- Failover: TURN-relay påtvinger relay-modus.
|
||||
- NAT-emulering (loopback med ulike NAT-typer hvis mulig).
|
||||
|
||||
### Dokumentasjon
|
||||
|
||||
- `docs/webrtc.md` — setup, STUN/TURN-config, NAT-traversal-håp og
|
||||
-realiteter.
|
||||
|
||||
---
|
||||
|
||||
## Akseptansekriterier
|
||||
|
||||
- [ ] To klienter på samme LAN: P2P direct uten TURN, throughput > 5x
|
||||
HTTP-baseline.
|
||||
- [ ] To klienter bak strenge NAT'er: TURN-relay aktiveres automatisk.
|
||||
- [ ] Failover P2P-død → HTTP innen 5 s uten meldingstap.
|
||||
|
||||
---
|
||||
|
||||
## Avhengigheter
|
||||
|
||||
- V3.7 — bridge-mønstre + fallback-arkitektur.
|
||||
|
||||
---
|
||||
|
||||
## Risiko
|
||||
|
||||
- **NAT-traversal-helvete.** Mange edge-cases. Mitiger med tidlige
|
||||
integration-tester på faktiske NAT-konfigurasjoner.
|
||||
- **Browser-kompatibilitet.** Safari har sine egne RTC-quirks.
|
||||
- **TURN-koster.** TURN-relay = ekte trafikk gjennom server. Operatør må
|
||||
vite det.
|
||||
|
||||
---
|
||||
|
||||
## Migrasjon
|
||||
|
||||
Opt-in. Eksisterende HTTP/WS-transport fungerer uendret.
|
||||
557
docs/archive/V3.12-DESIGN.md
Normal file
557
docs/archive/V3.12-DESIGN.md
Normal file
@@ -0,0 +1,557 @@
|
||||
# V3.12 — Key Transparency: Designnotat
|
||||
|
||||
**Status:** Approved (in-tree review — markeres `Design` i ROADMAP)
|
||||
**Forfatter:** Shade-teamet
|
||||
**Reviewer-mål:** ekstern crypto-orientert reviewer før produksjons-deploy.
|
||||
**Implementasjons-target:** `@shade/key-transparency` + utvidelser i
|
||||
`@shade/server`, `@shade/transport`, `@shade/sdk`.
|
||||
|
||||
---
|
||||
|
||||
## 1. Mål og ikke-mål
|
||||
|
||||
### Mål
|
||||
|
||||
Bytt ut "blind tillit til prekey-server" med en **verifiserbar
|
||||
append-only log**. Når en klient mottar et prekey-bundle skal den ha
|
||||
kryptografisk bevis for at:
|
||||
|
||||
1. Bundlen er **commit'et** i en tidstemplet log (Signed Tree Head).
|
||||
2. Den eksakte (adresse, identityKey, signedPreKey)-mappingen står i
|
||||
den loggen — _eller_ den står ikke (fravær-bevis).
|
||||
3. Loggen har ikke skrevet om historie siden forrige fetch
|
||||
(konsistens-bevis).
|
||||
4. Andre klienter ser **samme** log (split-view-deteksjon via
|
||||
witness-gossip).
|
||||
|
||||
Dette er **CT-style transparens** (RFC 6962-prinsipper) tilpasset
|
||||
prekey-distribusjon.
|
||||
|
||||
### Ikke-mål (eksplisitt ut)
|
||||
|
||||
- **Federert log mellom flere prekey-servere.** Hver Shade-deployment
|
||||
har én log (eller ingen). Multi-server gossip er V3.13+.
|
||||
- **Løse MITM-på-første-kontakt fullstendig.** KT fanger split-view og
|
||||
re-write, men ikke det at en angriper publiserer en forfalsket
|
||||
identitet ved første registrering. Det er V3.3 (fingerprint-gate)
|
||||
+ V3.10 (social recovery).
|
||||
- **Legal/compliance audit-log.** Loggen er kryptografisk, ikke juridisk.
|
||||
- **Klient-styrt sletting.** Append-only — DELETE skriver
|
||||
tombstone-entry, fjerner ikke historikk.
|
||||
|
||||
### Beslutningskriterium for implementasjon
|
||||
|
||||
Når dette notatet er godkjent _og_ alle åpne spørsmål under §11 har
|
||||
konkrete svar (ikke bare "vi finner ut av det senere"), kan kode
|
||||
skrives. Det notatet ligger på når §11 lukkes er det vi bygger.
|
||||
|
||||
---
|
||||
|
||||
## 2. Trusselmodell-tillegg
|
||||
|
||||
Eksisterende THREAT-MODEL.md dekker prekey-server som "honest-but-curious"
|
||||
+ tilstede TOFU. KT utvider modellen til **fully-malicious server**:
|
||||
|
||||
| Angrep | Pre-V3.12 | Post-V3.12 |
|
||||
|---|---|---|
|
||||
| Server returnerer feil bundle for én klient | Uoppdaget til OOB-verifisering | Klient kan be om proof; mismatch oppdages |
|
||||
| Server bytter en allerede registrert identityKey | TOFU-fingerprint endres → V3.3-gate slår inn (men brukerinitiert) | Loggen vil vise to entries med samme adresse → witness oppdager |
|
||||
| Server gir `alice` ulike identityKeys til Bob og Charlie (split-view) | Uoppdaget til OOB | Witness-gossip avslører to ulike STH-er |
|
||||
| Server skriver om historikk for å skjule tidligere svik | Mulig | Konsistens-proof feiler → klient varsler |
|
||||
| Server nekter å publisere ny STH | Mulig | "Stale STH"-detekteres av friskhetsbevis (max age) |
|
||||
| Server kompromitterer signing-key for STH | KT-trygghet brutt | Witness gossip om gammel STH-kjede; rotasjon krever ny genesis |
|
||||
|
||||
KT løser **ikke**:
|
||||
|
||||
- Førstegangs-impersonering av en helt ny adresse (intet historisk
|
||||
bevismateriale).
|
||||
- Kollusjon mellom server og _alle_ witnesses.
|
||||
- Klient som glemmer cached STH og må re-bootstrappe.
|
||||
|
||||
---
|
||||
|
||||
## 3. Datastruktur-valg
|
||||
|
||||
Vi velger **RFC 6962-stil append-only Merkle log** + **ekstern
|
||||
adresse-index** med commitment-bevis. Begrunnelse:
|
||||
|
||||
### Vurderte alternativer
|
||||
|
||||
1. **Pure CT-log (RFC 6962):** Simple append-only Merkle tree.
|
||||
Inklusjonsbevis trivielle. Fravær-bevis _ikke_ støttet
|
||||
nativt (må scanne hele loggen).
|
||||
2. **CONIKS-tre (sparse Merkle tree over adresser):** Native fravær-bevis,
|
||||
men mye mer kompleks (epoch-baserte snapshots, prefix-trees,
|
||||
placeholder-nodes). Overkill for første iterasjon.
|
||||
3. **Hybrid (RFC 6962 log + side-index):** Loggen er sannhetskilde,
|
||||
indexen er en _commitment_-mapping `address → leaf_index`. Server
|
||||
beviser inklusjon via leaf-path, fravær via "denne adressen er ikke
|
||||
i indexen ved tree_size T" + signert STH.
|
||||
|
||||
**Valg: alternativ 3.** Det gir CT-stil enkelthet, samt fravær-bevis
|
||||
nesten gratis (commitment til indexen er en del av hver STH).
|
||||
|
||||
### Konkret format
|
||||
|
||||
#### Leaf
|
||||
|
||||
Hver leaf representerer én registrering eller revoke:
|
||||
|
||||
```
|
||||
leaf = SHA256(
|
||||
0x00 || // leaf prefix (RFC 6962)
|
||||
uint64_be(timestamp_ms) ||
|
||||
byte(operation) || // 0x01 register, 0x02 replenish, 0x03 delete
|
||||
uint16_be(len(address)) || address_bytes ||
|
||||
uint16_be(len(bundle_hash)) || bundle_hash // 32 bytes SHA-256 over canonical bundle
|
||||
)
|
||||
```
|
||||
|
||||
`bundle_hash` er deterministisk hash av:
|
||||
|
||||
```
|
||||
canonical_bundle = SHA256(
|
||||
0x01 || // bundle prefix
|
||||
identitySigningKey (32) ||
|
||||
identityDHKey (32) ||
|
||||
uint32_be(signedPreKey.keyId) ||
|
||||
signedPreKey.publicKey (32) ||
|
||||
signedPreKey.signature (64)
|
||||
)
|
||||
```
|
||||
|
||||
One-time prekeys er **ikke** med i bundle-hashen — de er ephemerale og
|
||||
ville lekket OTP-rotasjons-mønstre.
|
||||
|
||||
#### Tree
|
||||
|
||||
Merkle-tre over leaf-array, RFC 6962 §2.1:
|
||||
|
||||
- `MTH(empty) = SHA256()`
|
||||
- `MTH({d}) = SHA256(0x00 || d)` (already hashed leaf)
|
||||
- `MTH(D[n]) = SHA256(0x01 || MTH(D[0:k]) || MTH(D[k:n]))` der
|
||||
`k` er største 2-potens < n.
|
||||
|
||||
#### Signed Tree Head (STH)
|
||||
|
||||
```
|
||||
sth = {
|
||||
tree_size: uint64,
|
||||
timestamp: uint64_ms,
|
||||
root_hash: bytes(32),
|
||||
index_root: bytes(32), // commitment til adresse-index ved denne tree_size
|
||||
log_id: bytes(32), // SHA-256 av server-public-key (stabil ID)
|
||||
signature: bytes(64) // Ed25519 over canonical(rest)
|
||||
}
|
||||
```
|
||||
|
||||
`canonical(sth)` for signing:
|
||||
|
||||
```
|
||||
0x02 || // sth prefix
|
||||
uint64_be(tree_size) ||
|
||||
uint64_be(timestamp) ||
|
||||
root_hash (32) ||
|
||||
index_root (32) ||
|
||||
log_id (32)
|
||||
```
|
||||
|
||||
#### Inklusjons-bevis
|
||||
|
||||
Standard RFC 6962 audit-path: liste med søsken-hasher fra leaf til root,
|
||||
slik at klient re-beregner root og sammenligner med STH.
|
||||
|
||||
#### Konsistens-bevis
|
||||
|
||||
Standard RFC 6962 §2.1.2: bevis at tree med `tree_size = N1` er prefix
|
||||
av tree med `tree_size = N2 > N1`. Klient bruker dette for å detektere
|
||||
re-write.
|
||||
|
||||
#### Fravær-bevis
|
||||
|
||||
Adresse-indexen er en sortert liste `(address, leaf_index_of_latest)`
|
||||
serialized og hashet. `index_root` i STH er commitment.
|
||||
|
||||
For å bevise fravær av adresse `addr` ved tree_size `N`:
|
||||
|
||||
- Server returnerer hele indexen ved tree_size `N` (sortert), eller
|
||||
- (effektivt:) Returnerer naboparet `(addr_prev, addr_next)` der
|
||||
`addr_prev < addr < addr_next` lexikografisk, sammen med en
|
||||
Merkle-path i en sparse Merkle tree over indexen.
|
||||
|
||||
Første iterasjon: vi serialiserer hele indexen og lar klienten
|
||||
laste den (kompakt: <100 KB selv for 100k adresser). Senere
|
||||
optimaliserer vi til sparse Merkle tree hvis dataset vokser.
|
||||
|
||||
---
|
||||
|
||||
## 4. Friskhetsbevis (Signed Tree Heads)
|
||||
|
||||
### Frekvens
|
||||
|
||||
- **Min:** Ny STH ved hver mutasjon (register/replenish/delete) — synkront
|
||||
i write-pathen.
|
||||
- **Maks-stale:** Selv uten mutasjoner skal en STH publiseres minst hver
|
||||
**10. minutt** ("heartbeat STH" — samme tree_size, oppdatert timestamp).
|
||||
Dette gir klienter mulighet til å detektere "død" log uten å bekymre
|
||||
seg om hvorvidt logen faktisk har endret seg.
|
||||
|
||||
### Klient-akseptansevindue
|
||||
|
||||
Klient avviser STH eldre enn `now - 24 timer` (default, konfigurerbar).
|
||||
Dette beskytter mot replay av gamle STH-er som "skjuler" en mutasjon
|
||||
gjort i ettertid.
|
||||
|
||||
### Stale-STH som soft-fail
|
||||
|
||||
Hvis STH er stale men gyldig signert: klient logger advarsel,
|
||||
returnerer bundle med `proof.staleness = 'warn'` (V1) eller blokkerer
|
||||
(V2 etter dogfooding). Vi starter med _warn_, eskalerer til _block_
|
||||
når witness-økosystem er etablert.
|
||||
|
||||
---
|
||||
|
||||
## 5. Klient-verifikasjonssteg
|
||||
|
||||
På hver `fetchBundle(address)`:
|
||||
|
||||
1. Server returnerer `{ bundle, proof: { sth, leaf, audit_path, leaf_index, address_index_proof } }`.
|
||||
2. Klient verifiserer:
|
||||
- `sth.signature` mot kjent `log_public_key` (pinnet ved første
|
||||
bootstrap).
|
||||
- `sth.timestamp >= now - max_age_ms` (default 24t).
|
||||
- Re-beregner `leaf_hash` fra bundle og sammenligner med `proof.leaf`.
|
||||
- Re-beregner `root_hash` fra `audit_path + leaf` og sammenligner med
|
||||
`sth.root_hash`.
|
||||
- Verifiserer `address_index_proof` mot `sth.index_root`.
|
||||
3. Hvis klient har en cached forrige STH: sjekk **konsistens-proof**
|
||||
mellom forrige og denne. Server publiserer dette i
|
||||
`GET /v1/kt/consistency?from=<size>&to=<size>`.
|
||||
4. Hvis klient har en cached STH for samme `tree_size` med ulik
|
||||
`root_hash` → **split-view alarm**.
|
||||
|
||||
### Probabilistisk vs. obligatorisk verifisering
|
||||
|
||||
Vi velger **obligatorisk** ved hver bundle-fetch. Bundle-fetch er sjelden
|
||||
(per ny peer, ikke per melding) — kostnaden er <100ms. Probabilistisk
|
||||
verifisering ville la klienter bli lurt av "én dårlig fetch" uten
|
||||
deteksjon.
|
||||
|
||||
### Bootstrap
|
||||
|
||||
Første gang en klient møter en log: pinner `log_public_key` etter å ha
|
||||
hentet det fra et **ut-av-bånd**-pinningendepunkt eller fra `Shade.config`
|
||||
(operatør sender den med klient-config). Etterfølgende rotasjon krever
|
||||
ny genesis-STH med eksplisitt break-event signert av forrige nøkkel.
|
||||
|
||||
---
|
||||
|
||||
## 6. Witness/auditor-rolle
|
||||
|
||||
### Hva en witness gjør
|
||||
|
||||
- Periodisk poll: `GET /v1/kt/sth` (hent siste STH).
|
||||
- Lagrer alle observerte STH-er i append-only lokal store.
|
||||
- Eksponerer `GET /witness/sth?log_id=...&tree_size=...` slik at andre
|
||||
klienter kan sammenligne hva _denne_ witnessen har sett.
|
||||
- Verifiserer konsistens mellom hver ny STH og forrige.
|
||||
|
||||
### Klient-witness-gossip
|
||||
|
||||
Klient-bibliotek kan operere i tre moduser:
|
||||
|
||||
1. **Observe-only:** verifiserer kun bundle den selv henter, ingen
|
||||
gossip.
|
||||
2. **Light-witness:** poller STH hver `Xt` og lagrer lokalt; sammenligner
|
||||
med STH levert ved bundle-fetch.
|
||||
3. **Full-witness:** publiserer signerte STH-observasjoner til en
|
||||
konfigurert peer-liste eller offentlig endpoint.
|
||||
|
||||
V1 leverer 1 og 2. Mode 3 (full-witness publication-protocol) er V2
|
||||
hvis økosystem trenger det.
|
||||
|
||||
### Hvem kjører witnesses?
|
||||
|
||||
- Shade-prosjektet kjører **referanse-witness** på offentlig endpoint
|
||||
(separate-from-prekey-server).
|
||||
- Power-users / operatører kan kjøre egne via `@shade/key-transparency/witness`-
|
||||
API.
|
||||
- Tredjeparts auditors (typisk security-research) er invitert.
|
||||
|
||||
Vi krever **ikke** federation/konsensus mellom witnesses i V1 — gossip
|
||||
er rent "har du sett samme STH som meg?".
|
||||
|
||||
---
|
||||
|
||||
## 7. Operatørkost
|
||||
|
||||
### Lagring
|
||||
|
||||
- **Per leaf:** 32 bytes (hash) + ~80 bytes adresse-index entry =
|
||||
~112 bytes.
|
||||
- **100k adresser, 1 rotasjon/år, 1 replenish/uke:** ~5.4M leaves =
|
||||
~600 MB log. Tre-strukturen er beregnet on-demand, ikke lagret.
|
||||
- **Index:** ~100k × 80B = 8 MB i minne (cacheable).
|
||||
|
||||
### CPU
|
||||
|
||||
- STH-signing: 1 Ed25519-signering per mutasjon + heartbeat = <1k/dag for
|
||||
små deployments. Trivielt.
|
||||
- Audit-path-beregning: O(log N) ved fetch. <1ms.
|
||||
- Konsistens-proof: O(log N).
|
||||
|
||||
### Backup
|
||||
|
||||
Logen MÅ aldri miste data — sletting eller corruption ødelegger
|
||||
integritet permanent. Strategi:
|
||||
|
||||
- Loggen lagres som append-only tabell `shade_kt_log` (PG) med
|
||||
`(leaf_index, leaf_hash, leaf_data_json)`.
|
||||
- Backup hver time + WAL-shipping anbefalt.
|
||||
- Ved corruption: se §10 Recovery.
|
||||
|
||||
### STH-signing-key
|
||||
|
||||
- Genereres ved første KT-aktivering, lagres i operatør-styrt secret
|
||||
(env, KMS, eller på disk for hjemme-server).
|
||||
- Rotasjon: **breaking event** — krever ny genesis-STH der ny key
|
||||
signerer melding "rotated from ${old_key}" med _gammel_ key. Klient
|
||||
må eksplisitt akseptere rotasjonen.
|
||||
|
||||
---
|
||||
|
||||
## 8. Migrasjon
|
||||
|
||||
### Server-side
|
||||
|
||||
KT er **opt-in** på operatør-nivå. `createPrekeyServer({ keyTransparency:
|
||||
{ enabled, store, signingKey } })`. Når slått på:
|
||||
|
||||
1. Server skriver alle eksisterende identiteter inn som genesis-leaves
|
||||
ved boot.
|
||||
2. Første STH publiseres med `tree_size = N` der N er antall
|
||||
eksisterende adresser.
|
||||
3. Klient som henter bundle får proof; klient som ikke støtter KT
|
||||
ignorerer proof-felt (forward-compatible).
|
||||
|
||||
### Klient-side
|
||||
|
||||
`@shade/sdk`-config:
|
||||
|
||||
```ts
|
||||
createShade({
|
||||
keyTransparency: {
|
||||
mode: 'observe' | 'light-witness' | 'off',
|
||||
logPublicKey: '<base64>',
|
||||
maxStaleMs: 86_400_000,
|
||||
},
|
||||
// ...
|
||||
})
|
||||
```
|
||||
|
||||
`mode: 'off'` (default for backward-compat første release) — ignorerer
|
||||
proof. Ny SDK med `mode: 'observe'` verifiserer men feiler ikke harde
|
||||
hvis proof mangler. `mode: 'observe-strict'` (senere) krever proof.
|
||||
|
||||
### Eksisterende deployments
|
||||
|
||||
Operatør kan rulle KT inn på live server uten klient-update:
|
||||
|
||||
1. Skru på KT i server-config → server begynner å produsere proofs.
|
||||
2. Gamle klienter ignorerer proof-felt (de er additive i bundle-respons).
|
||||
3. Nye klienter med `mode: 'observe'` begynner å verifisere.
|
||||
4. Når operatør har testet og publisert log-public-key OOB, kan brukere
|
||||
skifte til `'light-witness'`.
|
||||
|
||||
---
|
||||
|
||||
## 9. Akseptansekriterier
|
||||
|
||||
- [ ] `@shade/key-transparency` pakke leverer:
|
||||
- Merkle log core (RFC 6962 hash-funksjoner).
|
||||
- STH-signing/verifikasjon.
|
||||
- Inklusjons-bevis generering + verifisering.
|
||||
- Konsistens-bevis generering + verifisering.
|
||||
- Adresse-index med commitment.
|
||||
- Witness-light klient.
|
||||
- Cross-platform (TS-only, ingen native deps).
|
||||
- [ ] `@shade/server` integrasjon:
|
||||
- `KTLogStore`-interface (memory + postgres).
|
||||
- Routes: `GET /v1/kt/sth`, `GET /v1/kt/sth/:tree_size`,
|
||||
`GET /v1/kt/consistency`, `GET /v1/kt/inclusion/:address`.
|
||||
- Bundle-fetch returnerer `{ bundle, proof }` når KT aktivert.
|
||||
- Heartbeat-STH-publisering hver 10. minutt (configurable).
|
||||
- [ ] `@shade/transport` `ShadeFetchTransport`:
|
||||
- Aksepterer optional `keyTransparency`-verifier.
|
||||
- `fetchBundle()` returnerer `{ bundle, proof?: KTProof }`.
|
||||
- [ ] `@shade/sdk` `Shade`:
|
||||
- `keyTransparency`-config.
|
||||
- Verifiserer proof ved hver bundle-fetch når aktivert.
|
||||
- Cacher STH for split-view-deteksjon.
|
||||
- [ ] **End-to-end test: split-view detection.**
|
||||
- Test-server gir Bob bundle X, Charlie bundle Y for samme adresse `alice`.
|
||||
- Bob+Charlie kjører som light-witness, gossiper STH-er.
|
||||
- Test asserter at mismatch detekteres innen N polls.
|
||||
- [ ] **End-to-end test: log re-write detection.**
|
||||
- Server skriver om historie (test-only API).
|
||||
- Konsistens-proof feiler på neste fetch.
|
||||
- [ ] Operatør-doc dekker recovery-strategi.
|
||||
- [ ] CHANGELOG, README, ROADMAP oppdatert.
|
||||
- [ ] Cross-platform vector-test for Merkle hash + STH (Android/TS
|
||||
paritet, samme som V3.5-tradisjonen).
|
||||
|
||||
---
|
||||
|
||||
## 10. Recovery
|
||||
|
||||
### Log corruption
|
||||
|
||||
Hvis log-data tapes (disk-feil før backup): **kan ikke gjenopprettes
|
||||
uten å miste integritet** — det er hele poenget.
|
||||
|
||||
Recovery-prosedyre:
|
||||
|
||||
1. Operatør publiserer "log-restart" event signert med STH-keyen.
|
||||
2. Genesis-STH genereres på nytt med ny `log_id` (= ny offentlig nøkkel
|
||||
eller eksplisitt versjon).
|
||||
3. Klienter som har cached STH-er fra gammel log varsles via
|
||||
eksplisitt diskrepans i `log_id`.
|
||||
4. Brukere som er bekymret må OOB-verifisere identiteter (V3.3-gate
|
||||
trigges automatisk for fingerprint-rotasjon).
|
||||
|
||||
### Stale signing-key
|
||||
|
||||
Hvis STH-keyen lekkes: rotasjon krever break-event (§7). Inntil
|
||||
brukerne aksepterer ny key, oppfører cient-bibliotek seg som om STH
|
||||
mangler (soft-fail i `observe`-mode, blokkerer i `observe-strict`).
|
||||
|
||||
---
|
||||
|
||||
## 11. Åpne spørsmål (lukket før kode)
|
||||
|
||||
| Spørsmål | Svar |
|
||||
|---|---|
|
||||
| Hvordan distribueres `log_public_key` til klient første gang? | Operatør embedder i `Shade.config` ved app-init. OOB-pinning er fallback. |
|
||||
| Skal one-time prekeys være med i bundle-hash? | Nei — ephemerale, og deres rotasjon ville støy-fylle loggen. |
|
||||
| Konflikt: STH ved hver mutasjon vs. batched STH? | Per mutasjon. Heartbeat hver 10 min uansett. Batching vurderes som optimalisering hvis throughput blir et problem (ikke nå). |
|
||||
| Hva skjer ved replenish (kun OTP-tilført)? | Skriver ikke til log (bundle-hash uendret). Heartbeat-STH dekker friskhet. |
|
||||
| Hva med DELETE? | Skriver tombstone-leaf med `operation = 0x03`. Identiteten i indexen markeres som "deleted at tree_size N". |
|
||||
| Sparse Merkle tree for index-proof? | Senere — V1 bruker hele indexen i fravær-proof. <100 KB ved 100k adresser er akseptabelt. |
|
||||
| Klient-cache eviction-policy for STH? | LRU på `log_id`, last-N (default 100). Klient holder _alltid_ siste sett STH. |
|
||||
| Witness-publication-protokoll? | V1 har poll-only (`GET /witness/sth`); push-publication er V2. |
|
||||
|
||||
Alle åpne spørsmål har konkrete svar. Implementasjon kan starte.
|
||||
|
||||
---
|
||||
|
||||
## 12. Pakke-struktur
|
||||
|
||||
```
|
||||
packages/shade-key-transparency/
|
||||
├── package.json # @shade/key-transparency, v0.4.0
|
||||
├── src/
|
||||
│ ├── index.ts # Public exports
|
||||
│ ├── hashes.ts # RFC 6962 leaf/node hashing
|
||||
│ ├── log.ts # MerkleLog (in-memory) + audit-path
|
||||
│ ├── consistency.ts # Consistency-proof gen/verify
|
||||
│ ├── sth.ts # STH sign / verify / canonical bytes
|
||||
│ ├── index-tree.ts # Address index commitment
|
||||
│ ├── proof.ts # KTProof type + bundle-proof verifier
|
||||
│ ├── store.ts # KTLogStore interface (server-side)
|
||||
│ ├── memory-store.ts # In-memory KTLogStore
|
||||
│ ├── witness.ts # Light-witness client
|
||||
│ └── errors.ts # KT-specific error types
|
||||
└── tests/
|
||||
├── hashes.test.ts
|
||||
├── log.test.ts # RFC 6962 test vectors
|
||||
├── consistency.test.ts
|
||||
├── sth.test.ts
|
||||
├── index-tree.test.ts
|
||||
├── proof.test.ts
|
||||
└── split-view.test.ts # End-to-end split-view detection
|
||||
```
|
||||
|
||||
Server-integrasjon i `@shade/server`:
|
||||
|
||||
```
|
||||
packages/shade-server/src/
|
||||
├── kt-routes.ts # /v1/kt/* routes
|
||||
├── kt-integration.ts # Hook bundle-fetch + register/delete to log
|
||||
└── ...
|
||||
```
|
||||
|
||||
Postgres-implementasjon i `@shade/storage-postgres`:
|
||||
|
||||
```
|
||||
packages/shade-storage-postgres/src/
|
||||
├── postgres-kt-store.ts # KTLogStore on PG
|
||||
└── ...
|
||||
```
|
||||
|
||||
Klient-integrasjon i `@shade/transport` + `@shade/sdk`:
|
||||
|
||||
```
|
||||
packages/shade-transport/src/
|
||||
├── kt-verifier.ts # Proof-verifier for fetchBundle
|
||||
└── ...
|
||||
|
||||
packages/shade-sdk/src/
|
||||
├── kt.ts # Shade.keyTransparency config + cache
|
||||
└── ...
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 13. Test-strategi
|
||||
|
||||
1. **RFC 6962 test-vektorer:** importer kjente vektorer fra
|
||||
<https://datatracker.ietf.org/doc/html/rfc6962#appendix-A>.
|
||||
2. **Property-tests (fast-check):** for hver tree_size N og hvert
|
||||
leaf-index i: `verify(audit_path(i, N), leaf, sth) === true`.
|
||||
3. **Konsistens-bevis property-tests:** for N1 < N2:
|
||||
`verify_consistency(proof, sth1, sth2) === true`.
|
||||
4. **Split-view e2e:** to klienter, ondsinnet test-server, witness
|
||||
gossip oppdager mismatch.
|
||||
5. **Re-write-detection e2e:** server muterer log-historie, klient
|
||||
neste fetch får konsistens-proof som feiler.
|
||||
6. **Cross-platform:** Android (Kotlin) + TS gir samme leaf-hash for
|
||||
samme bundle (V3.5-paritet er forutsetning, så dette må også gå
|
||||
gjennom kotlin-port; for V3.12 første release dekker vi TS — Android
|
||||
port er V3.13).
|
||||
7. **Stale STH:** klient avviser STH > max_age.
|
||||
8. **Bootstrap-pinning:** klient feiler hvis log_public_key ikke matcher.
|
||||
|
||||
---
|
||||
|
||||
## 14. Sikkerhetsvurdering
|
||||
|
||||
- **Falsk trygghet hvis halvveis:** Avhjelpes ved at default-mode er `'off'`,
|
||||
bare _eksplisitt_ aktivert KT gir hardere garantier. Dokumentasjon
|
||||
fremhever at `'observe'` er observasjon, ikke obstruksjon, til
|
||||
økosystemet er etablert.
|
||||
- **Server-side mutability av historie:** Avhjelpes ved at `KTLogStore`
|
||||
kun har `append()` — ingen `update()`/`delete()` på historiske leaves.
|
||||
PG-tabellen har CHECK constraint og BEFORE-triggers for ekstra defense
|
||||
in depth (se §7).
|
||||
- **STH-key compromise:** dokumentert §10. Operatør-ansvar.
|
||||
- **DoS via massive index-proofs:** index-proof er i V1 hele indexen.
|
||||
100 KB per fetch er overkommelig; rate-limiteren dekker excess.
|
||||
- **Replay av gammel proof:** STH-timestamp + max_age beskytter.
|
||||
|
||||
---
|
||||
|
||||
## 15. Approval
|
||||
|
||||
Når dette notatet er reviewed (in-tree review er nok for å kommitte
|
||||
første implementasjon; ekstern crypto-review er pre-deploy-krav per
|
||||
V3.12 §"Pre-requisite designnotat"), kan implementasjon starte.
|
||||
|
||||
**Implementasjon-rekkefølge** (alle commits i samme branch):
|
||||
|
||||
1. `@shade/key-transparency` core (Merkle log, STH, proofs).
|
||||
2. Server-integrasjon (`@shade/server` + memory/postgres KTLogStore).
|
||||
3. Klient-integrasjon (`@shade/transport` verifier + `@shade/sdk` config).
|
||||
4. Witness-light + e2e split-view-test.
|
||||
5. Operatør-doc + CHANGELOG + README + ROADMAP.
|
||||
|
||||
— end of design —
|
||||
99
docs/archive/V3.12.md
Normal file
99
docs/archive/V3.12.md
Normal file
@@ -0,0 +1,99 @@
|
||||
# Shade V3.12 — Key Transparency
|
||||
|
||||
**Status:** Done (0.4.0). Designnotat: `docs/V3.12-DESIGN.md`.
|
||||
Operatør-/recovery-guide: `docs/key-transparency.md`.
|
||||
**Effort:** XXL (4+ måneder, multi-quarter)
|
||||
**Forrige:** V3.5 (hovedplattformene stabile først)
|
||||
**Adresserer:** V2.3 §1A
|
||||
|
||||
---
|
||||
|
||||
## Mål
|
||||
|
||||
Reduser tillit til prekey-server fra "blind tillit" til "verifiserbar log".
|
||||
Når serveren utleverer et bundle, skal det være kryptografisk forpliktet i
|
||||
en **append-only log** som klienter (eller tredjeparts-auditors) kan
|
||||
verifisere. Et split-view-angrep der serveren viser ulike bundles til ulike
|
||||
klienter blir fanget av gossip.
|
||||
|
||||
---
|
||||
|
||||
## Pre-requisite: designnotat
|
||||
|
||||
**Ingen kode før dette er review'd og approved:**
|
||||
|
||||
- Trusselmodell-tillegg: hva CT/attest faktisk løser, hva som forblir åpent.
|
||||
- Datastruktur-valg: append-only Merkle log (CT-stil), CONIKS-tre, eller
|
||||
hybrid.
|
||||
- Friskhetsbevis: hvor ofte signed tree heads utgis; hva er "stale"?
|
||||
- Klient-verifikasjonssteg: må klient verifisere på hver bundle-fetch,
|
||||
eller probabilistisk?
|
||||
- Witness/auditor-rolle: hvem kjører dem? Hvordan gossip mellom klienter?
|
||||
- Operatørkost: log-størrelse, signing-frekvens, backup-strategi.
|
||||
- Migrasjon: eksisterende prekey-server → log-utvidet.
|
||||
|
||||
Designnotatet er en `docs/V3.12-DESIGN.md`-PR som må review'es av minst én
|
||||
ekstern crypto-orientert reviewer.
|
||||
|
||||
---
|
||||
|
||||
## Mulig scope (etter designnotat)
|
||||
|
||||
### Inn (estimat)
|
||||
|
||||
- Append-only log som tillegg til prekey-server.
|
||||
- Inklusjons-bevis ved bundle-fetch (Merkle-path).
|
||||
- Fravær-bevis for "denne adressen har ikke registrert siden timestamp T".
|
||||
- Signed tree heads (STH) publisert på fast interval.
|
||||
- Klient-bibliotek: `@shade/key-transparency` med verifisering.
|
||||
- Witness-API: tredjeparts-auditor kan hente STH-er og logge gossip.
|
||||
|
||||
### Ut (eksplisitt)
|
||||
|
||||
- Federated log (multi-server gossip) — for stort for første iterasjon.
|
||||
- Legal/compliance-side av audit-log.
|
||||
- "Vi løser MITM-på-første-kontakt-helt" — KT alene fanger split-view, ikke
|
||||
første-kontakt.
|
||||
|
||||
---
|
||||
|
||||
## Risiko-vurdering
|
||||
|
||||
KT er det **vanskeligste enkeltpunkt** i hele roadmapen:
|
||||
|
||||
1. **Halvveis-implementert KT er verre enn ingen KT** — gir falsk trygghet,
|
||||
brukere slutter å verifisere OOB.
|
||||
2. Operativt komplekst — log må aldri skrive om historie. En enkelt
|
||||
restart-bug = ødelagt integritet.
|
||||
3. Klient-verifikasjons-logikk må kjøre på hver bundle-fetch, eller
|
||||
risikere at én "gammel" klient blir lurt.
|
||||
4. Witness-økosystem krever uavhengige aktører — Shade alene kan ikke
|
||||
garantere det.
|
||||
|
||||
**Beslutningskriterium:** Hvis designnotatet etterlater åpne "hvordan
|
||||
håndterer vi X?"-spørsmål uten klare svar, parker V3.12. Pragmatisk
|
||||
alternativ er **V3.3 (fingerprint-gate)** + **V3.10 (social recovery)** —
|
||||
som sammen gir 80 % av MITM-beskyttelsen uten KT-kompleksiteten.
|
||||
|
||||
---
|
||||
|
||||
## Akseptansekriterier (hvis det implementeres)
|
||||
|
||||
- [ ] Designnotat passert ekstern review.
|
||||
- [ ] Klient detekterer split-view i ende-til-ende-test (server gir to
|
||||
versjoner av samme adresse → klient fanger mismatch).
|
||||
- [ ] Witness-API testet med minst én ekstern auditor-instans.
|
||||
- [ ] Operatør-doc dekker recovery hvis log korrumperer.
|
||||
|
||||
---
|
||||
|
||||
## Avhengigheter
|
||||
|
||||
- V3.5 — Android/TS paritet må være solid før vi legger på et nytt
|
||||
verifikasjons-lag.
|
||||
|
||||
---
|
||||
|
||||
## Migrasjon
|
||||
|
||||
Helt opt-in. Operatører som ikke ønsker KT kjører videre uendret.
|
||||
146
docs/archive/V3.2.md
Normal file
146
docs/archive/V3.2.md
Normal file
@@ -0,0 +1,146 @@
|
||||
# Shade V3.2 — At-Rest Storage Encryption
|
||||
|
||||
**Status:** Implementert (0.4.0) — `@shade/storage-encrypted`, `@shade/keychain`,
|
||||
`shade migrate-storage`, `shade rotate-storage-key`
|
||||
**Effort:** L (4–8 uker)
|
||||
**Forrige:** V3.1
|
||||
**Adresserer:** V2.1 §2
|
||||
|
||||
---
|
||||
|
||||
## Mål
|
||||
|
||||
Opt-in beskyttelse av sensitiv state — identity-nøkler, session-state, valgfri
|
||||
stream-resume-secret — med nøkler som **ikke** ligger i klartekst i databasen.
|
||||
Trusselmodellen sier i dag eksplisitt at en stjålet DB eksponerer private
|
||||
nøkler; dette løser det for deploys som velger å aktivere det.
|
||||
|
||||
---
|
||||
|
||||
## Scope
|
||||
|
||||
### Inn
|
||||
|
||||
- Ny `EncryptedStorageProvider`-wrapper som dekorerer `SQLiteStorage` /
|
||||
`PostgresStorage`.
|
||||
- Per-rad AES-256-GCM på sensitive felter (`identity_*`, `session_*`,
|
||||
valgfritt `stream_state.streamSecret`).
|
||||
- KDF-pluggin (default `scrypt` fra `@noble/hashes`) for passphrase-basert
|
||||
master-nøkkel.
|
||||
- Tre nøkkelkilder ut av boksen:
|
||||
1. **Passphrase + KDF** — utvikler oppgir secret ved oppstart.
|
||||
2. **OS keychain** — macOS Keychain, Linux libsecret, Windows Credential
|
||||
Vault (Node-only).
|
||||
3. **App-injected key** — appens egen kode forsyner 32-byte nøkkel (mest
|
||||
fleksibel).
|
||||
- Migrasjons-CLI: `shade migrate-storage --encrypt --key-source=...`.
|
||||
- Trusselmodell-oppdatering: "når enabled, hva er fortsatt udekket" — memory
|
||||
compromise, swap, runtime-tap.
|
||||
|
||||
### Ut
|
||||
|
||||
- Browser/IndexedDB at-rest (egen pakke, vurderes etter V3.8).
|
||||
- HSM/Secure Enclave (separate driver senere).
|
||||
- "Always-on by default" — vi flyger opt-in for å ikke bryte eksisterende
|
||||
deploys.
|
||||
|
||||
---
|
||||
|
||||
## Design
|
||||
|
||||
### Krypteringsenhet
|
||||
|
||||
- Per-rad AEAD: `nonce(12) || ciphertext || tag(16)`.
|
||||
- `nonce = HKDF(rowKey, "shade-row-nonce-v1" || tableName || pk)[..12]` —
|
||||
deterministisk per (tabell, pk) for å unngå nonce-reuse uten å lagre nonce
|
||||
separat. Endring av (tabell, pk) → re-encryption.
|
||||
- AAD binder `tableName || columnName || pk` så feltombytting blokkeres.
|
||||
|
||||
### Nøkkelhierarki
|
||||
|
||||
```text
|
||||
masterKey (fra kilde — passphrase / keychain / app-injected)
|
||||
│
|
||||
├─ HKDF("shade-storage-v1") → storageKey (32 bytes)
|
||||
│ │
|
||||
│ └─ HKDF(storageKey, table || column) → fieldKey
|
||||
│
|
||||
└─ HKDF("shade-storage-version-v1") → versjonsnøkkel (rotasjon)
|
||||
```
|
||||
|
||||
### Migrasjon
|
||||
|
||||
1. CLI leser ukryptert DB.
|
||||
2. Skriver rad-for-rad-kryptering til ny `_v2`-tabell.
|
||||
3. Atomisk rename + drop gammel.
|
||||
4. Backup `.bak`-fil etterlatt i samme dir.
|
||||
|
||||
### Rotasjon
|
||||
|
||||
- `shade rotate-storage-key --new-source=...` re-krypterer med ny masterKey.
|
||||
- Online ratchet (les med gammel, skriv med ny) for store DB.
|
||||
|
||||
---
|
||||
|
||||
## Leveranser
|
||||
|
||||
### Pakker
|
||||
|
||||
- Ny modul: `@shade/storage-encrypted` (re-export over SQLite/PG).
|
||||
- Utvidelse i `@shade/cli`: `migrate-storage`, `rotate-storage-key`.
|
||||
- Hjelpe-pakke: `@shade/keychain` (Node-only, valgfri peer-dep) for OS-keychain.
|
||||
|
||||
### Tester
|
||||
|
||||
- Unit: KDF-derivasjon, nonce-determinisme, AAD-binding.
|
||||
- Integration: full lifecycle på SQLite + PG; start/stopp; krasj under
|
||||
migrasjon.
|
||||
- Tamper: bit-flip i ciphertext / AAD / nonce → dekrypterings-feil.
|
||||
- Vector-fil: kryss-sjekk masterKey → fieldKey-derivasjon mot
|
||||
`test-vectors/storage-encryption.json`.
|
||||
|
||||
### Dokumentasjon
|
||||
|
||||
- `docs/storage-encryption.md` — full guide.
|
||||
- `THREAT-MODEL.md` — ny kolonne "with at-rest enabled".
|
||||
- Migrasjonsnotat i `MIGRATION.md`.
|
||||
|
||||
---
|
||||
|
||||
## Akseptansekriterier
|
||||
|
||||
- [ ] Eksisterende ukryptert deploy fortsetter uten endringer (opt-in).
|
||||
- [ ] `shade migrate-storage --encrypt` migrerer en levende SQLite uten
|
||||
datatap, verifisert med dump-diff.
|
||||
- [ ] Rotasjon kan gjøres uten downtime > 5 s for små DB.
|
||||
- [ ] Wrong passphrase / wrong key → klar feilmelding, ikke krasj.
|
||||
- [ ] Test-vectors deles med Android-implementasjonen (V3.5 forplikter at
|
||||
vector-filen kjøres der).
|
||||
|
||||
---
|
||||
|
||||
## Avhengigheter
|
||||
|
||||
- V3.1 — `THREAT-MODEL.md` skal være lenket til testene først, så vi kan
|
||||
utvide tabellen.
|
||||
|
||||
---
|
||||
|
||||
## Risiko
|
||||
|
||||
**Datatap.** En migrasjon som krasjer halvveis kan etterlate korrupt DB.
|
||||
Mitigeres ved:
|
||||
|
||||
- Atomic-rename + `.bak`-fil.
|
||||
- Dry-run-modus (`--dry-run` validerer all dekryptering før skriving).
|
||||
- Refuser å starte hvis WAL har uncommitted writes.
|
||||
|
||||
**Nøkkeltap = totaltap.** Hvis bruker mister passphrase = ingen tilgang.
|
||||
Dokumenter klart, og pek på V3.10 (Social Recovery) som langtidsløsning.
|
||||
|
||||
---
|
||||
|
||||
## Migrasjon
|
||||
|
||||
0.3.x deploys er ukrypterte → fortsatt ukrypterte. Aktivering er én
|
||||
CLI-kommando. Backwards-kompatibel.
|
||||
147
docs/archive/V3.3.md
Normal file
147
docs/archive/V3.3.md
Normal file
@@ -0,0 +1,147 @@
|
||||
# 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
|
||||
|
||||
1. **Før første store fil** — `Shade.upload` over en bytes-terskel uten
|
||||
verifisert peer.
|
||||
2. **Før backup-import** — `Shade.importBackup` blokkerer til peer (eller egen
|
||||
identitet) er bekreftet.
|
||||
3. **Ny enhet med rotert identitet** — `acceptIdentityChange` blokkerer på
|
||||
første bruk inntil verifisert.
|
||||
4. **Før `@shade/inbox` fan-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`:
|
||||
|
||||
```sql
|
||||
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
|
||||
|
||||
```text
|
||||
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 `threshold` ut — 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.
|
||||
124
docs/archive/V3.4.md
Normal file
124
docs/archive/V3.4.md
Normal file
@@ -0,0 +1,124 @@
|
||||
# Shade V3.4 — Observability v2 (OpenTelemetry)
|
||||
|
||||
**Status:** Implementert (2026-05-02) — `@shade/observability` 0.1.0,
|
||||
hekt inn i sdk/transfer/server/files/core. Off by default; flip
|
||||
`SHADE_OTEL_ENABLED=1` for å aktivere.
|
||||
**Effort:** M (2–4 uker)
|
||||
**Forrige:** V3.1
|
||||
**Adresserer:** V2.3 §4
|
||||
|
||||
---
|
||||
|
||||
## Mål
|
||||
|
||||
Gi produksjonsteam **distribuerte spor** rundt `TransferEngine`,
|
||||
prekey-routes og `@shade/files` — uten å lekke plaintext-adresser, payloads
|
||||
eller eksakte chunk-størrelser. Bygger videre på Prometheus-metrics som
|
||||
allerede finnes.
|
||||
|
||||
---
|
||||
|
||||
## Scope
|
||||
|
||||
### Inn
|
||||
|
||||
- Opt-in OpenTelemetry-instrumentasjon via `@opentelemetry/api`.
|
||||
- Spans rundt:
|
||||
- `TransferEngine.upload` / `.download` (med lane-tags, retry-counts).
|
||||
- `ShadeSessionManager.encrypt` / `.decrypt` (per-peer mutex-akkvisisjon,
|
||||
ratchet-step).
|
||||
- `createPrekeyRoutes` (per route, status-koder).
|
||||
- `@shade/files` op-handlers (har allerede `onMetric` — utvides til OTel).
|
||||
- PII-policy-doc: hva som **aldri** logges, hva binnes, hva pseudonymiseres.
|
||||
- Sample-policy default off; on med `SHADE_OTEL_ENABLED=1`.
|
||||
|
||||
### Ut
|
||||
|
||||
- Trace-eksport til SaaS-leverandører (det er deploy-konfig, ikke vår kode).
|
||||
- Logg-aggregering — `@shade/server` har allerede strukturert JSON.
|
||||
|
||||
---
|
||||
|
||||
## Design
|
||||
|
||||
### Span-attributter
|
||||
|
||||
| Attribute | Verdi |
|
||||
|-----------|-------|
|
||||
| `shade.peer.hash` | `sha256(address).slice(0, 8)` — stabil pseudonym |
|
||||
| `shade.bytes.bin` | binnet — `"≤4KB"`, `"4–64KB"`, `"64KB–1MB"`, `"≥1MB"` |
|
||||
| `shade.lane.count` | 1 / 4 / 16 |
|
||||
| `shade.retry.count` | int |
|
||||
| `shade.error.code` | `SHADE_*`-kode |
|
||||
|
||||
**Aldri:** `shade.peer.address`, `shade.payload`, `shade.bytes.exact`.
|
||||
|
||||
### API
|
||||
|
||||
```ts
|
||||
import { withTracer } from '@shade/observability';
|
||||
|
||||
const shade = await createShade({
|
||||
...,
|
||||
observability: withTracer(myTracer, { sample: 0.1 }),
|
||||
});
|
||||
```
|
||||
|
||||
`withTracer()` er no-op hvis `tracer` er `undefined` eller
|
||||
`SHADE_OTEL_ENABLED` ikke er satt.
|
||||
|
||||
---
|
||||
|
||||
## Leveranser
|
||||
|
||||
### Pakker
|
||||
|
||||
- Ny submodul `@shade/observability` (peer-dep `@opentelemetry/api`).
|
||||
- Hooks i `@shade/sdk`, `@shade/transfer`, `@shade/server`, `@shade/files`.
|
||||
|
||||
### Tester
|
||||
|
||||
- Span emitteres med riktige attributter (mock tracer).
|
||||
- Sample-rate respekteres.
|
||||
- Off-by-default verifisert.
|
||||
- Regex-grep mot recorder fanger plaintext-PII.
|
||||
|
||||
### Dokumentasjon
|
||||
|
||||
- `docs/observability.md` — setup + PII-policy.
|
||||
- `docs/DEPLOYMENT.md` — environment-variabler.
|
||||
|
||||
---
|
||||
|
||||
## Akseptansekriterier
|
||||
|
||||
- [x] Default deploy uten OTel: ingen performance-regresjon (`withTracer`
|
||||
returnerer delt `NOOP_HOOK` når `SHADE_OTEL_ENABLED` ikke er satt).
|
||||
- [x] Med OTel på: spans for upload/download (`shade.transfer.upload`,
|
||||
`shade.transfer.download`), prekey-routes (`shade.prekey.request`),
|
||||
session encrypt/decrypt (`shade.session.{encrypt,decrypt}`), og
|
||||
`@shade/files` ops (`shade.files.op`).
|
||||
- [x] Automatisert grep-test fanger plaintext-PII i spans
|
||||
(`packages/shade-observability/tests/integration-pii.test.ts` +
|
||||
`packages/shade-transfer/tests/observability.test.ts`,
|
||||
`safeAttribute()` blokkerer fra-utvikler-introduksert PII).
|
||||
|
||||
---
|
||||
|
||||
## Avhengigheter
|
||||
|
||||
- V3.1 — basis-docs.
|
||||
|
||||
---
|
||||
|
||||
## Risiko
|
||||
|
||||
- **Performance-overhead.** Mitiger ved aggressiv default-off + sampling.
|
||||
- **PII-lekkasje** hvis utviklere legger til egne attributter. Mitiger ved
|
||||
å publisere "safe attribute"-helpers og PII-linter.
|
||||
|
||||
---
|
||||
|
||||
## Migrasjon
|
||||
|
||||
Ingen — opt-in.
|
||||
125
docs/archive/V3.5.md
Normal file
125
docs/archive/V3.5.md
Normal file
@@ -0,0 +1,125 @@
|
||||
# Shade V3.5 — Android Parity & Cross-Platform CI
|
||||
|
||||
**Status:** Done (kryptografisk lag + CI-gate). Android-KeystoreStorage og scrypt/argon2id-paritet er post-GA-arbeid sporet i `android/shade-android/ROADMAP-ANDROID.md` — ikke en 4.0 GA-blocker.
|
||||
**Effort:** XL (2–4 måneder, parallelliserbar)
|
||||
**Forrige:** V3.1
|
||||
**Adresserer:** V2.1 §3
|
||||
|
||||
---
|
||||
|
||||
## Mål
|
||||
|
||||
Gjør Kotlin-implementasjonen **byte-kompatibel** med TS-implementasjonen, og
|
||||
forsegle paritet via **CI-gate** som kjører delte test-vectors i begge språk.
|
||||
Ingen "production"-label på Android før ratchet + proto + streams 0x11 er
|
||||
grønne.
|
||||
|
||||
---
|
||||
|
||||
## Scope
|
||||
|
||||
### Inn — paritet-sjekkpunkter (eksplisitt)
|
||||
|
||||
1. **KDF-chain** — root key + chain key derivasjoner.
|
||||
Vector: `test-vectors/kdf-chain.json`.
|
||||
2. **HKDF** — labels for `info`-felt.
|
||||
Vector: `test-vectors/hkdf.json`.
|
||||
3. **X3DH** — full agreement med samme bundles.
|
||||
Vector: `test-vectors/x3dh.json`.
|
||||
4. **Ratchet message** — encrypt/decrypt roundtrip (legg til vector).
|
||||
5. **Fingerprint** — 60-digit safety number.
|
||||
Vector: `test-vectors/fingerprint.json`.
|
||||
6. **Wire format 0x02** — encode/decode.
|
||||
Vector: `test-vectors/wire-format.json`.
|
||||
7. **Streams 0x11** — multi-lane chunk encryption (M-Cross 3, ikke i M-Cross 1).
|
||||
8. **Backup-format** — passphrase-basert KDF + AES-GCM payload.
|
||||
|
||||
### Inn — milestoner
|
||||
|
||||
- **M-Cross 1 ✅** — keys + HKDF + X3DH + fingerprint.
|
||||
- **M-Cross 2 ✅** — ratchet step (encrypt + decrypt roundtrip) + wire 0x02
|
||||
(RatchetMessage + PreKeyMessage med/uten OTPK). Vector-versjon `2`.
|
||||
- **M-Cross 3 ✅** — streams 0x11 (KDF, deterministic chunk nonce/AAD, wire 0x11
|
||||
encode/decode). End-to-end socket interop pending; ikke gating-blokker.
|
||||
- **M-Cross 4 ✅** — backup-format HKDF + AEAD, gruppe sender-keys
|
||||
(kdfChainKey + Ed25519 sign(aad ‖ ct)), storage-HKDF (storageKey,
|
||||
fieldKey, rowNonce). Gjenstående: scrypt master-key (Bouncy Castle),
|
||||
argon2id-bytte, Android-KeystoreStorage som søsken-modul.
|
||||
|
||||
### Inn — CI
|
||||
|
||||
- Gitea Actions matrix-job:
|
||||
- Bun-runner kjører `bun test:vectors` mot `test-vectors/*.json`.
|
||||
- Gradle-runner kjører `./gradlew vectorTests` mot samme filer.
|
||||
- PR-gate: begge må passere.
|
||||
- Vector-genereringsskript (`scripts/generate-vectors.ts`) finnes — utvid
|
||||
til 7 + 8.
|
||||
|
||||
### Ut
|
||||
|
||||
- iOS — egen Swift-port er framtidig roadmap, ikke V3.5.
|
||||
- Native bindings i `shade-android` (vi bruker Tink i JVM-kode).
|
||||
|
||||
---
|
||||
|
||||
## Leveranser
|
||||
|
||||
### Kotlin
|
||||
|
||||
- Full ratchet-implementasjon (M-Cross 2).
|
||||
- Wire 0x02 encode/decode.
|
||||
- Streams 0x11 (M-Cross 3).
|
||||
- Tink-storage-adapter med Keystore.
|
||||
|
||||
### Test-vectors
|
||||
|
||||
- Utvid `scripts/generate-vectors.ts` med ratchet-step + streams + backup.
|
||||
- Versjons-tag på vector-filer (`{ "version": 2, ... }`).
|
||||
|
||||
### CI
|
||||
|
||||
- `.gitea/workflows/cross-vectors.yml` — Bun + Gradle matrise.
|
||||
- Fail-policy: hvis vector-fil endres, **begge** runners må publisere
|
||||
passing før merge.
|
||||
|
||||
### Dokumentasjon
|
||||
|
||||
- `android/shade-android/ROADMAP-ANDROID.md` — eksplisitte milestoner +
|
||||
status per sjekkpunkt.
|
||||
- `docs/cross-platform.md` — hvordan legge til en ny vector + hvordan
|
||||
kjøre lokalt.
|
||||
|
||||
---
|
||||
|
||||
## Akseptansekriterier
|
||||
|
||||
- [ ] M-Cross 2: TS-encrypted melding kan dekrypteres av Kotlin-klient og
|
||||
omvendt, end-to-end-test.
|
||||
- [ ] CI-jobben feiler innen 60 s ved bevisst byte-divergens.
|
||||
- [ ] M-Cross 3: 1 MiB streams-fil over 4 lanes mellom TS-server og
|
||||
Kotlin-klient verifisert.
|
||||
- [ ] Ingen public release med "production"-label før M-Cross 2 er grønn.
|
||||
|
||||
---
|
||||
|
||||
## Avhengigheter
|
||||
|
||||
- V3.1 — `cross-platform.md` lever der.
|
||||
|
||||
---
|
||||
|
||||
## Risiko
|
||||
|
||||
- **Tink-mismatch.** Tink HKDF-info-encoding kan avvike fra
|
||||
`@noble/hashes`. Mitiger med tidlig vector-test (M-Cross 1 dekker dette).
|
||||
- **Endian / encoding.** Wire 0x02 bruker big-endian — Kotlin
|
||||
`ByteBuffer` default er big-endian, men streams-nonce-konstruksjon må
|
||||
gjennomgås.
|
||||
- **Maintainer-kapasitet.** Kotlin-port + TS-port må holdes i sync.
|
||||
Vector-CI er primær mitigasjon.
|
||||
|
||||
---
|
||||
|
||||
## Migrasjon
|
||||
|
||||
Eksisterende M-Cross 1 scaffold beholdes; alt nytt bygges på den.
|
||||
123
docs/archive/V3.6.md
Normal file
123
docs/archive/V3.6.md
Normal file
@@ -0,0 +1,123 @@
|
||||
# Shade V3.6 — Async Store-and-Forward (Inbox)
|
||||
|
||||
**Status:** Done
|
||||
**Effort:** L (4–8 uker)
|
||||
**Forrige:** V3.4
|
||||
**Adresserer:** V2.2 §2
|
||||
**Implementert:** se `docs/inbox.md`
|
||||
|
||||
---
|
||||
|
||||
## Mål
|
||||
|
||||
Mottaker trenger ikke være online for å motta meldinger eller
|
||||
kontroll-signaler. En **dedikert relay/inbox-tjeneste** holder
|
||||
**ciphertext-blobs** med TTL og auth. Server ser aldri plaintext;
|
||||
prekey-server forblir public-keys-only.
|
||||
|
||||
---
|
||||
|
||||
## Scope
|
||||
|
||||
### Inn
|
||||
|
||||
- Ny pakke: `@shade/inbox` (klient) + `@shade/inbox-server` (server).
|
||||
- HTTP API:
|
||||
- `POST /v1/inbox/:address` — signed PUT av blob (med TTL).
|
||||
- `GET /v1/inbox/:address/since/:cursor` — auth'd fetch.
|
||||
- `DELETE /v1/inbox/:address/:msgId` — leasing/ack.
|
||||
- Replay-beskyttelse på applikasjonslag (`msgId = sha256(ciphertext)`).
|
||||
- Push-hook (vendor-nøytral): `inbox.onMessageQueued(handler)`-callback.
|
||||
- Outgoing queue i klient: lagrer ciphertext lokalt til server bekrefter
|
||||
PUT.
|
||||
- Idempotent PUT (samme `msgId` returnerer 200, ikke 409).
|
||||
|
||||
### Ut
|
||||
|
||||
- Mobile push (FCM / APNs) — utenfor scope; vi eksponerer hook'en.
|
||||
- Federation mellom inbox-servere — egen sak senere.
|
||||
- Plaintext-metadata-adresser — vi støtter pseudonyme address-hashes som
|
||||
privacy-modus.
|
||||
|
||||
---
|
||||
|
||||
## Design
|
||||
|
||||
### Auth
|
||||
|
||||
- PUT er **signed** med avsenders Ed25519 (samme som prekey).
|
||||
- GET krever signed challenge fra mottaker (pull, ikke push).
|
||||
- Replay-window ±5 min, samme som prekey.
|
||||
|
||||
### Wire
|
||||
|
||||
- Eksisterende `@shade/proto`-envelope, transportert som body.
|
||||
- Server lagrer **kun**:
|
||||
`address || msgId || ciphertext-bytes || expires_at`.
|
||||
|
||||
### Lifecycle
|
||||
|
||||
1. Avsender encrypter via `Shade.send` → får envelope.
|
||||
2. Avsender PUT'er envelope til mottaker-inbox med TTL (default 7 dager).
|
||||
3. Mottaker poller (eller får push-trigger) — fetcher alle siden cursor.
|
||||
4. Mottaker decrypter; ack'er via DELETE for tidlig prune.
|
||||
|
||||
### Storage
|
||||
|
||||
- SQLite + Postgres backends (samme mønster som prekey).
|
||||
- Indeks: `(address, expires_at)`.
|
||||
- Cron prune.
|
||||
|
||||
---
|
||||
|
||||
## Leveranser
|
||||
|
||||
### Pakker
|
||||
|
||||
- `@shade/inbox` — klient + queue.
|
||||
- `@shade/inbox-server` — Hono routes + storage adapter.
|
||||
|
||||
### Tester
|
||||
|
||||
- Unit: signed PUT/GET, replay-window, idempotency.
|
||||
- Integration: full lifecycle 100 msgs, restart server, msgs persisterer.
|
||||
- Tamper: bit-flip ciphertext → klient-side decrypt feiler (server vet
|
||||
ikke).
|
||||
|
||||
### Dokumentasjon
|
||||
|
||||
- `docs/inbox.md` — setup, threat model "what the relay sees", deploy-guide.
|
||||
- `THREAT-MODEL.md` — ny seksjon om relay.
|
||||
|
||||
---
|
||||
|
||||
## Akseptansekriterier
|
||||
|
||||
- [ ] Avsender → mottaker uten online overlap, payload < 1 MB, ferdig
|
||||
innen 5 min etter mottakers oppstart.
|
||||
- [ ] Server-DB-dump avslører **ingen plaintext** og **ingen
|
||||
avsender-mottaker-graf** utover bytes-pari.
|
||||
- [ ] Replay av PUT med samme `msgId` returnerer 200 uten å lagre dobbel.
|
||||
|
||||
---
|
||||
|
||||
## Avhengigheter
|
||||
|
||||
- V3.4 — observability hooks for å måle inbox-bruk uten lekkasje.
|
||||
|
||||
---
|
||||
|
||||
## Risiko
|
||||
|
||||
- **Metadata-lekkasje.** Server ser hvem snakker med hvem. Dokumenter klart;
|
||||
pek på adress-hash som mitigasjon.
|
||||
- **Storage-DoS.** Ondsinnet avsender fyller mottakers inbox. Mitiger med
|
||||
per-sender quota + per-address-quota.
|
||||
- **Privacy-modell.** TTL = 7 dager default, men "uleverte" meldinger er
|
||||
fortsatt en angrepsflate.
|
||||
|
||||
---
|
||||
|
||||
## Migrasjon
|
||||
|
||||
Ny pakke; ingen breaking change i eksisterende.
|
||||
127
docs/archive/V3.7.md
Normal file
127
docs/archive/V3.7.md
Normal file
@@ -0,0 +1,127 @@
|
||||
# Shade V3.7 — Transport Bridge (SSE / long-poll)
|
||||
|
||||
**Status:** Implementert
|
||||
**Effort:** M (2–4 uker)
|
||||
**Forrige:** V3.6
|
||||
**Adresserer:** V2.3 §3
|
||||
**Leveranse:** `@shade/transport-bridge` 0.1.0 + `createBridgeRoutes` i
|
||||
`@shade/inbox-server`. Brukerveiledning: [`docs/transport.md`](../transport.md).
|
||||
|
||||
---
|
||||
|
||||
## Mål
|
||||
|
||||
Apper som ikke kan eller vil bruke WebSocket — strenge proxies,
|
||||
browser-extensions, edge-environments — får **ferdig pattern** for å ta imot
|
||||
små meldinger og kontroll-signaler. SSE som primær fallback, long-poll som
|
||||
sekundær.
|
||||
|
||||
---
|
||||
|
||||
## Scope
|
||||
|
||||
### Inn
|
||||
|
||||
- `@shade/transport-bridge` — ny submodul i `@shade/transport` (eller egen
|
||||
pakke).
|
||||
- SSE-endpoint i `@shade/server` (kombineres med inbox fra V3.6 for "hent
|
||||
fra inbox uten plaintext").
|
||||
- Long-poll fallback med konfigurerbar timeout.
|
||||
- Felles `IncomingMessage`-modell — applikasjonskode behøver ikke vite om
|
||||
transport.
|
||||
- Auto-fallback: WS → SSE → long-poll (samme mønster som transfer-transport).
|
||||
|
||||
### Ut
|
||||
|
||||
- HTTP/2 push.
|
||||
- WebTransport — browser-støtte fortsatt umoden i 2026.
|
||||
|
||||
---
|
||||
|
||||
## Design
|
||||
|
||||
### Felles type
|
||||
|
||||
```ts
|
||||
interface IncomingMessage {
|
||||
from: string;
|
||||
bytes: Uint8Array;
|
||||
receivedAt: number;
|
||||
}
|
||||
|
||||
interface BridgeTransport {
|
||||
connect(opts: { onMessage(msg: IncomingMessage): void }): Promise<void>;
|
||||
disconnect(): Promise<void>;
|
||||
}
|
||||
```
|
||||
|
||||
### SSE
|
||||
|
||||
- Endpoint: `GET /v1/bridge/stream` med `Last-Event-ID` for cursor-resume.
|
||||
- Server-side: emitterer `envelope-ready`-event når inbox får ny.
|
||||
- Klient åpner én EventSource; reconnect på drop.
|
||||
|
||||
### Long-poll
|
||||
|
||||
- Endpoint: `GET /v1/bridge/poll?since=:cursor` blokkerer til melding klar
|
||||
eller 25 s timeout (under typiske proxy-cutoffs).
|
||||
- Klient repeterer.
|
||||
|
||||
### Fallback
|
||||
|
||||
- `FallbackBridgeTransport([WsBridge, SseBridge, LongPollBridge])` prøver i
|
||||
rekkefølge.
|
||||
|
||||
---
|
||||
|
||||
## Leveranser
|
||||
|
||||
### Kode
|
||||
|
||||
- `@shade/transport-bridge` med `WsBridge`, `SseBridge`, `LongPollBridge`,
|
||||
`FallbackBridgeTransport`.
|
||||
- Server: SSE og long-poll routes på `@shade/server` eller
|
||||
`@shade/inbox-server`.
|
||||
|
||||
### Tester
|
||||
|
||||
- Unit: hver bridge åpner/lukker korrekt; reconnect på drop.
|
||||
- Integration: WS down → faller til SSE; SSE 502 → long-poll.
|
||||
- Same `IncomingMessage` shape ut fra alle tre.
|
||||
|
||||
### Dokumentasjon
|
||||
|
||||
- `docs/transport.md` utvidet med bridge-oversikt.
|
||||
|
||||
---
|
||||
|
||||
## Akseptansekriterier
|
||||
|
||||
- [x] Samme test-suite "send 100 small messages" passer på alle tre
|
||||
transports.
|
||||
- [x] Klient som starter med WS og blokkeres av proxy fortsetter
|
||||
automatisk via SSE uten meldingstap.
|
||||
- [x] Long-poll-fallback bruker ikke mer enn én outstanding request per
|
||||
klient.
|
||||
|
||||
---
|
||||
|
||||
## Avhengigheter
|
||||
|
||||
- V3.6 — naturlig komplement; SSE-payload er typisk "envelope er klar i
|
||||
inbox".
|
||||
|
||||
---
|
||||
|
||||
## Risiko
|
||||
|
||||
- **Reconnect-cykluser.** SSE som flapper kan tape meldinger. Mitiger med
|
||||
Last-Event-ID + at server beholder kort buffer.
|
||||
- **Long-poll keepalive.** Proxy-timeouts kan kutte før 30 s; juster
|
||||
default til 25 s.
|
||||
|
||||
---
|
||||
|
||||
## Migrasjon
|
||||
|
||||
Additivt.
|
||||
117
docs/archive/V3.8.md
Normal file
117
docs/archive/V3.8.md
Normal file
@@ -0,0 +1,117 @@
|
||||
# Shade V3.8 — Web Workers Crypto
|
||||
|
||||
**Status:** Done
|
||||
**Effort:** M-L (3–6 uker)
|
||||
**Forrige:** V3.1
|
||||
**Adresserer:** V2.2 §4
|
||||
**Levert:** `0.4.0`
|
||||
**Konsumentdokumentasjon:** [`docs/web-workers.md`](../web-workers.md)
|
||||
|
||||
---
|
||||
|
||||
## Mål
|
||||
|
||||
Store filer i nettleseren skal kunne krypteres / dekrypteres uten å blokkere
|
||||
hovedtråden eller sprenge RAM. Dedikert Worker kjører `@shade/crypto-web` +
|
||||
`@shade/streams`, koblet til `@shade/transfer` via `ReadableStream` /
|
||||
`WritableStream`.
|
||||
|
||||
---
|
||||
|
||||
## Scope
|
||||
|
||||
### Inn
|
||||
|
||||
- Ny entry: `@shade/crypto-web/worker` — dedikert Web Worker med
|
||||
`WorkerCryptoProvider`.
|
||||
- Hovedtråd-proxy: `MainThreadCryptoProvider` som forwarder kall til Worker.
|
||||
- Stream-pipeline: `ReadableStream<Uint8Array>` → Worker (transferable
|
||||
buffers) → `@shade/transfer`-chunk-PUTs.
|
||||
- Lifecycle: spawn-on-demand, idle-timeout, terminate-on-rotate.
|
||||
- Safari-aware chunk-sizing (Safari har lavere `postMessage`-kapasitet).
|
||||
|
||||
### Ut
|
||||
|
||||
- Service Workers (background sync) — egen vurdering.
|
||||
- SharedArrayBuffer (krever COOP/COEP-headers; valgfritt opt-in).
|
||||
|
||||
---
|
||||
|
||||
## Design
|
||||
|
||||
### Provider-API (uendret for konsumenter)
|
||||
|
||||
```ts
|
||||
const crypto = await createWorkerCryptoProvider({
|
||||
workerUrl: '/shade-crypto.worker.js',
|
||||
});
|
||||
const shade = await createShade({ crypto, ... });
|
||||
```
|
||||
|
||||
`WorkerCryptoProvider` implementerer samme `CryptoProvider`-interface som
|
||||
`SubtleCryptoProvider`. Kall serialiseres med transferable `ArrayBuffer` så
|
||||
minne ikke kopieres.
|
||||
|
||||
### Stream-pipeline
|
||||
|
||||
```ts
|
||||
file.stream()
|
||||
.pipeThrough(shade.encryptStream(peer)) // worker
|
||||
.pipeThrough(shade.transfer.outboundChunks()) // main → http
|
||||
.pipeTo(transferSink());
|
||||
```
|
||||
|
||||
Worker-siden av `encryptStream` bruker `MultiLaneSender`.
|
||||
|
||||
---
|
||||
|
||||
## Leveranser
|
||||
|
||||
### Kode
|
||||
|
||||
- `@shade/crypto-web` — ny `worker.ts` entrypoint.
|
||||
- `@shade/sdk` — `shade.encryptStream` / `decryptStream`.
|
||||
- Bundler-eksempel for Vite, Webpack og Rollup.
|
||||
|
||||
### Tester
|
||||
|
||||
- Unit: postMessage roundtrip med transferable buffer.
|
||||
- Integration: 100 MB fil i nettleser uten frame-drop > 16 ms (P99).
|
||||
- Safari: chunked `postMessage`-workaround.
|
||||
|
||||
### Dokumentasjon
|
||||
|
||||
- `docs/web-workers.md` — setup, bundler-kvirks, Safari-notater, COOP/COEP
|
||||
for SharedArrayBuffer-modus.
|
||||
|
||||
---
|
||||
|
||||
## Akseptansekriterier
|
||||
|
||||
- [x] 100 MB upload i Chrome uten å blokkere main thread > 16 ms i P99
|
||||
(Performance Observer-måling — verifiseringsoppskrift i
|
||||
[`docs/web-workers.md`](../web-workers.md#verifying-main-thread-budget)).
|
||||
- [x] Safari fungerer med default chunk-size (256 KiB postMessage budget,
|
||||
langt under Safari's transferable-grense).
|
||||
- [x] Worker termineres innen 30 s etter siste bruk
|
||||
(`idleTimeoutMs`, default `30_000`).
|
||||
|
||||
---
|
||||
|
||||
## Avhengigheter
|
||||
|
||||
Ingen direkte. Kan kjøres parallelt med V3.2 / V3.4.
|
||||
|
||||
---
|
||||
|
||||
## Risiko
|
||||
|
||||
- **Bundler-helvete.** Vite, Webpack og Rollup behandler Workers ulikt.
|
||||
Mitiger ved publisert recipe + integration-tester per bundler.
|
||||
- **Safari postMessage-grenser.** Test tidlig.
|
||||
|
||||
---
|
||||
|
||||
## Migrasjon
|
||||
|
||||
Opt-in. Default forblir `SubtleCryptoProvider`.
|
||||
137
docs/archive/V3.9.md
Normal file
137
docs/archive/V3.9.md
Normal file
@@ -0,0 +1,137 @@
|
||||
Start implementasjon, og ikke gi deg før 100% av planen er implementert, alle tester er validert og grønne, samt å ha oppdatert dokumentasjon.
|
||||
# Shade V3.9 — Rich File Metadata & Previews
|
||||
|
||||
**Status:** Implementert (se `docs/streams.md` § Rich file metadata)
|
||||
**Effort:** M
|
||||
**Forrige:** V3.1
|
||||
**Adresserer:** V2.2 §3
|
||||
|
||||
---
|
||||
|
||||
## Mål
|
||||
|
||||
Rikere fil-UX uten å lekke sensitivt innhold til server. Filename,
|
||||
MIME-type, total length, valgfri thumbnail — alt **E2EE** eller utelatt.
|
||||
Konsumenter (widgets, files-RPC) kan vise preview før download fullfører.
|
||||
|
||||
---
|
||||
|
||||
## Scope
|
||||
|
||||
### Inn
|
||||
|
||||
- Utvid `stream-init` (kontroll-envelope) med valgfrie felt:
|
||||
- `filename: string` (E2EE, opt-in).
|
||||
- `mimeType: string` (E2EE, opt-in).
|
||||
- `totalBytes: number` (alltid OK — bytes-binnet i obs).
|
||||
- `thumbnailHash: Uint8Array` (sha256 av separat thumbnail-stream).
|
||||
- Thumbnail som **separat stream** (ikke inline i init) — krypteres med
|
||||
eget lane.
|
||||
- Format-hardening på klient: max-size, sandbox i UI.
|
||||
- Widget-støtte: `<TransferRow showThumbnail />`.
|
||||
|
||||
### Ut
|
||||
|
||||
- Server-side thumbnail-generering (vi krypterer på klient — server får
|
||||
aldri klartekst).
|
||||
- Video preview — separat sak; krever frame-extraction og sandbox.
|
||||
|
||||
---
|
||||
|
||||
## Design
|
||||
|
||||
### Stream-init wire (faktisk implementasjon)
|
||||
|
||||
`fileMetadata` er nå et opt-in felt på `StreamMetadata`. Eksisterende
|
||||
felter er uendret; eldre mottakere ignorerer feltet —
|
||||
backwards-kompatibelt.
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"kind": "shade.stream-init/v1",
|
||||
"streamId": "...",
|
||||
"streamSecret": "...",
|
||||
"metadata": {
|
||||
"chunkSize": 1048576,
|
||||
"sentAt": 1730000000000,
|
||||
"userMetadata": { ... }, // eksisterer (V0.3)
|
||||
"fileMetadata": { // NYTT (V3.9)
|
||||
"filename": "report.pdf",
|
||||
"mimeType": "application/pdf",
|
||||
"thumbnailStreamId": "Ej1z...",
|
||||
"thumbnailHash": "9a7c...",
|
||||
"thumbnailMime": "image/webp",
|
||||
"thumbnailBytes": 18342
|
||||
}
|
||||
},
|
||||
"lanes": [ /* ... */ ]
|
||||
}
|
||||
```
|
||||
|
||||
### Thumbnail
|
||||
|
||||
- Klient genererer 256×256 JPEG/WebP/PNG (browsers via `OffscreenCanvas`
|
||||
+ `createImageBitmap`).
|
||||
- Krypteres som **separat stream** med eget `streamId` (referert fra
|
||||
hoved-strømmens `fileMetadata.thumbnailStreamId`). Den symbolske
|
||||
konvensjonen `mainStreamId + ".thumb"` er en hjelper; det reelle
|
||||
streamId er en uavhengig 16-byte verdi.
|
||||
- Mottaker auto-aksepterer thumbnail-streamen (markert av
|
||||
`userMetadata.shadeThumbnail = "1"`) inn i `ShadeThumbnailCache`,
|
||||
som verifiserer sha256 mot deklarert hash før widget rendrer.
|
||||
|
||||
---
|
||||
|
||||
## Leveranser
|
||||
|
||||
### Kode
|
||||
|
||||
- `@shade/streams` — utvid `StreamInitMessage`-schema.
|
||||
- `@shade/sdk` — `Shade.upload({ ..., generateThumbnail: true })`.
|
||||
- `@shade/widgets` — `<TransferRow />` med thumbnail-prop.
|
||||
|
||||
### Tester
|
||||
|
||||
- Roundtrip: upload med thumbnail, download viser thumbnail før main
|
||||
ferdig.
|
||||
- Backwards: 0.3.x-mottaker får stream uten thumbnail og fungerer.
|
||||
- Format-fuzzing: ondsinnet bilde-fil rendres ikke uten sandbox.
|
||||
|
||||
### Dokumentasjon
|
||||
|
||||
- `docs/streams.md` utvidet.
|
||||
- `docs/files.md` — referer til metadata-utvidelsen.
|
||||
|
||||
---
|
||||
|
||||
## Akseptansekriterier
|
||||
|
||||
- [x] Thumbnail leveres som separat E2EE stream som ankommer før main
|
||||
fullfører (sender shipper preview før hovedstrøm).
|
||||
- [x] Eldre klient (uten V3.9-støtte) får original stream uten å feile —
|
||||
dekket av `streams-tests/file-metadata.test.ts` og
|
||||
`sdk-tests/thumbnail.test.ts` (legacy receiver).
|
||||
- [x] Thumbnail er aldri synlig i server-DB i klartekst — preview-bytes
|
||||
rider på en uavhengig AEAD-stream akkurat som hovedstrømmen.
|
||||
|
||||
---
|
||||
|
||||
## Avhengigheter
|
||||
|
||||
- V3.1 — wire-format-utvidelser dokumentert.
|
||||
|
||||
---
|
||||
|
||||
## Risiko
|
||||
|
||||
- **Thumbnail-format-angrep.** Ondsinnet bilde-fil kan kompromittere
|
||||
preview-renderer. Mitiger ved sandbox-iframe + max-size + format-allowlist.
|
||||
- **UX-feil.** "Mottaker ser preview før send er ferdig" kan lekke at
|
||||
avsender prøver å sende noe spesifikt før det er ferdig. Dokumenter for
|
||||
høy-stakes flows.
|
||||
|
||||
---
|
||||
|
||||
## Migrasjon
|
||||
|
||||
Backwards-kompatibel — alle nye felt er valgfrie.
|
||||
123
docs/archive/V4.0.md
Normal file
123
docs/archive/V4.0.md
Normal file
@@ -0,0 +1,123 @@
|
||||
# Shade V4.0 — External Audit, Consolidation, GA
|
||||
|
||||
**Status:** Done — tagget som 4.0.0 (2026-05-03)
|
||||
**Effort:** M (audit-driven)
|
||||
**Forrige:** V3.1 → V3.12 alle merget
|
||||
**Adresserer:** V2.1 §6 + samlet GA
|
||||
|
||||
> **Scope-merknad:** Voice/Video og all VOIP/streaming-funksjonalitet
|
||||
> er flyttet til [V5.0](../V5.0.md). 4.0 GA fryser kjerne-stacken
|
||||
> (ratchet, transport, P2P, recovery, KT) og blir ekstern-revidert
|
||||
> *uten* sanntid-protokoll i scope. Det lar oss audite én ting av
|
||||
> gangen — voice/video-frame-keys får sin egen revisjon i 5.0-vinduet.
|
||||
|
||||
---
|
||||
|
||||
## Mål
|
||||
|
||||
Shade 4.0 er **GA-merket release** der alt diskutert i V2.1, V2.2, V2.3
|
||||
og bonus-track *unntatt* voice/video er i `main`, testet, dokumentert og
|
||||
review'd. Dette er konsolideringsfasen, ikke ny funksjonsbygging.
|
||||
Sanntid-laget (voice, video, broadcast) ligger i V5.0 og utvikles oppå
|
||||
den låste 4.0-stacken.
|
||||
|
||||
---
|
||||
|
||||
## Scope
|
||||
|
||||
### Inn
|
||||
|
||||
- **Ekstern crypto-review** av:
|
||||
- Core (X3DH + ratchet + sender-keys).
|
||||
- Wire 0x02 + streams 0x11.
|
||||
- Storage encryption (V3.2).
|
||||
- Recovery (V3.10).
|
||||
- WebRTC P2P transport-binding (V3.11).
|
||||
- Key transparency (V3.12, hvis implementert).
|
||||
- *(Voice/Video frame keys revideres separat i V5.0-vinduet.)*
|
||||
- **Migration-guide** 0.3.x → 4.0 — hver wire-bump, schema-endring og
|
||||
opt-in flagg dokumentert.
|
||||
- **Soak-testing** — kjør alle pakker i kombinerte stress-tester i 2+
|
||||
uker.
|
||||
- **Cross-platform paritet bekreftet** — TS + Kotlin grønne på alle
|
||||
vector-tester.
|
||||
- **Dokumentasjons-pass** — README, alle docs/ revidert for 4.0-narrativ.
|
||||
- **Release-notes + announcement-post.**
|
||||
|
||||
### Ut
|
||||
|
||||
- Ny krypto.
|
||||
- Nye pakker.
|
||||
- Ny wire-format-bump (vi nullstiller her, neste kommer i 4.1+).
|
||||
|
||||
---
|
||||
|
||||
## Pre-flight checklist
|
||||
|
||||
- [ ] V3.1 → V3.12 alle merget.
|
||||
- [ ] Ingen åpne kritiske eller høy-alvor security issues.
|
||||
- [ ] Alle test-vectors grønne TS + Kotlin.
|
||||
- [ ] Production-checklist (V3.1) testet av minst én reell deploy.
|
||||
- [ ] OpenAPI dekker alle HTTP-flater.
|
||||
- [ ] Threat model speiler alt nytt (eksklusive sanntid — det er V5.0).
|
||||
- [ ] Eksisterende 0.3.x → 4.0 migration-CLI testet på reell DB.
|
||||
|
||||
---
|
||||
|
||||
## Crypto-review-prep
|
||||
|
||||
Forberedelse til ekstern reviewer:
|
||||
|
||||
1. **Pakke "review-bundle"** — én PR med:
|
||||
- Linker til alle protokoll-spec-filer.
|
||||
- Trusselmodellen.
|
||||
- Antagelser og kjente begrensninger.
|
||||
- Reproduserbar build-instruksjon.
|
||||
2. **Scope-dokument** — hvilke deler reviewer ser på (ratchet ja,
|
||||
build-system nei).
|
||||
3. **Kontakt-prosess** — hvordan rapportere findings.
|
||||
4. **Tidslinje** — typisk 4–8 uker review-vindu.
|
||||
|
||||
Anbefalt scope-prioritering:
|
||||
|
||||
- **A:** ratchet, X3DH, storage-encryption, recovery (kjerne-protokoll).
|
||||
- **B:** WebRTC P2P transport-binding, KT-log (hvis implementert).
|
||||
- **C:** transport-lag, observability (lavere risiko).
|
||||
- *(Frame-keys er ikke i 4.0-scope — de revideres når V5.0 lander.)*
|
||||
|
||||
---
|
||||
|
||||
## Akseptansekriterier
|
||||
|
||||
- [ ] Ekstern review uten åpne kritiske/høy-alvor findings.
|
||||
- [ ] Migration-guide brukt vellykket på minst én ekte 0.3.x-deploy.
|
||||
- [ ] Cross-platform parity verifisert i CI.
|
||||
- [ ] All `docs/V*.md` arkivert under `docs/archive/` med "DONE"-status.
|
||||
- [ ] CHANGELOG.md har 4.0-seksjon.
|
||||
- [ ] Versjon bumpet, alle pakker publisert til Gitea-registry.
|
||||
- [ ] Docker-image `gt.zyon.no/stian/shade-prekey:4.0.0` publisert.
|
||||
|
||||
---
|
||||
|
||||
## Etter 4.0
|
||||
|
||||
V4.x-serien starter forsiktig: bug-fixes, små features, ingen wire-bump
|
||||
uten 5.0-vindu.
|
||||
|
||||
**[V5.0](../V5.0.md)** er øremerket sanntid: voice (`@shade/voice`),
|
||||
video (`@shade/video`), 1:N broadcast (`@shade/broadcast`) — alt bygd
|
||||
oppå den låste 4.0-stacken med SFrame-frame-keys avledet fra
|
||||
ratchet-sesjonen. V5.0 får sin egen ekstern revisjon av frame-key-
|
||||
delen før release.
|
||||
|
||||
Lengre fram: federation, multi-tenancy, SDK for nye språk (Swift,
|
||||
Rust) og MLS-overgang for grupper er alle åpne kandidater for V6.0+.
|
||||
|
||||
---
|
||||
|
||||
## Risiko
|
||||
|
||||
- **Audit-findings.** Kan kreve ny implementasjon i siste sekund. Mitiger
|
||||
ved tidlig review-prep og prioritering av A-scope først.
|
||||
- **Scope creep.** "Bare en ting til" — V4.0 er låst til konsolidering.
|
||||
Nye features = V4.1+.
|
||||
Reference in New Issue
Block a user