feat: WmailHub v1.0.0 —— Cloudflare Email Workers 邮件接收与转发平台(本地可用版本)
- 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 生成
This commit is contained in:
@@ -0,0 +1,55 @@
|
||||
/** sim 模式的 Cloudflare 授权模拟页:确认后调用 approve,再跳回节点页 */
|
||||
import { useEffect, useState } from "react";
|
||||
import { useNavigate, useSearchParams } from "react-router-dom";
|
||||
import { Button, Card, Space, App } from "antd";
|
||||
import { oauthSimApprove } from "../api.ts";
|
||||
|
||||
/** # 函数
|
||||
* 模拟授权页(仅本地 sim 模式;真实部署直接跳 Cloudflare 授权页)
|
||||
*/
|
||||
export function OAuthSimPage() {
|
||||
const [params] = useSearchParams();
|
||||
const navigate = useNavigate();
|
||||
const { message } = App.useApp();
|
||||
const state = params.get("state") ?? "";
|
||||
const [busy, setBusy] = useState(false);
|
||||
|
||||
const approve = async () => {
|
||||
setBusy(true);
|
||||
try {
|
||||
const res = await oauthSimApprove(state);
|
||||
if (res.ok) {
|
||||
message.success("Cloudflare 授权与自动安装完成");
|
||||
navigate(`/nodes?provision=${encodeURIComponent(res.node_id)}`, { replace: true });
|
||||
} else {
|
||||
message.error(res.error ?? "安装失败");
|
||||
navigate("/nodes", { replace: true });
|
||||
}
|
||||
} catch (err) {
|
||||
message.error(err instanceof Error ? err.message : "授权失败");
|
||||
navigate("/nodes", { replace: true });
|
||||
} finally {
|
||||
setBusy(false);
|
||||
}
|
||||
};
|
||||
|
||||
// state 缺失直接回节点页
|
||||
useEffect(() => {
|
||||
if (!state) navigate("/nodes", { replace: true });
|
||||
}, [state, navigate]);
|
||||
|
||||
return (
|
||||
<div className="login-page">
|
||||
<Card className="login-card" title="Cloudflare 授权(本地模拟)" styles={{ header: { textAlign: "center" } }}>
|
||||
<p>sim 模式下,该页面模拟 Cloudflare OAuth 授权同意流程。</p>
|
||||
<p className="muted">真实部署时,这里会跳转到 dash.cloudflare.com 的授权页面。</p>
|
||||
<Space style={{ width: "100%", justifyContent: "center", marginTop: 16 }}>
|
||||
<Button onClick={() => navigate("/nodes")}>拒绝</Button>
|
||||
<Button type="primary" loading={busy} onClick={() => void approve()}>
|
||||
同意授权
|
||||
</Button>
|
||||
</Space>
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user