diff --git a/README.md b/README.md index 08d336f2f..6482b05e5 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,7 @@ One of the problems I noticed with the servers out there is that the "bases" are - Live Console - Auto Restart on failure detection - Auto Restart on schedule +- Password brute-force protection ## Installation @@ -71,7 +72,7 @@ $ npm i - [x] Write the admin log component (or part of another?) - [x] Separate the web routes - [ ] Add custom commands to the config file -- [ ] **Add a simple rate limiter (MUST)** +- [x] **Add a simple rate limiter (MUST)** - [x] Write some documentation - [x] **Automatically check for updates (MUST)** - [ ] Add hitch detection diff --git a/package-lock.json b/package-lock.json index 2879579fe..e36a6adfa 100644 --- a/package-lock.json +++ b/package-lock.json @@ -483,6 +483,11 @@ "vary": "~1.1.2" } }, + "express-rate-limit": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-4.0.3.tgz", + "integrity": "sha512-9+v6DXQdLLd4EqdEkXXM1ctdVNgjw4w8V1WLvlpnIb2SZ5wJ3Kvu8FOMzBPIAX+iO1F24AG640eOOHCv/0GmKg==" + }, "express-session": { "version": "1.16.1", "resolved": "https://registry.npmjs.org/express-session/-/express-session-1.16.1.tgz", diff --git a/package.json b/package.json index 74a4443ed..fead7109d 100644 --- a/package.json +++ b/package.json @@ -33,6 +33,7 @@ "cors": "^2.8.5", "discord.js": "^11.4.2", "express": "^4.16.4", + "express-rate-limit": "^4.0.3", "express-session": "^1.16.1", "express-socket.io-session": "^1.3.5", "lodash.template": "^4.4.0", diff --git a/src/components/webServer.js b/src/components/webServer.js index 0349b5add..13b2a4224 100644 --- a/src/components/webServer.js +++ b/src/components/webServer.js @@ -1,11 +1,12 @@ //Requires const fs = require('fs'); +const path = require('path'); const bcrypt = require('bcrypt'); const httpServer = require('http'); const express = require('express'); const session = require('express-session'); +const rateLimit = require("express-rate-limit"); const template = require('lodash.template'); -const path = require('path'); const cors = require('cors'); const { dir, log, logOk, logWarn, logError, cleanTerminal } = require('../extras/console'); const Webroutes = require('../webroutes'); @@ -19,14 +20,19 @@ module.exports = class WebServer { resave: false, saveUninitialized: false }); - + this.authLimiter = rateLimit({ + windowMs: this.config.limiterMinutes * 60 * 1000, // 15 minutes + max: this.config.limiterAttempts, // limit each IP to 5 requests per 15 minutes + message: render('login', {message:`Too many login attempts, enjoy your ${this.config.limiterMinutes} minutes of cooldown.`}) + }); + this.app = express(); - this.httpServer = httpServer.createServer(this.app); this.app.use(cors()); this.app.use(this.session); this.app.use(express.urlencoded({extended: true})) this.app.use(express.static('public', {index: false})) this.setupRoutes() + this.httpServer = httpServer.createServer(this.app); try { this.httpServer.listen(this.config.port, '0.0.0.0', () => { logOk(`::Started at http://${globals.config.publicIP}:${this.config.port}/`, context); @@ -52,7 +58,7 @@ module.exports = class WebServer { res.send(render('login', {message:''})); } }); - this.app.post('/auth', async (req, res) => { + this.app.post('/auth', this.authLimiter, async (req, res) => { if(typeof req.body.password == 'undefined'){ req.redirect('/'); return; @@ -68,10 +74,6 @@ module.exports = class WebServer { res.redirect('/'); }); - this.app.get('/test', globals.authenticator.sessionCheckerWeb, async (req, res) => { - res.send('
'+JSON.stringify(req.session, null, 2)+''); - }); - this.app.post('/action', globals.authenticator.sessionCheckerWeb, async (req, res) => { await Webroutes.action(res, req).catch((err) => { this.handleRouteError(res, "[action] Route Internal Error", err); diff --git a/src/extras/config.js b/src/extras/config.js index 6e667a6f5..68fc9b048 100644 --- a/src/extras/config.js +++ b/src/extras/config.js @@ -74,6 +74,8 @@ try { cfg.webServer = { port: parseInt(configFile.webServer.port) || 40121, bufferTime: parseInt(configFile.webServer.bufferTime) || 1500, //removed from template - deprecate? + limiterMinutes: parseInt(configFile.webServer.limiterMinutes) || 15, //removed from template + limiterAttempts: parseInt(configFile.webServer.limiterAttempts) || 5, //removed from template }; cfg.webConsole = { //nothing to configure diff --git a/version.json b/version.json index 225dc43c7..4c3858bd7 100644 --- a/version.json +++ b/version.json @@ -1,4 +1,4 @@ { - "version": "0.8.0", - "changelog": "Schedule/Failure Auto Restarter. You will need to copy server-template.json again. Modified the start command." + "version": "0.9.0", + "changelog": "Schedule/Failure Auto Restarter. You will need to copy server-template.json again. Modified the start command. Password brute-force protection." } \ No newline at end of file