const DEFAULT_PROXY_TARGET = 'https://cloud.dify.ai' const SECURE_COOKIE_PREFIX_PATTERN = /^__(Host|Secure)-/ const SAME_SITE_NONE_PATTERN = /^samesite=none$/i const COOKIE_PATH_PATTERN = /^path=/i const COOKIE_DOMAIN_PATTERN = /^domain=/i const COOKIE_SECURE_PATTERN = /^secure$/i const COOKIE_PARTITIONED_PATTERN = /^partitioned$/i const HOST_PREFIX_COOKIE_NAMES = new Set([ 'access_token', 'csrf_token', 'refresh_token', 'webapp_access_token', ]) const isPassportCookie = (cookieName: string) => cookieName.startsWith('passport-') const shouldUseHostPrefix = (cookieName: string) => { const normalizedCookieName = cookieName.replace(SECURE_COOKIE_PREFIX_PATTERN, '') return HOST_PREFIX_COOKIE_NAMES.has(normalizedCookieName) || isPassportCookie(normalizedCookieName) } const toUpstreamCookieName = (cookieName: string) => { if (cookieName.startsWith('__Host-')) return cookieName if (cookieName.startsWith('__Secure-')) return `__Host-${cookieName.replace(SECURE_COOKIE_PREFIX_PATTERN, '')}` if (!shouldUseHostPrefix(cookieName)) return cookieName return `__Host-${cookieName}` } const toLocalCookieName = (cookieName: string, options: LocalCookieRewriteOptions) => { if (options.localSecure) return cookieName return cookieName.replace(SECURE_COOKIE_PREFIX_PATTERN, '') } type LocalCookieRewriteOptions = { localSecure: boolean } export const rewriteCookieHeaderForUpstream = (cookieHeader?: string) => { if (!cookieHeader) return cookieHeader return cookieHeader .split(/;\s*/) .filter(Boolean) .map((cookie) => { const separatorIndex = cookie.indexOf('=') if (separatorIndex === -1) return cookie const cookieName = cookie.slice(0, separatorIndex).trim() const cookieValue = cookie.slice(separatorIndex + 1) return `${toUpstreamCookieName(cookieName)}=${cookieValue}` }) .join('; ') } const rewriteSetCookieValueForLocal = ( setCookieValue: string, options: LocalCookieRewriteOptions, ) => { const [rawCookiePair, ...rawAttributes] = setCookieValue.split(';') const separatorIndex = rawCookiePair.indexOf('=') if (separatorIndex === -1) return setCookieValue const cookieName = rawCookiePair.slice(0, separatorIndex).trim() const cookieValue = rawCookiePair.slice(separatorIndex + 1) const rewrittenAttributes = rawAttributes .map(attribute => attribute.trim()) .filter(attribute => !COOKIE_DOMAIN_PATTERN.test(attribute) && (options.localSecure || !COOKIE_SECURE_PATTERN.test(attribute)) && (options.localSecure || !COOKIE_PARTITIONED_PATTERN.test(attribute)), ) .map((attribute) => { if (!options.localSecure && SAME_SITE_NONE_PATTERN.test(attribute)) return 'SameSite=Lax' if (COOKIE_PATH_PATTERN.test(attribute)) return 'Path=/' return attribute }) return [`${toLocalCookieName(cookieName, options)}=${cookieValue}`, ...rewrittenAttributes].join('; ') } export const rewriteSetCookieHeadersForLocal = ( setCookieHeaders: string | string[] | undefined, options: LocalCookieRewriteOptions, ): string[] | undefined => { if (!setCookieHeaders) return undefined const normalizedHeaders = Array.isArray(setCookieHeaders) ? setCookieHeaders : [setCookieHeaders] return normalizedHeaders.map(setCookieValue => rewriteSetCookieValueForLocal(setCookieValue, options)) } export { DEFAULT_PROXY_TARGET }