first commit
This commit is contained in:
41
server/utils/password.ts
Normal file
41
server/utils/password.ts
Normal file
@@ -0,0 +1,41 @@
|
||||
import { randomBytes, scryptSync, timingSafeEqual } from 'node:crypto'
|
||||
|
||||
const PASSWORD_HASH_PREFIX = 'scrypt'
|
||||
const DERIVED_KEY_LENGTH = 64
|
||||
|
||||
/**
|
||||
* Gera hash de senha com scrypt e salt aleatório.
|
||||
*
|
||||
* @param password Senha em texto puro.
|
||||
* @returns Hash no formato `scrypt$salt$hash`.
|
||||
*/
|
||||
export function hashPassword(password: string): string {
|
||||
const salt = randomBytes(16).toString('base64url')
|
||||
const derivedKey = scryptSync(password, salt, DERIVED_KEY_LENGTH).toString('base64url')
|
||||
|
||||
return `${PASSWORD_HASH_PREFIX}$${salt}$${derivedKey}`
|
||||
}
|
||||
|
||||
/**
|
||||
* Compara senha em texto puro com hash salvo no banco.
|
||||
*
|
||||
* @param password Senha informada no login.
|
||||
* @param encodedHash Hash armazenado no banco.
|
||||
* @returns `true` quando a senha confere; caso contrário, `false`.
|
||||
*/
|
||||
export function verifyPassword(password: string, encodedHash: string): boolean {
|
||||
const [prefix, salt, storedHash] = encodedHash.split('$')
|
||||
|
||||
if (prefix !== PASSWORD_HASH_PREFIX || !salt || !storedHash) {
|
||||
return false
|
||||
}
|
||||
|
||||
const derivedKey = scryptSync(password, salt, DERIVED_KEY_LENGTH)
|
||||
const storedKeyBuffer = Buffer.from(storedHash, 'base64url')
|
||||
|
||||
if (derivedKey.length !== storedKeyBuffer.length) {
|
||||
return false
|
||||
}
|
||||
|
||||
return timingSafeEqual(derivedKey, storedKeyBuffer)
|
||||
}
|
||||
Reference in New Issue
Block a user