rate limit socket connections

This commit is contained in:
AlecM33
2022-03-01 21:11:26 -05:00
parent 07ec22820e
commit cd76cd0a1a
8 changed files with 61 additions and 14 deletions

View File

@@ -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 */

View File

@@ -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);
}
}

View File

@@ -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;