This commit is contained in:
Sebastien Riviere
2025-09-05 23:37:19 +02:00
parent 999c9a8b77
commit 93f9a05b1a
13 changed files with 356 additions and 400 deletions

View File

@@ -1,31 +1,19 @@
/*
This module manages the admin access to the server via websocket.
It receives messages, checks permissions, manages authentication and performs actions by calling functions from other modules.
This module also exposes functions to send messages via socket to all admins
*/
import { io } from "./index.js";
import game from "./game.js"
import zoneManager from "./zone_manager.js"
import { playersBroadcast, sendUpdatedTeamInformations } from "./team_socket.js";
import { createHash } from "crypto";
import { config } from "dotenv";
import game from "./game.js"
import zoneManager from "./zone_manager.js"
config();
const ADMIN_PASSWORD_HASH = process.env.ADMIN_PASSWORD_HASH;
/**
* Send a message to all logged in admin sockets
* @param {String} event The event name
* @param {String} data The data to send
*/
export function secureAdminBroadcast(event, data) {
loggedInSockets.forEach(s => {
io.of("admin").to(s).emit(event, data);
});
}
// Array of logged in sockets
let loggedInSockets = [];
export function initAdminSocketHandler() {
@@ -33,52 +21,63 @@ export function initAdminSocketHandler() {
console.log("Connection of an admin");
let loggedIn = false;
socket.on("disconnect", () => {
console.log("Disconnection of an admin");
const login = (password) => {
if (loggedIn) return false;
if (createHash('sha256').update(password).digest('hex') !== ADMIN_PASSWORD_HASH) return false;
loggedInSockets.push(socket.id);
loggedIn = true;
return true;
}
const logout = () => {
if (!loggedIn) return false;
loggedInSockets = loggedInSockets.filter(s => s !== socket.id);
loggedIn = false;
return true;
}
socket.on("disconnect", () => {
console.log("Disconnection of an admin");
logout();
});
socket.on("logout", () => {
loggedInSockets = loggedInSockets.filter(s => s !== socket.id);
loggedIn = false;
})
socket.on("login", (password) => {
const hash = createHash('sha256').update(password).digest('hex');
if (hash === ADMIN_PASSWORD_HASH && !loggedIn) {
loggedInSockets.push(socket.id);
loggedIn = true;
socket.emit("teams", game.teams);
socket.emit("game_state", {
state: game.state,
date: game.stateDate
});
socket.emit("current_zone", {
begin: zoneManager.getCurrentZone(),
end: zoneManager.getNextZone(),
endDate: zoneManager.currentZoneEndDate,
});
socket.emit("settings", game.getSettings());
}
logout();
});
socket.on("update_settings", (settings) => {
if (!loggedIn) return;
game.changeSettings(settings);
secureAdminBroadcast("settings", game.getSettings());
})
socket.on("login", (password) => {
if (!login(password)) return;
socket.emit("teams", game.teams);
socket.emit("game_state", {
state: game.state,
date: game.stateDate
});
socket.emit("current_zone", {
begin: zoneManager.getCurrentZone(),
end: zoneManager.getNextZone(),
endDate: zoneManager.currentZoneEndDate,
});
socket.emit("settings", game.getSettings());
});
socket.on("add_team", (teamName) => {
if (!loggedIn) return;
game.addTeam(teamName);
secureAdminBroadcast("teams", game.teams);
});
socket.on("remove_team", (teamId) => {
if (!loggedIn) return;
game.removeTeam(teamId);
secureAdminBroadcast("teams", game.teams);
});
socket.on("reorder_teams", (newOrder) => {
if (!loggedIn) return;
game.reorderTeams(newOrder);
});
socket.on("capture_team", (teamId, newTeam) => {
if (!loggedIn) return;
game.captureTeam(teamId, newTeam);
});
socket.on("change_state", (state) => {
@@ -86,22 +85,9 @@ export function initAdminSocketHandler() {
game.setState(state);
});
// Use is sending a new list containing the new order of the teams
// Note that we never check if the new order contains the same teams as the old order, so it behaves more like a setTeams function
// But the frontend should always send the same teams in a different order
socket.on("reorder_teams", (newOrder) => {
socket.on("update_settings", (settings) => {
if (!loggedIn) return;
game.reorderTeams(newOrder);
secureAdminBroadcast("teams", game.teams);
game.teams.forEach(t => sendUpdatedTeamInformations(t.id));
game.changeSettings(settings);
});
socket.on("update_team", (teamId, newTeam) => {
if (!loggedIn) return;
game.updateTeam(teamId, newTeam);
secureAdminBroadcast("teams", game.teams);
sendUpdatedTeamInformations(teamId);
sendUpdatedTeamInformations(game.getTeam(teamId).chased);
})
});
}