/** * Temporary 30-second auth for email render (Puppeteer). * Isolated from auth.js to avoid circular dependency with utils.js -> auth.js -> keycloak.js -> database.js -> utils.js */ import config from '../../config.js'; import crypto from 'crypto'; import jwt from 'jsonwebtoken'; import NodeCache from 'node-cache'; import log4js from 'log4js'; const logger = log4js.getLogger('EmailRenderAuth'); logger.level = config.server?.logLevel || 'info'; const EMAIL_RENDER_TTL = 30; const emailRenderAuthCache = new NodeCache({ stdTTL: EMAIL_RENDER_TTL }); /** * Creates a temporary auth code for email render (Puppeteer) with 30-second TTL. * The UI exchanges this code via getLoginToken to establish a brief session for rendering. * @param {Object} userDoc - User document (must have username, email, _id, etc.) * @returns {string} authCode to pass in URL query params */ export const createEmailRenderAuthCode = (userDoc) => { const authCode = crypto.randomBytes(32).toString('hex'); const expiresAt = Date.now() + EMAIL_RENDER_TTL * 1000; const accessToken = jwt.sign( { preferred_username: userDoc.username }, config.auth.sessionSecret, { expiresIn: EMAIL_RENDER_TTL } ); const tokenData = { access_token: accessToken, expires_at: expiresAt, _id: userDoc._id, username: userDoc.username, email: userDoc.email, name: userDoc.name, firstName: userDoc.firstName, lastName: userDoc.lastName, }; emailRenderAuthCache.set(authCode, tokenData); logger.debug(`Created email render auth code (TTL ${EMAIL_RENDER_TTL}s) for user ${userDoc.username}`); return authCode; }; /** * Exchanges an email render auth code for token data. Consumes the code (one-time use). * @param {string} code - The auth code from URL query * @returns {Object|null} Token data or null if invalid/expired */ export const getAndConsumeEmailRenderTokenData = (code) => { const data = emailRenderAuthCache.get(code); if (data) { emailRenderAuthCache.del(code); return data; } return null; };