const express = require('express'); const router = express.Router(); const http = require('http'); const jwt = require('jsonwebtoken'); const { ManagementUser } = require('../models'); const auditLogger = require('../utils/dataRetentionAuditLogger'); /** * Data Retention Metrics Proxy * Proxies requests to the data retention microservice * RESTRICTED ACCESS: Management users only */ const DATA_RETENTION_HOST = process.env.DATA_RETENTION_HOST || 'data-retention'; const DATA_RETENTION_PORT = process.env.DATA_RETENTION_PORT || 3001; /** * Management authentication middleware * Only allows authenticated management users with proper permissions */ const requireManagementAuth = async (req, res, next) => { try { // Check for management auth token const token = req.headers.authorization?.replace('Bearer ', ''); if (!token) { await auditLogger.logAuthFailure(req, req.path, 'No authentication token provided'); return res.status(401).json({ success: false, error: 'Management authentication required', message: 'This endpoint requires management portal authentication' }); } // Verify JWT token let decoded; try { decoded = jwt.verify(token, process.env.JWT_SECRET || 'your-super-secret-jwt-key-change-in-production'); } catch (jwtError) { await auditLogger.logAuthFailure(req, req.path, `Invalid JWT token: ${jwtError.message}`); return res.status(401).json({ success: false, error: 'Invalid management token', message: 'Authentication token is invalid or expired' }); } // Verify this is a management user if (decoded.type !== 'management') { await auditLogger.logPermissionDenied(null, req, req.path, 'Not a management user token'); return res.status(403).json({ success: false, error: 'Management access required', message: 'This endpoint requires management portal privileges' }); } // Verify user still exists and is active const managementUser = await ManagementUser.findByPk(decoded.id); if (!managementUser || !managementUser.is_active) { await auditLogger.logPermissionDenied(decoded, req, req.path, 'Management user not found or inactive'); return res.status(403).json({ success: false, error: 'Management user not found or inactive', message: 'Management user account is not active' }); } // Check if user has permission to access system metrics const hasMetricsAccess = managementUser.role === 'super_admin' || (managementUser.permissions && managementUser.permissions.includes('system_metrics')); if (!hasMetricsAccess) { await auditLogger.logPermissionDenied(managementUser, req, req.path, 'Insufficient permissions for system metrics'); return res.status(403).json({ success: false, error: 'Insufficient permissions', message: 'This endpoint requires system metrics permissions' }); } // Log access for security audit console.log(`📊 Data retention metrics accessed by management user: ${managementUser.username} (${managementUser.role})`); req.managementUser = managementUser; next(); } catch (error) { console.error('Management auth error:', error); res.status(500).json({ success: false, error: 'Authentication error', message: 'Failed to verify management authentication' }); } }; /** * IP restriction middleware (additional security layer) * Only allow access from management container or specified IPs */ const requireManagementNetwork = async (req, res, next) => { const clientIP = req.ip || req.connection.remoteAddress; const forwardedFor = req.headers['x-forwarded-for']; // Allow internal Docker network (management container) const allowedNetworks = [ '127.0.0.1', '::1', 'localhost', // Docker internal networks /^172\.(1[6-9]|2[0-9]|3[0-1])\./, // Docker default bridge /^10\./, // Docker custom networks /^192\.168\./ // Local networks ]; // Check if request is from management container or allowed network const isAllowed = allowedNetworks.some(network => { if (typeof network === 'string') { return clientIP === network || forwardedFor === network; } else { return network.test(clientIP) || (forwardedFor && network.test(forwardedFor)); } }); if (!isAllowed) { await auditLogger.logNetworkDenied(req, req.path); console.warn(`🚫 Data retention access denied from IP: ${clientIP} (forwarded: ${forwardedFor})`); return res.status(403).json({ success: false, error: 'Network access denied', message: 'Access to data retention metrics is restricted to management network' }); } next(); }; /** * Make HTTP request to data retention service */ function makeRequest(path) { return new Promise((resolve, reject) => { const options = { hostname: DATA_RETENTION_HOST, port: DATA_RETENTION_PORT, path: path, method: 'GET', timeout: 5000 }; const req = http.request(options, (res) => { let data = ''; res.on('data', (chunk) => { data += chunk; }); res.on('end', () => { try { const result = JSON.parse(data); resolve({ status: res.statusCode, data: result }); } catch (error) { reject(new Error(`Failed to parse response: ${error.message}`)); } }); }); req.on('error', (error) => { reject(new Error(`Request failed: ${error.message}`)); }); req.on('timeout', () => { req.destroy(); reject(new Error('Request timeout')); }); req.end(); }); } /** * Apply security middleware to all data retention routes */ router.use(requireManagementNetwork); router.use(requireManagementAuth); /** * GET /api/data-retention/metrics * Get detailed metrics from data retention service * RESTRICTED: Management users only */ router.get('/metrics', async (req, res) => { try { // Add security headers res.setHeader('X-Content-Type-Options', 'nosniff'); res.setHeader('X-Frame-Options', 'DENY'); res.setHeader('X-XSS-Protection', '1; mode=block'); const response = await makeRequest('/metrics'); if (response.status === 200) { // Log successful access await auditLogger.logSuccess(req.managementUser, req, '/metrics'); console.log(`✅ Data retention metrics accessed by ${req.managementUser.username}`); res.json({ success: true, data: response.data, timestamp: new Date().toISOString(), accessedBy: { username: req.managementUser.username, role: req.managementUser.role } }); } else { res.status(response.status).json({ success: false, error: 'Failed to fetch metrics from data retention service' }); } } catch (error) { console.error(`❌ Data retention metrics error for ${req.managementUser.username}:`, error); res.status(503).json({ success: false, error: 'Data retention service unavailable', details: error.message }); } }); /** * GET /api/data-retention/health * Get health status from data retention service * RESTRICTED: Management users only */ router.get('/health', async (req, res) => { try { // Add security headers res.setHeader('X-Content-Type-Options', 'nosniff'); res.setHeader('X-Frame-Options', 'DENY'); res.setHeader('X-XSS-Protection', '1; mode=block'); const response = await makeRequest('/health'); if (response.status === 200) { console.log(`✅ Data retention health checked by ${req.managementUser.username}`); res.json({ success: true, data: response.data, timestamp: new Date().toISOString(), accessedBy: { username: req.managementUser.username, role: req.managementUser.role } }); } else { res.status(response.status).json({ success: false, error: 'Failed to fetch health from data retention service' }); } } catch (error) { console.error(`❌ Data retention health error for ${req.managementUser.username}:`, error); res.status(503).json({ success: false, error: 'Data retention service unavailable', details: error.message }); } }); /** * GET /api/data-retention/stats * Get basic statistics from data retention service * RESTRICTED: Management users only */ router.get('/stats', async (req, res) => { try { // Add security headers res.setHeader('X-Content-Type-Options', 'nosniff'); res.setHeader('X-Frame-Options', 'DENY'); res.setHeader('X-XSS-Protection', '1; mode=block'); const response = await makeRequest('/stats'); if (response.status === 200) { console.log(`✅ Data retention stats accessed by ${req.managementUser.username}`); res.json({ success: true, data: response.data, timestamp: new Date().toISOString(), accessedBy: { username: req.managementUser.username, role: req.managementUser.role } }); } else { res.status(response.status).json({ success: false, error: 'Failed to fetch stats from data retention service' }); } } catch (error) { console.error(`❌ Data retention stats error for ${req.managementUser.username}:`, error); res.status(503).json({ success: false, error: 'Data retention service unavailable', details: error.message }); } }); /** * GET /api/data-retention/status * Get combined status including service connectivity * RESTRICTED: Management users only */ router.get('/status', async (req, res) => { try { // Add security headers res.setHeader('X-Content-Type-Options', 'nosniff'); res.setHeader('X-Frame-Options', 'DENY'); res.setHeader('X-XSS-Protection', '1; mode=block'); const [healthResponse, metricsResponse] = await Promise.allSettled([ makeRequest('/health'), makeRequest('/metrics') ]); const result = { success: true, service: { name: 'data-retention-service', connected: false, error: null }, health: null, metrics: null, timestamp: new Date().toISOString(), accessedBy: { username: req.managementUser.username, role: req.managementUser.role } }; if (healthResponse.status === 'fulfilled' && healthResponse.value.status === 200) { result.service.connected = true; result.health = healthResponse.value.data; } else { result.service.error = healthResponse.reason?.message || 'Health check failed'; } if (metricsResponse.status === 'fulfilled' && metricsResponse.value.status === 200) { result.metrics = metricsResponse.value.data; } console.log(`✅ Data retention status accessed by ${req.managementUser.username}`); res.json(result); } catch (error) { console.error(`❌ Data retention status error for ${req.managementUser.username}:`, error); res.status(503).json({ success: false, error: 'Failed to get data retention service status', details: error.message }); } }); module.exports = router;