UNPKG

@daitanjs/security

Version:

A lightweight library for token generation and verification.

218 lines (216 loc) 7.54 kB
var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/security/src/index.js var src_exports = {}; __export(src_exports, { decodeJWT: () => decodeJWT, generateAlphanumericOTP: () => generateAlphanumericOTP, generateJWT: () => generateJWT, generateNumericOTP: () => generateNumericOTP, verifyJWT: () => verifyJWT, verifyOTP: () => verifyOTP }); module.exports = __toCommonJS(src_exports); var import_crypto = __toESM(require("crypto"), 1); var import_jsonwebtoken = __toESM(require("jsonwebtoken"), 1); var import_uuid = require("uuid"); var import_development = require("@daitanjs/development"); var import_error = require("@daitanjs/error"); var logger = (0, import_development.getLogger)("daitan-security"); var DEFAULT_OTP_LENGTH = 6; var DEFAULT_OTP_VALIDITY_MS = 5 * 60 * 1e3; var generateNumericOTP = ({ length = DEFAULT_OTP_LENGTH, validityMs = DEFAULT_OTP_VALIDITY_MS } = {}) => { if (!Number.isInteger(length) || length <= 0 || length > 10) { throw new import_error.DaitanInvalidInputError( "OTP length must be a positive integer, typically between 4 and 10." ); } if (typeof validityMs !== "number" || validityMs <= 0) { throw new import_error.DaitanInvalidInputError( "OTP validityMs must be a positive number." ); } let otp = ""; for (let i = 0; i < length; i++) { otp += import_crypto.default.randomInt(0, 10).toString(); } const expiresAt = Date.now() + validityMs; logger.debug( `Generated numeric OTP (length ${length}), expires at ${new Date( expiresAt ).toISOString()}` ); return { otp, expiresAt }; }; var generateAlphanumericOTP = ({ length = 8, validityMs = DEFAULT_OTP_VALIDITY_MS } = {}) => { if (!Number.isInteger(length) || length <= 0 || length > 32) { throw new import_error.DaitanInvalidInputError( "Alphanumeric OTP length must be a positive integer, typically between 6 and 32." ); } if (typeof validityMs !== "number" || validityMs <= 0) { throw new import_error.DaitanInvalidInputError( "OTP validityMs must be a positive number." ); } const characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; let otp = ""; const randomBytes = import_crypto.default.randomBytes(length); for (let i = 0; i < length; i++) { otp += characters[randomBytes[i] % characters.length]; } const expiresAt = Date.now() + validityMs; logger.debug( `Generated alphanumeric OTP (length ${length}), expires at ${new Date( expiresAt ).toISOString()}` ); return { otp, expiresAt }; }; var verifyOTP = ({ submittedOTP, storedOTP, storedOTPExpiresAt }) => { if (typeof submittedOTP !== "string" || !submittedOTP || typeof storedOTP !== "string" || !storedOTP || typeof storedOTPExpiresAt !== "number") { logger.warn("verifyOTP: Invalid parameters received for OTP verification."); return false; } if (Date.now() > storedOTPExpiresAt) { logger.debug("OTP verification failed: OTP has expired."); return false; } const isValid = import_crypto.default.timingSafeEqual( Buffer.from(submittedOTP), Buffer.from(storedOTP) ); if (!isValid) { logger.debug( "OTP verification failed: Submitted OTP does not match stored OTP." ); } else { logger.debug("OTP verification successful."); } return isValid; }; var DEFAULT_JWT_EXPIRY = "1h"; var generateJWT = ({ payload, secretOrPrivateKey, options = {} }) => { if (!payload || typeof payload !== "object" || Array.isArray(payload)) { throw new import_error.DaitanInvalidInputError( "JWT payload must be a non-null plain object." ); } if (!secretOrPrivateKey) { throw new import_error.DaitanInvalidInputError( "JWT secret or private key is required for signing." ); } const jwtOptions = { expiresIn: DEFAULT_JWT_EXPIRY, jwtid: (0, import_uuid.v4)(), // JWT ID (jti) claim, useful for revocation or tracking ...options // User-provided options override defaults }; try { const token = import_jsonwebtoken.default.sign(payload, secretOrPrivateKey, jwtOptions); logger.debug( `Generated JWT with JTI: ${jwtOptions.jwtid}, expires: ${jwtOptions.expiresIn}.` ); return token; } catch (error) { logger.error(`Error generating JWT: ${error.message}`, { errorName: error.name }); throw new import_error.DaitanOperationError( `JWT signing failed: ${error.message}`, {}, error ); } }; var verifyJWT = ({ token, secretOrPublicKey, options = {} }) => { if (!token || typeof token !== "string") { throw new import_error.DaitanInvalidInputError( "JWT token string is required for verification." ); } if (!secretOrPublicKey) { throw new import_error.DaitanInvalidInputError( "JWT secret or public key is required for verification." ); } try { const decoded = import_jsonwebtoken.default.verify(token, secretOrPublicKey, options); logger.debug("JWT verified successfully.", { jti: decoded.jti, sub: decoded.sub }); return decoded; } catch (error) { logger.warn(`JWT verification failed: ${error.message}`, { errorName: error.name, tokenPreview: token.substring(0, 20) + "..." }); throw error; } }; var decodeJWT = ({ token, options = {} }) => { if (!token || typeof token !== "string") { logger.warn("decodeJWT: Invalid or missing token string provided."); return null; } try { const decoded = import_jsonwebtoken.default.decode(token, options); if (decoded === null) { logger.warn("decodeJWT: Token was malformed and could not be decoded.", { tokenPreview: token.substring(0, 20) + "..." }); } else { logger.debug("JWT decoded (signature NOT VERIFIED)."); } return decoded; } catch (error) { logger.error(`Error during JWT decode (unexpected): ${error.message}`, { errorName: error.name }); return null; } }; // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { decodeJWT, generateAlphanumericOTP, generateJWT, generateNumericOTP, verifyJWT, verifyOTP }); //# sourceMappingURL=index.cjs.map