You've already forked fm-dx-webserver
mirror of
https://github.com/KubaPro010/fm-dx-webserver.git
synced 2026-02-26 22:13:53 +01:00
sync to upstream
This commit is contained in:
@@ -3,12 +3,19 @@ const { serverConfig } = require('./server_config');
|
||||
const { logChat } = require('./console');
|
||||
const helpers = require('./helpers');
|
||||
|
||||
function heartbeat() { // WebSocket heartbeat helper
|
||||
this.isAlive = true;
|
||||
}
|
||||
|
||||
function createChatServer(storage) {
|
||||
if (!serverConfig.webserver.chatEnabled) return null;
|
||||
|
||||
const chatWss = new WebSocket.Server({ noServer: true });
|
||||
|
||||
chatWss.on('connection', (ws, request) => {
|
||||
ws.isAlive = true;
|
||||
ws.on('pong', heartbeat);
|
||||
|
||||
const clientIp = request.headers['x-forwarded-for'] || request.socket.remoteAddress;
|
||||
const userCommandHistory = {};
|
||||
|
||||
@@ -25,19 +32,18 @@ function createChatServer(storage) {
|
||||
ws.send(JSON.stringify(historyMessage));
|
||||
});
|
||||
|
||||
const ipMessage = {
|
||||
ws.send(JSON.stringify({
|
||||
type: 'clientIp',
|
||||
ip: clientIp,
|
||||
admin: request.session?.isAdminAuthenticated
|
||||
};
|
||||
}));
|
||||
|
||||
ws.send(JSON.stringify(ipMessage));
|
||||
|
||||
const userCommands = {};
|
||||
let lastWarn = { time: 0 };
|
||||
|
||||
ws.on('message', (message) => {
|
||||
helpers.antispamProtection(
|
||||
message = helpers.antispamProtection(
|
||||
message,
|
||||
clientIp,
|
||||
ws,
|
||||
@@ -45,9 +51,12 @@ function createChatServer(storage) {
|
||||
lastWarn,
|
||||
userCommandHistory,
|
||||
'5',
|
||||
'chat'
|
||||
'chat',
|
||||
512
|
||||
);
|
||||
|
||||
if(!message) return;
|
||||
|
||||
let messageData;
|
||||
|
||||
try {
|
||||
@@ -57,8 +66,6 @@ function createChatServer(storage) {
|
||||
return;
|
||||
}
|
||||
|
||||
console.log("Chat message:", messageData);
|
||||
|
||||
delete messageData.admin;
|
||||
delete messageData.ip;
|
||||
delete messageData.time;
|
||||
@@ -90,6 +97,25 @@ function createChatServer(storage) {
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
ws.on('close', () => {
|
||||
ws.isAlive = false;
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* We will not always be receiving data, so some proxies may terminate the connection, this prevents it.
|
||||
*/
|
||||
const interval = setInterval(() => {
|
||||
chatWss.clients.forEach((ws) => {
|
||||
if (ws.isAlive === false) return ws.terminate();
|
||||
ws.isAlive = false;
|
||||
ws.ping();
|
||||
});
|
||||
}, 30000);
|
||||
|
||||
chatWss.on('close', () => {
|
||||
clearInterval(interval);
|
||||
});
|
||||
|
||||
return chatWss;
|
||||
|
||||
@@ -250,12 +250,18 @@ function checkLatency(host, port = 80, timeout = 2000) {
|
||||
});
|
||||
}
|
||||
|
||||
function antispamProtection(message, clientIp, ws, userCommands, lastWarn, userCommandHistory, lengthCommands, endpointName) {
|
||||
const command = message.toString();
|
||||
function antispamProtection(message, clientIp, ws, userCommands, lastWarn, userCommandHistory, lengthCommands, endpointName, maxPayloadSize = 1024 * 1024) {
|
||||
const rawCommand = message.toString();
|
||||
const command = rawCommand.replace(/[\r\n]+/g, '');
|
||||
const now = Date.now();
|
||||
const normalizedClientIp = clientIp?.replace(/^::ffff:/, '');
|
||||
if (endpointName === 'text') consoleCmd.logDebug(`Command received from \x1b[90m${clientIp}\x1b[0m: ${command}`);
|
||||
|
||||
if (command.length > maxPayloadSize) {
|
||||
consoleCmd.logWarn(`Command from \x1b[90m${normalizedClientIp}\x1b[0m on \x1b[90m/${endpointName}\x1b[0m exceeded maximum payload size (${parseInt(command.length / 1024)} KB / ${parseInt(maxPayloadSize / 1024)} KB).`);
|
||||
return "";
|
||||
}
|
||||
|
||||
// Initialize user command history if not present
|
||||
if (!userCommandHistory[clientIp]) userCommandHistory[clientIp] = [];
|
||||
|
||||
|
||||
@@ -356,7 +356,7 @@ wss.on('connection', (ws, request) => {
|
||||
let lastWarn = { time: 0 };
|
||||
|
||||
ws.on('message', (message) => {
|
||||
const command = helpers.antispamProtection(message, clientIp, ws, userCommands, lastWarn, userCommandHistory, '18', 'text');
|
||||
const command = helpers.antispamProtection(message, clientIp, ws, userCommands, lastWarn, userCommandHistory, '18', 'text', 16 * 1024);
|
||||
|
||||
if (!clientIp.includes("127.0.0.1")) {
|
||||
if (((command.startsWith('X') || command.startsWith('Y')) && !request.session.isAdminAuthenticated) ||
|
||||
|
||||
BIN
web/favicon.png
BIN
web/favicon.png
Binary file not shown.
|
Before Width: | Height: | Size: 5.9 KiB |
24
web/favicon.svg
Normal file
24
web/favicon.svg
Normal file
@@ -0,0 +1,24 @@
|
||||
<svg width="128" height="128" viewBox="0 0 128 128"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
|
||||
<!-- Outer hollow circle -->
|
||||
<circle
|
||||
cx="64"
|
||||
cy="64"
|
||||
r="54"
|
||||
fill="none"
|
||||
stroke="#A7A88B"
|
||||
stroke-width="20"
|
||||
/>
|
||||
|
||||
<!-- Inner hollow circle -->
|
||||
<circle
|
||||
cx="64"
|
||||
cy="64"
|
||||
r="22"
|
||||
fill="none"
|
||||
stroke="#FFFFFF"
|
||||
stroke-width="18"
|
||||
/>
|
||||
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 382 B |
@@ -15,7 +15,7 @@
|
||||
<script src="js/libs/chartjs-adapter-luxon.umd.min.js"></script>
|
||||
<script src="js/libs/chartjs-plugin-streaming.min.js"></script>
|
||||
|
||||
<link rel="icon" type="image/png" href="favicon.png" />
|
||||
<link rel="icon" type="image/svg+xml" href="favicon.svg" id="favicon" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
|
||||
<meta property="og:title" content="FM-DX WebServer [<%= tunerName %>]">
|
||||
|
||||
@@ -75,6 +75,27 @@ function getQueryParameter(name) {
|
||||
return urlParams.get(name);
|
||||
}
|
||||
|
||||
function updateFavicon(color) {
|
||||
function rgbToHex(rgb) {
|
||||
const result = rgb.match(/\d+/g);
|
||||
return "#" + result.slice(0, 3).map(x =>(+x).toString(16).padStart(2, "0")).join("");
|
||||
}
|
||||
|
||||
const hex = rgbToHex(color);
|
||||
|
||||
const svg = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 128 128">
|
||||
<circle cx="64" cy="64" r="54" fill="none" stroke="${hex}" stroke-width="20"/>
|
||||
<circle cx="64" cy="64" r="22" fill="none" stroke="white" stroke-width="18"/>
|
||||
</svg>`;
|
||||
|
||||
const base64 = btoa(svg);
|
||||
|
||||
$('#favicon').attr(
|
||||
'href',
|
||||
`data:image/svg+xml;base64,${base64}`
|
||||
);
|
||||
}
|
||||
|
||||
function setTheme(themeName) {
|
||||
const themeColors = themes[themeName];
|
||||
if (themeColors) {
|
||||
@@ -94,6 +115,7 @@ function setTheme(themeName) {
|
||||
$(':root').css('--color-text', themeColors[2]);
|
||||
$(':root').css('--color-text-2', textColor2);
|
||||
$('.wrapper-outer').css('background-color', backgroundColorWithOpacity);
|
||||
updateFavicon(themeColors[1]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<script src="js/libs/jquery.min.js"></script>
|
||||
<link href="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.4/leaflet.min.css" type="text/css" rel="stylesheet">
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.4/leaflet.min.js"></script>
|
||||
<link rel="icon" type="image/png" href="favicon.png" />
|
||||
<link rel="icon" type="image/svg+xml" href="favicon.svg" id="favicon" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
</head>
|
||||
<body>
|
||||
@@ -16,7 +16,7 @@
|
||||
<div class="wrapper-outer wrapper-full">
|
||||
<div id="wrapper">
|
||||
<div class="panel-100 no-bg">
|
||||
<img class="top-25" src="favicon.png" height="64px">
|
||||
<img class="top-25" src="favicon.svg" height="64px">
|
||||
<p>You are currently not logged in as an administrator and therefore can't change the settings.</p>
|
||||
<p>Please login below.</p>
|
||||
</div>
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<script src="js/libs/jquery.min.js"></script>
|
||||
<link href="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.4/leaflet.min.css" type="text/css" rel="stylesheet">
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.4/leaflet.min.js"></script>
|
||||
<link rel="icon" type="image/png" href="favicon.png" />
|
||||
<link rel="icon" type="image/svg+xml" href="favicon.svg" id="favicon" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<script src="js/libs/jquery.min.js"></script>
|
||||
<link href="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.4/leaflet.min.css" type="text/css" rel="stylesheet">
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.4/leaflet.min.js"></script>
|
||||
<link rel="icon" type="image/png" href="favicon.png" />
|
||||
<link rel="icon" type="image/svg+xml" href="favicon.svg" id="favicon" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
Reference in New Issue
Block a user