snakeia-server 1.2.7 → 2.0.0

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/.drone.yml CHANGED
@@ -15,5 +15,5 @@ steps:
15
15
  password:
16
16
  from_secret: REGISTRY_PASSWORD
17
17
  tags:
18
- - 1.2.7
18
+ - 2.0.0
19
19
  - latest
@@ -147,6 +147,8 @@ if(!isMainThread) {
147
147
  "confirmExit": false,
148
148
  "getInfos": false,
149
149
  "getInfosGame": false,
150
+ "getInfosControls": false,
151
+ "getInfosGoal": false,
150
152
  "errorOccurred": game.errorOccurred,
151
153
  "aiStuck": game.aiStuck,
152
154
  "precAiStuck": false,
@@ -167,6 +169,8 @@ if(!isMainThread) {
167
169
  "confirmExit": false,
168
170
  "getInfos": false,
169
171
  "getInfosGame": false,
172
+ "getInfosControls": false,
173
+ "getInfosGoal": false,
170
174
  "errorOccurred": game.errorOccurred,
171
175
  "engineLoading": game.engineLoading
172
176
  });
@@ -180,6 +184,8 @@ if(!isMainThread) {
180
184
  "confirmExit": false,
181
185
  "getInfos": false,
182
186
  "getInfosGame": false,
187
+ "getInfosControls": false,
188
+ "getInfosGoal": false,
183
189
  "errorOccurred": game.errorOccurred,
184
190
  "engineLoading": game.engineLoading
185
191
  });
@@ -192,6 +198,8 @@ if(!isMainThread) {
192
198
  "confirmExit": false,
193
199
  "getInfos": false,
194
200
  "getInfosGame": false,
201
+ "getInfosControls": false,
202
+ "getInfosGoal": false,
195
203
  "errorOccurred": game.errorOccurred,
196
204
  "engineLoading": game.engineLoading
197
205
  });
@@ -208,6 +216,8 @@ if(!isMainThread) {
208
216
  "confirmExit": false,
209
217
  "getInfos": false,
210
218
  "getInfosGame": false,
219
+ "getInfosControls": false,
220
+ "getInfosGoal": false,
211
221
  "errorOccurred": game.errorOccurred,
212
222
  "engineLoading": game.engineLoading
213
223
  });
@@ -224,6 +234,8 @@ if(!isMainThread) {
224
234
  "confirmExit": false,
225
235
  "getInfos": false,
226
236
  "getInfosGame": false,
237
+ "getInfosControls": false,
238
+ "getInfosGoal": false,
227
239
  "errorOccurred": game.errorOccurred,
228
240
  "engineLoading": game.engineLoading
229
241
  });
@@ -242,6 +254,8 @@ if(!isMainThread) {
242
254
  "confirmExit": false,
243
255
  "getInfos": false,
244
256
  "getInfosGame": false,
257
+ "getInfosControls": false,
258
+ "getInfosGoal": false,
245
259
  "errorOccurred": game.errorOccurred,
246
260
  "engineLoading": game.engineLoading
247
261
  });
package/Player.js CHANGED
@@ -16,9 +16,12 @@
16
16
  * You should have received a copy of the GNU General Public License
17
17
  * along with "SnakeIA Server". If not, see <http://www.gnu.org/licenses/>.
18
18
  */
19
+ const { jwtVerify } = require("jose");
20
+
19
21
  class Player {
20
- constructor(token, id, snake, ready, version) {
22
+ constructor(token, name, id, snake, ready, version) {
21
23
  this.token = token;
24
+ this.name = name;
22
25
  this.id = id;
23
26
  this.snake = snake;
24
27
  this.ready = ready;
@@ -26,7 +29,7 @@ class Player {
26
29
  }
27
30
 
28
31
  get username() {
29
- return Player.getUsername(this);
32
+ return this.name;
30
33
  }
31
34
 
32
35
  static getPlayer(array, id) {
@@ -57,7 +60,7 @@ class Player {
57
60
  }
58
61
 
59
62
  static getPlayerToken(array, token) {
60
- if (!token) return null;
63
+ if(!token) return null;
61
64
  for (let i = 0; i < array.length; i++) {
62
65
  if (array[i] != null && array[i].token == token) {
63
66
  return array[i];
@@ -68,7 +71,7 @@ class Player {
68
71
  }
69
72
 
70
73
  static getPlayerAllGamesToken(token, games) {
71
- if (!token) return null;
74
+ if(!token) return null;
72
75
  const keys = Object.keys(games);
73
76
 
74
77
  for (let i = 0; i < keys.length; i++) {
@@ -101,27 +104,28 @@ class Player {
101
104
  return Player.getPlayerAllGamesToken(token, games) != null;
102
105
  }
103
106
 
104
- static getUsername(player) {
107
+ static getSocketToken(socket) {
108
+ return socket?.handshake?.auth?.token
109
+ || socket?.handshake?.query?.token
110
+ || socket?.request?.cookies?.token;
111
+ }
112
+
113
+ static getUsernameSocket(socket, jsonWebTokenSecretKey) {
105
114
  try {
106
- const decoded_token = jwt.verify(player.token, jsonWebTokenSecretKey);
107
- return decoded_token && decoded_token.username
108
- ? decoded_token.username
109
- : null;
115
+ const token = Player.getSocketToken(socket);
116
+
117
+ return Player.getUsernameToken(token, jsonWebTokenSecretKey);
110
118
  } catch (e) {
111
119
  return null;
112
120
  }
113
121
  }
114
122
 
115
- static getUsernameSocket(socket) {
123
+ static async getUsernameToken(token, jsonWebTokenSecretKey) {
116
124
  try {
117
- const decoded_token = jwt.verify(
118
- socket.handshake.auth.token ||
119
- socket.handshake.query.token ||
120
- socket.request.cookies.token,
121
- jsonWebTokenSecretKey
122
- );
123
- return decoded_token && decoded_token.username
124
- ? decoded_token.username
125
+ const { payload } = await jwtVerify(token, jsonWebTokenSecretKey);
126
+
127
+ return payload && payload.username
128
+ ? payload.username
125
129
  : null;
126
130
  } catch (e) {
127
131
  return null;
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.2.7 (2/22/2026)
11
+ * Version 2.0.0 (05/08/2026)
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,7 +74,7 @@ You can create another configuration file in the **config** directory named **lo
74
74
  ````
75
75
  {
76
76
  "ServerConfig": {
77
- "version": "1.2.7", // The server version
77
+ "version": "2.0.0", // The server version
78
78
  "port": 3000, // The port where the server runs
79
79
  "enableHttps": false, // Enable or disable HTTPS listening on the server. If disabled, the server will only listen on HTTP.
80
80
  "httpsCertFile": "path/to/https/cert.pem", // Path to HTTPS certificate file
@@ -93,6 +93,7 @@ You can create another configuration file in the **config** directory named **lo
93
93
  "aiUltraModelID": null, // ID of the model (as returned by the API at the URL above) to load for the Ultra AI. Can be left empty; in that case, the default model provided by the API will be loaded
94
94
  "aiUltraCustomModelURL": null, // A URL pointing to a custom AI model to load. Must be a TensorFlow.js model trained for the Ultra AI. If there's an issue, game initialization will fail when Ultra AIs are present in the game
95
95
  "playerWaitTime": 45000, // The time while waiting for players to join a room (ms)
96
+ "matchmakingWaitTime": 30000, // The amount of time you must wait before resuming matchmaking after a game ends (ms)
96
97
  "enableMaxTimeGame": true, // Enable time limit for each game
97
98
  "maxTimeGame": 300000, // The time limit for each game (ms)
98
99
  "enableAuthentication": true, // Enable authentification when connecting to the server
@@ -105,8 +106,12 @@ You can create another configuration file in the **config** directory named **lo
105
106
  "recaptchaApiUrl": "https://www.google.com/recaptcha/api/siteverify", // ReCaptcha API URL
106
107
  "recaptchaPublicKey": "", // ReCaptcha public key (if not provided, the ReCaptcha will be disabled)
107
108
  "recaptchaPrivateKey": "", // ReCaptcha private key (if not provided, the ReCaptcha will be disabled)
108
- "authentMaxRequest": 50, // Maximum request for authentication
109
- "authentWindowMs": 900000, // Time when the authentication requests are saved (ms)
109
+ "authentMaxRequest": 15, // Maximum number of authentication attempts per time window
110
+ "authentWindowMs": 900000, // Time window duration (for authentication) in ms (900000 = 15 minutes)
111
+ "adminAuthentMaxRequest": 5, // Maximum number of authentication attempts on the admin panel per time window
112
+ "adminAuthentWindowMs": 900000, // Time window duration (for admin authentication) in ms (900000 = 15 minutes)
113
+ "adminActionsMaxRequest": 30, // Maximum number of actions on the admin panel per time window
114
+ "adminActionsWindowMs": 60000, // Time window duration (for admin actions) in ms (60000 = 1 minute)
110
115
  "ipBan": [], // A list of IP to ban
111
116
  "usernameBan": [], // A list of usernames to ban
112
117
  "contactBan": "", // A contact URL displayed when an user is banned
@@ -126,6 +131,42 @@ You can create another configuration file in the **config** directory named **lo
126
131
 
127
132
  ## Changelog
128
133
 
134
+ * Version 2.0.0 (5/8/2026):
135
+ - ⚠️ Breaking Changes:
136
+ - Authentication is no longer compatible with SnakeIA 3.1.0 and earlier versions;
137
+ - Clients must be updated to SnakeIA 3.2.0 to support the new authentication method;
138
+ - An explicit error message is now displayed when an incompatible client attempts to authenticate;
139
+ - Updated to SnakeIA 3.2.0 to benefit from the latest improvements;
140
+ - Matchmaking now automatically restarts 30 seconds after the end of a game (configurable through the `matchmakingWaitTime` setting);
141
+ - Bug fixes and security improvements:
142
+ - Fixed a security issue in the previous authentication system:
143
+ - The socket ID was transmitted through the authentication URL;
144
+ - An attacker could reuse this URL to retrieve the victim's token;
145
+ - The impact remained limited since accounts are currently ephemeral;
146
+ - Improved security by implementing CSRF protection on most endpoints (previously, only a few endpoints were covered);
147
+ - Strengthened the rate limiting system:
148
+ - Stricter rate limiting rules;
149
+ - Added rate limiting for administration actions;
150
+ - Separate configurations for:
151
+ - User authentication;
152
+ - Administrator authentication;
153
+ - Administration actions;
154
+ - Fixed issues related to retrieving usernames from tokens;
155
+ - Fixed a server crash occurring when modifying the configuration from the administration/moderation panel while the configuration file was read-only;
156
+ - Technical improvements:
157
+ - Migrated to the Jose library for authentication token management;
158
+ - Improved HTTP responses to better comply with REST API standards across multiple endpoints;
159
+ - Codebase refactoring;
160
+ - Updated dependencies.
161
+
162
+ * Version 2.0.0-beta.1 (3/7/2026):
163
+ - ⚠️ Breaking Changes:
164
+ - Authentication is no longer compatible with SnakeIA 3.1.0 and earlier versions.
165
+ An update to SnakeIA will be released soon to restore compatibility.
166
+ - Bug fixes and security improvements
167
+ - Code refactoring
168
+ - Dependency updates
169
+
129
170
  * Version 1.2.7 (2/22/2026):
130
171
  - Update dependencies + SnakeIA to version 3.1.0
131
172
 
@@ -229,7 +270,7 @@ Un serveur pour mon jeu [SnakeIA](https://github.com/Eliastik/snakeia), écrit e
229
270
 
230
271
  ## À propos de ce serveur
231
272
 
232
- * Version 1.2.7 (22/02/2026)
273
+ * Version 2.0.0 (08/05/2026)
233
274
  * Made in France by Eliastik - [eliastiksofts.com](http://eliastiksofts.com) - Contact : [eliastiksofts.com/contact](http://eliastiksofts.com/contact)
234
275
  * Licence : GNU GPLv3 (voir le fichier LICENCE.txt)
235
276
 
@@ -295,7 +336,7 @@ Vous pouvez créer un fichier de configuration **local.json** dans le dossier **
295
336
  ````
296
337
  {
297
338
  "ServerConfig": {
298
- "version": "1.2.7", // La version du serveur
339
+ "version": "2.0.0", // La version du serveur
299
340
  "port": 3000, // Le port sur lequel lancer le server
300
341
  "enableHttps": false, // Activer ou désactiver l'écoute du serveur en HTTPS. Si désactivé, le serveur n'écoutera qu'en HTTP.
301
342
  "httpsCertFile": "path/to/https/cert.pem", // Chemin vers le certificat HTTPS
@@ -314,6 +355,7 @@ Vous pouvez créer un fichier de configuration **local.json** dans le dossier **
314
355
  "aiUltraModelID": null, // ID du modèle (tel que retourné par l'API à l'URL du dessus) à charger pour l'IA Ultra. Peut rester vide, dans ce cas, le modèle par défaut fourni par l'API sera chargé
315
356
  "aiUltraCustomModelURL": null, // Une URL pointant vers un modèle d'IA à charger. Doit être un modèle Tensorflow.js entraîné pour l'IA Ultra. En cas de soucis, l'initialisation du jeu plantera quand des IA Ultra seront dans la partie
316
357
  "playerWaitTime": 45000, // Le temps durant lequel attendre la connexion d'autres joueurs à la salle (ms)
358
+ "matchmakingWaitTime": 30000, // Le temps durant lequel attendre avant de recommencer le matchmaking après la fin d'une partie (ms)
317
359
  "enableMaxTimeGame": true, // Activer la limite de temps pour chaque partie
318
360
  "maxTimeGame": 300000, // La limite de temps pour chaque partie (ms)
319
361
  "enableAuthentication": true, // Activer l'authentification lors de la connexion au serveur
@@ -326,8 +368,12 @@ Vous pouvez créer un fichier de configuration **local.json** dans le dossier **
326
368
  "recaptchaApiUrl": "https://www.google.com/recaptcha/api/siteverify", // URL de l'API ReCaptcha
327
369
  "recaptchaPublicKey": "", // Clé publique ReCaptcha (si non fournie, le ReCaptcha sera désactivé)
328
370
  "recaptchaPrivateKey": "", // Clé privée ReCaptcha (si non fournie, le ReCaptcha sera désactivé)
329
- "authentMaxRequest": 50, // Nombre maximal de requêtes lors de l'authentification
330
- "authentWindowMs": 900000, // Temps durant lequel les tentatives d'authentification seront enregistrées (ms)
371
+ "authentMaxRequest": 15, // Nombre maximal de tentatives d'authentification par fenêtre de temps
372
+ "authentWindowMs": 900000, // Durée de la fenêtre de temps (pour l'authentification) en ms (900000 = 15 minutes)
373
+ "adminAuthentMaxRequest": 5, // Nombre maximal de tentatives d'authentification sur l'interface d'administration par fenêtre de temps
374
+ "adminAuthentWindowMs": 900000, // Durée de la fenêtre de temps (pour l'authentification admin) en ms (900000 = 15 minutes)
375
+ "adminActionsMaxRequest": 30, // Nombre maximal d'actions sur l'interface d'administration par fenêtre de temps
376
+ "adminActionsWindowMs": 60000, // Durée de la fenêtre de temps (pour les actions admin) en ms (60000 = 1 minute)
331
377
  "ipBan": [], // Une liste d'IPs à bannir
332
378
  "usernameBan": [], // Une liste de noms d'utilisateur à bannir
333
379
  "contactBan": "", // Une URL de contact à afficher lorsque l'utilisateur est banni
@@ -347,6 +393,42 @@ Vous pouvez créer un fichier de configuration **local.json** dans le dossier **
347
393
 
348
394
  ## Journal des changements
349
395
 
396
+ * Version 2.0.0 (08/05/2026) :
397
+ - ⚠️ Breaking Changes :
398
+ - L'authentification n'est plus compatible avec SnakeIA 3.1.0 et versions inférieures ;
399
+ - Le client doit être mis à jour vers SnakeIA 3.2.0 pour être compatible avec la nouvelle méthode d'authentification ;
400
+ - Une erreur explicite est désormais affichée à l'authentification lorsqu'un client incompatible tente de se connecter ;
401
+ - Mise à jour vers SnakeIA 3.2.0 pour profiter des dernières améliorations ;
402
+ - Le matchmaking se relance automatiquement au bout de 30 secondes après la fin d'une partie (paramétrable via la configuration `matchmakingWaitTime`) ;
403
+ - Correction de bugs et améliorations de sécurité :
404
+ - Correction d'une faille de sécurité dans l'ancien système d'authentification :
405
+ - L'ID du socket était transmis dans l'URL d'authentification ;
406
+ - Un attaquant pouvait alors réutiliser cette URL pour récupérer le token de sa victime ;
407
+ - L'impact restait limité car les comptes sont actuellement éphémères ;
408
+ - Amélioration de la sécurité avec la mise en place d'une protection CSRF sur la plupart des endpoints (auparavant, seuls quelques endpoints étaient couverts) ;
409
+ - Renforcement du système de rate limiting :
410
+ - Règles plus restrictives ;
411
+ - Ajout du rate limiting pour les actions d'administration ;
412
+ - Configuration distincte pour :
413
+ - L'authentification utilisateur ;
414
+ - L'authentification administrateur ;
415
+ - Les actions d'administration ;
416
+ - Correction de bugs avec la récupération du nom d'utilisateur des tokens ;
417
+ - Correction d'un crash du serveur lors de la modification de la configuration via le panneau d'administration/modération si le fichier de configuration était en lecture seule ;
418
+ - Améliorations techniques :
419
+ - Migration vers la librairie Jose pour la gestion des tokens d'authentification ;
420
+ - Améliorations des réponses HTTP (respectent les normes API REST) des différents endpoints ;
421
+ - Refactorisation du code ;
422
+ - Mise à jour des dépendances
423
+
424
+ * Version 2.0.0-beta.1 (07/03/2026) :
425
+ - ⚠️ Breaking Changes :
426
+ - L'authentification n'est plus compatible avec SnakeIA 3.1.0 et versions inférieures
427
+ Une mise à jour de SnakeIA sera publiée prochainement pour rétablir la compatibilité.
428
+ - Correction de bugs et améliorations de sécurité
429
+ - Refactorisation du code
430
+ - Mise à jour des dépendances
431
+
350
432
  * Version 1.2.7 (22/02/2026) :
351
433
  - Mise à jour des dépendences + SnakeIA vers 3.1.0
352
434
 
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "ServerConfig": {
3
- "version": "1.2.7",
3
+ "version": "2.0.0",
4
4
  "port": 3000,
5
5
  "enableHttps": false,
6
6
  "httpsCertFile": "path/to/https/cert.pem",
@@ -19,6 +19,7 @@
19
19
  "aiUltraModelID": null,
20
20
  "aiUltraCustomModelURL": null,
21
21
  "playerWaitTime": 60000,
22
+ "matchmakingWaitTime": 30000,
22
23
  "enableMaxTimeGame": true,
23
24
  "maxTimeGame": 300000,
24
25
  "enableAuthentication": true,
@@ -31,8 +32,12 @@
31
32
  "recaptchaApiUrl": "https://www.google.com/recaptcha/api/siteverify",
32
33
  "recaptchaPublicKey": "",
33
34
  "recaptchaPrivateKey": "",
34
- "authentMaxRequest": 50,
35
+ "authentMaxRequest": 15,
35
36
  "authentWindowMs": 900000,
37
+ "adminAuthentMaxRequest": 5,
38
+ "adminAuthentWindowMs": 900000,
39
+ "adminActionsMaxRequest": 30,
40
+ "adminActionsWindowMs": 60000,
36
41
  "ipBan": [],
37
42
  "usernameBan": [],
38
43
  "contactBan": "",
package/locales/en.json CHANGED
@@ -61,5 +61,6 @@
61
61
  "moderator": "Moderator",
62
62
  "administrator": "Administrator",
63
63
  "role": "Role:",
64
- "loggedInAs": "Logged in as"
64
+ "loggedInAs": "Logged in as",
65
+ "clientNotCompatible": "Your version of the game is not compatible with this server (server version: %s). Update your game, then try again."
65
66
  }
package/locales/fr.json CHANGED
@@ -61,5 +61,6 @@
61
61
  "moderator": "Modérateur",
62
62
  "administrator": "Administrateur",
63
63
  "role": "Rôle :",
64
- "loggedInAs": "Connecté en tant que"
64
+ "loggedInAs": "Connecté en tant que",
65
+ "clientNotCompatible": "Votre version du jeu n'est pas compatible avec ce serveur (version serveur : %s). Mettez à jour votre jeu, puis réessayez."
65
66
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "snakeia-server",
3
- "version": "1.2.7",
3
+ "version": "2.0.0",
4
4
  "description": "Server for multiplaying in SnakeIA (https://github.com/Eliastik/snakeia)",
5
5
  "main": "server.js",
6
6
  "scripts": {
@@ -19,20 +19,29 @@
19
19
  "homepage": "https://github.com/Eliastik/snakeia-server#readme",
20
20
  "dependencies": {
21
21
  "body-parser": "^2.2.2",
22
- "config": "^4.3.0",
22
+ "config": "^4.4.1",
23
23
  "cookie-parser": "^1.4.7",
24
24
  "csrf-csrf": "^4.0.3",
25
- "ejs": "^4.0.1",
25
+ "ejs": "^5.0.2",
26
26
  "express": "^5.2.1",
27
- "express-rate-limit": "^8.2.1",
27
+ "express-rate-limit": "^8.5.1",
28
28
  "html-entities": "^2.6.0",
29
29
  "i18n": "^0.15.3",
30
- "jsonwebtoken": "^9.0.3",
30
+ "jose": "^6.2.3",
31
31
  "node-fetch": "^3.3.2",
32
32
  "seedrandom": "^3.0.5",
33
- "snakeia": "^3.1.0",
33
+ "semver": "^7.7.4",
34
+ "snakeia": "^3.2.0",
34
35
  "socket.io": "^4.8.3",
35
36
  "socket.io-cookie-parser": "^1.0.0",
36
37
  "winston": "^3.19.0"
38
+ },
39
+ "overrides": {
40
+ "@tensorflow/tfjs-node": {
41
+ "tar": "^7.5.10"
42
+ },
43
+ "@mapbox/node-pre-gyp": {
44
+ "tar": "^7.5.10"
45
+ }
37
46
  }
38
47
  }