const express = require('express'); const initTotp = require('./totp'); const initKeys = require('./keys'); const initSessionHandlers = require('./session-handlers'); const initSsoGate = require('./sso-gate'); const initLogin = require('./login'); const { createAuthProviderRegistry } = require('../../src/auth/providers'); /** * Auth routes aggregator * Assembles all auth sub-routes with their dependencies * @param {Object} ctx - Application context (for backward compatibility) * @returns {express.Router} */ /** * Pull the SMTP/email provider config from whichever source has it. * * Resolution order: * 1. ctx.emailProviderConfig — explicit override (operator or env) * 2. ctx.notification.getConfig?.().providers.email — reuse the same * SMTP settings notifications use. This is the "magic" — operators * configure SMTP once for system notifications and email-auth picks * it up automatically. * 3. null — provider will operate in dev-console fallback mode. */ function _extractEmailConfig(ctx) { if (ctx.emailProviderConfig && typeof ctx.emailProviderConfig === 'object') { return ctx.emailProviderConfig; } const n = ctx.notification; if (n && typeof n.getConfig === 'function') { const cfg = n.getConfig(); if (cfg && cfg.providers && cfg.providers.email) return cfg.providers.email; } return null; } module.exports = function(ctx) { const router = express.Router(); // Extract dependencies from context const deps = { authManager: ctx.authManager, credentialManager: ctx.credentialManager, totpConfig: ctx.totpConfig, saveTotpConfig: ctx.saveTotpConfig, session: ctx.session, asyncHandler: ctx.asyncHandler, errorResponse: ctx.errorResponse, log: ctx.log, // Additional deps for sso-gate fetchT: ctx.fetchT, getServiceById: ctx.getServiceById, licenseManager: ctx.licenseManager, servicesStateManager: ctx.servicesStateManager, renewCSRFToken: ctx.middlewareResult?.renewCSRFToken, // For DC-046 pluggable auth providers (EmailMagicLink, OIDC, …). // Pass-through — providers like the EmailMagicLinkProvider need // notificationManager for SMTP delivery, plus the siteConfig for // building verification links. notificationManager: ctx.notification, siteConfig: ctx.siteConfig, // DC-047: data-directory resolution for the email-token JSON store. platformPaths: ctx.platformPaths || null, }; const { getAppSession, appSessionCache } = initSessionHandlers(deps); // DC-046: pluggable auth provider registry. The TOTP provider is wired // here against the existing totpConfig / saveTotpConfig objects so it // behaves identically to the legacy /api/v1/totp/* routes mounted below. const registry = createAuthProviderRegistry( { credentialManager: ctx.credentialManager, session: ctx.session, saveTotpConfig: ctx.saveTotpConfig, config: { totp: ctx.totpConfig, email: ctx.emailProviderConfig || { enabled: true } }, log: ctx.log, renewCSRFToken: ctx.middlewareResult?.renewCSRFToken, // DC-047: EmailMagicLinkProvider needs SMTP config + a public URL // resolver + the data dir for the token store. All three come from // existing global config — no new config knobs required. emailConfig: _extractEmailConfig(ctx), siteConfig: ctx.siteConfig || {}, platformPaths: deps.platformPaths, }, ctx.siteConfig ); ctx.authProviders = registry; // exposed for /api/v1/auth/methods, etc. // NEW (DC-046): pluggable /api/v1/auth/login/* routes. Frontends should // migrate here over time — the legacy /api/v1/totp/* routes below stay // for back-compat. Mounted under `/auth` so internal paths // (`/login/methods`, `/disable/:provider`) resolve at the canonical // `/api/v1/auth/login/*` and `/api/v1/auth/disable/*` URLs that match // PUBLIC_ROUTES and the documented login UI contract. router.use('/auth', initLogin({ registry, asyncHandler: ctx.asyncHandler, errorResponse: ctx.errorResponse, log: ctx.log, })); router.use(initTotp(deps)); router.use(initKeys(deps)); router.use(initSsoGate({ ...deps, getAppSession, appSessionCache })); return router; };