add a simple rate limiter
This commit is contained in:
parent
7bebf6d471
commit
3bc1fdbde7
3 changed files with 45 additions and 1 deletions
|
@ -2,6 +2,7 @@ const User = require('../../../models/User');
|
|||
const secret = require('../../../secret');
|
||||
const config = require('../../../config');
|
||||
const Category = require('../../../models/Category');
|
||||
const RateLimiter = require('./ratelimiter');
|
||||
|
||||
const jwt = require('jsonwebtoken');
|
||||
const siolib = require('socket.io');
|
||||
|
@ -11,6 +12,11 @@ class GatewayServer {
|
|||
constructor(httpServer) {
|
||||
this._io = siolib(httpServer);
|
||||
this._gateway = this._io.of('/gateway');
|
||||
this.rateLimiter = new RateLimiter({
|
||||
points: 5,
|
||||
time: 1000,
|
||||
minPoints: 0
|
||||
});
|
||||
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;
|
||||
content = content.trim();
|
||||
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
|
||||
const categoryTitle = socket.joinedCategories[category._id];
|
||||
|
|
33
api/v1/gateway/ratelimiter.js
Normal file
33
api/v1/gateway/ratelimiter.js
Normal 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;
|
|
@ -3,7 +3,7 @@ module.exports = {
|
|||
mainServerPort: 3000,
|
||||
},
|
||||
address: 'localhost',
|
||||
mongoUrl: 'mongodb://localhost:27017/app',
|
||||
mongoUrl: 'mongodb://192.168.0.105:27017/app',
|
||||
bcryptRounds: 10,
|
||||
roleMap: {
|
||||
'BANNED': 0,
|
||||
|
|
Reference in a new issue