Status: backlog — design decided, not started
Linked TODO: TODO.md → Backlog → WASM PWA Book Reader
Books are gated behind push subscription. Once a user downloads a chapter, nothing prevents them from sharing the file. Need practical protection against casual copying and automated scraping — not NSA-level DRM, but enough to make sharing impractical.
| Layer | JS only | WASM + Canvas |
|---|---|---|
| Decryption logic | Readable in DevTools | Compiled binary, no source view |
| Key in memory | JS variable, console-accessible | WASM linear memory, isolated from JS heap |
| Rendered content | DOM text nodes — trivially selectable | Canvas bitmap — no text nodes |
| Anti-instrumentation | Easy to patch | Hard to hook without recompiling |
Cloudflare KV
└── chapters/{bookId}/{chapterId} ← AES-256-GCM encrypted blob
push-gate worker /key endpoint (authenticated by push endpoint + HMAC)
└── returns per-user AES key, short TTL, tied to push subscription endpoint
└── key revoked automatically when user unsubscribes (endpoint gone)
PWA Service Worker
└── caches encrypted chapter blobs (never plaintext)
└── fetches key from push-gate on first chapter open, caches key in memory only
WASM module (Rust → wasm-pack, or AssemblyScript)
└── receives: encrypted blob + AES key (passed from JS, never stored back)
└── decrypts in WASM linear memory
└── renders page text to OffscreenCanvas
└── transfers canvas bitmap to main thread
Reader shell (HTML/JS)
└── page-flip UI
└── receives canvas bitmaps, draws to visible <canvas>
└── aria-label per page for screen readers (text summary, not full content)
{ endpoint, grants } in KVpush-gate /key?bookId=X/key returns 403Canvas rendering disables: screen readers, in-page search, copy-paste, print-to-text.
Mitigation options (choose one per book):
aria-label="Page 3: [first 50 chars of page content]" — readable by screen readers, not useful for scrapingvisibility:hidden for sighted users)| Option | Pros | Cons |
|---|---|---|
| Rust + wasm-pack | Best performance, AES crates available, smallest binary | Rust learning curve |
| AssemblyScript | TypeScript-like syntax, easier for JS devs | Fewer crypto libs, larger binary |
| C + Emscripten | Established, many crypto libs | Complex toolchain |
Recommendation: Rust + wasm-pack. aes-gcm crate is well-audited.