From 49c6e08b98622357ca259490a3ae3abea67f0923 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Marek=20Farka=C5=A1?=
Date: Sat, 11 Jan 2025 20:30:57 +0100
Subject: [PATCH] banlist & config fixes
---
package.json | 2 +-
server/endpoints.js | 58 +++++++++++++---
server/helpers.js | 15 ++--
server/server_config.js | 29 +++++---
web/css/breadcrumbs.css | 4 ++
web/css/helpers.css | 4 ++
web/js/init.js | 4 +-
web/js/setup.js | 49 +++++++++++++
web/setup.ejs | 148 ++++++----------------------------------
9 files changed, 157 insertions(+), 156 deletions(-)
diff --git a/package.json b/package.json
index d2e9fb3..2e21a9a 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "fm-dx-webserver",
- "version": "1.3.2",
+ "version": "1.3.3",
"description": "FM DX Webserver",
"main": "index.js",
"scripts": {
diff --git a/server/endpoints.js b/server/endpoints.js
index 094f1ac..d9518d2 100644
--- a/server/endpoints.js
+++ b/server/endpoints.js
@@ -19,7 +19,10 @@ const { allPluginConfigs } = require('./plugins');
// Endpoints
router.get('/', (req, res) => {
let requestIp = req.headers['x-forwarded-for'] || req.connection.remoteAddress;
- if(serverConfig.webserver.banlist.includes(requestIp)) {
+ const normalizedIp = requestIp.replace(/^::ffff:/, '');
+ const isBanned = serverConfig.webserver.banlist.some(banEntry => banEntry[0] === normalizedIp);
+
+ if (isBanned) {
res.render('403');
logInfo(`Web client (${requestIp}) is banned`);
return;
@@ -164,7 +167,12 @@ router.get('/rdsspy', (req, res) => {
router.get('/api', (req, res) => {
const { ps_errors, rt0_errors, rt1_errors, ims, eq, ant, st_forced, previousFreq, txInfo, ...dataToSend } = dataHandler.dataToSend;
- res.json(dataToSend);
+ res.json({
+ ...dataToSend,
+ txInfo: txInfo,
+ ps_errors: ps_errors,
+ ant: ant
+ });
});
@@ -212,16 +220,47 @@ router.get('/kick', (req, res) => {
});
router.get('/addToBanlist', (req, res) => {
- const ipAddress = req.query.ip; // Extract the IP address parameter from the query string
- // Terminate the WebSocket connection for the specified IP address
- if(req.session.isAdminAuthenticated) {
- helpers.kickClient(ipAddress);
+ const ipAddress = req.query.ip;
+ const location = 'Unknown';
+ const date = Date.now();
+ const reason = req.query.reason;
+
+ userBanData = [ipAddress, location, date, reason];
+
+ if (typeof serverConfig.webserver.banlist !== 'object') {
+ serverConfig.webserver.banlist = [];
+ }
+
+ if (req.session.isAdminAuthenticated) {
+ serverConfig.webserver.banlist.push(userBanData);
+ configSave();
+ res.json({ success: true, message: 'IP address added to banlist.' });
+ helpers.kickClient(ipAddress);
+ } else {
+ res.status(403).json({ success: false, message: 'Unauthorized access.' });
}
- setTimeout(() => {
- res.redirect('/setup');
- }, 500);
});
+router.get('/removeFromBanlist', (req, res) => {
+ const ipAddress = req.query.ip;
+
+ if (typeof serverConfig.webserver.banlist !== 'object') {
+ serverConfig.webserver.banlist = [];
+ }
+
+ const banIndex = serverConfig.webserver.banlist.findIndex(ban => ban[0] === ipAddress);
+
+ if (banIndex === -1) {
+ return res.status(404).json({ success: false, message: 'IP address not found in banlist.' });
+ }
+
+ serverConfig.webserver.banlist.splice(banIndex, 1);
+ configSave();
+
+ res.json({ success: true, message: 'IP address removed from banlist.' });
+});
+
+
router.post('/saveData', (req, res) => {
const data = req.body;
let firstSetup;
@@ -290,6 +329,7 @@ router.get('/static_data', (req, res) => {
rdsMode: serverConfig.webserver.rdsMode || false,
tunerName: serverConfig.identification.tunerName || '',
tunerDesc: serverConfig.identification.tunerDesc || '',
+ ant: serverConfig.antennas || {}
});
});
diff --git a/server/helpers.js b/server/helpers.js
index c2f3f7b..4bbf442 100644
--- a/server/helpers.js
+++ b/server/helpers.js
@@ -181,12 +181,15 @@ function antispamProtection(message, clientIp, ws, userCommands, lastWarn, userC
if (userCommandHistory[clientIp].length >= 8) {
consoleCmd.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);
- consoleCmd.logInfo(`User \x1b[90m${clientIp}\x1b[0m has been added to the banlist due to extreme spam.`);
- configSave();
- }
+ // Check if the normalized IP is already in the banlist
+ const isAlreadyBanned = serverConfig.webserver.banlist.some(banEntry => banEntry[0] === normalizedClientIp);
+
+ if (!isAlreadyBanned) {
+ // Add the normalized IP to the banlist
+ serverConfig.webserver.banlist.push([normalizedClientIp, 'Unknown', Date.now(), '[Auto ban] Spam']);
+ consoleCmd.logInfo(`User \x1b[90m${normalizedClientIp}\x1b[0m has been added to the banlist due to extreme spam.`);
+ configSave();
+ }
ws.close(1008, 'Bot-like behavior detected');
return command; // Return command value before closing connection
diff --git a/server/server_config.js b/server/server_config.js
index 02c77af..4142841 100644
--- a/server/server_config.js
+++ b/server/server_config.js
@@ -8,7 +8,7 @@ let configName = 'config';
const index = process.argv.indexOf('--config');
if (index !== -1 && index + 1 < process.argv.length) {
configName = process.argv[index + 1];
- logInfo('Loading with a custom config file:', configName + '.json')
+ logInfo('Loading with a custom config file:', configName + '.json');
}
const configPath = path.join(__dirname, '../' + configName + '.json');
@@ -99,16 +99,19 @@ let serverConfig = {
lockToAdmin: false,
autoShutdown: false,
enableDefaultFreq: false,
- defaultFreq: "87.5"
+ defaultFreq: "87.5",
+ testThing: "yes it works"
};
-function deepMerge(target, source)
-{
+function deepMerge(target, source) {
Object.keys(source).forEach(function(key) {
- if (typeof target[key] === 'object' && target[key] !== null) {
- deepMerge(target[key], source[key]);
+ if (typeof source[key] === 'object' && source[key] !== null) {
+ if (!target[key]) target[key] = {}; // Create missing object
+ deepMerge(target[key], source[key]); // Recursively merge
} else {
- target[key] = source[key];
+ if (target[key] === undefined) {
+ target[key] = source[key]; // Add missing fields
+ }
}
});
}
@@ -124,7 +127,6 @@ function configUpdate(newConfig) {
deepMerge(serverConfig, newConfig);
}
-
function configSave() {
fs.writeFile(configPath, JSON.stringify(serverConfig, null, 2), (err) => {
if (err) {
@@ -139,9 +141,16 @@ function configExists() {
return fs.existsSync(configPath);
}
-if (fs.existsSync(configPath)) {
+if (configExists()) {
const configFileContents = fs.readFileSync(configPath, 'utf8');
- serverConfig = JSON.parse(configFileContents);
+ try {
+ const configFile = JSON.parse(configFileContents);
+ deepMerge(configFile, serverConfig);
+ serverConfig = configFile;
+ configSave();
+ } catch (err) {
+ logError('Error parsing config file:', err);
+ }
}
module.exports = {
diff --git a/web/css/breadcrumbs.css b/web/css/breadcrumbs.css
index 72a64ad..f53d1dc 100644
--- a/web/css/breadcrumbs.css
+++ b/web/css/breadcrumbs.css
@@ -112,6 +112,10 @@ label {
margin-right: 5px;
}
+table .form-group {
+ margin: 0;
+}
+
#settings, #back-btn, #users-online-container {
background: transparent;
border: 0;
diff --git a/web/css/helpers.css b/web/css/helpers.css
index f269f30..1b48c71 100644
--- a/web/css/helpers.css
+++ b/web/css/helpers.css
@@ -210,6 +210,10 @@
background-color: var(--color-2) !important;
}
+table .input-text {
+ background-color: var(--color-1) !important;
+}
+
.pointer {
cursor: pointer;
}
diff --git a/web/js/init.js b/web/js/init.js
index 3c66a94..8a62a34 100644
--- a/web/js/init.js
+++ b/web/js/init.js
@@ -1,9 +1,9 @@
-var currentDate = new Date('Nov 5, 2024 21:00:00');
+var currentDate = new Date('Jan 11, 2025 21:00:00');
var day = currentDate.getDate();
var month = currentDate.getMonth() + 1; // Months are zero-indexed, so add 1
var year = currentDate.getFullYear();
var formattedDate = day + '/' + month + '/' + year;
-var currentVersion = 'v1.3.2 [' + formattedDate + ']';
+var currentVersion = 'v1.3.3 [' + formattedDate + ']';
getInitialSettings();
removeUrlParameters();
diff --git a/web/js/setup.js b/web/js/setup.js
index 3424a4b..43d6edb 100644
--- a/web/js/setup.js
+++ b/web/js/setup.js
@@ -9,6 +9,7 @@ $(document).ready(function() {
showPanelFromHash();
initNav();
+ initBanlist();
});
/**
@@ -85,6 +86,54 @@ function initNav() {
});
}
+function initBanlist() {
+ $('.banlist-add').on('click', function(e) {
+ e.preventDefault();
+
+ const ipAddress = $('#banlist-add-ip').val();
+ const reason = $('#banlist-add-reason').val();
+
+ $.ajax({
+ url: '/addToBanlist',
+ method: 'GET',
+ data: { ip: ipAddress, reason: reason },
+ success: function(response) {
+ // Refresh the page if the request was successful
+ if (response.success) {
+ location.reload();
+ } else {
+ console.error('Failed to add to banlist');
+ }
+ },
+ error: function() {
+ console.error('Error occurred during the request');
+ }
+ });
+});
+
+$('.banlist-remove').on('click', function(e) {
+ e.preventDefault();
+
+ const ipAddress = $(this).closest('tr').find('td').first().text();
+
+ $.ajax({
+ url: '/removeFromBanlist',
+ method: 'GET',
+ data: { ip: ipAddress },
+ success: function(response) {
+ if (response.success) {
+ location.reload();
+ } else {
+ console.error('Failed to remove from banlist');
+ }
+ },
+ error: function() {
+ console.error('Error occurred during the request');
+ }
+ });
+});
+}
+
function toggleNav() {
const navOpen = $("#navigation").css('margin-left') === '0px';
const isMobile = window.innerWidth <= 768;
diff --git a/web/setup.ejs b/web/setup.ejs
index 5afa6a4..5e74f1a 100644
--- a/web/setup.ejs
+++ b/web/setup.ejs
@@ -101,7 +101,11 @@
<% if (connectedUsers.length > 0) { %>
<% connectedUsers.forEach(user => { %>
- <%= user.ip %>
+
+
+ <%= user.ip.replace('::ffff:', '') %>
+
+
<%= user.location %>
<%= user.time %>
Kick
@@ -288,23 +292,6 @@
RDS Mode
You can switch between American (RBDS) / Global (RDS) mode here.
<%- include('_components', {component: 'checkbox', cssClass: 'bottom-20', iconClass: '', label: 'American RDS mode (RBDS)', id: 'webserver-rdsMode'}) %>
-<<<<<<< HEAD
-
-
-
Chat options
- <%- include('_components', {component: 'checkbox', cssClass: '', label: 'Chat', id: 'webserver-chatEnabled'}) %>
-
-
-
-
Banlist
-
If you have users that don't behave on your server, you can choose to ban them by their IP address.
- You can see their IP address by hovering over their nickname. One IP per row.
-
- Banned users:
-
-
-
-=======
@@ -324,7 +311,6 @@
<% }); %>
Download new plugins here!
->>>>>>> 4b6d011 (rewrite update)
@@ -444,98 +430,6 @@
-
-
Tuner settings
-
-
-
Device type
- <%- include('_components', { component: 'dropdown', id: 'device-selector', inputId: 'device', label: 'Device', cssClass: '', placeholder: 'TEF668x / TEA685x',
- options: [
- { value: 'tef', label: 'TEF668x / TEA685x' },
- { value: 'xdr', label: 'XDR (F1HD / S10HDiP)' },
- { value: 'sdr', label: 'SDR (RTL-SDR / AirSpy)' },
- { value: 'other', label: 'Other' }
- ]
- }) %>
-
-
-
-
-
Connection type
-
If you want to choose the COM port directly, choose "Direct". If you use xdrd or your receiver is connected via Wi-Fi, choose TCP/IP.
-
-
-
-
Device / Server
-
-
-
Choose your desired COM port
- <%- include('_components', {
- component: 'dropdown',
- id: 'deviceList',
- inputId: 'xdrd-comPort',
- label: 'USB Device',
- cssClass: '',
- placeholder: 'Choose your USB device',
- options: serialPorts.map(serialPort => ({
- value: serialPort.path,
- label: `${serialPort.path} - ${serialPort.friendlyName}`
- }))
- }) %>
-
-
-<<<<<<< HEAD
-
-
If you are connecting your tuner wirelessly , enter the tuner IP. If you use xdrd , use 127.0.0.1 as your IP.
- <%- include('_components', {component: 'text', cssClass: 'w-150', label: 'xdrd IP address', id: 'xdrd-xdrdIp'}) %>
- <%- include('_components', {component: 'text', cssClass: 'w-100', label: 'xdrd port', id: 'xdrd-xdrdPort'}) %>
- <%- include('_components', {component: 'text', cssClass: 'w-150', label: 'xdrd password', id: 'xdrd-xdrdPassword', password: true}) %>
-
-
-
-
-
-
Startup
-
Startup volume
-
-
-
-
-
-
-
Default frequency
- <%- include('_components', {component: 'checkbox', cssClass: '', label: 'Default frequency for first client', id: 'enableDefaultFreq'}) %>
- <%- include('_components', {component: 'text', cssClass: 'w-100', placeholder: '87.5', label: 'Default frequency', id: 'defaultFreq'}) %>
-
-
-
Miscellaneous
-
-
-
Bandwidth switch
-
Bandwidth switch allows the user to set the bandwidth manually.
- <%- include('_components', {component: 'checkbox', cssClass: '', label: 'Bandwidth switch', id: 'bwSwitch'}) %>
-
-
-
Automatic shutdown
-
Toggling this option will put the tuner to sleep when no clients are connected.
- <%- include('_components', {component: 'checkbox', cssClass: '', label: 'Auto-shutdown', id: 'autoShutdown'}) %>
-
-
-
-
-
-
-=======
->>>>>>> 4b6d011 (rewrite update)
Identification & Map
@@ -578,16 +472,6 @@
-<<<<<<< HEAD
-
+
+ <%- include('_components', {component: 'text', cssClass: 'w-100', placeholder: 'IP address', label: '', id: 'banlist-add-ip'}) %>
+
+
+ <%- include('_components', {component: 'text', cssClass: 'w-150', placeholder: 'Ban reason (note)', label: '', id: 'banlist-add-reason'}) %>
+
+
+
+
<% if (banlist.length > 0) { %>
<% banlist.forEach(bannedUser => { %>
<% if (Array.isArray(bannedUser)) { %>
- <%= bannedUser[0] %>
+ <%= bannedUser[0] %>
<%= bannedUser[1] %>
- <%= new Date(parseInt(bannedUser[2]) * 1000).toLocaleString() %>
+ <%= new Date(parseInt(bannedUser[2])).toLocaleString() %>
<%= bannedUser[3] %>
<% } else { %>
- <%= bannedUser %>
+ <%= bannedUser %>
Unknown
Unknown
Unknown
<% } %>
-
+
<% }); %>
<% } else { %>
- The banlist is empty.
+ The banlist is empty.
<% } %>
@@ -648,7 +541,6 @@
Your server also needs to have a valid UUID, which is obtained by registering on maps in the Identification & Map tab.
<%- include('_components', {component: 'checkbox', cssClass: 'm-right-10', label: 'FMLIST integration', id: 'extras-fmlistIntegration'}) %>
->>>>>>> 4b6d011 (rewrite update)
You can also fill in your OMID from FMLIST.org, if you want the logs to be saved to your account.
<%- include('_components', {component: 'text', cssClass: 'w-100', placeholder: '', label: 'OMID', id: 'extras-fmlistOmid'}) %>