diff --git a/server/datahandler.js b/server/datahandler.js index d0e2291..2fac24f 100644 --- a/server/datahandler.js +++ b/server/datahandler.js @@ -272,7 +272,7 @@ function rdsReceived() { rdsTimeoutTimer = null; } if (serverConfig.webserver.rdsTimeout && serverConfig.webserver.rdsTimeout != 0) { - rdsTimeoutTimer = setInterval(rdsReset, serverConfig.webserver.rdsTimeout * 1000); + rdsTimeoutTimer = setTimeout(rdsReset, serverConfig.webserver.rdsTimeout * 1000); } } diff --git a/server/endpoints.js b/server/endpoints.js index cddcd50..87eb480 100644 --- a/server/endpoints.js +++ b/server/endpoints.js @@ -21,7 +21,7 @@ router.get('/', (req, res) => { let requestIp = req.headers['x-forwarded-for'] || req.connection.remoteAddress; const normalizedIp = requestIp?.replace(/^::ffff:/, ''); - const ipList = normalizedIp.split(',').map(ip => ip.trim()); // in case there are multiple IPs (proxy), we need to check all of them + const ipList = (normalizedIp || '').split(',').map(ip => ip.trim()).filter(Boolean); // in case there are multiple IPs (proxy), we need to check all of them const isBanned = ipList.some(ip => serverConfig.webserver.banlist.some(banEntry => banEntry[0] === ip)); @@ -140,12 +140,14 @@ router.get('/wizard', (req, res) => { audioDevices: result.videoDevices, serialPorts: serialPorts, memoryUsage: (process.memoryUsage.rss() / 1024 / 1024).toFixed(1) + ' MB', + memoryHeap: (process.memoryUsage().heapUsed / 1024 / 1024).toFixed(1) + ' MB', processUptime: formattedProcessUptime, consoleOutput: logs, plugins: allPluginConfigs, enabledPlugins: updatedConfig.plugins, onlineUsers: dataHandler.dataToSend.users, connectedUsers: storage.connectedUsers, + device: serverConfig.device, banlist: updatedConfig.webserver.banlist // Updated banlist from the latest config }); }); @@ -369,6 +371,14 @@ const logHistory = {}; function canLog(id) { const now = Date.now(); const sixtyMinutes = 60 * 60 * 1000; // 60 minutes in milliseconds + + // Remove expired entries + for (const [entryId, timestamp] of Object.entries(logHistory)) { + if ((now - timestamp) >= sixtyMinutes) { + delete logHistory[entryId]; + } + } + if (logHistory[id] && (now - logHistory[id]) < sixtyMinutes) { return false; // Deny logging if less than 60 minutes have passed } diff --git a/server/index.js b/server/index.js index c6bf156..da31ff5 100644 --- a/server/index.js +++ b/server/index.js @@ -319,59 +319,6 @@ app.set('view engine', 'ejs'); app.set('views', path.join(__dirname, '../web')); app.use('/', endpoints); -function antispamProtection(message, clientIp, ws, userCommands, lastWarn, userCommandHistory, lengthCommands, endpointName) { - const command = message.toString(); - const now = Date.now(); - if (endpointName === 'text') logDebug(`Command received from \x1b[90m${clientIp}\x1b[0m: ${command}`); - // Initialize user command history if not present - if (!userCommandHistory[clientIp]) { - userCommandHistory[clientIp] = []; - } - - // Record the current timestamp for the user - userCommandHistory[clientIp].push(now); - - // Remove timestamps older than 20 ms from the history - userCommandHistory[clientIp] = userCommandHistory[clientIp].filter(timestamp => now - timestamp <= 20); - - // Check if there are 8 or more commands in the last 20 ms - if (userCommandHistory[clientIp].length >= 8) { - logWarn(`User \x1b[90m${clientIp}\x1b[0m is spamming with rapid commands. Connection will be terminated and user will be banned.`); - - // Add to banlist if not already banned - if (!serverConfig.webserver.banlist.includes(clientIp)) { - serverConfig.webserver.banlist.push(clientIp); - logInfo(`User \x1b[90m${clientIp}\x1b[0m has been added to the banlist due to extreme spam.`); - console.log(serverConfig.webserver.banlist); - configSave(); - } - - ws.close(1008, 'Bot-like behavior detected'); - return command; // Return command value before closing connection - } - // Update the last message time for general spam detection - lastMessageTime = now; - // Initialize command history for rate-limiting checks - if (!userCommands[command]) { - userCommands[command] = []; - } - // Record the current timestamp for this command - userCommands[command].push(now); - // Remove timestamps older than 1 second - userCommands[command] = userCommands[command].filter(timestamp => now - timestamp <= 1000); - // If command count exceeds limit, close connection - if (userCommands[command].length > lengthCommands) { - if (now - lastWarn.time > 1000) { // Check if 1 second has passed - logWarn(`User \x1b[90m${clientIp}\x1b[0m is spamming command "${command}" in /${endpointName}. Connection will be terminated.`); - lastWarn.time = now; // Update the last warning time - } - ws.close(1008, 'Spamming detected'); - return command; // Return command value before closing connection - } - return command; // Return command value for normal execution -} - - /** * WEBSOCKET BLOCK */ @@ -697,50 +644,6 @@ pluginsWss.on('connection', (ws, request) => { }); }); -// Additional web socket for using plugins -pluginsWss.on('connection', (ws, request) => { - const clientIp = request.headers['x-forwarded-for'] || request.connection.remoteAddress; - const userCommandHistory = {}; - if (serverConfig.webserver.banlist?.includes(clientIp)) { - ws.close(1008, 'Banned IP'); - return; - } - // Anti-spam tracking for each client - const userCommands = {}; - let lastWarn = { time: 0 }; - - ws.on('message', message => { - // Anti-spam - const command = antispamProtection(message, clientIp, ws, userCommands, lastWarn, userCommandHistory, '10', 'data_plugins'); - - let messageData; - - try { - messageData = JSON.parse(message); // Attempt to parse the JSON - } catch (error) { - // console.error("Failed to parse message:", error); // Log the error - return; // Exit if parsing fails - } - - const modifiedMessage = JSON.stringify(messageData); - - // Broadcast the message to all other clients - pluginsWss.clients.forEach(client => { - if (client.readyState === WebSocket.OPEN) { - client.send(modifiedMessage); // Send the message to all clients - } - }); - }); - - ws.on('close', () => { - // logInfo('WebSocket Extra connection closed'); // Use custom logInfo function - }); - - ws.on('error', error => { - logError('WebSocket Extra error: ' + error); // Use custom logError function - }); -}); - function isPortOpen(host, port, timeout = 1000) { return new Promise((resolve) => { const socket = new net.Socket(); diff --git a/server/server_config.js b/server/server_config.js index fcf4290..d47d7f4 100644 --- a/server/server_config.js +++ b/server/server_config.js @@ -155,7 +155,7 @@ function configUpdate(newConfig) { function configSave() { try { fs.writeFileSync(configPath, JSON.stringify(serverConfig, null, 2)); - logInfo('Server config saved successfully.'); + setTimeout(() => logInfo('Server config saved successfully.'), 0); } catch (err) { logError(err); } diff --git a/server/tx_search.js b/server/tx_search.js index 2380cce..ef48664 100644 --- a/server/tx_search.js +++ b/server/tx_search.js @@ -31,7 +31,7 @@ if (typeof algorithms[algoSetting] !== 'undefined') { // IIFE to build the local TX DB cache from the endpoint. (async () => { try { - consoleCmd.logInfo('Fetching transmitter database...'); + setTimeout(() => consoleCmd.logInfo('Fetching transmitter database...'), 0); const response = await fetch(`https://maps.fmdx.org/api?qth=${serverConfig.identification.lat},${serverConfig.identification.lon}`); if (!response.ok) throw new Error(`HTTP error! Status: ${response.status}`); localDb = await response.json(); diff --git a/web/setup.ejs b/web/setup.ejs index 7d1b68e..c1b2e80 100644 --- a/web/setup.ejs +++ b/web/setup.ejs @@ -76,6 +76,7 @@
Memory usage