append timestamp to cookie name to prevent redirect loops

This commit is contained in:
miloschwartz 2025-03-21 21:38:06 -04:00
parent f37be774a6
commit f2a14e6a36
No known key found for this signature in database
2 changed files with 58 additions and 15 deletions

View file

@ -170,16 +170,17 @@ export function serializeResourceSessionCookie(
isHttp: boolean = false, isHttp: boolean = false,
expiresAt?: Date expiresAt?: Date
): string { ): string {
const now = new Date().getTime();
if (!isHttp) { if (!isHttp) {
if (expiresAt === undefined) { if (expiresAt === undefined) {
return `${cookieName}_s=${token}; HttpOnly; SameSite=Lax; Path=/; Secure; Domain=${"." + domain}`; return `${cookieName}_s.${now}=${token}; HttpOnly; SameSite=Lax; Path=/; Secure; Domain=${"." + domain}`;
} }
return `${cookieName}_s=${token}; HttpOnly; SameSite=Lax; Expires=${expiresAt.toUTCString()}; Path=/; Secure; Domain=${"." + domain}`; return `${cookieName}_s.${now}=${token}; HttpOnly; SameSite=Lax; Expires=${expiresAt.toUTCString()}; Path=/; Secure; Domain=${"." + domain}`;
} else { } else {
if (expiresAt === undefined) { if (expiresAt === undefined) {
return `${cookieName}=${token}; HttpOnly; SameSite=Lax; Path=/; Domain=${"." + domain}`; return `${cookieName}.${now}=${token}; HttpOnly; SameSite=Lax; Path=/; Domain=${"." + domain}`;
} }
return `${cookieName}=${token}; HttpOnly; SameSite=Lax; Expires=${expiresAt.toUTCString()}; Path=/; Domain=${"." + domain}`; return `${cookieName}.${now}=${token}; HttpOnly; SameSite=Lax; Expires=${expiresAt.toUTCString()}; Path=/; Domain=${"." + domain}`;
} }
} }

View file

@ -229,12 +229,10 @@ export async function verifyResourceSession(
return notAllowed(res); return notAllowed(res);
} }
const resourceSessionToken = const resourceSessionToken = extractResourceSessionToken(
sessions[ sessions,
`${config.getRawConfig().server.session_cookie_name}${ resource.ssl
resource.ssl ? "_s" : "" );
}`
];
if (resourceSessionToken) { if (resourceSessionToken) {
const sessionCacheKey = `session:${resourceSessionToken}`; const sessionCacheKey = `session:${resourceSessionToken}`;
@ -354,6 +352,50 @@ export async function verifyResourceSession(
} }
} }
function extractResourceSessionToken(
sessions: Record<string, string>,
ssl: boolean
) {
const prefix = `${config.getRawConfig().server.session_cookie_name}${
ssl ? "_s" : ""
}`;
const all: { cookieName: string; token: string; priority: number }[] =
[];
for (const [key, value] of Object.entries(sessions)) {
const parts = key.split(".");
const timestamp = parts[parts.length - 1];
// check if string is only numbers
if (!/^\d+$/.test(timestamp)) {
continue;
}
// cookie name is the key without the timestamp
const cookieName = key.slice(0, -timestamp.length - 1);
if (cookieName === prefix) {
all.push({
cookieName,
token: value,
priority: parseInt(timestamp)
});
}
}
// sort by priority in desc order
all.sort((a, b) => b.priority - a.priority);
const latest = all[0];
if (!latest) {
return;
}
return latest.token;
}
function notAllowed(res: Response, redirectUrl?: string) { function notAllowed(res: Response, redirectUrl?: string) {
const data = { const data = {
data: { valid: false, redirectUrl }, data: { valid: false, redirectUrl },