mirror of
https://github.com/whyour/qinglong.git
synced 2026-09-15 19:57:07 +08:00
fix: harden authentication and file access security
This commit is contained in:
@@ -0,0 +1,30 @@
|
||||
import { randomBytes, scrypt, timingSafeEqual } from 'crypto';
|
||||
import { promisify } from 'util';
|
||||
|
||||
const deriveKey = promisify(scrypt);
|
||||
const HASH_PREFIX = 'scrypt$';
|
||||
|
||||
export async function hashPassword(password: string): Promise<string> {
|
||||
const salt = randomBytes(16).toString('hex');
|
||||
const key = (await deriveKey(password, salt, 64)) as Buffer;
|
||||
return `${HASH_PREFIX}${salt}$${key.toString('hex')}`;
|
||||
}
|
||||
|
||||
export function isPasswordHash(password: string): boolean {
|
||||
return /^scrypt\$[a-f0-9]{32}\$[a-f0-9]{128}$/.test(password);
|
||||
}
|
||||
|
||||
export async function verifyPassword(
|
||||
password: string,
|
||||
stored: string,
|
||||
): Promise<boolean> {
|
||||
if (!isPasswordHash(stored)) {
|
||||
// Existing installations migrate after a successful password check.
|
||||
const input = Buffer.from(password);
|
||||
const expected = Buffer.from(stored);
|
||||
return input.length === expected.length && timingSafeEqual(input, expected);
|
||||
}
|
||||
const [, salt, hash] = stored.split('$');
|
||||
const key = (await deriveKey(password, salt, 64)) as Buffer;
|
||||
return timingSafeEqual(key, Buffer.from(hash, 'hex'));
|
||||
}
|
||||
Reference in New Issue
Block a user