add a simple rate limiter

This commit is contained in:
hippoz 2020-11-26 11:42:27 +02:00
parent 7bebf6d471
commit 3bc1fdbde7
3 changed files with 45 additions and 1 deletions

View file

@ -2,6 +2,7 @@ const User = require('../../../models/User');
const secret = require('../../../secret'); const secret = require('../../../secret');
const config = require('../../../config'); const config = require('../../../config');
const Category = require('../../../models/Category'); const Category = require('../../../models/Category');
const RateLimiter = require('./ratelimiter');
const jwt = require('jsonwebtoken'); const jwt = require('jsonwebtoken');
const siolib = require('socket.io'); const siolib = require('socket.io');
@ -11,6 +12,11 @@ class GatewayServer {
constructor(httpServer) { constructor(httpServer) {
this._io = siolib(httpServer); this._io = siolib(httpServer);
this._gateway = this._io.of('/gateway'); this._gateway = this._io.of('/gateway');
this.rateLimiter = new RateLimiter({
points: 5,
time: 1000,
minPoints: 0
});
this.eventSetup(); this.eventSetup();
} }
} }
@ -94,6 +100,11 @@ GatewayServer.prototype.eventSetup = function() {
if (!category || !content || !socket.joinedCategories || !socket.isConnected || !socket.user || !(typeof content === 'string') || !(typeof category._id === 'string')) return; if (!category || !content || !socket.joinedCategories || !socket.isConnected || !socket.user || !(typeof content === 'string') || !(typeof category._id === 'string')) return;
content = content.trim(); content = content.trim();
if (!content || content === '' || content === ' ' || content.length >= 2000) return; if (!content || content === '' || content === ' ' || content.length >= 2000) return;
if (!this.rateLimiter.consoom(socket.user.token)) { // TODO: maybe user ip instead of token?
console.log(`[E] [gateway] Rate limiting ${socket.user.username}`);
return;
}
// TODO: When/if category permissions are added, check if the user has permissions for that category // TODO: When/if category permissions are added, check if the user has permissions for that category
const categoryTitle = socket.joinedCategories[category._id]; const categoryTitle = socket.joinedCategories[category._id];

View file

@ -0,0 +1,33 @@
// This is "inspired" by rate-limiter-flexible
class RateLimiter {
constructor({ points=5, time=1000, minPoints=0 }) {
this.points = points;
this.minPoints = minPoints;
this.time = time;
this._flooding = {};
}
}
RateLimiter.prototype.consoom = function(discriminator) {
if (!this._flooding[discriminator]) this._flooding[discriminator] = { points: this.points, lastReset: Date.now() };
if (Math.abs(new Date() - this._flooding[discriminator].lastReset) >= this.time) {
this._flooding[discriminator] = { points: this.points, lastReset: Date.now() };
}
this._flooding[discriminator].points--;
if (this._flooding[discriminator].points <= this.minPoints) {
this._flooding[discriminator].flooding = true;
return false;
}
if (this._flooding[discriminator].flooding === true) {
return false;
}
return true;
};
module.exports = RateLimiter;

View file

@ -3,7 +3,7 @@ module.exports = {
mainServerPort: 3000, mainServerPort: 3000,
}, },
address: 'localhost', address: 'localhost',
mongoUrl: 'mongodb://localhost:27017/app', mongoUrl: 'mongodb://192.168.0.105:27017/app',
bcryptRounds: 10, bcryptRounds: 10,
roleMap: { roleMap: {
'BANNED': 0, 'BANNED': 0,