Files
CookieBridge/docs/architecture.md
徐枫 b6fbf7a921
Some checks failed
CI / test (22) (push) Has been cancelled
CI / docker (push) Has been cancelled
CI / extension (push) Has been cancelled
feat: implement M4 self-hosting, Docker & documentation
- Dockerfile with multi-stage build (Node 22 Alpine, sodium-native)
- docker-compose.yml with health check for easy self-hosting
- README with setup guide, API reference, and project overview
- Architecture docs (data flow, component breakdown, protocol constants)
- Security model docs (threat model, crypto primitives, self-hosting checklist)
- GitHub Actions CI pipeline (test, typecheck, Docker smoke test, extension builds)
- GitHub Actions release pipeline (GHCR push, extension zip artifacts)
- CONTRIBUTING.md with dev setup and code style guidelines

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-03-17 18:34:53 +08:00

140 lines
7.0 KiB
Markdown

# CookieBridge Architecture
## Overview
CookieBridge is a cross-device cookie sync system built on a zero-knowledge relay architecture. The relay server transports and stores encrypted cookie blobs but cannot decrypt them. All cryptographic operations happen client-side.
## Components
### Relay Server (`src/relay/`)
A plain Node.js HTTP + WebSocket server. No frameworks — just `http`, `ws`, and `sodium-native`.
- **server.ts** — Routes HTTP requests and upgrades WebSocket connections. Single entry point for all API traffic.
- **connections.ts** — Manages active WebSocket connections. Maps device IDs to sockets for real-time push.
- **auth.ts** — Two auth methods:
- **Token auth**: Bearer tokens issued at device registration. Used for HTTP and WebSocket.
- **Challenge-response**: Server sends random bytes, client signs with Ed25519. Used for WebSocket upgrade.
- **store.ts** — In-memory encrypted cookie blob storage. Keyed by `(deviceId, domain, cookieName, path)`. Limit: 10,000 cookies per device.
- **tokens.ts** — Device and agent registries. Tracks device metadata, pairing relationships, and agent access grants.
### Cryptography (`src/crypto/`)
All crypto uses libsodium via `sodium-native` (server) or `libsodium-wrappers-sumo` (extension).
| Operation | Algorithm | Purpose |
|-----------|-----------|---------|
| Encryption | XChaCha20-Poly1305 | Cookie payload encryption (AEAD) |
| Signing | Ed25519 | Message authentication, device identity |
| Key exchange | X25519 | Deriving shared secrets between paired devices |
| Key derivation | BLAKE2b (generic hash) | Deriving encryption keys from ECDH output |
### Sync Engine (`src/sync/`)
- **envelope.ts** — Wire format for WebSocket messages. Each message is signed and encrypted.
- **conflict.ts** — Last-writer-wins (LWW) conflict resolution. Uses Lamport clock timestamps. Ties broken by lexicographic device ID comparison.
### Browser Extension (`extension/`)
Single TypeScript codebase compiled per-browser via esbuild.
- **service-worker.ts** — Extension lifecycle, device registration, pairing orchestration, sync triggers.
- **api-client.ts** — HTTP client for relay server REST API.
- **connection.ts** — WebSocket manager with auto-reconnect and exponential backoff.
- **crypto.ts** — Client-side encryption/decryption using libsodium-wrappers-sumo.
- **sync.ts** — Processes incoming cookie updates, applies them via `chrome.cookies` API.
- **compat.ts** — Cross-browser abstraction layer for Chrome, Firefox, Edge, Safari API differences.
## Data Flow
### Device Registration
```
Extension Relay Server
│ │
│ POST /api/devices/register │
│ { deviceId, name, platform, │
│ encPub } │
│──────────────────────────────────▶│
│ │
│ { token, deviceId, ... } │
│◀──────────────────────────────────│
```
### Pairing
```
Device A Relay Server Device B
│ │ │
│ POST /api/pair │ │
│ { deviceId, x25519Pub,│ │
│ pairingCode } │ │
│──────────────────────▶│ │
│ │ │
│ │ POST /api/pair/accept │
│ │ { deviceId, x25519Pub,│
│ │ pairingCode } │
│ │◀──────────────────────│
│ │ │
│ { peerX25519PubKey } │ { peerX25519PubKey } │
│◀──────────────────────│──────────────────────▶│
│ │ │
│ derive shared secret │ derive shared secret │
│ (X25519 ECDH) │ (X25519 ECDH) │
```
### Cookie Sync (WebSocket)
```
Device A Relay Server Device B
│ │ │
│ cookie_sync envelope │ │
│ (signed + encrypted) │ │
│──────────────────────▶│ │
│ │ store encrypted blob │
│ │ │
│ │ forward envelope │
│ │──────────────────────▶│
│ │ │
│ │ decrypt│
│ │ apply │
│ ack │ │
│◀──────────────────────│◀──────────────────────│
```
### Cookie Sync (HTTP Polling)
```
Device Relay Server
│ │
│ POST /api/cookies │
│ { encrypted blob } │
│───────────────────────────────▶│
│ │
│ GET /api/cookies/updates │
│ ?since=<timestamp> │
│───────────────────────────────▶│
│ │
│ [ encrypted blobs ] │
│◀───────────────────────────────│
```
## Storage
All storage is **in-memory**. The relay server does not persist data to disk. Restarting the server clears all registrations, pairings, and stored cookies. Devices re-register and re-sync automatically on reconnection.
This is intentional for the current version — the server is a transient relay, not a database. Persistent storage may be added in a future milestone.
## Protocol Constants
| Constant | Value | Purpose |
|----------|-------|---------|
| `PROTOCOL_VERSION` | `2.0.0` | Wire protocol version |
| `MAX_STORED_COOKIES_PER_DEVICE` | 10,000 | Per-device cookie limit |
| `PAIRING_CODE_LENGTH` | 6 digits | Pairing code size |
| `PAIRING_TTL_MS` | 5 minutes | Pairing session expiry |
| `NONCE_BYTES` | 24 | XChaCha20 nonce size |
| `PING_INTERVAL_MS` | 30 seconds | WebSocket keepalive |
| `PONG_TIMEOUT_MS` | 10 seconds | Pong deadline |
| `POLL_INTERVAL_MS` | 5 seconds | HTTP polling default |