Files
dify/web/plugins/dev-proxy/cookies.ts
2026-03-13 12:52:19 +08:00

99 lines
3.0 KiB
TypeScript

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) => cookieName.replace(SECURE_COOKIE_PREFIX_PATTERN, '')
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) => {
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)
&& !COOKIE_SECURE_PATTERN.test(attribute)
&& !COOKIE_PARTITIONED_PATTERN.test(attribute),
)
.map((attribute) => {
if (SAME_SITE_NONE_PATTERN.test(attribute))
return 'SameSite=Lax'
if (COOKIE_PATH_PATTERN.test(attribute))
return 'Path=/'
return attribute
})
return [`${toLocalCookieName(cookieName)}=${cookieValue}`, ...rewrittenAttributes].join('; ')
}
export const rewriteSetCookieHeadersForLocal = (setCookieHeaders?: string | string[]): string[] | undefined => {
if (!setCookieHeaders)
return undefined
const normalizedHeaders = Array.isArray(setCookieHeaders)
? setCookieHeaders
: [setCookieHeaders]
return normalizedHeaders.map(rewriteSetCookieValueForLocal)
}
export { DEFAULT_PROXY_TARGET }