36 lines
1.2 KiB
TypeScript
36 lines
1.2 KiB
TypeScript
import { createHash, timingSafeEqual } from 'node:crypto'
|
|
import { verifyPassword } from './password.js'
|
|
|
|
const PREFIX = 'sha256:'
|
|
|
|
/**
|
|
* Секреты OIDC-клиентов — 32 случайных байта (высокая энтропия), поэтому
|
|
* медленный argon2 не нужен: SHA-256 + сравнение за постоянное время.
|
|
*/
|
|
export function hashClientSecret(secret: string): string {
|
|
return PREFIX + createHash('sha256').update(secret).digest('hex')
|
|
}
|
|
|
|
export type ClientSecretCheck = { ok: boolean; needsRehash: boolean }
|
|
|
|
export async function checkClientSecret(
|
|
stored: string,
|
|
secret: string,
|
|
): Promise<ClientSecretCheck> {
|
|
if (stored.startsWith(PREFIX)) {
|
|
const a = Buffer.from(stored)
|
|
const b = Buffer.from(hashClientSecret(secret))
|
|
return {
|
|
ok: a.length === b.length && timingSafeEqual(a, b),
|
|
needsRehash: false,
|
|
}
|
|
}
|
|
// Устаревший формат (argon2): проверяем и просим перехешировать при успехе.
|
|
try {
|
|
const ok = await verifyPassword(stored, secret)
|
|
return { ok, needsRehash: ok }
|
|
} catch {
|
|
return { ok: false, needsRehash: false }
|
|
}
|
|
}
|