diff --git a/apps/sim/app/api/tools/sap_s4hana/proxy/route.ts b/apps/sim/app/api/tools/sap_s4hana/proxy/route.ts index ae1e9c0605..bee4a8b84a 100644 --- a/apps/sim/app/api/tools/sap_s4hana/proxy/route.ts +++ b/apps/sim/app/api/tools/sap_s4hana/proxy/route.ts @@ -113,8 +113,8 @@ interface CsrfBundle { } function joinSetCookies(response: SecureFetchResponse): string { - const cookies = (response.headers.get('set-cookie') ?? '').split(/,\s*(?=[^=,;\s]+=)/) - return cookies + return response.headers + .getSetCookie() .map((c) => c.split(';')[0]?.trim()) .filter(Boolean) .join('; ') diff --git a/apps/sim/lib/core/security/input-validation.server.ts b/apps/sim/lib/core/security/input-validation.server.ts index ed23140ea4..90c65eca62 100644 --- a/apps/sim/lib/core/security/input-validation.server.ts +++ b/apps/sim/lib/core/security/input-validation.server.ts @@ -217,15 +217,22 @@ export interface SecureFetchOptions { export class SecureFetchHeaders { private headers: Map + private setCookies: string[] - constructor(headers: Record) { + constructor(headers: Record, setCookies: string[] = []) { this.headers = new Map(Object.entries(headers).map(([k, v]) => [k.toLowerCase(), v])) + this.setCookies = setCookies } get(name: string): string | null { return this.headers.get(name.toLowerCase()) ?? null } + /** Returns the raw `Set-Cookie` header values as an array. Each entry is one cookie. */ + getSetCookie(): string[] { + return [...this.setCookies] + } + toRecord(): Record { const record: Record = {} for (const [key, value] of this.headers) { @@ -384,11 +391,21 @@ export async function secureFetchWithPinnedIP( const bodyBuffer = Buffer.concat(chunks) const body = bodyBuffer.toString('utf-8') const headersRecord: Record = {} + let setCookieArray: string[] = [] for (const [key, value] of Object.entries(res.headers)) { - if (typeof value === 'string') { - headersRecord[key.toLowerCase()] = value + const lowerKey = key.toLowerCase() + if (lowerKey === 'set-cookie') { + if (Array.isArray(value)) { + setCookieArray = value + headersRecord[lowerKey] = value.join(', ') + } else if (typeof value === 'string') { + setCookieArray = [value] + headersRecord[lowerKey] = value + } + } else if (typeof value === 'string') { + headersRecord[lowerKey] = value } else if (Array.isArray(value)) { - headersRecord[key.toLowerCase()] = value.join(', ') + headersRecord[lowerKey] = value.join(', ') } } @@ -396,7 +413,7 @@ export async function secureFetchWithPinnedIP( ok: statusCode >= 200 && statusCode < 300, status: statusCode, statusText: res.statusMessage || '', - headers: new SecureFetchHeaders(headersRecord), + headers: new SecureFetchHeaders(headersRecord, setCookieArray), text: async () => body, json: async () => JSON.parse(body), arrayBuffer: async () =>