Add private operations portal and weekly accounting reports
This commit is contained in:
@@ -0,0 +1,19 @@
|
||||
import { randomBytes, scryptSync, timingSafeEqual } from 'node:crypto';
|
||||
|
||||
export function hashPassword(password) {
|
||||
if (password.length < 16 || password.length > 1024) throw new Error('Password must contain 16–1024 characters');
|
||||
const salt = randomBytes(16).toString('base64url');
|
||||
const key = scryptSync(password, salt, 64, { N: 16384, r: 8, p: 1 }).toString('base64url');
|
||||
return `scrypt$16384$8$1$${salt}$${key}`;
|
||||
}
|
||||
|
||||
export function validatePasswordHash(value) {
|
||||
if (!/^scrypt\$16384\$8\$1\$[A-Za-z0-9_-]{22}\$[A-Za-z0-9_-]{86}$/.test(value || '')) throw new Error('PASSWORD_HASH must be generated by scripts/hash-password.mjs');
|
||||
}
|
||||
|
||||
export function verifyPassword(password, hash) {
|
||||
if (typeof password !== 'string' || password.length > 1024) return false;
|
||||
validatePasswordHash(hash);
|
||||
const [, , , , salt, expected] = hash.split('$');
|
||||
return timingSafeEqual(scryptSync(password, salt, 64, { N: 16384, r: 8, p: 1 }), Buffer.from(expected, 'base64url'));
|
||||
}
|
||||
Reference in New Issue
Block a user