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.

65 lines
2.2 KiB

import {
createHash,
createHmac,
randomBytes,
scrypt as scryptCallback,
timingSafeEqual,
} from 'node:crypto';
import { promisify } from 'node:util';
import { avatarReference } from './avatar.mjs';
const scrypt = promisify(scryptCallback);
export const hashToken = (token) =>
createHash('sha256').update(token).digest('hex');
export const publicUser = (user) =>
user
? {
id: user.id,
name: user.name,
nick: user.nick,
createdAt: user.createdAt,
guest: Boolean(user.guest),
avatar: avatarReference(user),
}
: null;
export async function hashPassword(password) {
const salt = randomBytes(16).toString('hex');
const hash = await scrypt(password, salt, 64);
return `${salt}:${hash.toString('hex')}`;
}
export async function verifyPassword(password, encoded) {
const [salt, stored] = encoded.split(':');
const expected = Buffer.from(stored, 'hex');
const actual = await scrypt(password, salt, 64);
return expected.length === actual.length && timingSafeEqual(expected, actual);
}
export const hashPin = (pin, pepper) =>
hashPassword(createHmac('sha256', pepper).update(pin).digest('hex'));
export const verifyPin = (pin, encoded, pepper) =>
verifyPassword(
createHmac('sha256', pepper).update(pin).digest('hex'),
encoded,
);
export function cookieToken(header = '') {
const token = header
.split(';')
.map((v) => v.trim())
.find((v) => v.startsWith('mesa_session='))
?.slice(13);
return token && /^[a-f0-9]{64}$/.test(token) ? token : null;
}
export async function authenticate(store, token) {
if (!token) return null;
const session = await store.session(hashToken(token));
return session ? publicUser(await store.userById(session.userId)) : null;
}
export async function newSession(store, userId) {
const token = randomBytes(32).toString('hex');
const expiresAt = Date.now() + 30 * 24 * 60 * 60 * 1000;
await store.createSession({ hash: hashToken(token), userId, expiresAt });
return token;
}
export function sessionCookie(token, production) {
return `mesa_session=${token}; Path=/; HttpOnly; SameSite=Lax; Max-Age=${token ? 2592000 : 0}${production ? '; Secure' : ''}`;
}

Powered by TurnKey Linux.