36 lines
1.1 KiB
TypeScript
36 lines
1.1 KiB
TypeScript
import blake2b from 'blakejs';
|
|
|
|
const BACKEND_SECRET = process.env.BACKEND_SECRET || 'changeme_secret_key_for_production';
|
|
|
|
/**
|
|
* Hash a token with Blake2b-256 (2 iterations).
|
|
* This must match the Spring/Rust implementation exactly:
|
|
* - Uses Blake2b-256 (32 bytes output)
|
|
* - 2 iterations of hashing
|
|
* - Combines token + secret + salt (group name)
|
|
* - Returns hex-encoded hash (64 characters)
|
|
*/
|
|
export function hashToken(token: string, salt: string): string {
|
|
// First iteration: hash(token + secret + salt)
|
|
const input1 = token + BACKEND_SECRET + salt;
|
|
const hash1 = blake2b.blake2b(input1, undefined, 32);
|
|
|
|
// Second iteration: hash(hash1)
|
|
const hash2 = blake2b.blake2b(hash1, undefined, 32);
|
|
|
|
// Return hex-encoded (lowercase)
|
|
return Buffer.from(hash2).toString('hex').toLowerCase();
|
|
}
|
|
|
|
/**
|
|
* Verify if a token matches the stored hash.
|
|
*/
|
|
export function verifyToken(token: string, salt: string, storedHash: string): boolean {
|
|
try {
|
|
const computedHash = hashToken(token, salt);
|
|
return computedHash === storedHash.toLowerCase();
|
|
} catch {
|
|
return false;
|
|
}
|
|
}
|