{
  "version": 3,
  "sources": ["../src/index.js"],
  "sourcesContent": ["// security/src/index.js\n/**\n * @file Security utilities including OTP and JWT generation/verification.\n * @module @daitanjs/security\n *\n * @description\n * This library provides lightweight, focused security utilities for common tasks:\n * - **OTP (One-Time Password) Generation**: Create numeric or alphanumeric OTPs\n *   with configurable length and validity.\n * - **OTP Verification**: A conceptual helper for verifying submitted OTPs against stored ones.\n *   (Actual storage and retrieval of OTPs are handled by the consuming application).\n * - **JWT (JSON Web Token) Operations**: Generate, verify, and decode JWTs using\n *   the `jsonwebtoken` library. Includes default expiry and automatic `jti` (JWT ID) generation.\n *\n * All cryptographic operations rely on Node.js `crypto` module or the `jsonwebtoken` library.\n */\n\nimport crypto from 'crypto';\nimport jwt from 'jsonwebtoken';\nimport { v4 as uuidv4 } from 'uuid'; // For generating JWT IDs (jti)\nimport { getLogger } from '@daitanjs/development'; // For internal logging, if needed\nimport { DaitanInvalidInputError, DaitanOperationError } from '@daitanjs/error'; // For specific errors\n\nconst logger = getLogger('daitan-security'); // Logger for this module\n\n// --- OTP (One-Time Password) Functionality ---\n\nconst DEFAULT_OTP_LENGTH = 6;\nconst DEFAULT_OTP_VALIDITY_MS = 5 * 60 * 1000; // 5 minutes\n\n/**\n * @typedef {Object} OTPGenerationResult\n * @property {string} otp - The generated One-Time Password.\n * @property {number} expiresAt - Timestamp (in milliseconds since epoch) when the OTP expires.\n */\n\n/**\n * @typedef {Object} GenerateOTPOptions\n * @property {number} [length] - The desired length of the OTP.\n * @property {number} [validityMs] - The validity period of the OTP in milliseconds.\n */\n\n/**\n * Generates a cryptographically secure numeric One-Time Password (OTP).\n *\n * @public\n * @param {GenerateOTPOptions} [options={}] - Options for OTP generation.\n * @returns {OTPGenerationResult} An object containing the OTP string and its expiry timestamp.\n * @throws {DaitanInvalidInputError} If `length` is not a positive integer or `validityMs` is not a positive number.\n */\nexport const generateNumericOTP = ({\n  length = DEFAULT_OTP_LENGTH,\n  validityMs = DEFAULT_OTP_VALIDITY_MS,\n} = {}) => {\n  if (!Number.isInteger(length) || length <= 0 || length > 10) {\n    // Max length 10 for practical numeric OTPs\n    throw new DaitanInvalidInputError(\n      'OTP length must be a positive integer, typically between 4 and 10.'\n    );\n  }\n  if (typeof validityMs !== 'number' || validityMs <= 0) {\n    throw new DaitanInvalidInputError(\n      'OTP validityMs must be a positive number.'\n    );\n  }\n\n  // crypto.randomInt(max) generates an int in [0, max-1]. For length N, max is 10^N.\n  // A more direct way is to generate `length` random digits.\n  let otp = '';\n  for (let i = 0; i < length; i++) {\n    otp += crypto.randomInt(0, 10).toString();\n  }\n\n  const expiresAt = Date.now() + validityMs;\n  logger.debug(\n    `Generated numeric OTP (length ${length}), expires at ${new Date(\n      expiresAt\n    ).toISOString()}`\n  );\n  return { otp, expiresAt };\n};\n\n/**\n * Generates a cryptographically secure alphanumeric One-Time Password (OTP).\n *\n * @public\n * @param {GenerateOTPOptions} [options={length: 8, validityMs: DEFAULT_OTP_VALIDITY_MS}] - Options for OTP generation.\n * @returns {OTPGenerationResult} An object containing the OTP string and its expiry timestamp.\n * @throws {DaitanInvalidInputError} If `length` is not a positive integer or `validityMs` is not a positive number.\n */\nexport const generateAlphanumericOTP = ({\n  length = 8,\n  validityMs = DEFAULT_OTP_VALIDITY_MS,\n} = {}) => {\n  if (!Number.isInteger(length) || length <= 0 || length > 32) {\n    // Max length for practical OTPs\n    throw new DaitanInvalidInputError(\n      'Alphanumeric OTP length must be a positive integer, typically between 6 and 32.'\n    );\n  }\n  if (typeof validityMs !== 'number' || validityMs <= 0) {\n    throw new DaitanInvalidInputError(\n      'OTP validityMs must be a positive number.'\n    );\n  }\n\n  const characters =\n    'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';\n  let otp = '';\n  // Generate cryptographically secure random bytes\n  const randomBytes = crypto.randomBytes(length);\n  for (let i = 0; i < length; i++) {\n    // Map byte to character index\n    otp += characters[randomBytes[i] % characters.length];\n  }\n  const expiresAt = Date.now() + validityMs;\n  logger.debug(\n    `Generated alphanumeric OTP (length ${length}), expires at ${new Date(\n      expiresAt\n    ).toISOString()}`\n  );\n  return { otp, expiresAt };\n};\n\n/**\n * @typedef {Object} VerifyOTPOptions\n * @property {string} submittedOTP - The OTP submitted by the user.\n * @property {string} storedOTP - The OTP that was generated and stored by the application.\n * @property {number} storedOTPExpiresAt - The expiry timestamp (milliseconds since epoch) of the stored OTP.\n */\n\n/**\n * Verifies a submitted OTP against a stored OTP and its expiry time.\n * This is a conceptual helper. The actual storage and retrieval of `storedOTP`\n * and `storedOTPExpiresAt` is the responsibility of the consuming application.\n *\n * @public\n * @param {VerifyOTPOptions} options - Parameters for OTP verification.\n * @returns {boolean} True if the OTP is valid (matches and not expired), false otherwise.\n */\nexport const verifyOTP = ({ submittedOTP, storedOTP, storedOTPExpiresAt }) => {\n  if (\n    typeof submittedOTP !== 'string' ||\n    !submittedOTP ||\n    typeof storedOTP !== 'string' ||\n    !storedOTP ||\n    typeof storedOTPExpiresAt !== 'number'\n  ) {\n    logger.warn('verifyOTP: Invalid parameters received for OTP verification.');\n    return false;\n  }\n\n  if (Date.now() > storedOTPExpiresAt) {\n    logger.debug('OTP verification failed: OTP has expired.');\n    return false; // OTP has expired\n  }\n\n  // Constant-time comparison is not strictly necessary for OTPs of typical length,\n  // but good practice if maximum security is paramount. For simplicity, direct comparison is used.\n  const isValid = crypto.timingSafeEqual(\n    Buffer.from(submittedOTP),\n    Buffer.from(storedOTP)\n  );\n\n  if (!isValid) {\n    logger.debug(\n      'OTP verification failed: Submitted OTP does not match stored OTP.'\n    );\n  } else {\n    logger.debug('OTP verification successful.');\n  }\n  return isValid;\n};\n\n// --- JWT (JSON Web Token) Functionality ---\n\nconst DEFAULT_JWT_EXPIRY = '1h'; // Default expiry time for JWTs\n\n/**\n * @typedef {Object} GenerateJWTOptions\n * @property {object} payload - The payload to include in the JWT.\n * @property {string | Buffer} secretOrPrivateKey - The secret or private key for signing.\n * @property {jwt.SignOptions} [options] - Options for JWT signing (e.g., `expiresIn`).\n */\n\n/**\n * Generates a JSON Web Token (JWT).\n *\n * @public\n * @param {GenerateJWTOptions} params - Parameters for JWT generation.\n * @returns {string} The generated JWT string.\n * @throws {DaitanInvalidInputError} If `payload` or `secretOrPrivateKey` is missing or invalid.\n * @throws {DaitanOperationError} If `jsonwebtoken.sign` fails.\n */\nexport const generateJWT = ({ payload, secretOrPrivateKey, options = {} }) => {\n  if (!payload || typeof payload !== 'object' || Array.isArray(payload)) {\n    throw new DaitanInvalidInputError(\n      'JWT payload must be a non-null plain object.'\n    );\n  }\n  if (!secretOrPrivateKey) {\n    throw new DaitanInvalidInputError(\n      'JWT secret or private key is required for signing.'\n    );\n  }\n\n  const jwtOptions = {\n    expiresIn: DEFAULT_JWT_EXPIRY,\n    jwtid: uuidv4(), // JWT ID (jti) claim, useful for revocation or tracking\n    ...options, // User-provided options override defaults\n  };\n\n  try {\n    const token = jwt.sign(payload, secretOrPrivateKey, jwtOptions);\n    logger.debug(\n      `Generated JWT with JTI: ${jwtOptions.jwtid}, expires: ${jwtOptions.expiresIn}.`\n    );\n    return token;\n  } catch (error) {\n    logger.error(`Error generating JWT: ${error.message}`, {\n      errorName: error.name,\n    });\n    throw new DaitanOperationError(\n      `JWT signing failed: ${error.message}`,\n      {},\n      error\n    );\n  }\n};\n\n/**\n * @typedef {Object} VerifyJWTOptions\n * @property {string} token - The JWT string to verify.\n * @property {string | Buffer} secretOrPublicKey - The secret or public key for verification.\n * @property {jwt.VerifyOptions} [options] - Options for JWT verification.\n */\n\n/**\n * Verifies a JSON Web Token (JWT).\n *\n * @public\n * @param {VerifyJWTOptions} params - Parameters for JWT verification.\n * @returns {object | string} The decoded payload if verification is successful.\n * @throws {DaitanInvalidInputError} If `token` or `secretOrPublicKey` is missing.\n * @throws {jwt.JsonWebTokenError | jwt.TokenExpiredError | jwt.NotBeforeError} Throws specific errors from `jsonwebtoken` on failure.\n */\nexport const verifyJWT = ({ token, secretOrPublicKey, options = {} }) => {\n  if (!token || typeof token !== 'string') {\n    throw new DaitanInvalidInputError(\n      'JWT token string is required for verification.'\n    );\n  }\n  if (!secretOrPublicKey) {\n    throw new DaitanInvalidInputError(\n      'JWT secret or public key is required for verification.'\n    );\n  }\n\n  try {\n    const decoded = jwt.verify(token, secretOrPublicKey, options);\n    logger.debug('JWT verified successfully.', {\n      jti: decoded.jti,\n      sub: decoded.sub,\n    });\n    return decoded;\n  } catch (error) {\n    logger.warn(`JWT verification failed: ${error.message}`, {\n      errorName: error.name,\n      tokenPreview: token.substring(0, 20) + '...',\n    });\n    throw error;\n  }\n};\n\n/**\n * @typedef {Object} DecodeJWTOptions\n * @property {string} token - The JWT string to decode.\n * @property {jwt.DecodeOptions} [options] - Options for decoding.\n */\n\n/**\n * Decodes a JSON Web Token (JWT) without verifying its signature.\n *\n * @public\n * @param {DecodeJWTOptions} params - Parameters for JWT decoding.\n * @returns {null | string | { [key: string]: any }} The decoded payload or null if malformed.\n */\nexport const decodeJWT = ({ token, options = {} }) => {\n  if (!token || typeof token !== 'string') {\n    logger.warn('decodeJWT: Invalid or missing token string provided.');\n    return null;\n  }\n  try {\n    const decoded = jwt.decode(token, options);\n    if (decoded === null) {\n      logger.warn('decodeJWT: Token was malformed and could not be decoded.', {\n        tokenPreview: token.substring(0, 20) + '...',\n      });\n    } else {\n      logger.debug('JWT decoded (signature NOT VERIFIED).');\n    }\n    return decoded;\n  } catch (error) {\n    logger.error(`Error during JWT decode (unexpected): ${error.message}`, {\n      errorName: error.name,\n    });\n    return null;\n  }\n};\n"],
  "mappings": "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",
  "names": ["crypto", "uuidv4", "jwt"]
}
