A zero-knowledge archive for the memorable things people say: capture a quote with its screenshot and replay it as an oversized headline — the content is encrypted in your browser, so the server never sees it.
把嘉豪哥的逆天发言连同截图存档,回放成「头条新闻」。
—— 但是密码学。
-
Zero-knowledge: quote text and screenshots are encrypted client-side with the Web Crypto API (PBKDF2-SHA256 derives a root key; AES-GCM encrypts). The server stores only ciphertext plus a little plaintext metadata (speaker, time) — it can neither read nor decrypt the content.
-
No database: all relations are Cloudflare KV key conventions; a user's light records live in one aggregate key, so listing them is a single read.
-
Single Worker: one Cloudflare Worker serves the static frontend and the embedded
/api(Hono) — same origin, no CORS, no hard-coded backend URL. -
A quote's decryption key rides in the share link's URL fragment and is only minted in a logged-in client, so it can't double as an image host.
-
零知识加密:引用文本与截图在浏览器端用 Web Crypto 加密(PBKDF2-SHA256 派生根密钥,AES-GCM 加密)。服务端只存密文 + 少量明文元数据(说话人、时间),不拿内容明文,也不做加解密。
-
无数据库:所有关系用 Cloudflare KV 的键约定组织,一个用户的全部轻量记录聚合在单个键里,列表 = 一次读取。
-
单 Worker 部署:一个 Cloudflare Worker 同时服务静态前端和内嵌的
/api(Hono),同源、无 CORS、无需写死后端地址。 -
由于解密需要的密钥是用 hashtag 拼上去的,并且这个密钥只在已登录用户的前端生成,所以不能用做图床。
- Claude Opus4.8
- React 18 · TypeScript · Tailwind CSS v4 · Vite | Cloudflare Workers (Hono) + KV | pnpm workspace + Turborepo
pnpm install
pnpm dev # web :4313, service :8787 (Vite proxies /api -> wrangler dev)-
Each theme is a self-describing manifest at
apps/quotes/web/src/themes/<id>/theme.json; drop in a folder to add one — no contract or server change needed. -
主题外观是
apps/quotes/web/src/themes/<id>/theme.json下的自描述清单,放一个文件夹即可新增一个主题,无需改任何契约或服务端。
-
Create a KV namespace in the Cloudflare dashboard and put its id into
kv_namespaces(bothidandpreview_id) inapps/quotes/web/wrangler.jsonc. -
Deploy with the command below (
deploycollides with a built-in pnpm subcommand, hencerun).apps/quotes/serviceis for local dev and tests only — it isn't deployed on its own. -
在 Cloudflare 控制台建一个 KV namespace,把它的 id 填入
apps/quotes/web/wrangler.jsonc的kv_namespaces(id与preview_id)。 -
用下面的命令部署(
deploy与 pnpm 内置子命令同名,所以要带run)。apps/quotes/service只用于本地开发与测试,不单独部署。
pnpm --filter @quotes/quotes-web run deploy- Client-side crypto · 客户端加密:
apps/quotes/web/src/lib/crypto.ts - Server API · 服务端 API:
apps/quotes/service/src/index.ts - Shared contract (Zod) · 共享数据契约:
packages/contracts/src/quotes.ts
The key-derivation "domain separation" strings in
crypto.tsmust never change once deployed — changing them makes all existing data undecryptable.
注意:
crypto.ts中密钥派生的「域分隔字符串」一旦上线就不能再改——改了之后所有已有数据都将无法解密。