From b8804c5218ac63df4a114f65a37563c0aee131da Mon Sep 17 00:00:00 2001 From: Jeffery Date: Fri, 26 Jun 2026 14:01:30 +0800 Subject: [PATCH] =?UTF-8?q?fix(calculate-version):=20=E5=BC=B7=E5=8C=96?= =?UTF-8?q?=E8=BC=B8=E5=85=A5=E9=A9=97=E8=AD=89=E8=88=87=E9=8C=AF=E8=AA=A4?= =?UTF-8?q?=E8=A8=8A=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - config 對 GITEA_REPOSITORY 加入 owner/repo 格式驗證,拒絕路徑穿越與特殊字元 - releases JSON 解析失敗時,錯誤訊息納入截斷的回傳內容片段以利除錯 Co-Authored-By: Claude Opus 4.8 (1M context) --- app/config.js | 16 ++++++++++++++-- app/releases.js | 4 +++- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/app/config.js b/app/config.js index bf57afe..e2ccd7f 100644 --- a/app/config.js +++ b/app/config.js @@ -55,20 +55,32 @@ function assertHttpUrl(name, value) { } } +// 驗證 repository 為 owner/repo 格式(僅允許字母數字與 . _ -,且拒絕 . 與 .. 路徑穿越段) +function assertRepository(name, value) { + const parts = value.split('/'); + const valid = parts.length === 2 + && parts.every((part) => /^[A-Za-z0-9._-]+$/.test(part) && part !== '.' && part !== '..'); + if (!valid) { + throw new Error(`${name} 格式錯誤,必須為 owner/repo`); + } +} + /** * 從環境變數載入並驗證執行所需的設定。 * * GITEA_SERVER_URL 與 GITEA_REPOSITORY 為必填,未設定時會拋出錯誤;GITEA_SERVER_URL - * 另需為合法的 http/https URL;GITEA_TOKEN 為非必填,未設定時為 null;IS_BETA 會被正規化為布林值。 + * 另需為合法的 http/https URL,GITEA_REPOSITORY 另需為 owner/repo 格式; + * GITEA_TOKEN 為非必填,未設定時為 null;IS_BETA 會被正規化為布林值。 * * @param {Object} [env=process.env] - 環境變數來源物件,預設為 process.env。 * @returns {{ serverUrl: string, repository: string, token: (string|null), isBeta: boolean }} 已驗證的設定物件。 - * @throws {Error} 當 GITEA_SERVER_URL 或 GITEA_REPOSITORY 未設定,或 GITEA_SERVER_URL 非合法 http/https URL 時拋出。 + * @throws {Error} 當必填項未設定、GITEA_SERVER_URL 非合法 http/https URL,或 GITEA_REPOSITORY 非 owner/repo 格式時拋出。 */ function loadConfig(env = process.env) { const serverUrl = requireEnv('GITEA_SERVER_URL', env.GITEA_SERVER_URL); assertHttpUrl('GITEA_SERVER_URL', serverUrl); const repository = requireEnv('GITEA_REPOSITORY', env.GITEA_REPOSITORY); + assertRepository('GITEA_REPOSITORY', repository); const token = isUnset(env.GITEA_TOKEN) ? null : env.GITEA_TOKEN; const isBeta = normalizeBetaFlag(env.IS_BETA); diff --git a/app/releases.js b/app/releases.js index e2b049d..e057039 100644 --- a/app/releases.js +++ b/app/releases.js @@ -63,7 +63,9 @@ async function fetchReleases(baseUrl, options = {}) { try { pageJson = JSON.parse(text); } catch { - throw new Error(`release API 回傳資料無法解析 (page=${page})`); + // 附上截斷的回傳內容片段,便於除錯回傳格式異常 + const snippet = text.slice(0, 200); + throw new Error(`release API 回傳資料無法解析 (page=${page}): ${snippet}`); } if (pageJson === null) {