diff --git a/.drone.yml b/.drone.yml index c2130ee..66ffcde 100644 --- a/.drone.yml +++ b/.drone.yml @@ -10,14 +10,14 @@ steps: from_secret: git_password commands: - npm install - - export VERSION=$(node -e "console.log(require('./package.json').version)") + - echo "VERSION=$(node -e "console.log(require('./package.json').version)")" >> .env + - cat .env >> .tags + - name: build-docker-image image: plugins/docker settings: repo: swiftlogiclabs/cdn-app-insider - tags: - - latest - - v${VERSION} + tags_file: .tags dockerfile: Dockerfile username: from_secret: docker_username diff --git a/config/logs.js b/config/logs.js index ce141d4..60de6d6 100644 --- a/config/logs.js +++ b/config/logs.js @@ -1,147 +1,194 @@ const { format } = require('winston'); const winston = require('winston'); const DailyRotateFile = require('winston-daily-rotate-file'); +const fs = require('fs'); +const path = require('path'); +// Configuration des préfixes de logs avec couleurs const logPrefix = (label) => { - if (label === 'server') { - return '[🖥️ \x1b[32mServer\x1b[0m] '; - } else if (label === 'client') { - return '[🌐 \x1b[34mClient\x1b[0m] '; - } else if (label === 'Internal-Server-Error') { - return '[❗️ \x1b[38;5;9mInternal-Error\x1b[0m] '; - } else if (label === 'Authentification') { - return '[🔒 \x1b[33mAuthentification\x1b[0m] '; - } else if (label === 'Suspicious Request') { - return '[⚠️ \x1b[38;5;208mSuspicious Request\x1b[0m] '; - }else if (label === 'API Request') { - return '[⚙️ \x1b[38;5;9mAPI Request\x1b[0m] '; - } - return ''; + const prefixes = { + 'server': '[🖥️ \x1b[32mServer\x1b[0m]', + 'client': '[🌐 \x1b[34mClient\x1b[0m]', + 'Internal-Server-Error': '[❗️ \x1b[38;5;9mInternal-Error\x1b[0m]', + 'Authentification': '[🔒 \x1b[33mAuthentification\x1b[0m]', + 'Suspicious Request': '[⚠️ \x1b[38;5;208mSuspicious Request\x1b[0m]', + 'API Request': '[⚙️ \x1b[38;5;9mAPI Request\x1b[0m]', + 'File System': '[📁 \x1b[36mFile System\x1b[0m]', + 'Database': '[🗄️ \x1b[35mDatabase\x1b[0m]' + }; + return prefixes[label] || ''; }; +// Configuration du transport de fichiers rotatifs const createDailyRotateFileTransport = () => { - return new DailyRotateFile({ - filename: 'logs/log-%DATE%.log', - datePattern: 'YYYY-MM-DD', - zippedArchive: false, - maxSize: '20m', - maxFiles: '14d' - }); + return new DailyRotateFile({ + filename: 'logs/log-%DATE%.log', + datePattern: 'YYYY-MM-DD', + zippedArchive: true, + maxSize: '20m', + maxFiles: '14d', + format: format.combine( + format.timestamp(), + format.json() + ) + }); }; -const logger = winston.createLogger({ - format: format.combine( - format.label({ label: 'server' }), - format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }), - format.printf(info => { - const { timestamp, level, label, message } = info; - const prefix = logPrefix(label); - return `${prefix}[\x1b[36m${timestamp}\x1b[0m] ${message}`; - }) - ), - transports: [ - new winston.transports.Console(), - createDailyRotateFileTransport() - ] -}); +// Configuration du format de base pour tous les loggers +const createLoggerFormat = (label) => { + return format.combine( + format.label({ label }), + format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }), + format.printf(info => { + const { timestamp, label, message } = info; + const prefix = logPrefix(label); + return `${prefix} [\x1b[36m${timestamp}\x1b[0m] ${message}`; + }) + ); +}; -const ErrorLogger = winston.createLogger({ - format: format.combine( - format.label({ label: 'Internal-Server-Error' }), - format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }), - format.printf(info => { - const { timestamp, level, label, message } = info; - const prefix = logPrefix(label); - return `${prefix}[\x1b[36m${timestamp}\x1b[0m] ${message}`; - }) - ), - transports: [ - new winston.transports.Console(), - createDailyRotateFileTransport() - ] -}); +// Création des différents loggers +const createLogger = (label) => { + return winston.createLogger({ + format: createLoggerFormat(label), + transports: [ + new winston.transports.Console(), + createDailyRotateFileTransport() + ] + }); +}; -const clientLogger = winston.createLogger({ - format: format.combine( - format.label({ label: 'client' }), - format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }), - format.printf(info => { - const { timestamp, level, label, message } = info; - const prefix = logPrefix(label); - return `${prefix}[\x1b[36m${timestamp}\x1b[0m] ${message}`; - }) - ), - transports: [ - new winston.transports.Console(), - createDailyRotateFileTransport() - ] -}); +// Instanciation des loggers +const logger = createLogger('server'); +const clientLogger = createLogger('client'); +const ErrorLogger = createLogger('Internal-Server-Error'); +const authLogger = createLogger('Authentification'); +const suspiciousLogger = createLogger('Suspicious Request'); +const apiLogger = createLogger('API Request'); +const fileSystemLogger = createLogger('File System'); +const databaseLogger = createLogger('Database'); -const authLogger = winston.createLogger({ - format: format.combine( - format.label({ label: 'Authentification' }), - format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }), - format.printf(info => { - const { timestamp, level, label, message } = info; - const prefix = logPrefix(label); - return `${prefix}[\x1b[36m${timestamp}\x1b[0m] ${message}`; - }) - ), - transports: [ - new winston.transports.Console(), - createDailyRotateFileTransport() - ] -}); - -const suspiciousLogger = winston.createLogger({ - format: format.combine( - format.label({ label: 'Suspicious Request' }), - format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }), - format.printf(info => { - const { timestamp, level, label, message } = info; - const prefix = logPrefix(label); - return `${prefix}[\x1b[36m${timestamp}\x1b[0m] ${message}`; - }) - ), - transports: [ - new winston.transports.Console(), - createDailyRotateFileTransport() - ] -}); +// Fonction utilitaire pour vérifier les chemins +const checkPath = (url, paths) => { + return paths && paths.length > 0 && paths.some(p => url.startsWith(p.trim())); +}; +// Middleware principal de logging const logRequestInfo = (req, res, next) => { - const ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress; - const userAgent = req.headers['user-agent']; - req.log = clientLogger; - req.log.info(`[${ip}] - ${userAgent} - ${req.method} ${req.url}`); - next(); -}; + try { + // Lire la configuration + const setup = JSON.parse(fs.readFileSync(path.join(process.cwd(), 'data', 'setup.json'), 'utf-8'))[0]; + const logsConfig = setup.logs || { enabled: 'off', level: 'info' }; -const apiLogger = winston.createLogger({ - format: format.combine( - format.label({ label: 'API Request' }), - format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }), - format.printf(info => { - const { timestamp, level, label, message } = info; - const prefix = logPrefix(label); - return `${prefix}[\x1b[36m${timestamp}\x1b[0m] ${message}`; - }) - ), - transports: [ - new winston.transports.Console(), - createDailyRotateFileTransport() - ] -}); + // Vérifier si les logs sont activés + if (logsConfig.enabled !== 'on') { + return next(); + } + const ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress; + const userAgent = req.headers['user-agent']; + const url = req.originalUrl || req.url; + + // Vérifier d'abord includeOnly + if (logsConfig.includeOnly && logsConfig.includeOnly.length > 0) { + const isIncluded = logsConfig.includeOnly.some(p => url.startsWith(p.trim())); + if (!isIncluded) { + return next(); // Ne pas logger si le chemin n'est pas dans includeOnly + } + } + + // Ensuite vérifier excludePaths + if (logsConfig.excludePaths && logsConfig.excludePaths.length > 0) { + const isExcluded = logsConfig.excludePaths.some(p => url.startsWith(p.trim())); + if (isExcluded) { + return next(); // Ne pas logger si le chemin est dans excludePaths + } + } + + // Sélectionner le logger approprié et le niveau + let selectedLogger = clientLogger; + let logLevel = logsConfig.level || 'info'; + + if (url.startsWith('/api')) { + selectedLogger = apiLogger; + } else if (url.startsWith('/auth')) { + selectedLogger = authLogger; + } + + // Ne logger que si le niveau est activé + if (!logsConfig.levels || logsConfig.levels.includes(logLevel)) { + const logMessage = `[${ip}] - ${userAgent} - ${req.method} ${url}`; + selectedLogger[logLevel](logMessage); + } + + } catch (err) { + console.error('Error in logRequestInfo:', err); + } + + next(); +} + +// Middleware spécifique pour les requêtes API const logApiRequest = (req, res, next) => { - const start = Date.now(); - res.on('finish', () => { - const duration = Date.now() - start; - const ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress; - apiLogger.info(`[${ip}] - ${req.method} ${req.originalUrl} - ${res.statusCode} - ${duration}ms`); - }); - next(); + if (!req.originalUrl.startsWith('/api')) { + return next(); + } + + const start = Date.now(); + res.on('finish', () => { + try { + const setup = JSON.parse(fs.readFileSync(path.join(process.cwd(), 'data', 'setup.json'), 'utf-8'))[0]; + const logsConfig = setup.logs || { enabled: 'off' }; + + if (logsConfig.enabled !== 'on' || + (logsConfig.levels && !logsConfig.levels.includes('info'))) { + return; + } + + const duration = Date.now() - start; + const ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress; + apiLogger.info(`[${ip}] - ${req.method} ${req.originalUrl} - ${res.statusCode} - ${duration}ms`); + } catch (err) { + ErrorLogger.error(`Error in API logging: ${err.message}`); + } + }); + next(); }; +// Fonction utilitaire pour logger les erreurs système +const logSystemError = (error, context = '') => { + const errorMessage = `${context ? `[${context}] ` : ''}${error.message}`; + ErrorLogger.error(errorMessage); + if (error.stack) { + ErrorLogger.error(error.stack); + } +}; -module.exports = { logger, clientLogger, ErrorLogger, logRequestInfo, authLogger, suspiciousLogger, logApiRequest }; +// Middleware pour logger les erreurs 404 +const log404Error = (req, res, next) => { + suspiciousLogger.warn(`404 Not Found: ${req.method} ${req.originalUrl} from IP ${req.ip}`); + next(); +}; + +// Middleware pour logger les erreurs 500 +const log500Error = (error, req, res, next) => { + logSystemError(error, '500 Internal Server Error'); + next(error); +}; + +// Export des fonctionnalités +module.exports = { + logger, + clientLogger, + ErrorLogger, + authLogger, + suspiciousLogger, + apiLogger, + fileSystemLogger, + databaseLogger, + logRequestInfo, + logApiRequest, + logSystemError, + log404Error, + log500Error +}; \ No newline at end of file diff --git a/models/reportManager.js b/models/reportManager.js deleted file mode 100644 index ce60b99..0000000 --- a/models/reportManager.js +++ /dev/null @@ -1,100 +0,0 @@ -const os = require('os'); -const fs = require('fs'); -const path = require('path'); -const ip = require('ip'); -const { logger, logRequestInfo, ErrorLogger } = require('../config/logs'); -const packageJson = require('../package.json'); -const si = require('systeminformation'); -const fetch = require('node-fetch'); - -class SystemReport { - static async generate() { - const date = new Date(); - date.setDate(date.getDate() - 1); - const previousDate = date.toISOString().split('T')[0]; - - const logFile = path.join(__dirname, '..', 'logs', `log-${previousDate}.log`); - const logs = fs.readFileSync(logFile, 'utf-8'); - - const internalErrors = logs.split('\n').filter(line => /\[38;5;9mInternal-Error/.test(line)); - - if (internalErrors.length === 0) { - logger.info('No internal errors in yesterday\'s logs. No report will be generated.'); - return null; - } - - function formatUptime(uptime) { - const days = Math.floor(uptime / (24 * 60 * 60)); - uptime %= (24 * 60 * 60); - const hours = Math.floor(uptime / (60 * 60)); - uptime %= (60 * 60); - const minutes = Math.floor(uptime / 60); - return `${days}d ${hours}h ${minutes}m`; - } - - const osInfo = { - type: os.type(), - platform: os.platform(), - arch: os.arch(), - release: os.release(), - uptime: formatUptime(os.uptime()), - loadavg: os.loadavg().map(load => (load / os.cpus().length) * 100) - }; - - const networkInterfaces = os.networkInterfaces(); - const serverUptime = os.uptime(); - const systemLoad = os.loadavg(); - - const diskUsage = await si.fsSize(); - const cpuTemperature = await si.cpuTemperature(); - - const userInfo = os.userInfo(); - - const systemInfo = { - memoryInfo: ((os.totalmem() - os.freemem()) / os.totalmem() * 100).toFixed(2), - cpuInfo: (os.cpus().length / os.cpus().length * 100).toFixed(2), - diskInfo: ((os.totalmem() - os.freemem()) / os.totalmem() * 100).toFixed(2), - ipAddress: ip.address(), - cdnVersion: packageJson.version, - osInfo: osInfo, - userInfo: userInfo, - errors: internalErrors, - networkInterfaces: networkInterfaces, - serverUptime: serverUptime, - systemLoad: systemLoad, - diskUsage: diskUsage, - cpuTemperature: cpuTemperature, - }; - - const filename = path.join(__dirname, '..', 'report', `report_${previousDate}_${ip.address()}.json`); - fs.writeFileSync(filename, JSON.stringify(systemInfo, null, 2)); - - logger.info("Preparing to send report..."); - logger.info("Report:", JSON.stringify(systemInfo, null, 2)); - - - try { - const response = await fetch('https://cdn-apollon-p198-61m1.dinawo.fr/api/report/receive', { - method: 'POST', - headers: { - 'Content-Type': 'application/json' - }, - body: JSON.stringify(systemInfo) - }); - - if (!response.ok) { - throw new Error(`HTTP error! status: ${response.status}`); - } else { - const data = await response.json(); - logger.info('Report sent successfully. Response data:', data); - } - } catch (error) { - console.error(error); - logger.error('Failed to send report. Error:', error); - } - - return systemInfo; - } -} - -module.exports = SystemReport; diff --git a/package-lock.json b/package-lock.json index e15a6bf..52d567e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@cdn-app/insider-myaxrin-labs-dinawo", - "version": "1.0.0-beta.17", + "version": "1.1.0-beta.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@cdn-app/insider-myaxrin-labs-dinawo", - "version": "1.0.0-beta.17", + "version": "1.1.0-beta.1", "license": "ISC", "dependencies": { "@auth/express": "^0.5.1", @@ -256,9 +256,9 @@ } }, "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", - "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz", + "integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==", "license": "MIT", "dependencies": { "@jridgewell/set-array": "^1.2.1", @@ -454,9 +454,9 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "22.10.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.1.tgz", - "integrity": "sha512-qKgsUwfHZV2WCWLAnVP1JqnpE6Im6h3Y0+fYgMTasNQ7V++CBX5OT1as0g0f+OyubbFqhf6XVNIsmN4IIhEgGQ==", + "version": "22.10.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.2.tgz", + "integrity": "sha512-Xxr6BBRCAOQixvonOye19wnzyDiUtTeqldOOmj3CkeblonbccA12PFwlufvRdrpjXxqnmUaeiU5EOA+7s5diUQ==", "license": "MIT", "dependencies": { "undici-types": "~6.20.0" @@ -493,6 +493,15 @@ "node": ">= 0.6" } }, + "node_modules/accepts/node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/activedirectory": { "version": "0.7.2", "resolved": "https://registry.npmjs.org/activedirectory/-/activedirectory-0.7.2.tgz", @@ -827,9 +836,9 @@ } }, "node_modules/axios": { - "version": "1.7.8", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.8.tgz", - "integrity": "sha512-Uu0wb7KNqK2t5K+YQyVCLM76prD5sRFjKHbJYCP1J7JFGEQ6nN7HWn9+04LAeiJ3ji54lgS/gZCH1oxyrf1SPw==", + "version": "1.7.9", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.9.tgz", + "integrity": "sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw==", "license": "MIT", "dependencies": { "follow-redirects": "^1.15.6", @@ -1111,16 +1120,44 @@ } }, "node_modules/call-bind": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", - "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", + "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", "license": "MIT", "dependencies": { + "call-bind-apply-helpers": "^1.0.0", "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", "get-intrinsic": "^1.2.4", - "set-function-length": "^1.2.1" + "set-function-length": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.1.tgz", + "integrity": "sha512-BhYE+WDaywFg2TBWYNXAE+8B1ATnThNBqXHP5nQu0jWJdVvY2hvkpyB3qOmtmDePiS5/BDQ8wASEWGMWRG148g==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.2.tgz", + "integrity": "sha512-0lk0PHFe/uz0vl527fG9CgdE9WdafjDbCXvBbs+LUv000TVt2Jjhqbs4Jwm8gz070w8xXyEAxrPOMullsxXeGg==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "get-intrinsic": "^1.2.5" }, "engines": { "node": ">= 0.4" @@ -1346,15 +1383,6 @@ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "license": "MIT" }, - "node_modules/compression/node_modules/negotiator": { - "version": "0.6.4", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.4.tgz", - "integrity": "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -1515,9 +1543,9 @@ } }, "node_modules/daisyui": { - "version": "4.12.14", - "resolved": "https://registry.npmjs.org/daisyui/-/daisyui-4.12.14.tgz", - "integrity": "sha512-hA27cdBasdwd4/iEjn+aidoCrRroDuo3G5W9NDKaVCJI437Mm/3eSL/2u7MkZ0pt8a+TrYF3aT2pFVemTS3how==", + "version": "4.12.22", + "resolved": "https://registry.npmjs.org/daisyui/-/daisyui-4.12.22.tgz", + "integrity": "sha512-HDLWbmTnXxhE1MrMgSWjVgdRt+bVYHvfNbW3GTsyIokRSqTHonUTrxV3RhpPDjGIWaHt+ELtDCTYCtUFgL2/Nw==", "dev": true, "license": "MIT", "dependencies": { @@ -1547,9 +1575,9 @@ } }, "node_modules/debug": { - "version": "4.3.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", - "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", "license": "MIT", "dependencies": { "ms": "^2.1.3" @@ -1726,9 +1754,9 @@ } }, "node_modules/dotenv": { - "version": "16.4.5", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz", - "integrity": "sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==", + "version": "16.4.7", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz", + "integrity": "sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==", "license": "BSD-2-Clause", "engines": { "node": ">=12" @@ -1751,6 +1779,20 @@ "node": ">=0.10" } }, + "node_modules/dunder-proto": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.0.tgz", + "integrity": "sha512-9+Sj30DIu+4KvHqMfLUGLFYL2PkURSYMVXJyXe92nFRvlYq5hBjLEhblKB+vkd/WVlUYMWigiY07T91Fkk0+4A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/eastasianwidth": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", @@ -1853,6 +1895,23 @@ "node": ">= 0.6" } }, + "node_modules/engine.io/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, "node_modules/entities": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", @@ -1863,13 +1922,10 @@ } }, "node_modules/es-define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", - "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", "license": "MIT", - "dependencies": { - "get-intrinsic": "^1.2.4" - }, "engines": { "node": ">= 0.4" } @@ -1883,6 +1939,18 @@ "node": ">= 0.4" } }, + "node_modules/es-object-atoms": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.0.0.tgz", + "integrity": "sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", @@ -1920,9 +1988,9 @@ } }, "node_modules/express": { - "version": "4.21.1", - "resolved": "https://registry.npmjs.org/express/-/express-4.21.1.tgz", - "integrity": "sha512-YSFlK1Ee0/GC8QaO91tHcDxJiE/X4FbpAyQWkxAvG6AXCuR65YzK8ua6D9hvi/TzUfZMpc+BwuM1IPw8fmQBiQ==", + "version": "4.21.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz", + "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", "license": "MIT", "dependencies": { "accepts": "~1.3.8", @@ -1944,7 +2012,7 @@ "methods": "~1.1.2", "on-finished": "2.4.1", "parseurl": "~1.3.3", - "path-to-regexp": "0.1.10", + "path-to-regexp": "0.1.12", "proxy-addr": "~2.0.7", "qs": "6.13.0", "range-parser": "~1.2.1", @@ -1959,6 +2027,10 @@ }, "engines": { "node": ">= 0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/express-fileupload": { @@ -2419,16 +2491,21 @@ } }, "node_modules/get-intrinsic": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", - "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.6.tgz", + "integrity": "sha512-qxsEs+9A+u85HhllWJJFicJfPDhRmjzoYdl64aMWW9yRIJmSyxdn8IEkuIM530/7T+lv0TIHd8L6Q/ra0tEoeA==", "license": "MIT", "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "dunder-proto": "^1.0.0", + "es-define-property": "^1.0.1", "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", "function-bind": "^1.1.2", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "hasown": "^2.0.0" + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.0.0" }, "engines": { "node": ">= 0.4" @@ -2483,13 +2560,10 @@ } }, "node_modules/gopd": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.1.0.tgz", - "integrity": "sha512-FQoVQnqcdk4hVM4JN1eromaun4iuS34oStkdlLENLdpULsuQcTyXj8w7ayhuUfPwEYZ1ZOooOTT6fdA9Vmx/RA==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", "license": "MIT", - "dependencies": { - "get-intrinsic": "^1.2.4" - }, "engines": { "node": ">= 0.4" }, @@ -2570,25 +2644,10 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/has-proto": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.1.0.tgz", - "integrity": "sha512-QLdzI9IIO1Jg7f9GT1gXpPpXArAn6cS31R1eEZqz08Gc+uQ8/XiqHWt17Fiw+2p6oTTIq5GXEpQkAlA88YRl/Q==", - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.7" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", "license": "MIT", "engines": { "node": ">= 0.4" @@ -2757,9 +2816,9 @@ } }, "node_modules/is-core-module": { - "version": "2.15.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.1.tgz", - "integrity": "sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==", + "version": "2.16.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.0.tgz", + "integrity": "sha512-urTSINYfAYgcbLb0yDQ6egFm6h3Mo1DcF9EkyXSRjjzdHbsulg01qhwWuXdOoUBuTkbQ80KDboXa0vFJ+BDH+g==", "license": "MIT", "dependencies": { "hasown": "^2.0.2" @@ -3036,12 +3095,15 @@ } }, "node_modules/lilconfig": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", - "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", + "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", "license": "MIT", "engines": { - "node": ">=10" + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" } }, "node_modules/lines-and-columns": { @@ -3199,6 +3261,15 @@ "semver": "bin/semver.js" } }, + "node_modules/math-intrinsics": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.0.0.tgz", + "integrity": "sha512-4MqMiKP90ybymYvsut0CH2g4XWbfLtmlCkXmtmdcDCxNB+mQcu1w/1+L/VD7vi/PSv7X2JYV7SCcR+jiPXnQtA==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", @@ -3273,9 +3344,9 @@ } }, "node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "version": "1.53.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.53.0.tgz", + "integrity": "sha512-oHlN/w+3MQ3rba9rqFr6V/ypF10LSkdwUysQL7GkXoTgIWeV+tcXGA852TBxH+gsh8UWoyhR1hKcoMJTuWflpg==", "license": "MIT", "engines": { "node": ">= 0.6" @@ -3293,6 +3364,15 @@ "node": ">= 0.6" } }, + "node_modules/mime-types/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/mimic-response": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-4.0.0.tgz", @@ -3590,9 +3670,9 @@ } }, "node_modules/negotiator": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", - "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.4.tgz", + "integrity": "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==", "license": "MIT", "engines": { "node": ">= 0.6" @@ -3655,9 +3735,9 @@ } }, "node_modules/nodemon": { - "version": "3.1.7", - "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.7.tgz", - "integrity": "sha512-hLj7fuMow6f0lbB0cD14Lz2xNjwsyruH251Pk4t/yIitCFJbmY1myuLlHm/q06aST4jg6EgAh74PIBBrRqpVAQ==", + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.9.tgz", + "integrity": "sha512-hdr1oIb2p6ZSxu3PB2JWWYS7ZQ0qvaZsc3hK8DR8f02kRzc8rjYmxAIvdz+aYC+8F2IjNaB7HMcSDg8nQpJxyg==", "dev": true, "license": "MIT", "dependencies": { @@ -4036,9 +4116,9 @@ "license": "ISC" }, "node_modules/path-to-regexp": { - "version": "0.1.10", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz", - "integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==", + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", + "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==", "license": "MIT" }, "node_modules/pause": { @@ -4320,18 +4400,6 @@ } } }, - "node_modules/postcss-load-config/node_modules/lilconfig": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.2.tgz", - "integrity": "sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow==", - "license": "MIT", - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/antonk52" - } - }, "node_modules/postcss-load-config/node_modules/yaml": { "version": "2.6.1", "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.6.1.tgz", @@ -4654,12 +4722,12 @@ } }, "node_modules/resolve": { - "version": "1.22.8", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", - "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "version": "1.22.9", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.9.tgz", + "integrity": "sha512-QxrmX1DzraFIi9PxdG5VkRfRwIgjwyud+z/iBwfRRrVmHc+P9Q7u2lSSpQ6bjr2gy5lrqIiU9vb6iAeGf2400A==", "license": "MIT", "dependencies": { - "is-core-module": "^2.13.0", + "is-core-module": "^2.16.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, @@ -4913,15 +4981,69 @@ } }, "node_modules/side-channel": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", - "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", "license": "MIT", "dependencies": { - "call-bind": "^1.0.7", "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.4", - "object-inspect": "^1.13.1" + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" }, "engines": { "node": ">= 0.4" @@ -4995,6 +5117,23 @@ "ws": "~8.17.1" } }, + "node_modules/socket.io-adapter/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, "node_modules/socket.io-parser": { "version": "4.2.4", "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz", @@ -5008,6 +5147,40 @@ "node": ">=10.0.0" } }, + "node_modules/socket.io-parser/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/socket.io/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, "node_modules/source-map-js": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", @@ -5325,9 +5498,9 @@ } }, "node_modules/sweetalert2": { - "version": "11.14.5", - "resolved": "https://registry.npmjs.org/sweetalert2/-/sweetalert2-11.14.5.tgz", - "integrity": "sha512-8MWk5uc/r6bWhiJWkUXyEuApfXAhSCZT8FFX7pZXL7YwaPxq+9Ynhi2dUzWkOFn9jvLjKj22CXuccZ+IHcnjvQ==", + "version": "11.15.0", + "resolved": "https://registry.npmjs.org/sweetalert2/-/sweetalert2-11.15.0.tgz", + "integrity": "sha512-34Xs0CFBac6I1cGG9d+XaBqJrp0F/0prr8rMYOcU0shU/XmkGkRtlCxWNi7PdKYGw9Qf6aoEHNYicX3au37nkw==", "license": "MIT", "funding": { "type": "individual", @@ -5335,9 +5508,9 @@ } }, "node_modules/systeminformation": { - "version": "5.23.5", - "resolved": "https://registry.npmjs.org/systeminformation/-/systeminformation-5.23.5.tgz", - "integrity": "sha512-PEpJwhRYxZgBCAlWZhWIgfMTjXLqfcaZ1pJsJn9snWNfBW/Z1YQg1mbIUSWrEV3ErAHF7l/OoVLQeaZDlPzkpA==", + "version": "5.23.13", + "resolved": "https://registry.npmjs.org/systeminformation/-/systeminformation-5.23.13.tgz", + "integrity": "sha512-4Cn39sTXp7eN9rV/60aNdCXgpQ5xPcUUPIbwJjqTKj4/bNcSYtgZvFdXvZj6pRHP4h17uk6MfdMP5Fm6AK/b0Q==", "license": "MIT", "os": [ "darwin", @@ -5361,9 +5534,9 @@ } }, "node_modules/tailwindcss": { - "version": "3.4.15", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.15.tgz", - "integrity": "sha512-r4MeXnfBmSOuKUWmXe6h2CcyfzJCEk4F0pptO5jlnYSIViUkVmsawj80N5h2lO3gwcmSb4n3PuN+e+GC1Guylw==", + "version": "3.4.16", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.16.tgz", + "integrity": "sha512-TI4Cyx7gDiZ6r44ewaJmt0o6BrMCT5aK5e0rmJ/G9Xq3w7CX/5VXl/zIPEJZFUK5VEqwByyhqNPycPlvcK4ZNw==", "license": "MIT", "dependencies": { "@alloc/quick-lru": "^5.2.0", @@ -5375,7 +5548,7 @@ "glob-parent": "^6.0.2", "is-glob": "^4.0.3", "jiti": "^1.21.6", - "lilconfig": "^2.1.0", + "lilconfig": "^3.1.3", "micromatch": "^4.0.8", "normalize-path": "^3.0.0", "object-hash": "^3.0.0", diff --git a/package.json b/package.json index f2c801e..8ce3f13 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@cdn-app/insider-myaxrin-labs-dinawo", - "version": "1.0.0-beta.17", + "version": "1.1.0-beta.1", "description": "", "main": "server.js", "scripts": { diff --git a/public/css/paramadminsettingsetup.styles.css b/public/css/paramadminsettingsetup.styles.css new file mode 100644 index 0000000..c74019b --- /dev/null +++ b/public/css/paramadminsettingsetup.styles.css @@ -0,0 +1,387 @@ +@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&display=swap'); + +:root { + /* Light theme */ + --background: 0 0% 100%; + --foreground: 222.2 84% 4.9%; + --card: 0 0% 100%; + --card-foreground: 222.2 84% 4.9%; + --popover: 0 0% 100%; + --popover-foreground: 222.2 84% 4.9%; + --primary: 222.2 47.4% 11.2%; + --primary-foreground: 210 40% 98%; + --secondary: 210 40% 96.1%; + --secondary-foreground: 222.2 47.4% 11.2%; + --muted: 210 40% 96.1%; + --muted-foreground: 215.4 16.3% 46.9%; + --accent: 210 40% 96.1%; + --accent-foreground: 222.2 47.4% 11.2%; + --destructive: 0 84.2% 60.2%; + --destructive-foreground: 210 40% 98%; + --border: 214.3 31.8% 91.4%; + --input: 214.3 31.8% 91.4%; + --ring: 222.2 84% 4.9%; + --radius: 0.5rem; +} + +.dark { + /* Dark theme */ + --background: 222.2 84% 4.9%; + --foreground: 210 40% 98%; + --card: 222.2 84% 4.9%; + --card-foreground: 210 40% 98%; + --popover: 222.2 84% 4.9%; + --popover-foreground: 210 40% 98%; + --primary: 210 40% 98%; + --primary-foreground: 222.2 47.4% 11.2%; + --secondary: 217.2 32.6% 17.5%; + --secondary-foreground: 210 40% 98%; + --muted: 217.2 32.6% 17.5%; + --muted-foreground: 215 20.2% 65.1%; + --accent: 217.2 32.6% 17.5%; + --accent-foreground: 210 40% 98%; + --destructive: 0 62.8% 30.6%; + --destructive-foreground: 210 40% 98%; + --border: 217.2 32.6% 17.5%; + --input: 217.2 32.6% 17.5%; + --ring: 212.7 26.8% 83.9%; +} + +/* Base styles */ +body { + font-family: 'Inter', sans-serif; + background-color: hsl(var(--background)); + color: hsl(var(--foreground)); + transition: background-color 0.3s ease, color 0.3s ease; +} + +/* Tabs styling */ +.tabs { + display: flex; + gap: 1rem; + border-bottom: 1px solid hsl(var(--border)); + margin-bottom: 2rem; + overflow-x: auto; + padding-bottom: 0.5rem; +} + +.tab { + padding: 0.75rem 1.5rem; + border-radius: var(--radius); + cursor: pointer; + transition: all 0.3s ease; + white-space: nowrap; + display: flex; + align-items: center; + gap: 0.5rem; + background: transparent; + color: hsl(var(--foreground)); + border: none; +} + +.tab:hover { + background-color: hsl(var(--accent)); + color: hsl(var(--accent-foreground)); +} + +.tab.active { + background-color: hsl(var(--primary)); + color: hsl(var(--primary-foreground)); +} + +.tab-content { + display: none; +} + +.tab-content.active { + display: block; + animation: fadeIn 0.3s ease-out; +} + +/* Cards styling */ +.settings-card { + background-color: hsl(var(--card)); + border: 1px solid hsl(var(--border)); + border-radius: var(--radius); + padding: 1.5rem; + margin-bottom: 1.5rem; +} + +.settings-card-header { + display: flex; + align-items: center; + gap: 0.75rem; + margin-bottom: 1.5rem; +} + +.settings-card-title { + font-size: 1.25rem; + font-weight: 600; + color: hsl(var(--card-foreground)); +} + +/* Form elements */ +.form-group { + margin-bottom: 1.5rem; +} + +.form-control { + width: 100%; + padding: 0.75rem; + border-radius: var(--radius); + border: 1px solid hsl(var(--border)); + background-color: hsl(var(--background)); + color: hsl(var(--foreground)); + transition: border-color 0.3s ease; +} + +.form-control:focus { + outline: none; + border-color: hsl(var(--ring)); + box-shadow: 0 0 0 2px hsl(var(--ring) / 0.2); +} + +/* Switch toggle */ +.switch { + position: relative; + display: inline-block; + width: 3.5rem; + height: 2rem; +} + +.switch input { + opacity: 0; + width: 0; + height: 0; +} + +.slider { + position: absolute; + cursor: pointer; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: hsl(var(--muted)); + transition: .4s; + border-radius: 2rem; +} + +.slider:before { + position: absolute; + content: ""; + height: 1.5rem; + width: 1.5rem; + left: 0.25rem; + bottom: 0.25rem; + background-color: white; + transition: .4s; + border-radius: 50%; +} + +input:checked + .slider { + background-color: hsl(var(--primary)); +} + +input:checked + .slider:before { + transform: translateX(1.5rem); +} + +/* Buttons */ +.btn { + display: inline-flex; + align-items: center; + justify-content: center; + padding: 0.75rem 1.5rem; + border-radius: var(--radius); + font-weight: 500; + transition: all 0.3s ease; + cursor: pointer; + border: none; +} + +.btn-primary { + background-color: hsl(var(--primary)); + color: hsl(var(--primary-foreground)); +} + +.btn-secondary { + background-color: hsl(var(--secondary)); + color: hsl(var(--secondary-foreground)); +} + +.btn-icon { + padding: 0.5rem; + border-radius: 50%; +} + +/* IP List */ +.ip-entry { + display: flex; + gap: 0.5rem; + margin-bottom: 0.5rem; +} + +/* Path List */ +.path-entry { + display: flex; + align-items: center; + justify-content: space-between; + padding: 0.5rem 1rem; + background-color: hsl(var(--secondary)); + border-radius: var(--radius); + margin-bottom: 0.5rem; +} + +/* Log Levels */ +.log-level-btn { + padding: 0.5rem 1rem; + border-radius: var(--radius); + background-color: hsl(var(--secondary)); + color: hsl(var(--secondary-foreground)); + transition: all 0.3s ease; +} + +.log-level-btn.active { + background-color: hsl(var(--primary)); + color: hsl(var(--primary-foreground)); +} + +/* Fixed bottom bar */ +.fixed-bottom-bar { + position: fixed; + bottom: 0; + left: 0; + right: 0; + padding: 1rem; + background-color: hsl(var(--background)); + border-top: 1px solid hsl(var(--border)); + z-index: 50; +} + +/* Theme switcher */ +.theme-switcher { + position: fixed; + top: 1rem; + right: 1rem; + padding: 0.75rem; + border-radius: 50%; + background-color: hsl(var(--secondary)); + color: hsl(var(--secondary-foreground)); + cursor: pointer; + transition: all 0.3s ease; + z-index: 50; +} + +.theme-switcher:hover { + background-color: hsl(var(--accent)); +} + +/* Nested settings */ +.nested-settings { + margin-top: 1rem; + padding-left:padding-left: 1.5rem; + border-left: 2px solid hsl(var(--border)); + animation: fadeIn 0.3s ease-out; +} + +/* Animations */ +@keyframes fadeIn { + from { + opacity: 0; + transform: translateY(-10px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +@keyframes fadeOut { + from { + opacity: 1; + transform: translateY(0); + } + to { + opacity: 0; + transform: translateY(-10px); + } +} + +/* Responsive adjustments */ +@media (max-width: 768px) { + .tabs { + flex-wrap: nowrap; + overflow-x: auto; + -webkit-overflow-scrolling: touch; + padding-bottom: 0.5rem; + } + + .tab { + padding: 0.5rem 1rem; + font-size: 0.875rem; + } + + .settings-card { + padding: 1rem; + } + + .fixed-bottom-bar { + padding: 0.75rem; + } + + .btn { + padding: 0.5rem 1rem; + font-size: 0.875rem; + } +} + +/* Dark mode adjustments */ +.dark .form-control { + background-color: hsl(var(--input)); +} + +.dark .settings-card { + background-color: hsl(var(--card)); +} + +/* Utility classes */ +.hidden { + display: none; +} + +.animate { + animation: fadeIn 0.3s ease-out; +} + +.fade-out { + animation: fadeOut 0.3s ease-out forwards; +} + +/* Modal styles */ +.modal-common-paths { + position: fixed; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + background-color: hsl(var(--background)); + border: 1px solid hsl(var(--border)); + border-radius: var(--radius); + padding: 1.5rem; + max-width: 500px; + width: 90%; + max-height: 80vh; + overflow-y: auto; + z-index: 1000; + box-shadow: 0 10px 25px rgba(0, 0, 0, 0.1); +} + +.modal-overlay { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: rgba(0, 0, 0, 0.5); + z-index: 999; +} \ No newline at end of file diff --git a/public/js/dashboard.js b/public/js/dashboard.js index 75a65b4..4a9781f 100644 --- a/public/js/dashboard.js +++ b/public/js/dashboard.js @@ -725,4 +725,14 @@ document.addEventListener('DOMContentLoaded', async function() { } catch (error) { console.error('Erreur lors du chargement:', error); } +}); + +fetch('/build-metadata') +.then(response => response.json()) +.then(data => { + document.getElementById('version-number').textContent = data.build_version; +}) +.catch(error => { + console.error('Error fetching version:', error); + document.getElementById('version-number').textContent = 'Version indisponible'; }); \ No newline at end of file diff --git a/public/js/folder.js b/public/js/folder.js index 9eb1333..b5cb6ca 100644 --- a/public/js/folder.js +++ b/public/js/folder.js @@ -412,3 +412,14 @@ async function showFileInfo(fileName) { }); }); }); + + // Fetch version from build-metadata API + fetch('/build-metadata') + .then(response => response.json()) + .then(data => { + document.getElementById('version-number').textContent = data.build_version; + }) + .catch(error => { + console.error('Error fetching version:', error); + document.getElementById('version-number').textContent = 'Version indisponible'; + }); \ No newline at end of file diff --git a/public/js/paramadminsettingsetup.script.js b/public/js/paramadminsettingsetup.script.js new file mode 100644 index 0000000..746220f --- /dev/null +++ b/public/js/paramadminsettingsetup.script.js @@ -0,0 +1,682 @@ +const body = document.body; +const themeSwitcher = document.getElementById('themeSwitcher'); + +// Gestion du thème +function setTheme(theme) { + if (theme === 'dark') { + body.classList.add('dark'); + } else { + body.classList.remove('dark'); + } + localStorage.setItem('theme', theme); +} + +const savedTheme = localStorage.getItem('theme'); +if (savedTheme) { + setTheme(savedTheme); +} else if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) { + setTheme('dark'); +} + +themeSwitcher.addEventListener('click', function() { + if (body.classList.contains('dark')) { + setTheme('light'); + } else { + setTheme('dark'); + } +}); + +// Gestion des formulaires LDAP et Discord +function toggleForm(formId, checkbox) { + const form = document.getElementById(formId); + form.style.display = checkbox.checked ? 'block' : 'none'; +} + +// Fonctions pour la gestion des IPs +function addIpField() { + const ipList = document.getElementById('ipList'); + const newField = document.createElement('div'); + newField.className = 'flex items-center space-x-2 animate'; + newField.innerHTML = ` + + + `; + ipList.appendChild(newField); +} + +function removeIpField(button) { + const fieldContainer = button.parentElement; + fieldContainer.classList.add('fade-out'); + setTimeout(() => { + fieldContainer.remove(); + }, 300); +} + +// Fonctions de validation IP +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}\.){3}\d{1,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); +} + +// Gestionnaire pour le switch des logs et les niveaux +document.addEventListener('DOMContentLoaded', function() { + const logsSwitch = document.getElementById('logsEnabled'); + const logsLevelsSection = document.getElementById('logsLevelsSection'); + const logsPathsSection = document.getElementById('logsPathsSection'); + + if (logsSwitch) { + logsSwitch.addEventListener('change', function() { + const isEnabled = this.checked; + + // Activer/désactiver visuellement les sections + if (logsLevelsSection) logsLevelsSection.style.opacity = isEnabled ? '1' : '0.5'; + if (logsPathsSection) logsPathsSection.style.opacity = isEnabled ? '1' : '0.5'; + + if (!isEnabled) { + // Décocher tous les niveaux de log + document.querySelectorAll('input[name="logs[levels][]"]').forEach(checkbox => { + checkbox.checked = false; + checkbox.parentElement.classList.remove('bg-blue-600'); + checkbox.parentElement.classList.add('bg-gray-700'); + }); + } + }); + } +}); + +function toggleLogLevel(button) { + if (!document.getElementById('logsEnabled').checked) { + return; // Ne rien faire si les logs sont désactivés + } + button.classList.toggle('bg-blue-600'); + button.classList.toggle('bg-gray-700'); + const checkbox = button.querySelector('input[type="checkbox"]'); + checkbox.checked = !checkbox.checked; +} + +// Gestion du formulaire principal +async function handleFormSubmit(e) { + e.preventDefault(); + + // Validation des IPs + const ipInputs = document.querySelectorAll('input[name="allowedIps[]"]'); + let hasError = false; + + ipInputs.forEach(input => { + input.classList.remove('ip-error'); + const value = input.value.trim(); + if (value && !validateIP(value)) { + input.classList.add('ip-error'); + hasError = true; + } + }); + + if (hasError) { + Swal.fire({ + icon: 'error', + title: 'Erreur de validation', + text: 'Veuillez vérifier le format des IPs saisies' + }); + return; + } + + try { + const formData = new FormData(this); + const formObject = {}; + + // Traitement des données du formulaire + formData.forEach((value, key) => { + if (key.includes('[') && key.includes(']')) { + const parts = key.split('['); + const mainKey = parts[0]; + const subKey = parts[1].replace(']', ''); + + if (!formObject[mainKey]) { + formObject[mainKey] = {}; + } + + if (key.endsWith('[]')) { + if (!formObject[mainKey][subKey.replace('[]', '')]) { + formObject[mainKey][subKey.replace('[]', '')] = []; + } + formObject[mainKey][subKey.replace('[]', '')].push(value); + } else { + formObject[mainKey][subKey] = value; + } + } else { + formObject[key] = value; + } + }); + + // Gestion de l'état enabled/disabled des logs + formObject.logs.enabled = document.getElementById('logsEnabled')?.checked ? 'on' : 'off'; + + // Si les logs sont désactivés + if (formObject.logs.enabled === 'off') { + formObject.logs = { + enabled: 'off', + levels: [], + excludePaths: [], + includeOnly: [] + }; + } else { + // Si les logs sont activés, on s'assure d'avoir tous les champs + if (!formObject.logs.levels) formObject.logs.levels = []; + if (!formObject.logs.excludePaths) formObject.logs.excludePaths = []; + if (!formObject.logs.includeOnly) formObject.logs.includeOnly = []; + } + + + // Gérer l'état des services + if (!formObject.services) formObject.services = {}; + + // Service de nettoyage de fichiers + formObject.services.fileCleanup = { + enabled: document.getElementById('fileCleanupEnabled')?.checked ? 'on' : 'off', + ...(document.getElementById('fileCleanupEnabled')?.checked && { + schedule: document.getElementById('fileCleanupSchedule')?.value + }) + }; + + // Service de gestion des rapports + formObject.services.reportManager = { + enabled: document.getElementById('reportManagerEnabled')?.checked ? 'on' : 'off', + ...(document.getElementById('reportManagerEnabled')?.checked && { + schedule: document.getElementById('reportSchedule')?.value, + endpoint: document.getElementById('reportEndpoint')?.value + }) + }; + + // Gérer l'état de LDAP + if (!formObject.ldap) formObject.ldap = {}; + formObject.ldap.enabled = document.getElementById('ldapEnabled').checked ? 'on' : 'off'; + if (formObject.ldap.enabled === 'off') { + delete formObject.ldap.url; + delete formObject.ldap.baseDN; + delete formObject.ldap.username; + delete formObject.ldap.password; + } + + // Gérer l'état de Discord + if (!formObject.discord) formObject.discord = {}; + formObject.discord.enabled = document.getElementById('discordEnabled').checked ? 'on' : 'off'; + if (formObject.discord.enabled === 'off') { + delete formObject.discord.clientID; + delete formObject.discord.clientSecret; + delete formObject.discord.identifyURL; + delete formObject.discord.authorizedIDs; + } + + console.log('Form data to be sent:', formObject); + + const response = await fetch('/api/dpanel/dashboard/admin/update-setup', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify(formObject) + }); + + const result = await response.json(); + + if (result.success) { + Swal.fire({ + icon: 'success', + title: 'Configuration mise à jour', + text: result.message + }).then(() => { + window.location.reload(); + }); + } else { + throw new Error(result.message || 'Erreur lors de la mise à jour'); + } + } catch (error) { + console.error('Erreur:', error); + Swal.fire({ + icon: 'error', + title: 'Erreur', + text: error.message || 'Une erreur est survenue lors de la mise à jour' + }); + } +} + +function showCommonPaths(type) { + const paths = [ + '/api/', + '/auth/', + '/public/', + '/build-metadata', + '/attachments/', + '/favicon.ico', + '/dpanel/' + ]; + + const modalContent = ` +
Gérez les paramètres et la configuration de votre application
+