Files
agenticSystem/mcp-server/utils/cmsTargetSafety.js
2026-04-08 23:52:54 +00:00

70 lines
2.5 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 || "");
const mode = typeof target === "string" ? "local" : (target?.mode || "local");
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 (!["http:", "https:"].includes(parsedApiUrl.protocol)) {
throw new Error(
`[${context}] Unsafe ACAI_API_WEB_URL protocol "${parsedApiUrl.protocol}".`
);
}
// Modo "production": el .acai del proyecto autoriza explicitamente apuntar
// al sitio real. Saltamos el whitelist de hosts internos. Usar SOLO para
// testing/debug controlado — el agente IA puede modificar produccion.
if (mode === "production") {
return {
publicUrl,
apiUrl,
forgeHost: typeof target === "string" ? null : (target?.forge_host || null),
};
}
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(", ")}. ` +
`Set "mode": "production" in .acai to bypass this check (intended for testing only).`
);
}
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);
}