File size: 1,083 Bytes
9ccc46a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import { timingSafeEqual, randomBytes, scryptSync } from 'node:crypto';

const PREFIX = 'scrypt';
const KEY_LENGTH = 64;

function hashWithSalt(password: string, salt: string): string {
  return scryptSync(password, salt, KEY_LENGTH).toString('base64');
}

export function isPasswordHash(value: string): boolean {
  return value.startsWith(`${PREFIX}$`);
}

export function hashPassword(password: string): string {
  const salt = randomBytes(16).toString('base64');
  const hash = hashWithSalt(password, salt);
  return `${PREFIX}$${salt}$${hash}`;
}

export function verifyPassword(password: string, stored: string): boolean {
  if (!stored) return true;
  if (!isPasswordHash(stored)) return password === stored;

  const [, salt, expected] = stored.split('$');
  if (!salt || !expected) return false;

  const actual = hashWithSalt(password, salt);
  const expectedBytes = Buffer.from(expected, 'base64');
  const actualBytes = Buffer.from(actual, 'base64');
  if (expectedBytes.length !== actualBytes.length) return false;
  return timingSafeEqual(expectedBytes, actualBytes);
}