You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

48 lines
1.7 KiB

import { createHmac, timingSafeEqual } from 'node:crypto';
import { terms } from '../shared/terms.mjs';
export const TERMS_COOKIE = 'juegoland_terms';
export const TERMS_MAX_AGE = 365 * 24 * 60 * 60;
const signature = (payload, secret) =>
createHmac('sha256', secret)
.update(`juegoland-terms:${payload}`)
.digest('hex');
export function termsCookie(secret, production, now = Date.now()) {
const payload = `${terms.version}.${Math.floor(now / 1000)}`;
return `${TERMS_COOKIE}=${payload}.${signature(payload, secret)}; Path=/; HttpOnly; SameSite=Lax; Max-Age=${TERMS_MAX_AGE}${production ? '; Secure' : ''}`;
}
export function clearTermsCookie(production) {
return `${TERMS_COOKIE}=; Path=/; HttpOnly; SameSite=Lax; Max-Age=0${production ? '; Secure' : ''}`;
}
export function termsAcceptance(header = '', secret, now = Date.now()) {
const rejected = {
accepted: false,
version: terms.version,
acceptedAt: null,
expiresAt: null,
};
const value = header
.split(';')
.map((part) => part.trim())
.find((part) => part.startsWith(`${TERMS_COOKIE}=`))
?.slice(TERMS_COOKIE.length + 1);
const match = value?.match(
/^(\d{4}-\d{2}-\d{2}\.\d+)\.(\d{10})\.([a-f0-9]{64})$/,
);
if (!match || match[1] !== terms.version) return rejected;
const issuedAt = Number(match[2]) * 1000;
if (issuedAt > now || now >= issuedAt + TERMS_MAX_AGE * 1000) return rejected;
const expected = Buffer.from(
signature(`${match[1]}.${match[2]}`, secret),
'hex',
);
if (!timingSafeEqual(expected, Buffer.from(match[3], 'hex'))) return rejected;
return {
accepted: true,
version: terms.version,
acceptedAt: new Date(issuedAt).toISOString(),
expiresAt: new Date(issuedAt + TERMS_MAX_AGE * 1000).toISOString(),
};
}

Powered by TurnKey Linux.