Skip to content

pnck/Quotes

Repository files navigation

Quotes · 嘉豪

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.

把嘉豪哥的逆天发言连同截图存档,回放成「头条新闻」。
—— 但是密码学。

How it works · 工作原理

  • 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 拼上去的,并且这个密钥只在已登录用户的前端生成,所以不能用做图床。

Stack · 技术栈

  • Claude Opus4.8
  • React 18 · TypeScript · Tailwind CSS v4 · Vite | Cloudflare Workers (Hono) + KV | pnpm workspace + Turborepo

Local development · 本地开发

pnpm install
pnpm dev          # web :4313, service :8787 (Vite proxies /api -> wrangler dev)

Themes · 主题

  • 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 下的自描述清单,放一个文件夹即可新增一个主题,无需改任何契约或服务端。

Self-hosting on Cloudflare · 自行部署到 Cloudflare

  1. Create a KV namespace in the Cloudflare dashboard and put its id into kv_namespaces (both id and preview_id) in apps/quotes/web/wrangler.jsonc.

  2. Deploy with the command below (deploy collides with a built-in pnpm subcommand, hence run). apps/quotes/service is for local dev and tests only — it isn't deployed on its own.

  3. 在 Cloudflare 控制台建一个 KV namespace,把它的 id 填入 apps/quotes/web/wrangler.jsonckv_namespacesidpreview_id)。

  4. 用下面的命令部署(deploy 与 pnpm 内置子命令同名,所以要带 run)。apps/quotes/service 只用于本地开发与测试,不单独部署。

pnpm --filter @quotes/quotes-web run deploy

Where to audit · 审计入口

  • 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.ts must never change once deployed — changing them makes all existing data undecryptable.

注意:crypto.ts 中密钥派生的「域分隔字符串」一旦上线就不能再改——改了之后所有已有数据都将无法解密。

About

Amaze your dumb ass friends.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors