From 726b05bc0b1f77fcccca33ce5bfb2f9a8797cd7f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 25 Mar 2026 08:15:48 +0000 Subject: [PATCH] fix: address code review feedback - timer leaks, CORS, validation, cache TTL - Fix timer leak in fetchNotionProfile/loadDatabaseCache with finally block - Remove HTTP origin from CORS whitelist (HTTPS-only) - Validate devId against DEV_REGISTRY instead of regex - Fix cache TTL check to use >= instead of > - Fix chat.js count queries to use page_size 100 instead of 1 Co-authored-by: qinfendebingshuo <207279273+qinfendebingshuo@users.noreply.github.com> Agent-Logs-Url: https://github.com/qinfendebingshuo/guanghulab/sessions/a260ce18-279a-4490-af90-a90a7b1f46cd --- backend/api-server/routes/chat.js | 6 +++--- backend/api-server/routes/dev.js | 9 +++------ backend/api-server/server.js | 1 - backend/api-server/services/cache.js | 2 +- docs/index.html | 14 ++++++++------ 5 files changed, 15 insertions(+), 17 deletions(-) diff --git a/backend/api-server/routes/chat.js b/backend/api-server/routes/chat.js index 88ea70c0..258b1692 100644 --- a/backend/api-server/routes/chat.js +++ b/backend/api-server/routes/chat.js @@ -55,7 +55,7 @@ router.post('/chat/context', async function(req, res) { // 获取 Agent 注册表计数 try { if (dbConfig.agentRegistry) { - var agents = await notionService.queryDB(dbConfig.agentRegistry, null, null, 1); + var agents = await notionService.queryDB(dbConfig.agentRegistry, null, null, 100); context.agents_count = agents.results ? agents.results.length : 0; } } catch (_) {} @@ -66,7 +66,7 @@ router.post('/chat/context', async function(req, res) { var syslogs = await notionService.queryDB(dbConfig.syslogInbox, { property: 'DEV编号', rich_text: { equals: devId } - }, null, 1); + }, null, 100); context.syslogs_count = syslogs.results ? syslogs.results.length : 0; } } catch (_) {} @@ -75,7 +75,7 @@ router.post('/chat/context', async function(req, res) { try { if (dbConfig.ticketBook) { var tickets = await notionService.queryDB(dbConfig.ticketBook, - { property: '状态', select: { does_not_equal: '已完成' } }, null, 1); + { property: '状态', select: { does_not_equal: '已完成' } }, null, 100); context.tickets_count = tickets.results ? tickets.results.length : 0; } } catch (_) {} diff --git a/backend/api-server/routes/dev.js b/backend/api-server/routes/dev.js index 291c1262..0c47b5ac 100644 --- a/backend/api-server/routes/dev.js +++ b/backend/api-server/routes/dev.js @@ -28,15 +28,12 @@ var DEV_REGISTRY = { router.get('/dev/:devId', async function(req, res) { var devId = req.params.devId; - // 验证 devId 格式 - if (!/^DEV-\d{3}$/.test(devId)) { - return res.status(400).json({ error: true, code: 'INVALID_DEV_ID', message: '无效的开发者编号格式' }); + // 验证 devId + if (!DEV_REGISTRY[devId]) { + return res.status(404).json({ error: true, code: 'DEV_NOT_FOUND', message: '开发者不存在' }); } var devInfo = DEV_REGISTRY[devId]; - if (!devInfo) { - return res.status(404).json({ error: true, code: 'DEV_NOT_FOUND', message: '开发者不存在' }); - } var profile = { dev_id: devId, diff --git a/backend/api-server/server.js b/backend/api-server/server.js index 5e454e22..e4426c22 100644 --- a/backend/api-server/server.js +++ b/backend/api-server/server.js @@ -18,7 +18,6 @@ const app = express(); app.use(cors({ origin: [ 'https://guanghulab.com', - 'http://guanghulab.com', 'https://www.guanghulab.com', 'https://qinfendebingshuo.github.io' ], diff --git a/backend/api-server/services/cache.js b/backend/api-server/services/cache.js index ca33699f..302fe868 100644 --- a/backend/api-server/services/cache.js +++ b/backend/api-server/services/cache.js @@ -14,7 +14,7 @@ var store = new Map(); function get(key) { var item = store.get(key); if (!item) return null; - if (Date.now() - item.time > (item.ttl || DEFAULT_TTL)) { + if (Date.now() - item.time >= (item.ttl || DEFAULT_TTL)) { store.delete(key); return null; } diff --git a/docs/index.html b/docs/index.html index 3b042598..98a9aa98 100644 --- a/docs/index.html +++ b/docs/index.html @@ -1771,9 +1771,10 @@ async function fetchNotionProfile(devId) { try { const ctrl = new AbortController(); const tid = setTimeout(function() { ctrl.abort(); }, 5000); - const res = await fetch(API_BASE + '/dev/' + encodeURIComponent(devId), { signal: ctrl.signal }); - clearTimeout(tid); - if (res.ok) { const d = await res.json(); d._source = 'realtime'; return d; } + try { + const res = await fetch(API_BASE + '/dev/' + encodeURIComponent(devId), { signal: ctrl.signal }); + if (res.ok) { const d = await res.json(); d._source = 'realtime'; return d; } + } finally { clearTimeout(tid); } } catch (e) { console.debug('[通道B] profile fetch failed, 降级到通道A:', e.message); } } // 通道A(GitHub 缓存) @@ -1791,9 +1792,10 @@ async function loadDatabaseCache(name) { try { const ctrl = new AbortController(); const tid = setTimeout(function() { ctrl.abort(); }, 5000); - const res = await fetch(API_BASE + '/databases/' + encodeURIComponent(name), { signal: ctrl.signal }); - clearTimeout(tid); - if (res.ok) return await res.json(); + try { + const res = await fetch(API_BASE + '/databases/' + encodeURIComponent(name), { signal: ctrl.signal }); + if (res.ok) return await res.json(); + } finally { clearTimeout(tid); } } catch (e) { console.debug('[通道B] database ' + name + ' fetch failed:', e.message); } } // 通道A(GitHub 缓存)