mirror of
https://github.com/KeygraphHQ/shannon.git
synced 2026-07-11 15:26:39 +02:00
72 lines
1.7 KiB
JavaScript
72 lines
1.7 KiB
JavaScript
/**
|
|
* TOTP Validator
|
|
*
|
|
* Validates TOTP secrets and provides base32 decoding.
|
|
* Ported from tools/generate-totp-standalone.mjs (lines 43-72).
|
|
*/
|
|
|
|
/**
|
|
* Base32 decode function
|
|
* Ported from generate-totp-standalone.mjs
|
|
*
|
|
* @param {string} encoded - Base32 encoded string
|
|
* @returns {Buffer} Buffer containing decoded bytes
|
|
*/
|
|
export function base32Decode(encoded) {
|
|
const alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567';
|
|
const cleanInput = encoded.toUpperCase().replace(/[^A-Z2-7]/g, '');
|
|
|
|
if (cleanInput.length === 0) {
|
|
return Buffer.alloc(0);
|
|
}
|
|
|
|
const output = [];
|
|
let bits = 0;
|
|
let value = 0;
|
|
|
|
for (const char of cleanInput) {
|
|
const index = alphabet.indexOf(char);
|
|
if (index === -1) {
|
|
throw new Error(`Invalid base32 character: ${char}`);
|
|
}
|
|
|
|
value = (value << 5) | index;
|
|
bits += 5;
|
|
|
|
if (bits >= 8) {
|
|
output.push((value >>> (bits - 8)) & 255);
|
|
bits -= 8;
|
|
}
|
|
}
|
|
|
|
return Buffer.from(output);
|
|
}
|
|
|
|
/**
|
|
* Validate TOTP secret
|
|
* Must be base32-encoded string
|
|
*
|
|
* @param {string} secret - Secret to validate
|
|
* @returns {boolean} true if valid, throws Error if invalid
|
|
*/
|
|
export function validateTotpSecret(secret) {
|
|
if (!secret || secret.length === 0) {
|
|
throw new Error('TOTP secret cannot be empty');
|
|
}
|
|
|
|
// Check if it's valid base32 (only A-Z and 2-7, case-insensitive)
|
|
const base32Regex = /^[A-Z2-7]+$/i;
|
|
if (!base32Regex.test(secret.replace(/[^A-Z2-7]/gi, ''))) {
|
|
throw new Error('TOTP secret must be base32-encoded (characters A-Z and 2-7)');
|
|
}
|
|
|
|
// Try to decode to ensure it's valid
|
|
try {
|
|
base32Decode(secret);
|
|
} catch (error) {
|
|
throw new Error(`Invalid TOTP secret: ${error instanceof Error ? error.message : String(error)}`);
|
|
}
|
|
|
|
return true;
|
|
}
|