Basic brute force detection added. Accounts throttle by captcha after 5 failed attempts, and locked out for 24 hours after 200 attempts.
This commit is contained in:
parent
e0f53df176
commit
9c18c23ad5
13 changed files with 463 additions and 50 deletions
|
|
@ -14,32 +14,58 @@ GNU Affero General Public License for more details.
|
|||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.*/
|
||||
|
||||
//Config
|
||||
const config = require('../../../../config.json');
|
||||
|
||||
//npm imports
|
||||
const {validationResult, matchedData} = require('express-validator');
|
||||
|
||||
//local imports
|
||||
const accountUtils = require('../../../utils/sessionUtils');
|
||||
const sessionUtils = require('../../../utils/sessionUtils');
|
||||
const {exceptionHandler, errorHandler} = require('../../../utils/loggerUtils');
|
||||
|
||||
const altchaUtils = require('../../../utils/altchaUtils');
|
||||
const session = require('express-session');
|
||||
|
||||
//api account functions
|
||||
module.exports.post = async function(req, res){
|
||||
try{
|
||||
//Check validation results
|
||||
const validResult = validationResult(req);
|
||||
|
||||
//if we don't have errors
|
||||
if(validResult.isEmpty()){
|
||||
const data = matchedData(req);
|
||||
const {user, pass} = data;
|
||||
|
||||
//Pull sanatzied/validated data
|
||||
const {user, pass} = matchedData(req);
|
||||
|
||||
//try to authenticate the session, and return a successful code if it works
|
||||
await accountUtils.authenticateSession(user, pass, req);
|
||||
await sessionUtils.authenticateSession(user, pass, req);
|
||||
return res.sendStatus(200);
|
||||
}else{
|
||||
res.status(400);
|
||||
res.send({errors: validResult.array()})
|
||||
return res.send({errors: validResult.array()})
|
||||
}
|
||||
}catch(err){
|
||||
exceptionHandler(res, err);
|
||||
//Check validation results
|
||||
const validResult = validationResult(req);
|
||||
|
||||
//if we don't have errors
|
||||
if(validResult.isEmpty()){
|
||||
//Get login attempts for current user
|
||||
const {user} = matchedData(req);
|
||||
const attempts = sessionUtils.getLoginAttempts(user)
|
||||
|
||||
//if we've gone over max attempts and
|
||||
if(attempts.count > sessionUtils.throttleAttempts){
|
||||
//tell client it needs a captcha
|
||||
return res.sendStatus(429);
|
||||
}
|
||||
}else{
|
||||
res.status(400);
|
||||
return res.send({errors: validResult.array()})
|
||||
}
|
||||
|
||||
//
|
||||
return exceptionHandler(res, err);
|
||||
}
|
||||
|
||||
}
|
||||
64
src/controllers/loginController.js
Normal file
64
src/controllers/loginController.js
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
/*Canopy - The next generation of stoner streaming software
|
||||
Copyright (C) 2024 Rainbownapkin and the TTN Community
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.*/
|
||||
|
||||
//Config
|
||||
const config = require('../../config.json');
|
||||
|
||||
//NPM Imports
|
||||
const {validationResult, matchedData} = require('express-validator');
|
||||
|
||||
//Local Imports
|
||||
const sessionUtils = require('../utils/sessionUtils');
|
||||
const altchaUtils = require('../utils/altchaUtils');
|
||||
|
||||
//register page functions
|
||||
module.exports.get = async function(req, res){
|
||||
//Check for validation errors
|
||||
const validResult = validationResult(req);
|
||||
|
||||
//If there are none
|
||||
if(validResult.isEmpty()){
|
||||
//Get username from sanatized/validated data
|
||||
const {user} = matchedData(req);
|
||||
const attempts = sessionUtils.getLoginAttempts(user);
|
||||
|
||||
//if we have previous attempts for this user
|
||||
if(attempts != null){
|
||||
if(attempts.count > sessionUtils.maxAttempts){
|
||||
return res.render('lockedAccount', {instance: config.instanceName, user: req.session.user});
|
||||
}
|
||||
|
||||
//If the users login's are being throttled
|
||||
if(attempts.count > sessionUtils.throttleAttempts){
|
||||
//Get diffuculty based on amount of attempts past the max amount
|
||||
const difficulty = attempts.count - sessionUtils.throttleAttempts;
|
||||
//Generate challenge unique to specific user, with difficulty set based on failed login attempts
|
||||
const challenge = await altchaUtils.genCaptcha(difficulty, user);
|
||||
|
||||
//Render page
|
||||
return res.render('login', {instance: config.instanceName, user: req.session.user, challenge});
|
||||
}
|
||||
//otherwise
|
||||
}else{
|
||||
//Render generic page
|
||||
return res.render('login', {instance: config.instanceName, user: req.session.user, challenge: null});
|
||||
}
|
||||
//if we received invalid input
|
||||
}else{
|
||||
//Render pretend nothing happened, send out a generic page
|
||||
return res.render('login', {instance: config.instanceName, user: req.session.user, challenge: null});
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue