Add password login, set-password, business images migration, and user serialization.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,35 @@
|
||||
import { randomBytes, scrypt, timingSafeEqual } from 'crypto';
|
||||
import { promisify } from 'util';
|
||||
|
||||
const scryptAsync = promisify(scrypt);
|
||||
const KEY_LENGTH = 64;
|
||||
|
||||
export async function hashPassword(password: string): Promise<string> {
|
||||
const salt = randomBytes(16).toString('hex');
|
||||
const derived = (await scryptAsync(password, salt, KEY_LENGTH)) as Buffer;
|
||||
return `scrypt:${salt}:${derived.toString('hex')}`;
|
||||
}
|
||||
|
||||
export async function verifyPassword(
|
||||
password: string,
|
||||
stored: string,
|
||||
): Promise<boolean> {
|
||||
const parts = stored.split(':');
|
||||
if (parts.length !== 3 || parts[0] !== 'scrypt') {
|
||||
return false;
|
||||
}
|
||||
const [, salt, hashHex] = parts;
|
||||
if (!salt || !hashHex) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
const derived = (await scryptAsync(password, salt, KEY_LENGTH)) as Buffer;
|
||||
const expected = Buffer.from(hashHex, 'hex');
|
||||
if (derived.length !== expected.length) {
|
||||
return false;
|
||||
}
|
||||
return timingSafeEqual(derived, expected);
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user