69 lines
3 KiB
Markdown
69 lines
3 KiB
Markdown
# 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.
|