fix(security): 伺服器端強制 Turnstile 驗證 + KV 批量清理工具(修復大量刪除逾時) - #4
Merged
Merged
Conversation
先前批量刪除以「100 筆/批、每筆 3 個 KV delete、逐筆 await」的方式
進行,一次刪除上萬筆時:
- 每個請求 300 個序列子請求 → 超出 Cloudflare ~100s 上限 → 524。
- 免費方案 50 子請求/請求上限下更是直接失敗。
- 前端用陣列 includes 比對失敗清單,造成 O(n^2) 卡頓。
後端 (admin DELETE silent 模式):
- 改為 Promise.all 平行刪除,請求數秒內完成,避免 524。
- 移除 disabled:${id} 的刪除——該鍵在本專案從未被寫入(停用狀態存於
link metadata),可省下 1/3 子請求。
- 單次上限放寬至 200 筆。
前端 (/admin/cleanup):
- 切成 200 筆/批,並以並行度 3 處理,加速上萬筆刪除。
- 批次失敗時自動對半拆分重試,自動適應不同方案的子請求上限。
- 改用 Set 記錄成功/失敗,消除 O(n^2) 卡頓;失敗項目保留可重試。
- 進度顯示成功/失敗即時數量。
There was a problem hiding this comment.
Pull request overview
This PR improves the admin-side bulk deletion workflow for short links stored in LINKS_KV, focusing on making large cleanup operations faster and less likely to time out by adjusting server-side delete behavior and optimizing the /admin/cleanup UI’s batching strategy.
Changes:
- Updates admin DELETE handling to support larger batches (up to 200 IDs) and perform silent-mode deletions in parallel with a single summary Discord notification.
- Optimizes the
/admin/cleanuppage’s bulk delete flow with bounded concurrency, automatic batch splitting on failure, andSet-based bookkeeping to avoid UI slowdowns.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| functions/admin/index.js | Adjusts admin delete API limits and implements parallelized silent bulk deletion with summary notification. |
| functions/admin/cleanup.js | Improves bulk delete client logic via chunking, concurrency control, and retry-by-splitting to handle large datasets efficiently. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+199
to
+202
| // 靜默批量模式(清理用):平行刪除、不逐筆讀取或發送 Discord 通知, | ||
| // 避免一次刪除大量項目時拖慢請求、轟炸 webhook 或超出子請求上限。 | ||
| // 注意:本專案從未寫入 disabled:${id} 鍵(停用狀態存於 link metadata), | ||
| // 因此只需刪 link: 與 stats:,可省下 1/3 子請求。 |
Comment on lines
+432
to
+434
| // 刪除單一批次;若請求失敗(例如超出子請求上限),自動對半拆分重試, | ||
| // 直到批次小於 MIN_BATCH 才判定失敗。回傳成功刪除的 id 陣列。 | ||
| async function deleteOneBatch(batch, okSet, failedSet, onProgress) { |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
背景
有人繞過前端、直接呼叫公開建立 API 大量灌入短網址,導致 KV 內累積上萬筆無用資料。
根因
functions/api/public-create.js只在前端跑 Cloudflare Turnstile,伺服器端完全沒驗證 —— 前端把turnstileToken放進 body,後端收到後直接忽略。攻擊者只要直接POST /api/public-create(校內 IP 即可過白名單)就能無限建立短網址。functions/lib/validation.js早已寫好verifyTurnstile(),SPEC.md第 168 行也明文要求驗證 Turnstile,只是從未被實作。變更內容
🔒 安全性修復(
api/public-create.js)verifyTurnstile(turnstileToken, env.TURNSTILE_SECRET, ip)。DEV_MODE=true可略過(本機測試)。🧹 KV 批量清理工具(新頁面
/admin/cleanup)⚡ 大量刪除效能修復(修 524 逾時 / 卡頓)
先前批量刪除為「100 筆/批、每筆 3 個 KV delete、逐筆 await」,一次刪上萬筆時每個請求 300 個序列子請求 → 超出 Cloudflare ~100s 上限 → 524;免費方案 50 子請求上限下更直接失敗。
adminDELETE 的silent模式改為Promise.all平行刪除,請求數秒內完成。disabled:${id}的刪除——該鍵在本專案從未被寫入(停用狀態存於 link metadata),可省下 1/3 子請求。Set記錄成功/失敗,消除 O(n²) 卡頓,失敗項目保留可重試。對既有資料的影響
無。此 PR 不會自動讀寫、遷移或修改任何現有 KV 資料:
[id].js完全未改,所有現有短網址照常運作。list+getWithMetadata),刪除只在管理員主動勾選後才發生。Production 必須設定環境變數
TURNSTILE_SECRET(對應前端的TURNSTILE_SITE_KEY)。因改為 fail-closed,若未設定,新建短網址功能會被擋下(但不影響既有短網址轉址)。https://claude.ai/code/session_01Y6XCMnr6W2tWg5ynwq1Yst
Generated by Claude Code