added rate-limiting

This commit is contained in:
James Shiffer 2020-06-23 20:13:01 -07:00
parent 0421691545
commit 76aa016ef6
No known key found for this signature in database
GPG Key ID: C0DB8774A1B3BA45
3 changed files with 1885 additions and 77 deletions

1913
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -12,6 +12,7 @@
"test": "run-p --race dev cy:run" "test": "run-p --race dev cy:run"
}, },
"dependencies": { "dependencies": {
"@babel/runtime": "^7.10.3",
"bcrypt": "^4.0.1", "bcrypt": "^4.0.1",
"body-parser": "^1.19.0", "body-parser": "^1.19.0",
"cl-editor": "^2.0.0", "cl-editor": "^2.0.0",
@ -26,15 +27,22 @@
"mongoose-fuzzy-searching": "^1.3.1", "mongoose-fuzzy-searching": "^1.3.1",
"passport": "^0.4.1", "passport": "^0.4.1",
"passport-local": "^1.0.0", "passport-local": "^1.0.0",
"rate-limiter-flexible": "^2.1.7",
"session-file-store": "^1.4.0", "session-file-store": "^1.4.0",
"sirv": "^0.4.0" "sirv": "^0.4.0"
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "^7.10.3",
"@babel/plugin-proposal-object-rest-spread": "^7.10.3",
"@babel/plugin-syntax-dynamic-import": "^7.8.3",
"@babel/preset-env": "^7.10.3",
"babel-loader": "^8.1.0",
"npm-run-all": "^4.1.5", "npm-run-all": "^4.1.5",
"sapper": "^0.27.0", "sapper": "^0.27.0",
"svelte": "^3.0.0", "svelte": "^3.0.0",
"svelte-loader": "^2.9.0", "svelte-loader": "^2.9.0",
"webpack": "^4.7.0" "terser-webpack-plugin": "^3.0.6",
"webpack": "^4.43.0"
}, },
"repository": { "repository": {
"type": "git", "type": "git",

View File

@ -8,6 +8,7 @@ import mongoose from 'mongoose';
import passport from 'passport'; import passport from 'passport';
import { Strategy } from 'passport-local'; import { Strategy } from 'passport-local';
import sessionFileStore from 'session-file-store'; import sessionFileStore from 'session-file-store';
import { RateLimiterMemory } from 'rate-limiter-flexible';
import fileUpload from 'express-fileupload'; import fileUpload from 'express-fileupload';
import helmet from 'helmet'; import helmet from 'helmet';
import Article from './models/article.js'; import Article from './models/article.js';
@ -55,6 +56,32 @@ passport.use(new Strategy((username, password, done) => {
}); });
})); }));
const loginAttemptRateLimiter = new RateLimiterMemory({
points: 5,
duration: 3600,
blockDuration: 60
});
const registerRateLimiter = new RateLimiterMemory({
points: 1,
duration: 60,
blockDuration: 60
});
const rateLimiterMiddleware = rl => async function (req, res, next) {
try {
await rl.consume(req.ip);
next();
} catch (err) {
res.writeHead(429, {
'Content-Type': 'application/json'
});
res.end(JSON.stringify({
message: 'Too Many Requests'
}));
}
};
const isAuthor = function(req, res, next) { const isAuthor = function(req, res, next) {
if (req.user) { if (req.user) {
if (req.user.author) { if (req.user.author) {
@ -148,6 +175,17 @@ express()
})); }));
return false; return false;
} }
try {
await registerRateLimiter.consume();
} catch (err) {
res.writeHead(429, {
'Content-Type': 'application/json'
});
res.end(JSON.stringify({
message: `Too Many Requests`
}));
return false;
}
try { try {
const user = await User.findOne({ username: req.body.username }); const user = await User.findOne({ username: req.body.username });
if (user) { if (user) {
@ -181,6 +219,7 @@ express()
) )
.post('/cms/login', .post('/cms/login',
rateLimiterMiddleware(loginAttemptRateLimiter),
passport.authenticate('local', { failWithError: true }), passport.authenticate('local', { failWithError: true }),
function(req, res, next) { function(req, res, next) {
// handle success // handle success