diff --git a/.gitignore b/.gitignore index 80bc381..3ea2906 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,3 @@ -node_modules -package-lock.json -config.js .envrc .direnv diff --git a/package.json b/package.json deleted file mode 100644 index 0d668e7..0000000 --- a/package.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "name": "traque", - "version": "0.0.1", - "description": "appli pour la traque", - "dependencies": { - "socket.io": "^4.5.2" - } -} diff --git a/sample_config.js b/sample_config.js deleted file mode 100644 index 05a20e7..0000000 --- a/sample_config.js +++ /dev/null @@ -1,23 +0,0 @@ -// Configuration file for the server - -conscrits = ["team00", "team01"]; -vieux = ["npc0", "npc1"]; - -// return 0 for conscrit, 1 for vieux, 2 otherwise -function validator(id){ - if(conscrits.includes(id)) return 0; - if(vieux.includes(id)) return 1; - return 2; -} - -module.exports = { - "port": 9000, - "http_port": 9001, - "key": "certif/server.key", - "cert": "certif/server.crt", - "validator": validator, - - // Offset for the randomization of the blurred status - "lat_ofs": 0.0005, - "long_ofs": 0.0005, -} diff --git a/traque.js b/traque.js deleted file mode 100644 index 3ed1320..0000000 --- a/traque.js +++ /dev/null @@ -1,392 +0,0 @@ -/* struct equipe -{ - "id" : string, - "pos" : [lat : float, long : float], - "vieux": bool, - "state" : { - "invisibilty" : bool, - "blurred": bool, - "tracker" : bool, - "npc" : int, - "mallette": bool - }, - "codes" : { - "invisiblity" : int, - "blurred" : int - } -} - -Les messages à transmettre par le client : -- position, HTTP "/log?id=%ID&lat=%LAT&lon=%LON" -- use(code) -- (vieux) changeState (state) -Les messages à transmettre par le serveur : -- moving(id, color, position) -- setCodes(codes) -- (vieux) newState(state) -*/ - -// require = include -var https = require('https'); -var http = require('http'); -var url = require('url'); -var fs = require('fs'); -var config = require('./config.js'); - -// Textes d'interaction avec les conscrits -const MSG_BAD = "Code Incorrect"; -const MSG_TRACKED = "Vous êtes maintenant traqué.e.s !" -const MSG_TRACKER = "Vous pouvez maintenant traquer !"; -const MSG_CODES = { - blurred: "Votre positions est maintenant brouillée !", - invisibility: "Les autres équipes ne peuvent plus vous voir !" -}; -const bonus_delay = 10000;// 3*60*1000; - -var equipes = {}; - -console.log("Setup https server"); - -const option = { - key: fs.readFileSync(config.key), - cert: fs.readFileSync(config.cert) -}; - -function replaceAll_legacy(data, pattern, replacement){ - var replacing = data.replace(pattern, replacement); - while(replacing != data){ - data = replacing; - replacing = data.replace(pattern, replacement); - } - return data; -} - -// The server -var server = https.createServer(option, function(req, res){ - var q = url.parse(req.url, true); - var filename = "static" + q.pathname; - if(q.pathname.includes("..")) - filename = "static/dotdot.html"; - - if(q.pathname.startsWith("/tracking/")){ - id = q.pathname.substring("/tracking/".length); - gpslog = true; - if(id.startsWith("nolog/")){ - gpslog = false; - id = id.substring("nolog/".length); - } - var end_path = ["conscrit.html", "vieux.html", "invalid.html"][config.validator(id)]; - filename = "static/tracking/" + end_path; - return fs.readFile(filename, 'utf8', function(err, data){ - if(err) - throw new Error("where " + end_path + " is !?"); - - res.writeHead(200, {'Content-Type': 'text/html'}); - res.write(replaceAll_legacy(replaceAll_legacy(data, "%GPSLOG", gpslog), "%ID", id)); - return res.end(); - }); - } - - if(q.pathname == "/log"){ - //position logging - console.log("team " + q.query.id + " moved to (" + q.query.lat + "," + q.query.lon + ")"); - - var id = q.query.id; - if(id in equipes){ - equipes[id].pos = [q.query.lat, q.query.lon]; - emit_update(id); - } - - //return empty page - res.writeHead(200, {'Content-Type': 'text/html'}); - return res.end(); - } - fs.readFile(filename, function(err, data) { - if (err) { - console.log("404: ", q.pathname, filename); - res.writeHead(404, {'Content-Type': 'text/html'}); - return res.end("404 Not Found"); - } - if(filename.endsWith('.js')) - res.writeHead(200, {'Content-Type': 'text/javascript'}); - else if(filename.endsWith('.png')) - res.writeHead(200, {'Content-Type': 'image/png'}); - else if(filename.endsWith('.ico')) - res.writeHead(200, {'Content-Type': 'image/ico'}); - else - res.writeHead(200, {'Content-Type': 'text/html'}); - res.write(data); - return res.end(); - }); -}); - -console.log("Setup http redirection"); -//HTTP -> HTTPS redirect -var redirect_server = http.createServer(function(req, res){ - var url = `https://${req.headers.host.split(":")[0]}:${config.port}${req.url}`; - res.writeHead(301,{Location: url}); - res.end(); -}); - -console.log("Setup io server"); -const { Server } = require("socket.io"); -var io = new Server(server); - -io.use(function(socket, next){ - var id = socket.handshake.auth.id; - var type = socket.handshake.auth.type; - - if(type == "Admin") - next(); - else{ - var valid = config.validator(id); - if(valid == 0 && type == "conscrit" || - valid == 1 && type == "vieux"){ - if(!(id in equipes)){ - equipes[id] = default_team(id, valid); - emit_update(id); - } - next(); - } else - next(new Error("invalid")); - } -}); - -async function join_leave(team_id, join, leave){ - var sockets = await io.in(team_id).fetchSockets(); - for(s of sockets){ - for(r of join) - s.join(r); - for(r of leave) - s.leave(r); - } -} - -///////////////// -// Tracking room -// -// Everyone in this room is located -// sub-rooms : -// * "npc" room for non-player -// * "Tracker" room for trackers -// * "mallette" room for player with a mallette -// * "%ID" room of a team -// -// To join : -// auth = { -// type = "conscrit" | "vieux", -// id = "%ID" -// } -// "conscrit" are classical player, "vieux" are npcs (they can become tracker when needed) -var tracking = io.to("Tracking"); -var tracker = io.to("Tracker"); -var mallette = io.to("mallette"); - -///////////////// -// Admin room -// -// Room for admins -// To join : -// auth = { -// type = "Admin" -// } -var admin = io.to("Admin"); - -// visible color of a team -function color(team){ - if(team.state.tracker) return 1; - if(team.state.npc != 0) return team.state.npc - 0 + 2; - return 0; -} - -function admin_color(team){ - if(team.state.invisibility) return 2; - if(team.state.tracker) return 1; - if(team.state.npc != 0) return team.state.npc - 0 + 2; - return 0; -} - -// apparent information of a team, for tracker only -function apparent_info_tracker(equipe){ - if(equipe.state.invisibility) - return {"id": equipe.id, "color": color(equipe), "position": [0,0]}; - if(equipe.state.blurred) - return {"id": equipe.id, "color": color(equipe), - "position": [parseFloat(equipe.pos[0])+config.lat_ofs*(Math.random()*2-1), - parseFloat(equipe.pos[1])+config.long_ofs*(Math.random()*2-1)]}; - return {"id": equipe.id, "color": color(equipe), "position": equipe.pos}; -} - -// apparent information of a team, for mallette only -function apparent_info_mallette(equipe){ - if(equipe.state.npc == 0 && !equipe.state.tracker) - return {"id": equipe.id, "color": color(equipe), "position": equipe.pos}; - return apparent_info_agent(equipe); -} - -// apparent information of a team, for agent only -function apparent_info_agent(equipe){ - if(equipe.state.mallette) - return {"id": equipe.id, "color": color(equipe), "position": equipe.pos}; - if(equipe.state.npc == 0 && !equipe.state.tracker) - return {"id": equipe.id, "color": color(equipe), "position": [0,0]}; - return apparent_info_tracker(equipe); -} - -function emit_update(team_id) { - var equipe = equipes[team_id]; - tracker.except(team_id).emit('moving', apparent_info_tracker(equipe)); - mallette.except(team_id).emit('moving', apparent_info_mallette(equipe)); - tracking.except("Tracker").except("mallette").except(team_id).emit('moving', apparent_info_agent(equipe)); - - // the team, the npcs and the admins always have the real informations - admin.to("npc").to(team_id) - .emit('moving', {"id": team_id, "color": admin_color(equipe), "position": equipe.pos}); - admin.emit('update', equipe); -} - -// produces a team object populated with default values -function default_team(team_id, valid) { - var state = {}; - state.invisibility = valid != 0; - state.blurred = false; - state.tracker = false; - state.npc = valid; - state.mallette = false; - - var codes = {}; - codes.blurred = 0; - codes.invisibility = 0; - - var equipe = {}; - equipe.state = state; - equipe.codes = codes; - equipe.vieux = valid == 1; - equipe.pos = [0,0]; - equipe.id = team_id; - return equipe; -} - -function send_update(team){ - io.to(team.id).emit('moving', {"id": team.id, "color": color(team), "position": team.pos}); - for(other_id in equipes) - if(other_id != team.id){ - if(team.state.tracker) - io.to(team.id).emit('moving', apparent_info_tracker(equipes[other_id])); - else if(team.state.mallette) - io.to(team.id).emit('moving', apparent_info_mallette(equipes[other_id])); - else if(team.state.npc != 0) - io.to(team.id).emit('moving', {"id": other_id, "color": admin_color(equipes[other_id]), "position": equipes[other_id].pos}); - else - io.to(team.id).emit('moving', apparent_info_agent(equipes[other_id])); - } -} - -// connect a socket to the room corresponding to its team and send it infos -function team_join(team, socket){ - socket.join(team.id); - socket.emit('moving', {"id": team.id, "color": color(team), "position": team.pos}); - for(other_id in equipes) - if(other_id != team.id){ - if(team.state.tracker) - socket.emit('moving', apparent_info_tracker(equipes[other_id])); - else if(team.state.mallette) - socket.emit('moving', apparent_info_mallette(equipes[other_id])); - else if(team.state.npc != 0) - socket.emit('moving', {"id": other_id, "color": admin_color(equipes[other_id]), "position": equipes[other_id].pos}); - else - socket.emit('moving', apparent_info_agent(equipes[other_id])); - } -} - -console.log("Setup handlers"); -io.on('connection', function(socket){ - if(socket.handshake.auth.type == "conscrit") { - var id = socket.handshake.auth.id; - var equipe = equipes[id] - socket.join("Tracking"); - if(equipe.state.tracker) - socket.join("Tracker"); - if(equipe.state.mallette) - socket.join("mallette"); - team_join(equipe, socket); - - socket.on("useCode", function(code){ - if(code in equipe.codes && equipe.codes[code] > 0){ - equipe.codes[code] -= 1; - equipe.state[code] = true; - io.to(id).emit('popup', {content: MSG_CODES[code]}); - io.to(id).emit('setCodes', equipe.codes); - emit_update(id); - setTimeout(function(eq, c){ - eq.state[c] = false; - emit_update(eq.id); - }, bonus_delay, equipe, code); - } - }); - } - - if(socket.handshake.auth.type == "vieux"){ - var id = socket.handshake.auth.id; - var equipe = equipes[id] - socket.join("npc"); - team_join(equipe, socket); - - socket.on('changeState', function(d){ - equipe.state = d; - io.to(id).emit('newState', d); - emit_update(id); - }); - - socket.emit('newState', equipe.state); - } - - if(socket.handshake.auth.type == "Admin"){ - socket.join("Admin"); - - socket.on('newCode', function(d){ - equipes[d.id].codes[d.code] += 1; - io.to(d.id).emit('setCodes', equipes[d.id].codes); - admin.emit('update', equipes[d.id]); - }); - - socket.on('popup', function(d){ - tracking.emit('popup', {"content": d.content}); - }); - - socket.on('newTracker', function(d){ - io.emit('newTracker', d); - }); - - socket.on('setState', function(d){ - equipes[d.id].state = d.state; - var join = []; - var leave = []; - if(d.state.tracker) - join.push("Tracker"); - else - leave.push("Tracker"); - if(d.state.mallette){ - join.push("mallette"); - } else{ - leave.push("mallette"); - } - join_leave(d.id, join, leave); - send_update(equipes[d.id]); - emit_update(d.id); - if(equipes[d.id].vieux) - io.to(d.id).emit('newState', d.state); - }); - - for(i in equipes){ - var equipe = equipes[i]; - socket.emit('moving', {"id": equipe.id, "color": color(equipe), "position": equipe.pos}); - socket.emit('update', equipe); - } - } -}); - -console.log("Launch server"); -server.listen(config.port, "::"); -redirect_server.listen(config.http_port, "::"); -console.log("Running !");