add login rate limiter
This commit is contained in:
		
							parent
							
								
									8a481a1be0
								
							
						
					
					
						commit
						b77b33e790
					
				
					 3 changed files with 66 additions and 11 deletions
				
			
		|  | @ -1,8 +1,9 @@ | |||
| const basicAuth = require("express-basic-auth") | ||||
| const basicAuth = require("express-basic-auth"); | ||||
| const passwordHash = require("./password-hash"); | ||||
| const { R } = require("redbean-node"); | ||||
| const { setting } = require("./util-server"); | ||||
| const { debug } = require("../src/util"); | ||||
| const { loginRateLimiter } = require("./rate-limiter"); | ||||
| 
 | ||||
| /** | ||||
|  * | ||||
|  | @ -13,7 +14,7 @@ const { debug } = require("../src/util"); | |||
| exports.login = async function (username, password) { | ||||
|     let user = await R.findOne("user", " username = ? AND active = 1 ", [ | ||||
|         username, | ||||
|     ]) | ||||
|     ]); | ||||
| 
 | ||||
|     if (user && passwordHash.verify(password, user.password)) { | ||||
|         // Upgrade the hash to bcrypt
 | ||||
|  | @ -27,21 +28,30 @@ exports.login = async function (username, password) { | |||
|     } | ||||
| 
 | ||||
|     return null; | ||||
| } | ||||
| }; | ||||
| 
 | ||||
| function myAuthorizer(username, password, callback) { | ||||
| 
 | ||||
|     setting("disableAuth").then((result) => { | ||||
| 
 | ||||
|         if (result) { | ||||
|             callback(null, true) | ||||
|             callback(null, true); | ||||
|         } else { | ||||
|             // Login Rate Limit
 | ||||
|             loginRateLimiter.pass(null, 0).then((pass) => { | ||||
|                 if (pass) { | ||||
|                     exports.login(username, password).then((user) => { | ||||
|                 callback(null, user != null) | ||||
|             }) | ||||
|         } | ||||
|     }) | ||||
|                         callback(null, user != null); | ||||
| 
 | ||||
|                         if (user == null) { | ||||
|                             loginRateLimiter.removeTokens(1); | ||||
|                         } | ||||
|                     }); | ||||
|                 } else { | ||||
|                     callback(null, false); | ||||
|                 } | ||||
|             }); | ||||
| 
 | ||||
|         } | ||||
|     }); | ||||
| } | ||||
| 
 | ||||
| exports.basicAuth = basicAuth({ | ||||
|  |  | |||
							
								
								
									
										39
									
								
								server/rate-limiter.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								server/rate-limiter.js
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,39 @@ | |||
| const { RateLimiter } = require("limiter"); | ||||
| const { debug } = require("../src/util"); | ||||
| 
 | ||||
| class KumaRateLimiter { | ||||
|     constructor(config) { | ||||
|         this.errorMessage = config.errorMessage; | ||||
|         this.rateLimiter = new RateLimiter(config); | ||||
|     } | ||||
| 
 | ||||
|     async pass(callback, num = 1) { | ||||
|         const remainingRequests = await this.removeTokens(num); | ||||
|         debug("Rate Limit (remainingRequests):" + remainingRequests); | ||||
|         if (remainingRequests < 0) { | ||||
|             if (callback) { | ||||
|                 callback({ | ||||
|                     ok: false, | ||||
|                     msg: this.errorMessage, | ||||
|                 }); | ||||
|             } | ||||
|             return false; | ||||
|         } | ||||
|         return true; | ||||
|     } | ||||
| 
 | ||||
|     async removeTokens(num = 1) { | ||||
|         return await this.rateLimiter.removeTokens(num); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| const loginRateLimiter = new KumaRateLimiter({ | ||||
|     tokensPerInterval: 20, | ||||
|     interval: "minute", | ||||
|     fireImmediately: true, | ||||
|     errorMessage: "Too frequently, try again later." | ||||
| }); | ||||
| 
 | ||||
| module.exports = { | ||||
|     loginRateLimiter | ||||
| }; | ||||
|  | @ -52,6 +52,7 @@ const Database = require("./database"); | |||
| 
 | ||||
| debug("Importing Background Jobs"); | ||||
| const { initBackgroundJobs } = require("./jobs"); | ||||
| const { loginRateLimiter } = require("./rate-limiter"); | ||||
| 
 | ||||
| const { basicAuth } = require("./auth"); | ||||
| const { login } = require("./auth"); | ||||
|  | @ -281,6 +282,11 @@ exports.entryPage = "dashboard"; | |||
|         socket.on("login", async (data, callback) => { | ||||
|             console.log("Login"); | ||||
| 
 | ||||
|             // Login Rate Limit
 | ||||
|             if (! await loginRateLimiter.pass(callback)) { | ||||
|                 return; | ||||
|             } | ||||
| 
 | ||||
|             let user = await login(data.username, data.password); | ||||
| 
 | ||||
|             if (user) { | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue