chore: improve cookie helper functions (#5866)

This commit is contained in:
Jarrod Flesch
2024-04-15 22:11:17 -04:00
committed by GitHub
parent 8178d57ab9
commit 3db0557b07
2 changed files with 91 additions and 32 deletions

23
.vscode/launch.json vendored
View File

@@ -41,6 +41,13 @@
"request": "launch",
"type": "node-terminal"
},
{
"command": "node --no-deprecation test/dev.js auth",
"cwd": "${workspaceFolder}",
"name": "Run Dev Auth",
"request": "launch",
"type": "node-terminal"
},
{
"command": "pnpm run dev plugin-cloud-storage",
"cwd": "${workspaceFolder}",
@@ -69,36 +76,26 @@
}
},
{
"command": "pnpm run dev versions",
"command": "node --no-deprecation test/dev.js versions",
"cwd": "${workspaceFolder}",
"name": "Run Dev Versions",
"request": "launch",
"type": "node-terminal"
},
{
"command": "pnpm run dev localization",
"command": "node --no-deprecation test/dev.js localization",
"cwd": "${workspaceFolder}",
"name": "Run Dev Localization",
"request": "launch",
"type": "node-terminal"
},
{
"command": "pnpm run dev uploads",
"command": "node --no-deprecation test/dev.js uploads",
"cwd": "${workspaceFolder}",
"name": "Run Dev Uploads",
"request": "launch",
"type": "node-terminal"
},
{
"command": "PAYLOAD_BUNDLER=vite pnpm run dev fields",
"cwd": "${workspaceFolder}",
"name": "Run Dev Fields (Vite)",
"request": "launch",
"type": "node-terminal",
"env": {
"NODE_ENV": "production"
}
},
{
"command": "pnpm run test:int live-preview",
"cwd": "${workspaceFolder}",

View File

@@ -1,5 +1,6 @@
import type { Payload } from '../index.js'
import type { SanitizedCollectionConfig } from './../collections/config/types.js'
type CookieOptions = {
domain?: string
expires?: Date
@@ -7,53 +8,108 @@ type CookieOptions = {
maxAge?: number
name: string
path?: string
returnCookieAsObject: boolean
sameSite?: 'Lax' | 'None' | 'Strict'
secure?: boolean
value?: string
}
export const generateCookies = (cookies: CookieOptions[]): string => {
return cookies.map((options) => generateCookie(options)).join('; ')
type CookieObject = {
domain?: string
expires?: string
httpOnly?: boolean
maxAge?: number
name: string
path?: string
sameSite?: 'Lax' | 'None' | 'Strict'
secure?: boolean
value: string
}
export const generateCookie = (args: CookieOptions): string => {
const { name, domain, expires, httpOnly, maxAge, path, sameSite, secure: secureArg, value } = args
export const generateCookie = <ReturnCookieAsObject = boolean>(
args: CookieOptions,
): ReturnCookieAsObject extends true ? CookieObject : string => {
const {
name,
domain,
expires,
httpOnly,
maxAge,
path,
returnCookieAsObject,
sameSite,
secure: secureArg,
value,
} = args
let cookieString = `${name}=${value || ''}`
const cookieObject: CookieObject = {
name,
value,
}
const secure = secureArg || sameSite === 'None'
if (expires) {
cookieString += `; Expires=${expires.toUTCString()}`
if (returnCookieAsObject) {
cookieObject.expires = expires.toUTCString()
} else {
cookieString += `; Expires=${expires.toUTCString()}`
}
}
if (maxAge) {
cookieString += `; Max-Age=${maxAge}`
if (returnCookieAsObject) {
cookieObject.maxAge = maxAge
} else {
cookieString += `; Max-Age=${maxAge.toString()}`
}
}
if (domain) {
cookieString += `; Domain=${domain}`
if (returnCookieAsObject) {
cookieObject.domain = domain
} else {
cookieString += `; Domain=${domain}`
}
}
if (path) {
cookieString += `; Path=${path}`
if (returnCookieAsObject) {
cookieObject.path = path
} else {
cookieString += `; Path=${path}`
}
}
if (secure) {
cookieString += '; Secure'
if (returnCookieAsObject) {
cookieObject.secure = secure
} else {
cookieString += `; Secure=${secure}`
}
}
if (httpOnly) {
cookieString += '; HttpOnly'
if (returnCookieAsObject) {
cookieObject.httpOnly = httpOnly
} else {
cookieString += `; HttpOnly=${httpOnly}`
}
}
if (sameSite) {
cookieString += `; SameSite=${sameSite}`
if (returnCookieAsObject) {
cookieObject.sameSite = sameSite
} else {
cookieString += `; SameSite=${sameSite}`
}
}
return cookieString
return (returnCookieAsObject ? cookieObject : cookieString) as ReturnCookieAsObject extends true
? CookieObject
: string
}
type GetCookieExpirationArgs = {
/*
The number of seconds until the cookie expires
@@ -72,14 +128,17 @@ type GeneratePayloadCookieArgs = {
collectionConfig: SanitizedCollectionConfig
/* An instance of payload */
payload: Payload
/* The returnAs value */
returnCookieAsObject?: boolean
/* The token to be stored in the cookie */
token: string
}
export const generatePayloadCookie = ({
export const generatePayloadCookie = <T extends GeneratePayloadCookieArgs>({
collectionConfig,
payload,
returnCookieAsObject = false,
token,
}: GeneratePayloadCookieArgs): string => {
}: T): T['returnCookieAsObject'] extends true ? CookieObject : string => {
const sameSite =
typeof collectionConfig.auth.cookies.sameSite === 'string'
? collectionConfig.auth.cookies.sameSite
@@ -87,22 +146,24 @@ export const generatePayloadCookie = ({
? 'Strict'
: undefined
return generateCookie({
return generateCookie<T['returnCookieAsObject']>({
name: `${payload.config.cookiePrefix}-token`,
domain: collectionConfig.auth.cookies.domain ?? undefined,
expires: getCookieExpiration({ seconds: collectionConfig.auth.tokenExpiration }),
httpOnly: true,
path: '/',
returnCookieAsObject,
sameSite,
secure: collectionConfig.auth.cookies.secure,
value: token,
})
}
export const generateExpiredPayloadCookie = ({
export const generateExpiredPayloadCookie = <T extends Omit<GeneratePayloadCookieArgs, 'token'>>({
collectionConfig,
payload,
}: Omit<GeneratePayloadCookieArgs, 'token'>): string => {
returnCookieAsObject = false,
}: T): T['returnCookieAsObject'] extends true ? CookieObject : string => {
const sameSite =
typeof collectionConfig.auth.cookies.sameSite === 'string'
? collectionConfig.auth.cookies.sameSite
@@ -112,12 +173,13 @@ export const generateExpiredPayloadCookie = ({
const expires = new Date(Date.now() - 1000)
return generateCookie({
return generateCookie<T['returnCookieAsObject']>({
name: `${payload.config.cookiePrefix}-token`,
domain: collectionConfig.auth.cookies.domain ?? undefined,
expires,
httpOnly: true,
path: '/',
returnCookieAsObject,
sameSite,
secure: collectionConfig.auth.cookies.secure,
})