From 95ed2fa40311f54e6735a73c64e288a5560ac7ee Mon Sep 17 00:00:00 2001 From: rainbow napkin Date: Mon, 20 Oct 2025 05:15:34 -0400 Subject: [PATCH] Prepped session utils for remember me tokens. --- src/utils/sessionUtils.js | 73 ++++++++++++++++++++++++--------------- 1 file changed, 46 insertions(+), 27 deletions(-) diff --git a/src/utils/sessionUtils.js b/src/utils/sessionUtils.js index b1b15cd..584411d 100644 --- a/src/utils/sessionUtils.js +++ b/src/utils/sessionUtils.js @@ -41,16 +41,19 @@ const maxAttempts = 200; * Sole and Singular Session Authentication method. * All logins should happen through here, all other site-wide authentication should happen by sessions authenticated by this model. * This is important, as reducing authentication endpoints reduces attack surface. - * @param {String} user - Username to login as - * @param {String} pass - Password to authenticat session with + * + * Ended up not splitting this in two/three for remember-me tokens. Kind of fucked up it was actually easier this way... + * @param {String} identifier - Identifer used to identify account, either username or token UUID + * @param {String} secret - Secret to authenticate session with, either password or token secret * @param {express.Request} req - Express request object w/ session to authenticate + * @param {Boolean} useRememberMeToken - Whether or not we're using username/pass or remember-me tokens * @returns Username of authticated user upon success */ -module.exports.authenticateSession = async function(user, pass, req){ +module.exports.authenticateSession = async function(identifier, secret, req, useRememberMeToken = false){ //Fuck you yoda try{ //Grab previous attempts - const attempt = failedAttempts.get(user); + const attempt = failedAttempts.get(identifier); //If we're proxied use passthrough IP const ip = config.proxied ? req.headers['x-forwarded-for'] : req.ip; @@ -74,7 +77,7 @@ module.exports.authenticateSession = async function(user, pass, req){ } //If we have failed attempts - if(attempt != null){ + if(!useRememberMeToken && attempt != null){ //If we have more failed attempts than allowed if(attempt.count > maxAttempts){ throw loggerUtils.exceptionSmith("This account has been locked for at 24 hours due to a large amount of failed log-in attempts", "unauthorized"); @@ -86,14 +89,23 @@ module.exports.authenticateSession = async function(user, pass, req){ //Since we've already got access to the request and dont need to import anything, why bother getting it from a parameter? if(req.body.verification == null){ throw loggerUtils.exceptionSmith("Verification failed!", "unauthorized"); - }else if(!altchaUtils.verify(req.body.verification, user)){ + }else if(!altchaUtils.verify(req.body.verification, identifier)){ throw loggerUtils.exceptionSmith("Verification failed!", ""); } } } - //Authenticate the session - const userDB = await userModel.authenticate(user, pass); + //define/scope empty userDB variable + let userDB = null; + + //If we're using remember me tokens + if(useRememberMeToken){ + + //Otherwise + }else{ + //Fallback on to username/password authentication + userDB = await userModel.authenticate(identifier, secret); + } //Check for user ban const userBanDB = await userBanModel.checkBanByUserDoc(userDB); @@ -123,33 +135,40 @@ module.exports.authenticateSession = async function(user, pass, req){ //Tattoo hashed IP address to user account for seven days userDB.tattooIPRecord(ip); - //If we got to here then the log-in was successful. We should clear-out any failed attempts. - failedAttempts.delete(user); + if(!useRememberMeToken){ + //If we got to here then the log-in was successful. We should clear-out any failed attempts. + failedAttempts.delete(identifier); + } //return user return userDB.user; }catch(err){ - //Look for previous failed attempts - var attempt = failedAttempts.get(user); + //Failed attempts at good tokens are handled by the token schema by dropping the users effected tokens and screaming bloody murder + //Failed attempts with bad tokens don't need to be handled as it's not like attacking a bad UUID is going to get you anywhere anywho + //This also makes it way easier to re-use parts of this function + if(!useRememberMeToken){ + //Look for previous failed attempts + var attempt = failedAttempts.get(identifier); - //If this is the first attempt - if(attempt == null){ - //Create new attempt object - attempt = { - count: 1, - lastAttempt: new Date() - } - }else{ - //Create updated attempt object - attempt = { - count: attempt.count + 1, - lastAttempt: new Date() + //If this is the first attempt + if(attempt == null){ + //Create new attempt object + attempt = { + count: 1, + lastAttempt: new Date() + } + }else{ + //Create updated attempt object + attempt = { + count: attempt.count + 1, + lastAttempt: new Date() + } } + + //Commit the failed attempt to the failed sign-in cache + failedAttempts.set(identifier, attempt); } - //Commit the failed attempt to the failed sign-in cache - failedAttempts.set(user, attempt); - //y33t throw err; }