Finished up with remember me middleware.
This commit is contained in:
parent
e00e5a608b
commit
61ec3ffc52
|
|
@ -62,10 +62,13 @@ module.exports.post = async function(req, res){
|
|||
//Check config for protocol
|
||||
const secure = config.protocol.toLowerCase() == "https";
|
||||
|
||||
//Create expiration date for cookies (180 days)
|
||||
const expires = new Date(Date.now() + (1000 * 60 * 60 * 24 * 180))
|
||||
|
||||
//Set remember me ID and token as browser-side cookies for safe-keeping
|
||||
res.cookie("rememberme.id", authToken.id, {sameSite: 'strict', httpOnly: true, secure});
|
||||
res.cookie("rememberme.id", authToken.id, {sameSite: 'strict', httpOnly: true, secure, expires});
|
||||
//This should be the servers last interaction with the plaintext token before saving the hashed copy, and dropping it out of RAM
|
||||
res.cookie("rememberme.token", authToken.token, {sameSite: 'strict', httpOnly: true, secure});
|
||||
res.cookie("rememberme.token", authToken.token, {sameSite: 'strict', httpOnly: true, secure, expires});
|
||||
}
|
||||
|
||||
//Tell the browser everything is dandy
|
||||
|
|
|
|||
|
|
@ -81,6 +81,12 @@ rememberMeToken.pre('save', async function (next){
|
|||
next();
|
||||
});
|
||||
|
||||
//Methods
|
||||
rememberMeToken.methods.checkToken = async function(token){
|
||||
//Compare ingested token to saved hash
|
||||
return await hashUtil.compareRememberMeToken(token, this.token);
|
||||
}
|
||||
|
||||
//statics
|
||||
rememberMeToken.statics.genToken = async function(user, pass){
|
||||
//Authenticate user and pull document
|
||||
|
|
@ -104,4 +110,45 @@ rememberMeToken.statics.genToken = async function(user, pass){
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Authenticates an id and token pair
|
||||
* @param {String} id - id of token auth against
|
||||
* @param {String} token - token string to auth against
|
||||
* @param {String} failLine - Line to paste into custom error upon login failure
|
||||
* @returns {Mongoose.Document} - User DB Document upon success
|
||||
*/
|
||||
rememberMeToken.statics.authenticate = async function(id, token, failLine = "Bad Username or Password."){
|
||||
//check for missing pass
|
||||
if(!id || !token){
|
||||
throw loggerUtils.exceptionSmith("Missing id/token.", "validation");
|
||||
}
|
||||
|
||||
//get the token if it exists
|
||||
const tokenDB = await this.findOne({id});
|
||||
|
||||
//if not scream and shout
|
||||
if(!tokenDB){
|
||||
badLogin();
|
||||
}
|
||||
|
||||
//Check our password is correct
|
||||
if(await tokenDB.checkToken(token)){
|
||||
//Populate the user field
|
||||
await tokenDB.populate('user');
|
||||
|
||||
//Return the user doc
|
||||
return tokenDB.user;
|
||||
}else{
|
||||
//Nuke the token for security
|
||||
await tokenDB.deleteOne();
|
||||
//if not scream and shout
|
||||
badLogin();
|
||||
}
|
||||
|
||||
//standardize bad login response so it's unknown which is bad for security reasons.
|
||||
function badLogin(){
|
||||
throw loggerUtils.exceptionSmith(failLine, "unauthorized");
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = mongoose.model("rememberMe", rememberMeToken);
|
||||
|
|
@ -39,6 +39,7 @@ const pmHandler = require('./app/pm/pmHandler');
|
|||
const configCheck = require('./utils/configCheck');
|
||||
const scheduler = require('./utils/scheduler');
|
||||
const {errorMiddleware} = require('./utils/loggerUtils');
|
||||
const sessionUtils = require('./utils/sessionUtils');
|
||||
//Validator
|
||||
const accountValidator = require('./validators/accountValidator');
|
||||
//DB Model
|
||||
|
|
@ -143,6 +144,14 @@ mongoose.set("sanitizeFilter", true).connect(dbUrl).then(() => {
|
|||
process.exit();
|
||||
});
|
||||
|
||||
//Static File Server, set this up first to avoid middleware running on top of it
|
||||
//Serve client-side libraries
|
||||
app.use('/lib/bootstrap-icons',express.static(path.join(__dirname, '../node_modules/bootstrap-icons'))); //Icon set
|
||||
app.use('/lib/altcha',express.static(path.join(__dirname, '../node_modules/altcha/dist_external'))); //Self-Hosted PoW-based Captcha
|
||||
app.use('/lib/hls.js',express.static(path.join(__dirname, '../node_modules/hls.js/dist'))); //HLS Media Handler
|
||||
//Server public 'www' folder
|
||||
app.use(express.static(path.join(__dirname, '../www')));
|
||||
|
||||
//Set View Engine
|
||||
app.set('view engine', 'ejs');
|
||||
app.set('views', __dirname + '/views');
|
||||
|
|
@ -164,6 +173,9 @@ io.engine.use(sessionMiddleware);
|
|||
app.use(accountValidator.rememberMeID());
|
||||
app.use(accountValidator.rememberMeToken());
|
||||
|
||||
//Use remember me middleware
|
||||
app.use(sessionUtils.rememberMeMiddleware);
|
||||
|
||||
//Routes
|
||||
//Humie-Friendly
|
||||
app.use('/', indexRouter);
|
||||
|
|
@ -183,14 +195,6 @@ app.use('/tooltip', tooltipRouter);
|
|||
//Bot-Ready
|
||||
app.use('/api', apiRouter);
|
||||
|
||||
//Static File Server
|
||||
//Serve client-side libraries
|
||||
app.use('/lib/bootstrap-icons',express.static(path.join(__dirname, '../node_modules/bootstrap-icons'))); //Icon set
|
||||
app.use('/lib/altcha',express.static(path.join(__dirname, '../node_modules/altcha/dist_external'))); //Self-Hosted PoW-based Captcha
|
||||
app.use('/lib/hls.js',express.static(path.join(__dirname, '../node_modules/hls.js/dist'))); //HLS Media Handler
|
||||
//Server public 'www' folder
|
||||
app.use(express.static(path.join(__dirname, '../www')));
|
||||
|
||||
//Handle error checking
|
||||
app.use(errorMiddleware);
|
||||
|
||||
|
|
|
|||
|
|
@ -14,6 +14,9 @@ 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/>.*/
|
||||
|
||||
//npm imports
|
||||
const {validationResult, matchedData} = require('express-validator');
|
||||
|
||||
//Local Imports
|
||||
const config = require('../../config.json');
|
||||
const {userModel} = require('../schemas/user/userSchema.js');
|
||||
|
|
@ -101,7 +104,7 @@ module.exports.authenticateSession = async function(identifier, secret, req, use
|
|||
|
||||
//If we're using remember me tokens
|
||||
if(useRememberMeToken){
|
||||
|
||||
userDB = await rememberMeModel.authenticate(identifier, secret);
|
||||
//Otherwise
|
||||
}else{
|
||||
//Fallback on to username/password authentication
|
||||
|
|
@ -211,5 +214,44 @@ module.exports.processExpiredAttempts = function(){
|
|||
}
|
||||
}
|
||||
|
||||
module.exports.rememberMeMiddleware = function(req, res, next){
|
||||
//if we have an un-authenticated user
|
||||
if(req.session.user == null || req.session.user == ""){
|
||||
//Check validation result
|
||||
const validResult = validationResult(req);
|
||||
|
||||
//if we don't have errors
|
||||
if(validResult.isEmpty()){
|
||||
//Pull verified data from request
|
||||
const data = matchedData(req);
|
||||
|
||||
//If we have a valid remember me id and token
|
||||
if(data.rememberme != null && data.rememberme.id != null && data.rememberme.token != null){
|
||||
//Authenticate against standard auth function in remember me mode
|
||||
module.exports.authenticateSession(data.rememberme.id, data.rememberme.token, req, true).then((userDB)=>{
|
||||
//Jump to next middleware
|
||||
next();
|
||||
}).catch((err)=>{
|
||||
//Clear out remember me fields
|
||||
res.clearCookie('rememberme.id');
|
||||
res.clearCookie('rememberme.token');
|
||||
|
||||
//Bitch, Moan, and guess what? That's fuckin' right! COMPLAIN!!!!
|
||||
return loggerUtils.exceptionHandler(res, err);
|
||||
});
|
||||
}else{
|
||||
//Jump to next middleware, this looks gross but it's only because they made me use .then like a bunch of fucking dicks
|
||||
next();
|
||||
}
|
||||
}else{
|
||||
//Jump to next middleware
|
||||
next();
|
||||
}
|
||||
}else{
|
||||
//Jump to next middleware
|
||||
next();
|
||||
}
|
||||
}
|
||||
|
||||
module.exports.throttleAttempts = throttleAttempts;
|
||||
module.exports.maxAttempts = maxAttempts;
|
||||
Loading…
Reference in a new issue