Skip to content

Commit 00a8eb8

Browse files
committed
feat: add OpenAPI access control and configuration
- Introduced `openApiEnabled` configuration in the app settings. - Implemented middleware to restrict access to API routes when OpenAPI is disabled. - Updated API key creation logic to check OpenAPI status before proceeding. - Added user feedback for disabled API access in the frontend. - Created tests for OpenAPI functionality and response handling. - Updated environment configuration to include `ENABLE_OPENAPI` variable.
1 parent a0d94b4 commit 00a8eb8

15 files changed

Lines changed: 111 additions & 14 deletions

File tree

README.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -77,9 +77,10 @@
7777
- `EMAIL_DOMAIN`: 您的邮箱域名,例如 `example.com,example.net`
7878
- `TURNSTILE_KEY`: 您的 Turnstile 站点密钥,可选。
7979
- `TURNSTILE_SECRET`: 您的 Turnstile 密钥,可选。
80-
- `PASSWORD`: 站点访问密码(可选)。
81-
- `API_RATE_LIMIT_PER_MINUTE`: API 每分钟请求限制(可选,默认 100)。
82-
- `SHOW_AFF`: 是否展示推广弹框和常驻推广链接(可选,`true` 开启,默认不展示)。
80+
- `PASSWORD`: 站点访问密码(可选)。
81+
- `API_RATE_LIMIT_PER_MINUTE`: API 每分钟请求限制(可选,默认 100)。
82+
- `SHOW_AFF`: 是否展示推广弹框和常驻推广链接(可选,`true` 开启,默认不展示)。
83+
- `ENABLE_OPENAPI`: 是否开启 OpenAPI 调用功能(可选,默认开启;设置为 `false` 时禁用 API Key 创建与 `/api/v1/*` 调用)。
8384

8485
## 🔨 本地运行调试
8586

README_en.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ When deploying to Cloudflare Pages, you need to configure the following environm
133133
- `PASSWORD`: Site access password (optional).
134134
- `API_RATE_LIMIT_PER_MINUTE`: API rate limit per minute (optional, default 100).
135135
- `SHOW_AFF`: Show promotional popup and link (optional, `true` to enable, hidden by default).
136+
- `ENABLE_OPENAPI`: Whether to enable OpenAPI access (optional, enabled by default; set to `false` to disable API key creation and `/api/v1/*` access).
136137

137138
## Community Group
138139

@@ -144,4 +145,4 @@ GNU General Public License v3.0
144145

145146
## Star History
146147

147-
[![Star History Chart](https://api.star-history.com/svg?repos=oiov/vmail&type=Date)](https://star-history.com/#oiov/vmail&Date)
148+
[![Star History Chart](https://api.star-history.com/svg?repos=oiov/vmail&type=Date)](https://star-history.com/#oiov/vmail&Date)

docs/ai-deploy.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
部署后关键接口合同:
1111

12-
- `GET /config` 返回:`turnstileEnabled``sitePasswordEnabled``apiRateLimitPerMinute`
12+
- `GET /config` 返回:`turnstileEnabled``sitePasswordEnabled``apiRateLimitPerMinute``openApiEnabled`
1313
- `GET /api/stats` 返回:`totals``today``yesterday`
1414
- `POST /auth/unlock``GET /auth/status``POST /auth/logout`
1515

@@ -37,12 +37,14 @@
3737
- `TURNSTILE_SECRET`(可选)
3838
- `PASSWORD`(可选;为空时站点默认公开)
3939
- `API_RATE_LIMIT_PER_MINUTE`(可选;非法值或缺省回退到 `100`
40+
- `ENABLE_OPENAPI`(可选;默认开启,设置为 `false` 时禁用 API Key 创建与 `/api/v1/*`
4041

4142
行为说明:
4243

4344
-`TURNSTILE_KEY``TURNSTILE_SECRET` 任一缺失时,前后端都进入“无需人机验证”模式。
4445
-`PASSWORD` 为空时,前端不会出现站点解锁门禁;有值时需要先解锁站点。
4546
- `API_RATE_LIMIT_PER_MINUTE` 作用于 v1 API Key 中间件,按“每个 API Key、每分钟固定窗口”限流。
47+
-`ENABLE_OPENAPI=false` 时,`/api/api-keys``/api/v1/*` 会统一返回 `403 OPENAPI_DISABLED``/api-docs` 页面仅展示提示。
4648

4749
# 4. 数据库迁移与基础初始化
4850

@@ -88,6 +90,7 @@
8890
- `turnstileEnabled`
8991
- `sitePasswordEnabled`
9092
- `apiRateLimitPerMinute`
93+
- `openApiEnabled`
9194
2. 统计合同:
9295
- 请求 `GET /api/stats`
9396
- 断言返回结构含 `totals/today/yesterday`
@@ -104,8 +107,10 @@
104107
- 使用同一 API Key 连续请求 v1 API
105108
- 超过阈值返回 `429`
106109
- 响应头包含:`X-RateLimit-Limit``X-RateLimit-Remaining``Retry-After`
110+
-`ENABLE_OPENAPI=false``/api/api-keys``/api/v1/*` 返回 `403`
107111
6. 前端展示:
108112
- 首页 SiteStats 卡片显示增长率(today vs yesterday)
113+
- `/api-docs``openApiEnabled=false` 时展示禁用提示
109114

110115
# 7. 常见问题与回滚策略
111116

docs/github-action-tutorial.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
| `TURNSTILE_SECRET` | 可选,Cloudflare Turnstile 密钥 (Secret Key)。 | `xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx` |
2525
| `PASSWORD` | 可选,用于访问 Vmail 网站的密码。 | `password` |
2626
| `API_RATE_LIMIT_PER_MINUTE` | 可选,API 每分钟请求限制,默认为 `100`| `100` |
27+
| `ENABLE_OPENAPI` | 可选,是否开启 OpenAPI 调用功能;默认为开启,设置为 `false` 时禁用 API Key 创建和 `/api/v1/*`| `false` |
2728

2829
## 触发自动部署
2930

@@ -39,4 +40,4 @@
3940
## 注意事项
4041

4142
- 工作流文件 (`.github/workflows/deploy.yml`) 会自动从您的 Secrets 中读取配置并应用到 `wrangler.toml` 文件中,**请勿**直接将敏感信息写入 `wrangler.toml` 文件。
42-
- 如果您的数据库结构有变更(例如,修改了 `worker/src/database/schema.ts`),请记得生成新的迁移文件并提交到代码库中,GitHub Action 会自动帮您应用更新。
43+
- 如果您的数据库结构有变更(例如,修改了 `worker/src/database/schema.ts`),请记得生成新的迁移文件并提交到代码库中,GitHub Action 会自动帮您应用更新。

frontend/build/client/assets/main-Bd6k8RJl.css

Lines changed: 0 additions & 1 deletion
This file was deleted.

frontend/build/client/assets/main-EhQP4hi8.css

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

frontend/build/client/assets/main-BdocldXg.js renamed to frontend/build/client/assets/main-g6v1k0ut.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

frontend/build/client/index.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55
<link rel="icon" type="image/x-icon" href="/favicon.ico" />
66
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
77
<title>VMAIL - Virtual Temporary Email</title>
8-
<script type="module" crossorigin src="/assets/main-BdocldXg.js"></script>
9-
<link rel="stylesheet" crossorigin href="/assets/main-Bd6k8RJl.css">
8+
<script type="module" crossorigin src="/assets/main-g6v1k0ut.js"></script>
9+
<link rel="stylesheet" crossorigin href="/assets/main-EhQP4hi8.css">
1010
</head>
1111
<script
1212
defer

frontend/src/hooks/useConfig.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ export interface AppConfig {
77
turnstileEnabled: boolean;
88
sitePasswordEnabled: boolean;
99
apiRateLimitPerMinute: number;
10+
openApiEnabled: boolean;
1011
// feat: 添加 cookiesSecret 到配置中,以便前端加密时使用
1112
cookiesSecret: string;
1213
// feat: 控制是否展示推广弹框和常驻链接
@@ -23,4 +24,4 @@ export const useConfig = () => {
2324
throw new Error('useConfig 必须在 ConfigProvider 内部使用');
2425
}
2526
return context;
26-
};
27+
};

frontend/src/pages/ApiDocs.tsx

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,11 @@ API requests are rate limited based on your API Key configuration. Default limit
253253

254254
// 创建 API Key
255255
const handleCreateApiKey = async () => {
256+
if (!config.openApiEnabled) {
257+
toast.error("API access is currently disabled");
258+
return;
259+
}
260+
256261
if (!turnstileToken) {
257262
toast.error(t("Please complete the verification first"));
258263
return;
@@ -474,6 +479,11 @@ API requests are rate limited based on your API Key configuration. Default limit
474479
Vmail & NBility 联动注册送 Claude Code、Codex 免费额度
475480
</button>
476481
)}
482+
{!config.openApiEnabled && (
483+
<div className="mt-4 rounded-lg border border-amber-500/40 bg-amber-500/10 px-4 py-3 text-sm text-amber-100">
484+
当前管理员已禁用 API 访问,若有需要请自行部署。
485+
</div>
486+
)}
477487
</div>
478488

479489
{/* Get API Key Section */}
@@ -539,6 +549,11 @@ API requests are rate limited based on your API Key configuration. Default limit
539549
"Create a free API Key to access the API. Each key has a rate limit of 100 requests per minute.",
540550
)}
541551
</p>
552+
{!config.openApiEnabled && (
553+
<p className="mb-4 rounded-lg border border-amber-500/30 bg-amber-500/10 px-3 py-2 text-sm text-amber-100">
554+
当前实例已关闭 API 调用与 API Key 创建功能。
555+
</p>
556+
)}
542557
<div className="space-y-4">
543558
<div>
544559
<label className="block text-sm text-gray-400 mb-2">
@@ -566,7 +581,7 @@ API requests are rate limited based on your API Key configuration. Default limit
566581
</div>
567582
<button
568583
onClick={handleCreateApiKey}
569-
disabled={!turnstileToken || isCreating}
584+
disabled={!config.openApiEnabled || !turnstileToken || isCreating}
570585
className="px-6 py-2.5 bg-cyan-600 hover:bg-cyan-700 disabled:bg-gray-600 disabled:cursor-not-allowed rounded-lg font-medium transition-colors">
571586
{isCreating ? t("Creating...") : t("Create API Key")}
572587
</button>

0 commit comments

Comments
 (0)