Files
OmniRoute/open-sse/config/sap.ts
diegosouzapw 9e198184a7 fix(security): resolve 14 CodeQL code scanning alerts
- Replace polynomial regex /\/+$/ with loop-based stripTrailingSlashes()
  across 8 enterprise provider configs (azure-openai, azureAi, bedrock,
  datarobot, oci, sap, watsonx, audioSpeech) — fixes js/polynomial-redos

- Add prototype-pollution denylist guard in usageHistory.ts to reject
  __proto__/constructor/prototype as model keys — fixes
  js/prototype-polluting-assignment (#167, #168)

- Suppress 3 false-positive js/insufficient-password-hash alerts in
  chatgpt-web.ts and builtins.ts where SHA-256 is used for cache-key
  derivation, not password storage (#176, #177, #178)

- Add stripTrailingSlashes unit tests with ReDoS regression check
2026-04-27 20:00:10 -03:00

63 lines
1.9 KiB
TypeScript

import { stripTrailingSlashes } from "../utils/urlSanitize.ts";
export const SAP_DEFAULT_BASE_URL =
"https://example-aicore.cfapps.eu10.hana.ondemand.com/v2/lm/deployments/example-deployment";
function normalizeBaseUrl(value: string | null | undefined): string {
return stripTrailingSlashes((value || "").trim());
}
function sanitizeUrl(value: string): string {
try {
const parsed = new URL(value);
parsed.search = "";
parsed.hash = "";
return stripTrailingSlashes(parsed.toString());
} catch {
return value;
}
}
export function normalizeSapBaseUrl(value: string | null | undefined): string {
const normalized = normalizeBaseUrl(value || SAP_DEFAULT_BASE_URL);
if (!normalized) return SAP_DEFAULT_BASE_URL;
return sanitizeUrl(normalized.replace(/\/chat\/completions$/i, ""));
}
export function isSapDeploymentUrl(value: string | null | undefined): boolean {
const normalized = normalizeSapBaseUrl(value);
return /\/v2\/lm\/deployments\/[^/]+$/i.test(normalized);
}
export function buildSapChatUrl(value: string | null | undefined): string {
const normalized = normalizeSapBaseUrl(value);
if (normalized.endsWith("/chat/completions")) return normalized;
return `${normalized}/chat/completions`;
}
export function buildSapModelsUrl(value: string | null | undefined): string {
const normalized = normalizeSapBaseUrl(value);
const root = normalized.replace(/\/v2\/lm\/deployments\/[^/]+$/i, "");
return `${root}/v2/lm/scenarios/foundation-models/models`;
}
export function getSapResourceGroup(
providerSpecificData: Record<string, unknown> | null | undefined,
fallback = "default"
): string {
const candidates = [
providerSpecificData?.resourceGroup,
providerSpecificData?.aiResourceGroup,
providerSpecificData?.resource_group,
];
for (const candidate of candidates) {
if (typeof candidate === "string" && candidate.trim()) {
return candidate.trim();
}
}
return fallback;
}