"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.createSSORouter = createSSORouter; /** * SSO Controller — manages SSO provider configurations and TOTP/MFA. * Feature-gated: enterprise license required. */ const express_1 = require("express"); const SSOConfig_1 = require("../../domain/entities/SSOConfig"); const TOTPSecret_1 = require("../../domain/entities/TOTPSecret"); function createSSORouter(deps) { const router = (0, express_1.Router)(); const { ssoConfigRepository, totpRepository, totpService } = deps; // GET /api/sso/config — get SSO config for the current org router.get('/config', async (req, res, next) => { try { const user = req.user; if (!user?.orgId) return res.status(400).json({ error: 'No organization' }); const config = await ssoConfigRepository.findByOrganizationId(user.orgId); if (!config) return res.json(null); res.json({ id: config.id.toString(), provider: config.provider, enabled: config.enabled, config: config.config, createdAt: config.createdAt.toISOString(), }); } catch (err) { next(err); } }); // PUT /api/sso/config — create or update SSO config router.put('/config', async (req, res, next) => { try { const user = req.user; if (!user?.orgId) return res.status(400).json({ error: 'No organization' }); const { provider, enabled, config } = req.body; if (!['saml', 'oidc', 'ldap'].includes(provider)) { return res.status(400).json({ error: 'Invalid provider' }); } const existing = await ssoConfigRepository.findByOrganizationId(user.orgId); if (existing) { if (enabled !== undefined) { enabled ? existing.enable() : existing.disable(); } // Merge config fields Object.assign(existing.config, config ?? {}); await ssoConfigRepository.save(existing); return res.json({ id: existing.id.toString(), provider: existing.provider, enabled: existing.enabled }); } const ssoConfig = SSOConfig_1.SSOConfig.create({ organizationId: user.orgId, provider, enabled: enabled ?? true, config: config ?? {}, createdAt: new Date(), }); await ssoConfigRepository.save(ssoConfig); res.status(201).json({ id: ssoConfig.id.toString(), provider, enabled: ssoConfig.enabled }); } catch (err) { next(err); } }); // DELETE /api/sso/config — remove SSO config (disables SSO) router.delete('/config', async (req, res, next) => { try { const user = req.user; if (!user?.orgId) return res.status(400).json({ error: 'No organization' }); const config = await ssoConfigRepository.findByOrganizationId(user.orgId); if (!config) return res.status(404).json({ error: 'Not found' }); config.disable(); await ssoConfigRepository.save(config); res.json({ success: true }); } catch (err) { next(err); } }); // POST /api/sso/mfa/setup — generate TOTP secret for current user router.post('/mfa/setup', async (req, res, next) => { try { const user = req.user; const { otpauthUrl, secret } = totpService.generateSecret(user.id, user.email); // Save unverified secret const totpSecret = TOTPSecret_1.TOTPSecret.create({ userId: user.id, secret, verified: false, createdAt: new Date(), }); await totpRepository.save(totpSecret); res.json({ otpauthUrl, secret }); } catch (err) { next(err); } }); // POST /api/sso/mfa/verify — verify TOTP token and mark as verified router.post('/mfa/verify', async (req, res, next) => { try { const user = req.user; const { token } = req.body; const stored = await totpRepository.findByUserId(user.id); if (!stored) return res.status(400).json({ error: 'MFA not set up' }); if (!totpService.verify(stored.secret, token)) { return res.status(400).json({ error: 'Invalid token' }); } stored.verify(); await totpRepository.save(stored); res.json({ verified: true }); } catch (err) { next(err); } }); // DELETE /api/sso/mfa — remove MFA for current user router.delete('/mfa', async (req, res, next) => { try { const user = req.user; await totpRepository.delete(user.id); res.json({ success: true }); } catch (err) { next(err); } }); // GET /api/sso/mfa/status — check MFA status router.get('/mfa/status', async (req, res, next) => { try { const user = req.user; const stored = await totpRepository.findByUserId(user.id); res.json({ enabled: !!stored, verified: stored?.verified ?? false }); } catch (err) { next(err); } }); return router; }