Files
agenticSystem/mcp-server/utils/cmsTargetSafety.js
2026-04-01 23:16:45 +01:00

56 lines
1.9 KiB
JavaScript

const SAFE_INTERNAL_HOSTS = new Set(["web", "acai-web", "localhost", "127.0.0.1"]);
function parseUrl(url, fieldName, context) {
try {
return new URL(url);
} catch {
throw new Error(`[${context}] Invalid ${fieldName}: ${url || "<empty>"}`);
}
}
export function assertSafeCmsTarget(target, context = "cms") {
const publicUrl = typeof target === "string" ? target : (target?.web_url || "");
const apiUrl = typeof target === "string" ? target : (target?.api_web_url || "");
if (!apiUrl) {
throw new Error(
`[${context}] ACAI_API_WEB_URL is required. Refusing to use ACAI_WEB_URL directly for CMS requests.`
);
}
const parsedApiUrl = parseUrl(apiUrl, "ACAI_API_WEB_URL", context);
if (!SAFE_INTERNAL_HOSTS.has(parsedApiUrl.hostname)) {
throw new Error(
`[${context}] Unsafe ACAI_API_WEB_URL host "${parsedApiUrl.hostname}". ` +
`Only approved local hosts are allowed: ${Array.from(SAFE_INTERNAL_HOSTS).join(", ")}.`
);
}
if (!["http:", "https:"].includes(parsedApiUrl.protocol)) {
throw new Error(
`[${context}] Unsafe ACAI_API_WEB_URL protocol "${parsedApiUrl.protocol}".`
);
}
if (publicUrl) {
const parsedPublicUrl = parseUrl(publicUrl, "ACAI_WEB_URL", context);
const publicIsSafeInternal = SAFE_INTERNAL_HOSTS.has(parsedPublicUrl.hostname);
if (!publicIsSafeInternal && parsedPublicUrl.host === parsedApiUrl.host) {
throw new Error(
`[${context}] ACAI_API_WEB_URL resolves to the same public host as ACAI_WEB_URL (${parsedApiUrl.host}).`
);
}
}
return {
publicUrl,
apiUrl,
forgeHost: typeof target === "string" ? null : (target?.forge_host || null),
};
}
export function isSafeInternalHost(hostname) {
return SAFE_INTERNAL_HOSTS.has(hostname);
}