new chat window, bugfixes, component update

This commit is contained in:
Marek Farkaš
2025-04-22 21:23:11 +02:00
parent 79e4205612
commit 008441f93a
19 changed files with 286 additions and 150 deletions
+27 -4
View File
@@ -179,21 +179,44 @@ router.get('/api', (req, res) => {
});
const loginAttempts = {}; // Format: { 'ip': { count: 1, lastAttempt: 1234567890 } }
const MAX_ATTEMPTS = 25;
const WINDOW_MS = 15 * 60 * 1000;
const authenticate = (req, res, next) => {
const ip = req.ip || req.connection.remoteAddress;
const now = Date.now();
if (!loginAttempts[ip]) {
loginAttempts[ip] = { count: 0, lastAttempt: now };
} else if (now - loginAttempts[ip].lastAttempt > WINDOW_MS) {
loginAttempts[ip] = { count: 0, lastAttempt: now };
}
if (loginAttempts[ip].count >= MAX_ATTEMPTS) {
return res.status(403).json({
message: 'Too many login attempts. Please try again later.'
});
}
const { password } = req.body;
// Check if the entered password matches the admin password
loginAttempts[ip].lastAttempt = now;
if (password === serverConfig.password.adminPass) {
req.session.isAdminAuthenticated = true;
req.session.isTuneAuthenticated = true;
logInfo('User from ' + req.connection.remoteAddress + ' logged in as an administrator.');
logInfo(`User from ${ip} logged in as an administrator.`);
loginAttempts[ip].count = 0;
next();
} else if (password === serverConfig.password.tunePass) {
req.session.isAdminAuthenticated = false;
req.session.isTuneAuthenticated = true;
logInfo('User from ' + req.connection.remoteAddress + ' logged in with tune permissions.');
logInfo(`User from ${ip} logged in with tune permissions.`);
loginAttempts[ip].count = 0;
next();
} else {
loginAttempts[ip].count += 1;
res.status(403).json({ message: 'Login failed. Wrong password?' });
}
};
+2 -1
View File
@@ -132,6 +132,7 @@ function fetchBannedAS(callback) {
function processConnection(clientIp, locationInfo, currentUsers, ws, callback) {
const options = { year: "numeric", month: "numeric", day: "numeric", hour: "2-digit", minute: "2-digit" };
const connectionTime = new Date().toLocaleString([], options);
const normalizedClientIp = clientIp?.replace(/^::ffff:/, '');
fetchBannedAS((error, bannedAS) => {
if (error) {
@@ -155,7 +156,7 @@ function processConnection(clientIp, locationInfo, currentUsers, ws, callback) {
});
consoleCmd.logInfo(
`Web client \x1b[32mconnected\x1b[0m (${clientIp}) \x1b[90m[${currentUsers}]\x1b[0m Location: ${userLocation}`
`Web client \x1b[32mconnected\x1b[0m (${normalizedClientIp}) \x1b[90m[${currentUsers}]\x1b[0m Location: ${userLocation}`
);
callback("User allowed");
+2 -1
View File
@@ -388,6 +388,7 @@ wss.on('connection', (ws, request) => {
const output = serverConfig.xdrd.wirelessConnection ? client : serialport;
let clientIp = request.headers['x-forwarded-for'] || request.connection.remoteAddress;
const userCommandHistory = {};
const normalizedClientIp = clientIp?.replace(/^::ffff:/, '');
if (serverConfig.webserver.banlist?.includes(clientIp)) {
ws.close(1008, 'Banned IP');
@@ -509,7 +510,7 @@ wss.on('connection', (ws, request) => {
}
if (code !== 1008) {
logInfo(`Web client \x1b[31mdisconnected\x1b[0m (${clientIp}) \x1b[90m[${currentUsers}]`);
logInfo(`Web client \x1b[31mdisconnected\x1b[0m (${normalizedClientIp}) \x1b[90m[${currentUsers}]`);
}
});
+27 -12
View File
@@ -87,14 +87,11 @@ async function fetchTx(freq, piCode, rdsPs) {
const now = Date.now();
freq = parseFloat(freq);
if (isNaN(freq)) {
return;
}
if (isNaN(freq)) return;
if (now - lastFetchTime < fetchInterval
|| serverConfig.identification.lat.length < 2
|| freq < 87
|| (currentPiCode == piCode && currentRdsPs == rdsPs))
{
|| (currentPiCode == piCode && currentRdsPs == rdsPs)) {
return Promise.resolve();
}
@@ -107,15 +104,33 @@ async function fetchTx(freq, piCode, rdsPs) {
const url = "https://maps.fmdx.org/api/?freq=" + freq;
try {
const response = await fetch(url, { redirect: 'manual' });
if (!response.ok) throw new Error(`HTTP error! Status: ${response.status}`);
const data = await response.json();
// Try POST first
const postResponse = await fetch(url, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ freq }), // You can omit or customize this
redirect: 'manual'
});
if (!postResponse.ok) throw new Error(`POST failed: ${postResponse.status}`);
const data = await postResponse.json();
cachedData[freq] = data;
if(serverConfig.webserver.rdsMode == true) await loadUsStatesGeoJson();
if (serverConfig.webserver.rdsMode === true) await loadUsStatesGeoJson();
return processData(data, piCode, rdsPs);
} catch (error) {
console.error("Error fetching data:", error);
return null; // Return null to indicate failure
} catch (postError) {
console.warn("POST failed, trying GET:", postError);
try {
const getResponse = await fetch(url, { redirect: 'manual' });
if (!getResponse.ok) throw new Error(`GET failed: ${getResponse.status}`);
const data = await getResponse.json();
cachedData[freq] = data;
if (serverConfig.webserver.rdsMode === true) await loadUsStatesGeoJson();
return processData(data, piCode, rdsPs);
} catch (getError) {
console.error("GET also failed:", getError);
return null;
}
}
}