farmcontrol-api/src/services/misc/emailRenderAuth.js

59 lines
2.0 KiB
JavaScript

/**
* 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;
};