diff --git a/client/src/scripts/game.js b/client/src/scripts/game.js
index 5703b9b..bae1bc4 100644
--- a/client/src/scripts/game.js
+++ b/client/src/scripts/game.js
@@ -34,9 +34,15 @@ const game = () => {
UserUtility.validateAnonUserSignature(res.content)
);
});
+ socket.on("connect_error", (err) => {
+ toast('Connection error: ' + err, 'error', true, false);
+ });
socket.on('disconnect', () => {
toast('Disconnected. Attempting reconnect...', 'error', true, false);
});
+ socket.emit('hey');
+ socket.emit('hey');
+ socket.emit('hey');
setClientSocketHandlers(stateBucket, gameStateRenderer, socket, timerWorker, gameTimerManager);
}).catch((res) => {
toast(res.content, 'error', true);
diff --git a/client/src/styles/home.css b/client/src/styles/home.css
index 32a3d4f..2a1c656 100644
--- a/client/src/styles/home.css
+++ b/client/src/styles/home.css
@@ -68,6 +68,13 @@ img[src='../images/logo_cropped.gif'] {
margin: 3em 0 1em 0;
}
+#logo-container {
+ max-width: 400px;
+ width: 63vw;
+ min-width: 250px;
+ margin: 3em 0 1em 0;
+}
+
form > div {
margin: 15px 0;
}
diff --git a/client/src/views/home.html b/client/src/views/home.html
index d3efe1c..7436050 100644
--- a/client/src/views/home.html
+++ b/client/src/views/home.html
@@ -24,7 +24,9 @@
-

+
+

+
A tool to run werewolf when not in-person, or in any setting without a deck of cards.
diff --git a/package-lock.json b/package-lock.json
index 04be469..5862ab2 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -4227,6 +4227,11 @@
"resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
"integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="
},
+ "rate-limiter-flexible": {
+ "version": "2.3.6",
+ "resolved": "https://registry.npmjs.org/rate-limiter-flexible/-/rate-limiter-flexible-2.3.6.tgz",
+ "integrity": "sha512-8DVFOe89rreyut/vzwBI7vgXJynyYoYnH5XogtAKs0F/neAbCTTglXxSJ7fZeZamcFXZDvMidCBvps4KM+1srw=="
+ },
"raw-body": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.2.tgz",
diff --git a/package.json b/package.json
index 1f36708..d94643f 100644
--- a/package.json
+++ b/package.json
@@ -36,6 +36,7 @@
"jasmine": "^3.5.0",
"karma-jasmine": "^4.0.1",
"open": "^7.0.3",
+ "rate-limiter-flexible": "^2.3.6",
"socket.io": "^4.4.0",
"socket.io-client": "^4.4.0",
"webpack": "^5.65.0",
diff --git a/server/main.js b/server/main.js
index ddb2faa..9aeb704 100644
--- a/server/main.js
+++ b/server/main.js
@@ -22,24 +22,23 @@ const main = ServerBootstrapper.createServerWithCorrectHTTPProtocol(app, args.us
app.set('port', args.port);
-const inGameSocketServer = ServerBootstrapper.createSocketServer(main, app, args.port);
+const inGameSocketServer = ServerBootstrapper.createSocketServer(main, app, args.port, logger);
+const gameNamespace = ServerBootstrapper.createGameSocketNamespace(inGameSocketServer, logger);
let gameManager;
/* Instantiate the singleton game manager */
if (process.env.NODE_ENV.trim() === 'development') {
- gameManager = new GameManager(logger, globals.ENVIRONMENT.LOCAL).getInstance();
+ gameManager = new GameManager(logger, globals.ENVIRONMENT.LOCAL, gameNamespace).getInstance();
} else {
- gameManager = new GameManager(logger, globals.ENVIRONMENT.PRODUCTION).getInstance();
+ gameManager = new GameManager(logger, globals.ENVIRONMENT.PRODUCTION, gameNamespace).getInstance();
}
-gameManager.namespace = inGameSocketServer;
-
-inGameSocketServer.on('connection', function (socket) {
+gameNamespace.on('connection', function (socket) {
socket.on('disconnecting', (reason) => {
logger.trace('client socket disconnecting because: ' + reason);
});
- gameManager.addGameSocketHandlers(inGameSocketServer, socket);
+ gameManager.addGameSocketHandlers(gameNamespace, socket);
});
/* api endpoints */
diff --git a/server/modules/GameManager.js b/server/modules/GameManager.js
index c665b07..1ba9d0d 100644
--- a/server/modules/GameManager.js
+++ b/server/modules/GameManager.js
@@ -6,11 +6,11 @@ const GameStateCurator = require('./GameStateCurator');
const UsernameGenerator = require('./UsernameGenerator');
class GameManager {
- constructor (logger, environment) {
+ constructor (logger, environment, namespace) {
this.logger = logger;
this.environment = environment;
this.activeGameRunner = new ActiveGameRunner(logger).getInstance();
- this.namespace = null;
+ this.namespace = namespace;
}
addGameSocketHandlers = (namespace, socket) => {
@@ -477,10 +477,10 @@ function getGameSize (cards) {
}
class Singleton {
- constructor (logger, environment) {
+ constructor (logger, environment, namespace) {
if (!Singleton.instance) {
logger.info('CREATING SINGLETON GAME MANAGER');
- Singleton.instance = new GameManager(logger, environment);
+ Singleton.instance = new GameManager(logger, environment, namespace);
}
}
diff --git a/server/modules/ServerBootstrapper.js b/server/modules/ServerBootstrapper.js
index 24cb62e..a3036a3 100644
--- a/server/modules/ServerBootstrapper.js
+++ b/server/modules/ServerBootstrapper.js
@@ -4,6 +4,7 @@ const https = require('https');
const path = require('path');
const fs = require('fs');
const crypto = require('crypto');
+const { RateLimiterMemory } = require('rate-limiter-flexible');
const ServerBootstrapper = {
processCLIArgs: () => {
@@ -79,7 +80,7 @@ const ServerBootstrapper = {
return main;
},
- createSocketServer: (main, app, port) => {
+ createSocketServer: (main, app, port, logger) => {
let io;
if (process.env.NODE_ENV.trim() === 'development') {
io = require('socket.io')(main, {
@@ -91,8 +92,34 @@ const ServerBootstrapper = {
});
}
- return io.of('/in-game');
+ registerRateLimiter(io, logger);
+
+ return io;
+ },
+
+ createGameSocketNamespace(server, logger) {
+ const namespace = server.of('/in-game');
+ registerRateLimiter(namespace, logger);
+ return server.of('/in-game');
}
};
+function registerRateLimiter(server, logger) {
+ const rateLimiter = new RateLimiterMemory(
+ {
+ points: 10,
+ duration: 1
+ });
+
+ server.use(async (socket, next) => {
+ try {
+ await rateLimiter.consume(socket.handshake.address);
+ logger.trace('consumed point from ' + socket.handshake.address);
+ next();
+ } catch(rejection) {
+ next(new Error("Your connection has been blocked."));
+ }
+ });
+}
+
module.exports = ServerBootstrapper;