# Cipher End-to-end encrypted messenger — a WhatsApp/Signal-style app running entirely on Cloudflare. **Live:** https://cipher.theradicalparty.com ## Design The server is a **dumb key directory + encrypted relay**. It never sees message plaintext or private keys — only public keys and ciphertext. Real-time delivery plus offline store-and-forward, so messages arrive even when the recipient is away. | Concern | How | |---|---| | Encryption | **Signal Protocol** (X3DH + Double Ratchet) via libsignal, in the browser | | Real-time + offline queue | Per-user **Mailbox Durable Object** (WebSocket + SQLite queue) | | Key directory | **D1** — users, devices, prekey bundles (public keys only) | | Media | Client-side AES-GCM, ciphertext stored in **R2**; key travels inside the E2E message | | API | **Hono** on Workers | | Client | Installable **PWA**, IndexedDB key store, Web Push wake-up | | Identity | Username + password; QR device-linking planned | Private keys are generated on the device and stored only in IndexedDB. They are never transmitted. See `docs/` notes inline in each source file. ## Architecture ``` Alice (PWA) Cloudflare Worker Bob (PWA) ┌─────────────┐ publish pubkeys ┌──────────────┐ │ libsignal │ ──────────────────► │ D1 key dir │ │ IndexedDB │ ◄── prekey bundle ─ │ │ └─────┬───────┘ └──────────────┘ │ encrypt (X3DH/ratchet) │ POST ciphertext ┌──────────────┐ WS push ┌──────────┐ └───────────────────────────► │ Mailbox DO │ ───────────► │ decrypt │ │ (queue+WS) │ or queue │ locally │ encrypt media (AES-GCM) ─► R2 └──────────────┘ └──────────┘ ``` ## Develop ```bash npm install npm run dev # local Worker + assets npm run db:migrate:local # apply schema to local D1 ``` ## Deploy Push to `main` → Forgejo post-receive hook runs `wrangler deploy`. ```bash git pushall main # pushes to Forgejo (origin) + GitHub (backup) ``` ## Vendored crypto `public/js/vendor/libsignal.js` is a self-contained browser bundle of `@privacyresearch/libsignal-protocol-typescript` (built with esbuild + a Buffer shim). Rebuild with the esbuild command noted in the commit history if bumping the library — loading crypto from a CDN at runtime is intentionally avoided. ## Status Working: registration, login, key directory, E2E text + media, real-time and offline delivery (both verified live). Planned: QR multi-device linking, group chats (sender keys / MLS), WebRTC voice/video, Web Push fan-out, delivery/read receipts, disappearing messages.