const express = require('express'); const fs = require('fs'); const path = require('path'); const router = express.Router(); const bodyParser = require('body-parser'); const { logger } = require('../../../config/logs'); // Utilitaires pour la gestion des services const services = { fileCleanup: require('../../../services/fileCleanupService'), reportManager: require('../../../services/reportService') }; router.use(bodyParser.json()); // Fonction de nettoyage des objets function clean(obj) { for (let propName in obj) { if (obj[propName] === null || obj[propName] === undefined || obj[propName] === '') { delete obj[propName]; } else if (typeof obj[propName] === 'object') { clean(obj[propName]); if (Object.keys(obj[propName]).length === 0) { delete obj[propName]; } } } } // Validation des IPs function validateIP(ip) { if (!ip) return false; if (ip.includes('/')) { const [addr, bits] = ip.split('/'); const bitsNum = parseInt(bits); if (isIPv4(addr)) { return bitsNum >= 0 && bitsNum <= 32; } else if (isIPv6(addr)) { return bitsNum >= 0 && bitsNum <= 128; } return false; } return isIPv4(ip) || isIPv6(ip); } function isIPv4(ip) { const ipv4Regex = /^\d{1,3}(\.\d{1,3}){3}$/; if (!ipv4Regex.test(ip)) return false; const parts = ip.split('.'); return parts.every(part => { const num = parseInt(part); return num >= 0 && num <= 255; }); } function isIPv6(ip) { const ipv6Regex = /^(?:(?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|(?:[0-9a-fA-F]{1,4}:){1,7}:|(?:[0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|(?:[0-9a-fA-F]{1,4}:){1,5}(?::[0-9a-fA-F]{1,4}){1,2}|(?:[0-9a-fA-F]{1,4}:){1,4}(?::[0-9a-fA-F]{1,4}){1,3}|(?:[0-9a-fA-F]{1,4}:){1,3}(?::[0-9a-fA-F]{1,4}){1,4}|(?:[0-9a-fA-F]{1,4}:){1,2}(?::[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:(?:(?::[0-9a-fA-F]{1,4}){1,6})|:(?:(?::[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(?::[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(?:ffff(?::0{1,4}){0,1}:){0,1}(?:(?:25[0-5]|(?:2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(?:25[0-5]|(?:2[0-4]|1{0,1}[0-9]){0,1}[0-9])|(?:[0-9a-fA-F]{1,4}:){1,4}:(?:(?:25[0-5]|(?:2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(?:25[0-5]|(?:2[0-4]|1{0,1}[0-9]){0,1}[0-9]))$/; return ipv6Regex.test(ip); } // Fonction pour activer ou désactiver un service async function handleServices(newConfig, oldConfig) { if (!newConfig.services) return; for (const [serviceName, serviceConfig] of Object.entries(newConfig.services)) { const service = services[serviceName]; if (!service) { logger.warn(`Service ${serviceName} not found`); continue; } const oldServiceConfig = oldConfig?.services?.[serviceName] || {}; const wasEnabled = oldServiceConfig.enabled === 'on'; // ancien état const isEnabled = serviceConfig.enabled === 'on'; // nouvel état try { logger.info(`Processing service ${serviceName}: wasEnabled=${wasEnabled}, isEnabled=${isEnabled}`); if (isEnabled && !wasEnabled) { await service.updateConfig(serviceConfig); await service.start(); } else if (!isEnabled && wasEnabled) { await service.stop(); } else if (isEnabled && wasEnabled && JSON.stringify(serviceConfig) !== JSON.stringify(oldServiceConfig)) { await service.stop(); await service.updateConfig(serviceConfig); await service.start(); } } catch (error) { logger.error(`Error handling service ${serviceName}:`, error); throw error; } } } // Mise à jour de la configuration et gestion des services async function handleServicesUpdate(newConfig, oldConfig) { if (!newConfig.services) return; for (const [serviceName, serviceConfig] of Object.entries(newConfig.services)) { const oldServiceConfig = oldConfig?.services?.[serviceName] || {}; await handleServices(serviceName, serviceConfig, oldServiceConfig); } } // Route principale pour mettre à jour la configuration router.post('/', async (req, res) => { try { const setupPath = path.join(__dirname, '../../../data', 'setup.json'); const oldConfig = JSON.parse(fs.readFileSync(setupPath, 'utf-8'))[0]; // Validation et traitement des IPs autorisées if (req.body.allowedIps) { let ipsToProcess = Array.isArray(req.body.allowedIps) ? req.body.allowedIps : req.body.allowedIps[""] || []; req.body.allowedIps = ipsToProcess.filter(ip => validateIP(ip.trim())).map(ip => ip.trim()); } ['ldap', 'discord'].forEach(service => { if (req.body[service] && !req.body[service].enabled) { req.body[service] = { enabled: 'off' }; } }); // Traitement des services if (req.body.services) { for (const [key, value] of Object.entries(req.body.services)) { if (typeof value === 'string') { req.body.services[key] = { enabled: 'off', schedule: value }; // Par défaut 'off' et ajouter un schedule si nécessaire } // Si l'état n'est pas 'on' ou 'off', on le met à 'off' if (value.enabled !== 'on' && value.enabled !== 'off') { req.body.services[key].enabled = 'off'; } } } // Traitement des logs if (req.body.logs) { req.body.logs = { enabled: req.body.logs.enabled || "on", excludePaths: Array.isArray(req.body.logs.excludePaths) ? req.body.logs.excludePaths : [], includeOnly: Array.isArray(req.body.logs.includeOnly) ? req.body.logs.includeOnly : [], levels: Array.isArray(req.body.logs.levels) ? req.body.logs.levels : [] }; } // Fusion des anciennes et nouvelles configurations const newConfig = { ...oldConfig, ...req.body }; clean(newConfig); // Mise à jour des services await handleServicesUpdate(newConfig, oldConfig); // Sauvegarde de la nouvelle configuration fs.writeFileSync(setupPath, JSON.stringify([newConfig], null, 2)); res.status(200).json({ message: 'Configuration mise à jour avec succès.' }); } catch (error) { logger.error('Erreur lors de la mise à jour de la configuration:', error); res.status(500).json({ error: 'Erreur interne du serveur.' }); } }); module.exports = router;