74 lines
2.0 KiB
JavaScript
74 lines
2.0 KiB
JavaScript
const TwoFactorService = require("../services/TwoFactorService");
|
|
const logger = require("../utils/logger");
|
|
|
|
/**
|
|
* Middleware to require step-up authentication for sensitive actions.
|
|
* Only applies to users who have 2FA enabled.
|
|
*
|
|
* @param {string} action - The sensitive action being protected
|
|
* @returns {Function} Express middleware function
|
|
*/
|
|
const requireStepUpAuth = (action) => {
|
|
return async (req, res, next) => {
|
|
try {
|
|
// If user doesn't have 2FA enabled, skip step-up requirement
|
|
if (!req.user.twoFactorEnabled) {
|
|
return next();
|
|
}
|
|
|
|
// Check if user has a valid step-up session (within 5 minutes)
|
|
const isValid = TwoFactorService.validateStepUpSession(req.user);
|
|
|
|
if (!isValid) {
|
|
logger.info(
|
|
`Step-up authentication required for user ${req.user.id}, action: ${action}`
|
|
);
|
|
|
|
return res.status(403).json({
|
|
error: "Multi-factor authentication required",
|
|
code: "STEP_UP_REQUIRED",
|
|
action: action,
|
|
methods: getTwoFactorMethods(req.user),
|
|
});
|
|
}
|
|
|
|
next();
|
|
} catch (error) {
|
|
logger.error("Step-up auth middleware error:", error);
|
|
return res.status(500).json({
|
|
error: "An error occurred during authentication",
|
|
});
|
|
}
|
|
};
|
|
};
|
|
|
|
/**
|
|
* Get available 2FA methods for a user
|
|
* @param {Object} user - User object
|
|
* @returns {string[]} Array of available methods
|
|
*/
|
|
function getTwoFactorMethods(user) {
|
|
const methods = [];
|
|
|
|
// Primary method is always available
|
|
if (user.twoFactorMethod === "totp") {
|
|
methods.push("totp");
|
|
}
|
|
|
|
// Email is always available as a backup method
|
|
methods.push("email");
|
|
|
|
// Recovery codes are available if any remain
|
|
if (user.recoveryCodesHash) {
|
|
const recoveryData = JSON.parse(user.recoveryCodesHash);
|
|
const remaining = TwoFactorService.getRemainingRecoveryCodesCount(recoveryData);
|
|
if (remaining > 0) {
|
|
methods.push("recovery");
|
|
}
|
|
}
|
|
|
|
return methods;
|
|
}
|
|
|
|
module.exports = { requireStepUpAuth };
|