# WmailHub 基于 **Cloudflare Email Workers** 的轻量邮件接收与转发平台。 ```text Internet → Cloudflare Email Routing → Email Worker → Node → Console → D1/R2 ├→ Webhook ├→ API v1 └→ MCP ``` - **Console**(控制平面)= 前端(Vite + React + antd v6)+ 管理 API,部署在 Cloudflare Workers,负责 Cloudflare OAuth、账号/域名/邮箱/邮件管理、数据存储与 TTL 清理。 - **Node**(转发平面)= 纯后端转发节点(Bun),收到什么转发什么,不做业务判断。 - **Email Worker** = Cloudflare 邮件入口,只把邮件事件安全转发给 Node。 > **什么是「Node Ingress 地址」?** 即 Node 的邮件接收入口(如 `https://node.example.com/ingress/email`)。 > 链路是:Email Worker 在 Cloudflare 收到邮件 → POST 到该地址交给 Node → Node 用 HMAC 签名转发给 Console。 > Email Worker 部署在 Cloudflare 侧,必须被告知往哪里送,所以每个账号要配置这个地址 > (「设置 → 默认 Node Ingress 地址」给新账号用,账号详情里可单独改)。本地开发默认 `http://127.0.0.1:18788/ingress/email`。 ## 本地开发(无需 Cloudflare 账号) ```sh bun install bun run dev # 一键启动:console + node + email worker + 自动 OAuth(sim)安装 bun run dev -- --reset # 清空本地数据重新安装 bun test # 测试套件(协议安全/管线/TTL/Webhook/MCP/OAuth) bun tests/ui-smoke.ts # UI 冒烟(需本机 Playwright chromium) ``` 启动后: | 服务 | 地址 | | --- | --- | | Console(前端 + API) | http://127.0.0.1:18787 | | Node | http://127.0.0.1:18788/__health | | Email Worker(本地联调) | http://127.0.0.1:18789/__health | **登录**:默认 `admin / admin`。 **发测试邮件**(走完整链路 Worker→Node→Console): ```sh SECRET=$(python3 -c "import json;print(json.load(open('node/config.json'))['ingressSecret'])") curl -X POST http://127.0.0.1:18789/__email_test \ -H "X-WmailHub-Ingress-Secret: $SECRET" \ -H "X-WmailHub-Test-From: alice@example.org" \ -H "X-WmailHub-Test-To: hello@example.test" \ --data-binary @tests/fixtures/test-mail.eml ``` `bun run dev` 首次运行会自动:「添加账号」→ sim 模式 Cloudflare OAuth 自动创建账号 → 同步账号下全部域名 + catch-all 邮箱 → 逐域名配置 Email Workers → Node enrollment 换取身份(config.json,0600)→ 心跳上线。全程无需复制任何安装命令。 ## 功能 - **用户登录**:用户名密码(PBKDF2),默认 admin/admin,HMAC 签名会话 cookie;密码在「设置」中修改。 - **账号管理**:「添加账号」直达 Cloudflare OAuth(本地 sim / 真实 OAuth)→ 自动创建账号并同步该账号下全部域名;凭据轮换、Ingress 修改。 - **域名**:由 OAuth 自动同步(无手工添加);点击域名「设置 Email Workers」= 部署账号级 Email Worker + 开启 Email Routing + catch-all 规则;支持按账号筛选。 - **邮件管线**:MIME 解析(postal-mime)、附件、catch-all/精确匹配、大小限额、malformed 降级入库。 - **TTL**:邮件默认保留 1 天(`expires_at`),Cron 定期清理 R2 + DB + orphan,幂等。 - **Webhook(三级)**:配置落在 邮箱 → 域名 → 全局(设置)三级,收信时取第一个命中者转发 `email.received` 事件;支持自定义请求头与 key(key 默认以 `Authorization: Bearer ` 携带,并用于 `X-WmailHub-Signature` 签名);指数退避重试,SSRF 防护。 - **API v1**:`Authorization: Bearer wmh_...` 访问 `/api/v1/*`。 - **MCP**:`/api/v1/mcp`(JSON-RPC over HTTP),工具:`list_mailboxes` / `list_emails` / `get_email` / `create_mailbox` / `delete_mailbox`。 - **Key 管理**:API Key 与 MCP Key 在「设置」模态窗口内生成/撤销/删除,`wmh_` 前缀 + 随机串,总长 32 位;库中只存 SHA-256,明文仅创建时展示一次。 ## Node 协议(docs/04) ```text body_hash = SHA256(raw_body) canonical = METHOD \n PATH \n TIMESTAMP \n NONCE \n body_hash signature = HMAC-SHA256(node_credential_secret, canonical) ``` 请求头:`Authorization: WmailHub-Node `、`X-WmailHub-Timestamp`(±5 分钟)、`X-WmailHub-Nonce`(防重放)、`X-WmailHub-Body-SHA256`、`X-WmailHub-Signature`、`X-WmailHub-Protocol: 1`。 ## 目录结构 ```text WmailHub/ console/ Console(Workers 入口 src/worker.ts + 本地运行时 src/local/main.ts + 前端 frontend/) node/ Node 转发节点(Bun) worker/ Email Worker(Cloudflare 部署入口 + 本地联调 local.ts) shared/ 共享协议:HMAC 签名 / Key 生成 / 加密 / SSRF 防护 / Email Worker 脚本模板 migrations/ D1 schema tests/ bun test 测试 + UI 冒烟 + fixtures scripts/ dev 启动(前端构建走 vite) docs/ 设计文档(00~10) ``` ## 生产部署(Cloudflare Workers) 1. `bunx wrangler d1 create wmailhub` → 将 `database_id` 填入 `console/wrangler.jsonc` 2. `bunx wrangler r2 bucket create wmailhub` 3. `bunx wrangler d1 execute wmailhub --remote --file=./migrations/0001_init.sql` 4. `bunx wrangler d1 execute wmailhub --remote --file=./migrations/0002_accounts_webhooks.sql` 5. `cd console && bunx wrangler deploy`(前端先 `bun run build`) 6. `bunx wrangler secret put SESSION_SECRET --config console/wrangler.jsonc`(≥32 位随机串) 7. Cloudflare Dashboard 创建 OAuth App(client id/secret),配置 `CF_OAUTH_CLIENT_ID/SECRET` vars 与回调 `/api/oauth/cloudflare/callback`;未配置时自动进入 sim 模式(仅供本地) 8. Node 部署在任意能被 Email Worker 访问的服务器:`WMAILHUB_ENROLLMENT_TOKEN=... bun node/src/main.ts`(token 在账号详情「轮换凭据」后展示一次);并在「设置 → 默认 Node Ingress 地址」填其公网地址 Cron(`*/1 * * * *`)驱动 TTL 清理与 Webhook 重试;Email Worker 由 Console provisioning 自动上传,无需手工部署。 ## 安全设计(docs/08) - OAuth token、Node credential、ingress secret 全部 AES-256-GCM 加密存储;凭据撤销即时生效。 - Node→Console 强制 HTTPS + HMAC 签名 + timestamp 窗口 + nonce 防重放 + body hash 防篡改。 - Worker 只持有 Node ingress secret,不持有 Console 凭据。 - Webhook endpoint 防 SSRF(私网/loopback/metadata/非法 scheme;本地联调需显式 `WMAILHUB_ALLOW_PRIVATE_WEBHOOKS=1`)。 - 会话 cookie `SameSite=Strict` + 跨域 Origin 校验;日志不落 secret 与邮件正文。