- config 對 GITEA_REPOSITORY 加入 owner/repo 格式驗證,拒絕路徑穿越與特殊字元 - releases JSON 解析失敗時,錯誤訊息納入截斷的回傳內容片段以利除錯 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
91 lines
3.4 KiB
JavaScript
91 lines
3.4 KiB
JavaScript
'use strict';
|
||
|
||
/**
|
||
* 判斷環境變數值是否視為「未設定」。
|
||
*
|
||
* 下列任一情況皆視為未設定:undefined、null、空字串、字面字串 "null"。
|
||
*
|
||
* @param {*} value - 欲檢查的值(通常為環境變數字串)。
|
||
* @returns {boolean} 視為未設定時回傳 true,否則回傳 false。
|
||
*/
|
||
function isUnset(value) {
|
||
return value === undefined || value === null || value === '' || value === 'null';
|
||
}
|
||
|
||
/**
|
||
* 驗證必填環境變數;未設定時拋出錯誤。
|
||
*
|
||
* @param {string} name - 環境變數名稱,用於組出錯誤訊息。
|
||
* @param {*} value - 環境變數的值。
|
||
* @returns {*} 驗證通過後原樣回傳的 value。
|
||
* @throws {Error} 當 value 被視為未設定(undefined/null/空字串/"null")時拋出,訊息為 `${name} 未設定`。
|
||
*/
|
||
function requireEnv(name, value) {
|
||
if (isUnset(value)) {
|
||
throw new Error(`${name} 未設定`);
|
||
}
|
||
return value;
|
||
}
|
||
|
||
/**
|
||
* 將 beta 旗標正規化為布林值。
|
||
*
|
||
* 未設定時預設為 false;僅當值嚴格等於字面字串 "true" 時回傳 true。
|
||
*
|
||
* @param {*} value - beta 旗標環境變數的值。
|
||
* @returns {boolean} 啟用 beta 時回傳 true,否則回傳 false。
|
||
*/
|
||
function normalizeBetaFlag(value) {
|
||
if (isUnset(value)) {
|
||
return false;
|
||
}
|
||
return value === 'true';
|
||
}
|
||
|
||
// 驗證字串為合法的 http/https URL,否則拋出錯誤(避免指向非預期協定或格式錯誤的位址)
|
||
function assertHttpUrl(name, value) {
|
||
let parsed;
|
||
try {
|
||
parsed = new URL(value);
|
||
} catch {
|
||
throw new Error(`${name} 格式錯誤,必須為合法的 URL`);
|
||
}
|
||
if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {
|
||
throw new Error(`${name} 必須使用 http 或 https 協定`);
|
||
}
|
||
}
|
||
|
||
// 驗證 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_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 非合法 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);
|
||
|
||
return { serverUrl, repository, token, isBeta };
|
||
}
|
||
|
||
module.exports = { isUnset, requireEnv, normalizeBetaFlag, loadConfig };
|