UNPKG

totpify

Version:

Advanced TOTP Library with enhanced security features and algorithm support

140 lines 5.33 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.generateTOTP = generateTOTP; exports.verifyTOTP = verifyTOTP; exports.generateQRCode = generateQRCode; exports.generateRandomSecret = generateRandomSecret; const utils_1 = require("./utils"); const QRCode = __importStar(require("qrcode")); /** * Generates a Time-Based One-Time Password (TOTP) according to RFC 623 * @param secret The secret key as a string (Base32 encoded) or a Uint8Array * @param options Options for TOTP generation * @returns The generated TOTP code */ function generateTOTP(secret, options = {}) { const { algorithm = 'SHA-1', digits = 6, period = 30, timestamp = Date.now() } = options; if (!secret) { throw new Error('Secret must be provided'); } let secretBytes; if (typeof secret === 'string') { try { secretBytes = (0, utils_1.decodeBase32)(secret); } catch (error) { throw new Error(`Invalid secret: ${error.message}`); } } else { secretBytes = secret; } const counter = Math.floor(timestamp / 1000 / period); return (0, utils_1.generateHOTP)(secretBytes, counter, algorithm, digits); } /** * Verifies a Time-Based One-Time Password (TOTP) allowing for time skew * @param token The TOTP code to verify * @param secret The secret key as a string (Base32 encoded) or a Uint8Array * @param options Options for TOTP verification * @returns Result object with valid flag and time drift information */ function verifyTOTP(token, secret, options = {}) { const { window = 1, algorithm = 'SHA-1', digits = 6, period = 30, timestamp = Date.now() } = options; if (!token || token.length !== digits || !/^\d+$/.test(token)) { return { valid: false }; } for (let i = -window; i <= window; i++) { const checkTime = timestamp + i * period * 1000; const generatedToken = generateTOTP(secret, { algorithm, digits, period, timestamp: checkTime, }); if (generatedToken === token) { return { valid: true, delta: i }; } } return { valid: false }; } /** * Generates a QR code for easy TOTP setup with authenticator apps. * The QR code follows the 'otpauth://' URI format. * @param secret The secret key (Base32 encoded) * @param options Options for QR code generation * @returns Promise resolving to a data URL containing the QR code */ async function generateQRCode(secret, options = {}) { const { issuer = 'Totpify', account = 'user', width = 256, height = 256, } = options; const normalizedSecret = (0, utils_1.normalizeSecret)(secret); const encodedIssuer = encodeURIComponent(issuer); const encodedAccount = encodeURIComponent(account); const uri = `otpauth://totp/${encodedIssuer}:${encodedAccount}?secret=${normalizedSecret}&issuer=${encodedIssuer}`; try { return await QRCode.toDataURL(uri, { errorCorrectionLevel: 'H', type: 'image/png', margin: 1, width }); } catch (error) { throw new Error(`QR code generation failed: ${error.message}`); } } /** * Generates a random secret key in Base32 format for use with TOTP * @param length The length of the secret key in bytes (default: 20) * @returns Base32 encoded random secret */ function generateRandomSecret(length = 20) { const randomBytes = new Uint8Array(length); if (typeof window !== 'undefined' && window.crypto) { window.crypto.getRandomValues(randomBytes); } else { const crypto = require('crypto'); randomBytes.set(crypto.randomBytes(length)); } const base32Chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567'; let result = ''; for (let i = 0; i < length; i++) { result += base32Chars[randomBytes[i] % base32Chars.length]; } return result; } //# sourceMappingURL=totp.js.map