- Console:React 19 + antd 6.6.5 前端(登录 admin/admin)+ Hono 管理 API (Nodes/Domains/Mailboxes/Emails/Webhooks/Keys/OAuth/Admin) - Node:Bun 转发节点(HMAC 签名、有限重试、心跳、结构化日志、优雅退出) - Email Worker:Cloudflare email handler + 本地联调入口 - shared:HMAC 协议(docs/04)、wmh_ Key(32 位)、AES-GCM 加密、SSRF 防护 - 邮件管线:postal-mime 解析、附件、catch-all、限额、malformed 降级、TTL 1 天 - Webhook:签名投递、指数退避重试、SSRF 校验、投递日志 - API v1 + MCP(JSON-RPC,六工具,凭据 kind 隔离) - Cloudflare OAuth:真实 + 本地 sim 模式,自动安装管线(幂等,无需手工命令) - 测试:bun test 41 例(协议安全/管线/TTL/Webhook/SSRF/MCP/OAuth/鉴权)+ Playwright UI 冒烟 - LOGO/favicon 由 codex CLI 生成
5.3 KiB
5.3 KiB
WmailHub
基于 Cloudflare Email Workers 的轻量邮件接收与转发平台。
Internet → Cloudflare Email Routing → Email Worker → Node → Console → D1/R2
├→ Webhook
├→ API v1
└→ MCP
- Console(控制平面)= 前端(React + antd v6)+ 管理 API,部署在 Cloudflare Workers,负责 Cloudflare OAuth、Node/Domain/Mailbox/Email/Webhook 管理、数据存储与 TTL 清理。
- Node(转发平面)= 纯后端转发节点(Bun),收到什么转发什么,不做业务判断。
- Email Worker = Cloudflare 邮件入口,只把邮件事件安全转发给 Node。
本地开发(无需 Cloudflare 账号)
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):
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 首次运行会自动:创建本地 Node → enrollment 换取身份(config.json,0600)→ sim 模式 Cloudflare OAuth 自动安装(Email Worker / Email Routing / Domain example.test / catch-all Mailbox)→ Node 心跳上线。全程无需复制任何安装命令。
功能
- 用户登录:用户名密码(PBKDF2),默认 admin/admin,HMAC 签名会话 cookie。
- Node 管理:Add Node → Cloudflare OAuth(本地 sim / 真实 OAuth)→ 自动安装,步骤可视化,凭据轮换。
- 邮件管线:MIME 解析(postal-mime)、附件、catch-all/精确匹配、大小限额、malformed 降级入库。
- TTL:邮件默认保留 1 天(
expires_at),Cron 定期清理 R2 + DB + orphan,幂等。 - Webhook:
email.received事件推送,HMAC 签名头(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/list_webhooks。 - Key 管理:API Key 与 MCP Key 在后端设置,
wmh_前缀 + 随机串,总长 32 位;库中只存 SHA-256,明文仅创建时展示一次。
Node 协议(docs/04)
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 <node_id>、X-WmailHub-Timestamp(±5 分钟)、X-WmailHub-Nonce(防重放)、X-WmailHub-Body-SHA256、X-WmailHub-Signature、X-WmailHub-Protocol: 1。
目录结构
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 启动 / 前端构建
docs/ 设计文档(00~10)
生产部署(Cloudflare Workers)
bunx wrangler d1 create wmailhub→ 将database_id填入console/wrangler.jsoncbunx wrangler r2 bucket create wmailhubbunx wrangler d1 execute wmailhub --remote --file=./migrations/0001_init.sqlcd console && bunx wrangler deploy(前端先bun run build)bunx wrangler secret put SESSION_SECRET --config console/wrangler.jsonc(≥32 位随机串)- Cloudflare Dashboard 创建 OAuth App(client id/secret),配置
CF_OAUTH_CLIENT_ID/SECRETvars 与回调<PUBLIC_BASE_URL>/api/oauth/cloudflare/callback;未配置时自动进入 sim 模式(仅供本地) - Node 部署在任意能被 Email Worker 访问的服务器:
WMAILHUB_ENROLLMENT_TOKEN=... bun node/src/main.ts(token 在 Console「添加节点」后展示一次)
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 与邮件正文。