snakeia-server 1.1.3-7 → 1.1.4-1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/Dockerfile CHANGED
@@ -1,4 +1,4 @@
1
- FROM node:20-alpine
1
+ FROM node:22-alpine
2
2
  RUN addgroup -S snakeia-server && adduser -S snakeia-server -G snakeia-server && chown -R snakeia-server:snakeia-server /home/snakeia-server
3
3
  RUN apk add git
4
4
  WORKDIR /home/snakeia-server/server
package/README.md CHANGED
@@ -8,7 +8,7 @@ A server for my [SnakeIA](https://github.com/Eliastik/snakeia) game, written in
8
8
 
9
9
  ## About this server
10
10
 
11
- * Version 1.1.3.7 (9/19/2024)
11
+ * Version 1.1.4.1 (1/1/2025)
12
12
  * Made in France by Eliastik - [eliastiksofts.com](http://eliastiksofts.com) - Contact : [eliastiksofts.com/contact](http://eliastiksofts.com/contact)
13
13
  * License: GNU GPLv3 (see LICENCE.txt file)
14
14
 
@@ -74,9 +74,10 @@ You can create another configuration file in the **config** directory named **lo
74
74
  ````
75
75
  {
76
76
  "ServerConfig": {
77
- "version": "1.1.3.7", // The server version
77
+ "version": "1.1.4.1", // The server version
78
78
  "port": 3000, // The port where the server runs
79
- "proxyMode": false, // Set this value to true if your server is behind a proxy - defaults to false
79
+ "proxyMode": false, // Sets this value to true if your server is behind a proxy - defaults to false
80
+ "numberOfProxies": 1, // Sets the number of reverse proxies in front of the server. Default to 1. See: https://expressjs.com/en/guide/behind-proxies.html / https://express-rate-limit.mintlify.app/guides/troubleshooting-proxy-issues
80
81
  "enableMultithreading": true, // Enabling the use of different threads for the game engine, improves performance / requires a version of Nodejs that supports Worker Threads
81
82
  "maxPlayers": 20, // The maximum number of players for each room
82
83
  "maxRooms": 20, // The maximum number of room
@@ -119,6 +120,17 @@ You can create another configuration file in the **config** directory named **lo
119
120
 
120
121
  ## Changelog
121
122
 
123
+ * Version 1.1.4.1 (1/1/2024):
124
+ - Updated dependencies
125
+
126
+ * Version 1.1.4 (11/23/2024):
127
+ - Switched to csrf-csrf library instead of csurf (no longer maintained) for CSRF protection
128
+ - Added "numberOfProxies" parameter (default 1) to server configuration file
129
+ - Updated dependencies
130
+
131
+ * Version 1.1.3.8 (9/29/2024) :
132
+ - Updated dependencies
133
+
122
134
  * Version 1.1.3.7 (9/19/2024) :
123
135
  - Updated dependencies
124
136
 
@@ -170,7 +182,7 @@ Un serveur pour mon jeu [SnakeIA](https://github.com/Eliastik/snakeia), écrit e
170
182
 
171
183
  ## À propos de ce serveur
172
184
 
173
- * Version 1.1.3.7 (19/09/2024)
185
+ * Version 1.1.4.1 (1/1/2025)
174
186
  * Made in France by Eliastik - [eliastiksofts.com](http://eliastiksofts.com) - Contact : [eliastiksofts.com/contact](http://eliastiksofts.com/contact)
175
187
  * Licence : GNU GPLv3 (voir le fichier LICENCE.txt)
176
188
 
@@ -236,9 +248,10 @@ Vous pouvez créer un fichier de configuration **local.json** dans le dossier **
236
248
  ````
237
249
  {
238
250
  "ServerConfig": {
239
- "version": "1.1.3.7", // La version du serveur
251
+ "version": "1.1.4.1", // La version du serveur
240
252
  "port": 3000, // Le port sur lequel lancer le server
241
253
  "proxyMode": false, // Mettez à true si votre serveur est derrière un proxy - par défaut false
254
+ "numberOfProxies": 1, // Configure le nombre de proxies devant votre serveur. Par défaut 1. Voir : https://expressjs.com/en/guide/behind-proxies.html / https://express-rate-limit.mintlify.app/guides/troubleshooting-proxy-issues
242
255
  "enableMultithreading": true, // Activer l'utilisation de threads différents pour le moteur de jeu, améliore les performances / nécessite une version de Nodejs qui supporte les Worker Threads
243
256
  "maxPlayers": 20, // Le nombre maximal d'utilisateurs par salle
244
257
  "maxRooms": 20, // Le nombre maximal de salles
@@ -281,6 +294,17 @@ Vous pouvez créer un fichier de configuration **local.json** dans le dossier **
281
294
 
282
295
  ## Journal des changements
283
296
 
297
+ * Version 1.1.4.1 (1/1/2025) :
298
+ - Mise à jour des dépendences
299
+
300
+ * Version 1.1.4 (23/11/2024) :
301
+ - Passage à la bibliothèque logicielle csrf-csrf au lieu de csurf (qui n'était plus maintenue) pour la protection CSRF
302
+ - Ajout du paramètre "numberOfProxies" (par défaut à 1) dans le fichier de configuration du serveur
303
+ - Mise à jour des dépendences
304
+
305
+ * Version 1.1.3.8 (29/09/2024) :
306
+ - Mise à jour des dépendences
307
+
284
308
  * Version 1.1.3.7 (19/09/2024) :
285
309
  - Mise à jour des dépendences
286
310
 
@@ -335,7 +359,7 @@ Vous pouvez créer un fichier de configuration **local.json** dans le dossier **
335
359
 
336
360
  ## Déclaration de licence
337
361
 
338
- Copyright (C) 2020-2024 Eliastik (eliastiksofts.com)
362
+ Copyright (C) 2020-2025 Eliastik (eliastiksofts.com)
339
363
 
340
364
  Ce programme est un logiciel libre ; vous pouvez le redistribuer ou le modifier suivant les termes de la GNU General Public License telle que publiée par la Free Software Foundation ; soit la version 3 de la licence, soit (à votre gré) toute version ultérieure.
341
365
 
@@ -345,7 +369,7 @@ Vous devez avoir reçu une copie de la GNU General Public License en même temps
345
369
 
346
370
  ----
347
371
 
348
- Copyright (C) 2020-2024 Eliastik (eliastiksofts.com)
372
+ Copyright (C) 2020-2025 Eliastik (eliastiksofts.com)
349
373
 
350
374
  This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
351
375
 
@@ -1,8 +1,9 @@
1
1
  {
2
2
  "ServerConfig": {
3
- "version": "1.1.3.7",
3
+ "version": "1.1.4.1",
4
4
  "port": 3000,
5
5
  "proxyMode": false,
6
+ "numberOfProxies": 1,
6
7
  "enableMultithreading": true,
7
8
  "maxPlayers": 20,
8
9
  "maxRooms": 20,
@@ -3,6 +3,7 @@ version: "3.4"
3
3
  services:
4
4
  snakeia-server:
5
5
  image: eliastik/snakeia-server:latest
6
+ container_name: snakeia-server
6
7
  restart: unless-stopped
7
8
  # uncomment to build the image
8
9
  # build:
@@ -12,5 +13,8 @@ services:
12
13
  NODE_ENV: production
13
14
  volumes:
14
15
  - ./config/default.json:/home/snakeia-server/server/config/default.json
16
+ # - ./config/local.json:/home/snakeia-server/server/config/local.json
17
+ - ./error.log:/home/snakeia-server/server/logs/error.log
18
+ - ./server.log:/home/snakeia-server/server/logs/server.log
15
19
  ports:
16
20
  - "3000:3000"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "snakeia-server",
3
- "version": "1.1.3-7",
3
+ "version": "1.1.4-1",
4
4
  "description": "Server for multiplaying in SnakeIA (https://github.com/Eliastik/snakeia)",
5
5
  "main": "server.js",
6
6
  "scripts": {
@@ -20,19 +20,19 @@
20
20
  "dependencies": {
21
21
  "body-parser": "^1.20.3",
22
22
  "config": "^3.3.12",
23
- "cookie-parser": "^1.4.6",
24
- "csurf": "^1.11.0",
25
- "ejs": "^3.1.9",
26
- "express": "^4.21.0",
27
- "express-rate-limit": "^7.4.0",
23
+ "cookie-parser": "^1.4.7",
24
+ "csrf-csrf": "^3.1.0",
25
+ "ejs": "^3.1.10",
26
+ "express": "^4.21.2",
27
+ "express-rate-limit": "^7.5.0",
28
28
  "html-entities": "^2.5.2",
29
29
  "i18n": "^0.15.1",
30
30
  "jsonwebtoken": "^9.0.2",
31
31
  "node-fetch": "^3.3.2",
32
32
  "seedrandom": "^3.0.5",
33
- "snakeia": "git+https://git@github.com/Eliastik/snakeia.git#2.2",
34
- "socket.io": "^4.7.5",
33
+ "snakeia": "^2.2.0-0",
34
+ "socket.io": "^4.8.1",
35
35
  "socket.io-cookie-parser": "^1.0.0",
36
- "winston": "^3.14.2"
36
+ "winston": "^3.17.0"
37
37
  }
38
38
  }
package/server.js CHANGED
@@ -36,7 +36,7 @@ const ioCookieParser = require("socket.io-cookie-parser");
36
36
  const i18n = require("i18n");
37
37
  const rateLimit = require("express-rate-limit");
38
38
  const winston = require("winston");
39
- const csrf = require("csurf");
39
+ const { doubleCsrf } = require("csrf-csrf");
40
40
  const bodyParser = require("body-parser");
41
41
  const node_config = require("config");
42
42
 
@@ -55,6 +55,8 @@ config.port = process.env.PORT || config.port;
55
55
  const jsonWebTokenSecretKey = config.jsonWebTokenSecretKey && config.jsonWebTokenSecretKey.trim() != "" ? config.jsonWebTokenSecretKey : generateRandomJsonWebTokenSecretKey();
56
56
  const jsonWebTokenSecretKeyAdmin = config.jsonWebTokenSecretKeyAdmin && config.jsonWebTokenSecretKeyAdmin.trim() != "" ? config.jsonWebTokenSecretKeyAdmin : generateRandomJsonWebTokenSecretKey(jsonWebTokenSecretKey);
57
57
 
58
+ const productionMode = process.env.NODE_ENV === "production";
59
+
58
60
  // Update config to file
59
61
  function updateConfigToFile() {
60
62
  fs.writeFileSync(configFile, JSON.stringify({ "ServerConfig": config }, null, 4), "UTF-8");
@@ -73,14 +75,14 @@ const logger = winston.createLogger({
73
75
  exceptionHandlers: config.enableLoggingFile ? [new winston.transports.File({ filename: config.errorLogFile })] : []
74
76
  });
75
77
 
76
- if(process.env.NODE_ENV !== "production") {
78
+ if(!productionMode) {
77
79
  logger.add(new winston.transports.Console({
78
80
  format: winston.format.colorize()
79
81
  }));
80
82
  }
81
83
 
82
84
  if(config.proxyMode) {
83
- app.enable("trust proxy");
85
+ app.enable("trust proxy", config.numberOfProxies);
84
86
  }
85
87
 
86
88
  // Internationalization
@@ -1165,9 +1167,18 @@ function verifyFormAuthenticationAdmin(body) {
1165
1167
  });
1166
1168
  }
1167
1169
 
1168
- const csrfProtection = csrf({ cookie: true });
1170
+ const csrfSecret = generateRandomJsonWebTokenSecretKey(jsonWebTokenSecretKeyAdmin);
1171
+ const { doubleCsrfProtection, generateToken } = doubleCsrf({
1172
+ getSecret: () => csrfSecret,
1173
+ cookieName: productionMode ? "__Host-snakeia-server.x-csrf-token" : "snakeia-server.x-csrf-token",
1174
+ cookieOptions: {
1175
+ sameSite: productionMode ? "strict" : "lax",
1176
+ path: "/",
1177
+ secure: productionMode
1178
+ }
1179
+ });
1169
1180
 
1170
- app.get("/admin", csrfProtection, function(req, res) {
1181
+ app.get("/admin", doubleCsrfProtection, function(req, res) {
1171
1182
  if(req.cookies) {
1172
1183
  jwt.verify(req.cookies.tokenAdmin, jsonWebTokenSecretKeyAdmin, function(err, data) {
1173
1184
  if(invalidatedAdminTokens.includes(req.cookies.tokenAdmin)) err = true;
@@ -1195,7 +1206,7 @@ app.get("/admin", csrfProtection, function(req, res) {
1195
1206
  games: games,
1196
1207
  io: io,
1197
1208
  config: config,
1198
- csrfToken: req.csrfToken(),
1209
+ csrfToken: generateToken(req, res, true),
1199
1210
  serverLog: logFile,
1200
1211
  errorLog: errorLogFile,
1201
1212
  getIPSocketIO: getIPSocketIO
@@ -1288,14 +1299,14 @@ function adminAction(req, res, action) {
1288
1299
 
1289
1300
  const jsonParser = bodyParser.json();
1290
1301
 
1291
- app.post("/admin/:action", jsonParser, csrfProtection, function(req, res) {
1302
+ app.post("/admin/:action", jsonParser, doubleCsrfProtection, function(req, res) {
1292
1303
  adminAction(req, res, req.params.action);
1293
1304
  });
1294
1305
 
1295
1306
  app.use(function (err, req, res, next) {
1296
1307
  if(err.code !== "EBADCSRFTOKEN") return next(err);
1297
1308
  res.status(403);
1298
- res.send("Error");
1309
+ res.send("Error: invalid CSRF token");
1299
1310
  });
1300
1311
 
1301
1312
  const adminRateLimiter = rateLimit({
package/views/admin.html CHANGED
@@ -251,13 +251,13 @@
251
251
  </div>
252
252
  <% if(authent && games) { %>
253
253
  <script type="text/javascript">
254
- var token = document.querySelector("meta[name='csrf-token']").getAttribute("content");
254
+ const token = document.querySelector("meta[name='csrf-token']").getAttribute("content");
255
255
 
256
256
  function requestAction(action, data, element) {
257
257
  fetch("/admin/" + action, {
258
258
  credentials: "same-origin",
259
259
  headers: {
260
- "CSRF-Token": token,
260
+ "x-csrf-token": token,
261
261
  "Content-Type": "application/json",
262
262
  },
263
263
  method: "POST",
@@ -273,19 +273,19 @@
273
273
  });
274
274
  }
275
275
 
276
- var elements = document.querySelectorAll("[data-action]");
276
+ const elements = document.querySelectorAll("[data-action]");
277
277
 
278
278
  elements.forEach(function(element) {
279
- var action = element.dataset.action;
280
- var form = element.dataset.form;
281
- var data = {};
282
- var confirmAction = element.dataset.confirmAction;
279
+ const action = element.dataset.action;
280
+ const form = element.dataset.form;
281
+ const data = {};
282
+ const confirmAction = element.dataset.confirmAction;
283
283
 
284
284
  if(form) {
285
285
  form.split("&").forEach(function(element) {
286
286
  if(element) {
287
- var key = element.split("=")[0];
288
- var value = element.split("=")[1];
287
+ const key = element.split("=")[0];
288
+ const value = element.split("=")[1];
289
289
  data[key] = value;
290
290
  }
291
291
  });