From 2c3d2a413724ad8c488bf6114669103905b8f109 Mon Sep 17 00:00:00 2001 From: KubaPro010 Date: Sun, 22 Mar 2026 19:11:11 +0100 Subject: [PATCH] change some stuff --- server/chat.js | 4 +- server/endpoints.js | 135 +++++++++++++++++---------------- server/index.js | 25 +++--- server/rds.js | 1 - server/storage.js | 3 +- server/tx_search.js | 10 +-- {web => views}/403.ejs | 0 {web => views}/_bwSwitch.ejs | 0 {web => views}/_components.ejs | 0 {web => views}/index.ejs | 0 {web => views}/login.ejs | 0 {web => views}/setup.ejs | 0 {web => views}/wizard.ejs | 0 13 files changed, 89 insertions(+), 89 deletions(-) rename {web => views}/403.ejs (100%) rename {web => views}/_bwSwitch.ejs (100%) rename {web => views}/_components.ejs (100%) rename {web => views}/index.ejs (100%) rename {web => views}/login.ejs (100%) rename {web => views}/setup.ejs (100%) rename {web => views}/wizard.ejs (100%) diff --git a/server/chat.js b/server/chat.js index 2ae5b39..2b0cff2 100644 --- a/server/chat.js +++ b/server/chat.js @@ -8,7 +8,7 @@ function heartbeat() { // WebSocket heartbeat helper } function createChatServer(storage) { - if (!serverConfig.webserver.chatEnabled) return null; + if (!serverConfig.webserver.chatEnabled) return; const chatWss = new WebSocket.Server({ noServer: true }); @@ -118,7 +118,7 @@ function createChatServer(storage) { clearInterval(interval); }); - return chatWss; + storage.websocket_delegation.set("/chat", chatWss); } module.exports = { createChatServer }; \ No newline at end of file diff --git a/server/endpoints.js b/server/endpoints.js index bb3fbfd..08091f3 100644 --- a/server/endpoints.js +++ b/server/endpoints.js @@ -21,15 +21,14 @@ const allPluginConfigs = require('./plugins'); router.get('/', (req, res) => { let requestIp = helpers.getIpAddress(req); - const normalizedIp = requestIp?.replace(/^::ffff:/, ''); - const ipList = (normalizedIp || '').split(',').map(ip => ip.trim()).filter(Boolean); // in case there are multiple IPs (proxy), we need to check all of them (No we don't) + const ipList = (requestIp || '').split(',').map(ip => ip.trim()).filter(Boolean); // in case there are multiple IPs (proxy), we need to check all of them (No we don't) const banEntry = serverConfig.webserver.banlist.find(banEntry => ipList.includes(banEntry[0])); if (banEntry) { const reason = banEntry[3]; res.render('403', { reason }); - logInfo(`Web client (${normalizedIp}) is banned`); + logInfo(`Web client (${requestIp}) is banned`); return; } @@ -46,7 +45,7 @@ router.get('/', (req, res) => { })); parseAudioDevice((result) => { - res.render('wizard', { + res.render('wizard', { // Magical utility wizard isAdminAuthenticated: true, videoDevices: result.audioDevices, audioDevices: result.videoDevices, @@ -123,57 +122,57 @@ router.get('/wizard', (req, res) => { }) }) - router.get('/setup', (req, res) => { - let serialPorts; - function loadConfig() { +router.get('/setup', (req, res) => { + let serialPorts; + function loadConfig() { if (fs.existsSync(configPath)) { - const configFileContents = fs.readFileSync(configPath, 'utf8'); - return JSON.parse(configFileContents); + const configFileContents = fs.readFileSync(configPath, 'utf8'); + return JSON.parse(configFileContents); } return serverConfig; - } - - if(!req.session.isAdminAuthenticated) { - res.render('login'); - return; - } - - SerialPort.list() - .then((deviceList) => { - serialPorts = deviceList.map(port => ({ - path: port.path, - friendlyName: port.friendlyName, - })); - - parseAudioDevice((result) => { - const processUptimeInSeconds = Math.floor(process.uptime()); - const formattedProcessUptime = helpers.formatUptime(processUptimeInSeconds); - - const updatedConfig = loadConfig(); // Reload the config every time - res.render('setup', { - isAdminAuthenticated: req.session.isAdminAuthenticated, - videoDevices: result.audioDevices, - 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 - tunerProfiles: tunerProfiles.map((profile) => ({ - id: profile.id, - label: profile.label, - detailsHtml: helpers.parseMarkdown(profile.details || '') - })) - }); - }); - }) - }); + } + + if(!req.session.isAdminAuthenticated) { + res.render('login'); + return; + } + + SerialPort.list() + .then((deviceList) => { + serialPorts = deviceList.map(port => ({ + path: port.path, + friendlyName: port.friendlyName, + })); + + parseAudioDevice((result) => { + const processUptimeInSeconds = Math.floor(process.uptime()); + const formattedProcessUptime = helpers.formatUptime(processUptimeInSeconds); + + const updatedConfig = loadConfig(); // Reload the config every time + res.render('setup', { + isAdminAuthenticated: req.session.isAdminAuthenticated, + videoDevices: result.audioDevices, + 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 + tunerProfiles: tunerProfiles.map((profile) => ({ + id: profile.id, + label: profile.label, + detailsHtml: helpers.parseMarkdown(profile.details || '') + })) + }); + }); + }) +}); router.get('/rds', (req, res) => { @@ -197,11 +196,11 @@ router.get('/api', (req, res) => { const loginAttempts = {}; // Format: { 'ip': { count: 1, lastAttempt: 1234567890 } } -const MAX_ATTEMPTS = 15; +const MAX_ATTEMPTS = 10; const WINDOW_MS = 15 * 60 * 1000; const authenticate = (req, res, next) => { - const ip = req.ip || req.connection.remoteAddress; + const ip = helpers.getIpAddress(req); const now = Date.now(); if (!loginAttempts[ip]) loginAttempts[ip] = { count: 0, lastAttempt: now }; @@ -226,6 +225,8 @@ const authenticate = (req, res, next) => { loginAttempts[ip].count = 0; next(); } else { + req.session.isAdminAuthenticated = false; + req.session.isTuneAuthenticated = false; loginAttempts[ip].count += 1; res.status(403).json({ message: 'Login failed. Wrong password?' }); } @@ -245,16 +246,23 @@ router.get('/logout', (req, res) => { }); router.get('/kick', (req, res) => { - const ipAddress = req.query.ip; // Terminate the WebSocket connection for the specified IP address - if(req.session.isAdminAuthenticated) helpers.kickClient(ipAddress); + if(req.session.isAdminAuthenticated) helpers.kickClient(req.query.ip); + else { + res.status(403); + return; + } setTimeout(() => { res.redirect('/setup'); }, 500); }); router.get('/addToBanlist', (req, res) => { - if (!req.session.isAdminAuthenticated) return; + if (!req.session.isAdminAuthenticated) { + res.status(403); + return; + } + const ipAddress = req.query.ip; const location = 'Unknown'; const date = Date.now(); @@ -271,7 +279,10 @@ router.get('/addToBanlist', (req, res) => { }); router.get('/removeFromBanlist', (req, res) => { - if (!req.session.isAdminAuthenticated) return; + if (!req.session.isAdminAuthenticated) { + res.status(403); + return; + } const ipAddress = req.query.ip; @@ -303,9 +314,7 @@ router.post('/saveData', (req, res) => { }); router.get('/getData', (req, res) => { - if (configExists() === false) { - res.json(serverConfig); - } + if (configExists() === false) res.json(serverConfig); if(req.session.isAdminAuthenticated) { // Check if the file exists @@ -346,9 +355,7 @@ router.get('/static_data', (req, res) => { router.get('/server_time', (req, res) => { const serverTime = new Date(); // Get current server time const serverTimeUTC = new Date(serverTime.getTime() - (serverTime.getTimezoneOffset() * 60000)); // Adjust server time to UTC - res.json({ - serverTime: serverTimeUTC, - }); + res.json({ serverTime: serverTimeUTC }); }); router.get('/ping', (req, res) => { diff --git a/server/index.js b/server/index.js index fa847ca..ea914c8 100644 --- a/server/index.js +++ b/server/index.js @@ -30,6 +30,12 @@ const wss = new WebSocket.Server({ noServer: true }); const rdsWss = new WebSocket.Server({ noServer: true }); const pluginsWss = new WebSocket.Server({ noServer: true, perMessageDeflate: true }); +storage.websocket_delegation.set("/text", wss); +storage.websocket_delegation.set("/audio", audioWss); +storage.websocket_delegation.set("/rds", rdsWss); +storage.websocket_delegation.set("/rdsspy", rdsWss); +storage.websocket_delegation.set("/data_plugins", pluginsWss); + // Get all plugins from config and find corresponding server files const plugins = findServerFiles(serverConfig.plugins); @@ -40,10 +46,7 @@ if (plugins.length > 0) { }, 3000); // Initial delay of 3 seconds for the first plugin } -const terminalWidth = readline.createInterface({ - input: process.stdin, - output: process.stdout -}).output.columns; +const terminalWidth = readline.createInterface({input: process.stdin, output: process.stdout}).output.columns; console.log('\x1b[32m' + figlet.textSync("FM-DX Webserver")); console.log('\x1b[32m\x1b[2mby Noobish @ \x1b[4mFMDX.org + KubaPro010\x1b[0m'); @@ -66,7 +69,7 @@ const sessionMiddleware = session({ }); app.use(sessionMiddleware); app.use(bodyParser.json()); -const chatWss = createChatServer(storage); +createChatServer(storage); connectToXdrd(); connectToSerial(); @@ -276,7 +279,7 @@ client.on('error', (err) => { }); app.set('view engine', 'ejs'); -app.set('views', path.join(__dirname, '../web')); +app.set('views', path.join(__dirname, '../views')); app.use('/', endpoints); const tunerLockTracker = new WeakMap(); @@ -530,15 +533,7 @@ httpServer.on('upgrade', (request, socket, head) => { return; } - var upgradeWss = undefined; - - // TODO: make it a map, so plugins can register their url if needed - if (request.url === '/text') upgradeWss = wss; - else if (request.url === '/audio') upgradeWss = audioWss; - else if (request.url === '/chat' && serverConfig.webserver.chatEnabled === true) upgradeWss = chatWss; - else if (request.url === '/rds' || request.url === '/rdsspy') upgradeWss = rdsWss; - else if (request.url === '/data_plugins') upgradeWss = pluginsWss; - + const upgradeWss = storage.websocket_delegation.get(request.url); if(upgradeWss) { sessionMiddleware(request, {}, () => { upgradeWss.handleUpgrade(request, socket, head, (ws) => { diff --git a/server/rds.js b/server/rds.js index c165ecc..59fbccb 100644 --- a/server/rds.js +++ b/server/rds.js @@ -232,7 +232,6 @@ class RDSDecoder { if(d_error > 2) return; // Don't risk it - const idx = blockB & 0x3; const last_err = this.ps_errors[idx * 2]; diff --git a/server/storage.js b/server/storage.js index aee851e..56de98b 100644 --- a/server/storage.js +++ b/server/storage.js @@ -1,4 +1,5 @@ let connectedUsers = []; let chatHistory = []; +let websocket_delegation = new Map(); -module.exports = { connectedUsers, chatHistory }; \ No newline at end of file +module.exports = { connectedUsers, chatHistory, websocket_delegation }; \ No newline at end of file diff --git a/server/tx_search.js b/server/tx_search.js index 71214de..c4ee668 100644 --- a/server/tx_search.js +++ b/server/tx_search.js @@ -26,6 +26,7 @@ const WebSocket = require('ws'); // Get weighting values based on algorithm setting. // Defaults = algorithm 1 let weightedErp = 10; +let weightedDist = 400; const algorithms = [ [10, 400], [30, 500], @@ -287,9 +288,7 @@ async function fetchTx(freq, piCode, rdsPs) { if (filteredLocations.length > 1) { // Check for any 10kW+ stations within 700km, and don't Es weight if any found. - const tropoPriority = filteredLocations.some( - loc => loc.distanceKm < 700 && loc.erp >= 10 - ); + const tropoPriority = filteredLocations.some(loc => loc.distanceKm < 700 && loc.erp >= 10); let esMode = false; if (!tropoPriority) esMode = checkEs(); for (let loc of filteredLocations) loc.score = evaluateStation(loc, esMode); @@ -297,15 +296,14 @@ async function fetchTx(freq, piCode, rdsPs) { filteredLocations.sort((a, b) => b.score - a.score); match = filteredLocations[0]; // Have a maximum of 10 extra matches and remove any with less than 1/10 of the winning score - multiMatches = filteredLocations.slice(1, 11) - .filter(obj => obj.score >= (match.score / 10)); + multiMatches = filteredLocations.slice(1, 11).filter(obj => obj.score >= (match.score / 10)); } else if (filteredLocations.length === 1) { match = filteredLocations[0]; match.score = 1; } if (match) { - if (match.itu == 'USA') { // Also known as Dumbfuckinstan. they should not go to hell, but hell+ (it is NOT better) + if (match.itu == 'USA') { // Also known as Dumbfuckinstan. they should not go to hell, but hell+ (it is NOT better). Jews have anti-semitism, but what do americans have? const state = getStateForCoordinates(match.lat, match.lon); if (state) match.state = state; // Add state to matchingCity } diff --git a/web/403.ejs b/views/403.ejs similarity index 100% rename from web/403.ejs rename to views/403.ejs diff --git a/web/_bwSwitch.ejs b/views/_bwSwitch.ejs similarity index 100% rename from web/_bwSwitch.ejs rename to views/_bwSwitch.ejs diff --git a/web/_components.ejs b/views/_components.ejs similarity index 100% rename from web/_components.ejs rename to views/_components.ejs diff --git a/web/index.ejs b/views/index.ejs similarity index 100% rename from web/index.ejs rename to views/index.ejs diff --git a/web/login.ejs b/views/login.ejs similarity index 100% rename from web/login.ejs rename to views/login.ejs diff --git a/web/setup.ejs b/views/setup.ejs similarity index 100% rename from web/setup.ejs rename to views/setup.ejs diff --git a/web/wizard.ejs b/views/wizard.ejs similarity index 100% rename from web/wizard.ejs rename to views/wizard.ejs