Refactor auth routes: explicit dependency injection

- Updated all auth route modules to use destructured dependencies
- Added JSDoc comments for factory functions
- Replaced ctx. references with direct parameter access
- Updated auth/index.js to extract and pass explicit dependencies
- sso-gate.js maintains session helper exports from session-handlers
- All files pass syntax validation

Files refactored:
- routes/auth/keys.js
- routes/auth/session-handlers.js
- routes/auth/sso-gate.js
- routes/auth/totp.js
- routes/auth/index.js (orchestrator)
This commit is contained in:
Krystie
2026-03-29 21:42:30 -07:00
parent a4788c3f28
commit df3e8efdd0
5 changed files with 110 additions and 58 deletions

View File

@@ -2,11 +2,20 @@ const express = require('express');
const { renewCSRFToken } = require('../../csrf-protection');
const { ValidationError, AuthenticationError } = require('../../errors');
module.exports = function(ctx) {
module.exports = function({ authManager, asyncHandler, errorResponse, log }) {
const router = express.Router();
/**
* Auth TOTP routes factory
* @param {Object} deps - Explicit dependencies
* @param {Object} deps.authManager - Auth manager
* @param {Function} deps.asyncHandler - Async route handler wrapper
* @param {Function} deps.errorResponse - Error response helper
* @param {Object} deps.log - Logger instance
* @returns {express.Router}
*/
// Get current TOTP config (public route)
router.get('/totp/config', ctx.asyncHandler(async (req, res) => {
router.get('/totp/config', asyncHandler(async (req, res) => {
res.json({
success: true,
config: {
@@ -18,7 +27,7 @@ module.exports = function(ctx) {
}, 'totp-config-get'));
// Generate new TOTP secret + QR code
router.post('/totp/setup', ctx.asyncHandler(async (req, res) => {
router.post('/totp/setup', asyncHandler(async (req, res) => {
const { authenticator } = require('otplib');
const QRCode = require('qrcode');
@@ -46,7 +55,7 @@ module.exports = function(ctx) {
}, 'totp-setup'));
// Verify first code to confirm setup, then activate TOTP
router.post('/totp/verify-setup', ctx.asyncHandler(async (req, res) => {
router.post('/totp/verify-setup', asyncHandler(async (req, res) => {
const { authenticator } = require('otplib');
const { code } = req.body;
@@ -83,7 +92,7 @@ module.exports = function(ctx) {
}, 'totp-verify-setup'));
// Login: verify TOTP code and set session cookie
router.post('/totp/verify', ctx.asyncHandler(async (req, res) => {
router.post('/totp/verify', asyncHandler(async (req, res) => {
const { authenticator } = require('otplib');
const { code } = req.body;
@@ -105,19 +114,19 @@ module.exports = function(ctx) {
throw new AuthenticationError('[DC-111] Invalid code');
}
ctx.log.info('auth', 'TOTP verified, creating session', { ip: ctx.session.getClientIP(req), duration: ctx.totpConfig.sessionDuration });
log.info('auth', 'TOTP verified, creating session', { ip: ctx.session.getClientIP(req), duration: ctx.totpConfig.sessionDuration });
ctx.session.create(req, ctx.totpConfig.sessionDuration);
ctx.session.setCookie(res, ctx.totpConfig.sessionDuration);
// Rotate CSRF token for the new session
const newCsrfToken = renewCSRFToken(res, req.secure || req.protocol === 'https');
ctx.log.debug('auth', 'Session created', { sessions: ctx.session.ipSessions.size });
log.debug('auth', 'Session created', { sessions: ctx.session.ipSessions.size });
res.json({ success: true, message: 'Authenticated successfully', sessionDuration: ctx.totpConfig.sessionDuration, csrfToken: newCsrfToken });
}, 'totp-verify'));
// Check session validity (used by Caddy forward_auth)
router.get('/totp/check-session', ctx.asyncHandler(async (req, res) => {
router.get('/totp/check-session', asyncHandler(async (req, res) => {
// Never cache session checks — stale cached 200s cause auth loops
res.setHeader('Cache-Control', 'no-store, no-cache, must-revalidate');
res.setHeader('Pragma', 'no-cache');
@@ -127,7 +136,7 @@ module.exports = function(ctx) {
}
const valid = ctx.session.isValid(req);
ctx.log.debug('auth', 'Session check', { ip: ctx.session.getClientIP(req), valid, sessions: ctx.session.ipSessions.size });
log.debug('auth', 'Session check', { ip: ctx.session.getClientIP(req), valid, sessions: ctx.session.ipSessions.size });
if (valid) {
return res.status(200).json({ authenticated: true });
}
@@ -136,7 +145,7 @@ module.exports = function(ctx) {
}, 'totp-check-session'));
// Disable TOTP
router.post('/totp/disable', ctx.asyncHandler(async (req, res) => {
router.post('/totp/disable', asyncHandler(async (req, res) => {
const { code } = req.body;
// Always require a valid TOTP code when TOTP is active
@@ -169,7 +178,7 @@ module.exports = function(ctx) {
}, 'totp-disable'));
// Update TOTP settings (session duration)
router.post('/totp/config', ctx.asyncHandler(async (req, res) => {
router.post('/totp/config', asyncHandler(async (req, res) => {
const { sessionDuration } = req.body;
if (sessionDuration && !ctx.session.durations.hasOwnProperty(sessionDuration)) {