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
chat modularization
This commit is contained in:
121
server/chat.js
Normal file
121
server/chat.js
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
const WebSocket = require('ws');
|
||||||
|
const { serverConfig } = require('./server_config');
|
||||||
|
const { logChat } = require('./console');
|
||||||
|
const helpers = require('./helpers');
|
||||||
|
|
||||||
|
function createChatServer(storage) {
|
||||||
|
if (!serverConfig.webserver.chatEnabled) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const chatWss = new WebSocket.Server({ noServer: true });
|
||||||
|
|
||||||
|
chatWss.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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send chat history safely
|
||||||
|
storage.chatHistory.forEach((message) => {
|
||||||
|
const historyMessage = { ...message, history: true };
|
||||||
|
|
||||||
|
if (!request.session?.isAdminAuthenticated) {
|
||||||
|
delete historyMessage.ip;
|
||||||
|
}
|
||||||
|
|
||||||
|
ws.send(JSON.stringify(historyMessage));
|
||||||
|
});
|
||||||
|
|
||||||
|
const ipMessage = {
|
||||||
|
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,
|
||||||
|
clientIp,
|
||||||
|
ws,
|
||||||
|
userCommands,
|
||||||
|
lastWarn,
|
||||||
|
userCommandHistory,
|
||||||
|
'5',
|
||||||
|
'chat'
|
||||||
|
);
|
||||||
|
|
||||||
|
let messageData;
|
||||||
|
|
||||||
|
try {
|
||||||
|
messageData = JSON.parse(message);
|
||||||
|
} catch {
|
||||||
|
ws.send(JSON.stringify({ error: "Invalid message format" }));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("Chat message:", messageData);
|
||||||
|
|
||||||
|
delete messageData.admin;
|
||||||
|
delete messageData.ip;
|
||||||
|
delete messageData.time;
|
||||||
|
|
||||||
|
if (messageData.nickname != null) {
|
||||||
|
messageData.nickname = helpers.escapeHtml(String(messageData.nickname));
|
||||||
|
}
|
||||||
|
|
||||||
|
messageData.ip = clientIp;
|
||||||
|
|
||||||
|
const now = new Date();
|
||||||
|
messageData.time =
|
||||||
|
String(now.getHours()).padStart(2, '0') +
|
||||||
|
":" +
|
||||||
|
String(now.getMinutes()).padStart(2, '0');
|
||||||
|
|
||||||
|
if (serverConfig.webserver.banlist?.includes(clientIp)) return;
|
||||||
|
|
||||||
|
if (request.session?.isAdminAuthenticated === true) {
|
||||||
|
messageData.admin = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (messageData.nickname?.length > 32) {
|
||||||
|
messageData.nickname = messageData.nickname.substring(0, 32);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (messageData.message?.length > 255) {
|
||||||
|
messageData.message = messageData.message.substring(0, 255);
|
||||||
|
}
|
||||||
|
|
||||||
|
storage.chatHistory.push(messageData);
|
||||||
|
if (storage.chatHistory.length > 50) {
|
||||||
|
storage.chatHistory.shift();
|
||||||
|
}
|
||||||
|
|
||||||
|
logChat(messageData);
|
||||||
|
|
||||||
|
chatWss.clients.forEach((client) => {
|
||||||
|
if (client.readyState === WebSocket.OPEN) {
|
||||||
|
const responseMessage = { ...messageData };
|
||||||
|
|
||||||
|
if (!request.session?.isAdminAuthenticated) {
|
||||||
|
delete responseMessage.ip;
|
||||||
|
}
|
||||||
|
|
||||||
|
client.send(JSON.stringify(responseMessage));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return chatWss; // ← VERY IMPORTANT
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = { createChatServer };
|
||||||
@@ -9,7 +9,6 @@ const app = express();
|
|||||||
const httpServer = http.createServer(app);
|
const httpServer = http.createServer(app);
|
||||||
const WebSocket = require('ws');
|
const WebSocket = require('ws');
|
||||||
const wss = new WebSocket.Server({ noServer: true, perMessageDeflate: true });
|
const wss = new WebSocket.Server({ noServer: true, perMessageDeflate: true });
|
||||||
const chatWss = new WebSocket.Server({ noServer: true });
|
|
||||||
const rdsWss = new WebSocket.Server({ noServer: true });
|
const rdsWss = new WebSocket.Server({ noServer: true });
|
||||||
const pluginsWss = new WebSocket.Server({ noServer: true, perMessageDeflate: true });
|
const pluginsWss = new WebSocket.Server({ noServer: true, perMessageDeflate: true });
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
@@ -19,6 +18,7 @@ const client = new net.Socket();
|
|||||||
const { SerialPort } = require('serialport');
|
const { SerialPort } = require('serialport');
|
||||||
const audioServer = require('./stream/3las.server');
|
const audioServer = require('./stream/3las.server');
|
||||||
const tunnel = require('./tunnel');
|
const tunnel = require('./tunnel');
|
||||||
|
const { createChatServer } = require('./chat');
|
||||||
|
|
||||||
// File imports
|
// File imports
|
||||||
const helpers = require('./helpers');
|
const helpers = require('./helpers');
|
||||||
@@ -90,6 +90,8 @@ console.log('\x1b[32m\x1b[2mby Noobish @ \x1b[4mFMDX.org\x1b[0m');
|
|||||||
console.log("v" + pjson.version)
|
console.log("v" + pjson.version)
|
||||||
console.log('\x1b[90m' + '─'.repeat(terminalWidth - 1) + '\x1b[0m');
|
console.log('\x1b[90m' + '─'.repeat(terminalWidth - 1) + '\x1b[0m');
|
||||||
|
|
||||||
|
|
||||||
|
const chatWss = createChatServer(storage);
|
||||||
// Start ffmpeg
|
// Start ffmpeg
|
||||||
require('./stream/index');
|
require('./stream/index');
|
||||||
require('./plugins');
|
require('./plugins');
|
||||||
@@ -580,84 +582,6 @@ wss.on('connection', (ws, request) => {
|
|||||||
ws.on('error', console.error);
|
ws.on('error', console.error);
|
||||||
});
|
});
|
||||||
|
|
||||||
// CHAT WEBSOCKET BLOCK
|
|
||||||
chatWss.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;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Send chat history to the newly connected client
|
|
||||||
storage.chatHistory.forEach(function(message) {
|
|
||||||
message.history = true;
|
|
||||||
!request.session.isAdminAuthenticated ? delete message.ip : null;
|
|
||||||
ws.send(JSON.stringify(message));
|
|
||||||
});
|
|
||||||
|
|
||||||
const ipMessage = {
|
|
||||||
type: 'clientIp',
|
|
||||||
ip: clientIp,
|
|
||||||
admin: request.session.isAdminAuthenticated
|
|
||||||
};
|
|
||||||
ws.send(JSON.stringify(ipMessage));
|
|
||||||
|
|
||||||
// Anti-spam tracking for each client
|
|
||||||
const userCommands = {};
|
|
||||||
let lastWarn = { time: 0 };
|
|
||||||
|
|
||||||
ws.on('message', function incoming(message) {
|
|
||||||
// Anti-spam
|
|
||||||
const command = helpers.antispamProtection(message, clientIp, ws, userCommands, lastWarn, userCommandHistory, '5', 'chat');
|
|
||||||
|
|
||||||
let messageData;
|
|
||||||
|
|
||||||
try {
|
|
||||||
messageData = JSON.parse(message);
|
|
||||||
} catch (error) {
|
|
||||||
ws.send(JSON.stringify({ error: "Invalid message format" }));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Escape nickname and other potentially unsafe fields
|
|
||||||
if (messageData.nickname) {
|
|
||||||
messageData.nickname = helpers.escapeHtml(messageData.nickname);
|
|
||||||
}
|
|
||||||
|
|
||||||
messageData.ip = clientIp;
|
|
||||||
const currentTime = new Date();
|
|
||||||
|
|
||||||
const hours = String(currentTime.getHours()).padStart(2, '0');
|
|
||||||
const minutes = String(currentTime.getMinutes()).padStart(2, '0');
|
|
||||||
messageData.time = `${hours}:${minutes}`; // Adding current time to the message object in hours:minutes format
|
|
||||||
|
|
||||||
if (serverConfig.webserver.banlist?.includes(clientIp)) { return; }
|
|
||||||
if (request.session.isAdminAuthenticated === true) { messageData.admin = true; }
|
|
||||||
if (messageData.message.length > 255) { messageData.message = messageData.message.substring(0, 255); }
|
|
||||||
|
|
||||||
storage.chatHistory.push(messageData);
|
|
||||||
if (storage.chatHistory.length > 50) { storage.chatHistory.shift(); }
|
|
||||||
logChat(messageData);
|
|
||||||
|
|
||||||
chatWss.clients.forEach(function each(client) {
|
|
||||||
if (client.readyState === WebSocket.OPEN) {
|
|
||||||
// Only include IP for admin clients
|
|
||||||
let responseMessage = { ...messageData };
|
|
||||||
|
|
||||||
if (request.session.isAdminAuthenticated !== true) {
|
|
||||||
delete responseMessage.ip;
|
|
||||||
}
|
|
||||||
|
|
||||||
const modifiedMessage = JSON.stringify(responseMessage);
|
|
||||||
client.send(modifiedMessage);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
ws.on('close', function close() {});
|
|
||||||
});
|
|
||||||
|
|
||||||
// Additional web socket for using plugins
|
// Additional web socket for using plugins
|
||||||
pluginsWss.on('connection', (ws, request) => {
|
pluginsWss.on('connection', (ws, request) => {
|
||||||
const clientIp = request.headers['x-forwarded-for'] || request.connection.remoteAddress;
|
const clientIp = request.headers['x-forwarded-for'] || request.connection.remoteAddress;
|
||||||
@@ -739,7 +663,7 @@ httpServer.on('upgrade', (request, socket, head) => {
|
|||||||
logWarn('[Audio WebSocket] Audio server not ready — dropping client connection.');
|
logWarn('[Audio WebSocket] Audio server not ready — dropping client connection.');
|
||||||
socket.destroy();
|
socket.destroy();
|
||||||
}
|
}
|
||||||
} else if (request.url === '/chat') {
|
} else if (request.url === '/chat' && serverConfig.webserver.chatEnabled === true) {
|
||||||
sessionMiddleware(request, {}, () => {
|
sessionMiddleware(request, {}, () => {
|
||||||
chatWss.handleUpgrade(request, socket, head, (ws) => {
|
chatWss.handleUpgrade(request, socket, head, (ws) => {
|
||||||
chatWss.emit('connection', ws, request);
|
chatWss.emit('connection', ws, request);
|
||||||
|
|||||||
Reference in New Issue
Block a user