feat: implement auth system, passkeys, and user management
Add PostgreSQL and Redis integration for users and sessions Implement password and WebAuthn passkey login flows Add Docker stack, super-admin seeding, and protected routes
This commit is contained in:
52
server/utils/password.ts
Normal file
52
server/utils/password.ts
Normal file
@@ -0,0 +1,52 @@
|
||||
import { randomBytes, scrypt as scryptCallback, timingSafeEqual } from 'node:crypto'
|
||||
import { promisify } from 'node:util'
|
||||
|
||||
import { decodeBase64Url, encodeBase64Url } from './base64url'
|
||||
|
||||
const scrypt = promisify(scryptCallback)
|
||||
const SCRYPT_COST = 16_384
|
||||
const SCRYPT_BLOCK_SIZE = 8
|
||||
const SCRYPT_PARALLELIZATION = 1
|
||||
const KEY_LENGTH = 64
|
||||
|
||||
export async function hashPassword(password: string): Promise<string> {
|
||||
const salt = encodeBase64Url(randomBytes(16))
|
||||
const derivedKey = await scrypt(password, salt, KEY_LENGTH, {
|
||||
N: SCRYPT_COST,
|
||||
r: SCRYPT_BLOCK_SIZE,
|
||||
p: SCRYPT_PARALLELIZATION
|
||||
}) as Buffer
|
||||
|
||||
return [
|
||||
'scrypt',
|
||||
SCRYPT_COST,
|
||||
SCRYPT_BLOCK_SIZE,
|
||||
SCRYPT_PARALLELIZATION,
|
||||
salt,
|
||||
encodeBase64Url(derivedKey)
|
||||
].join('$')
|
||||
}
|
||||
|
||||
export async function verifyPassword(password: string, storedHash: string): Promise<boolean> {
|
||||
const [algorithm, cost, blockSize, parallelization, salt, key] = storedHash.split('$')
|
||||
|
||||
if (
|
||||
algorithm !== 'scrypt'
|
||||
|| !cost
|
||||
|| !blockSize
|
||||
|| !parallelization
|
||||
|| !salt
|
||||
|| !key
|
||||
) {
|
||||
return false
|
||||
}
|
||||
|
||||
const expectedKey = decodeBase64Url(key)
|
||||
const derivedKey = await scrypt(password, salt, expectedKey.length, {
|
||||
N: Number(cost),
|
||||
r: Number(blockSize),
|
||||
p: Number(parallelization)
|
||||
}) as Buffer
|
||||
|
||||
return timingSafeEqual(expectedKey, derivedKey)
|
||||
}
|
||||
Reference in New Issue
Block a user