@petercraftsmn/auth-util
Version:
Auth utility functions
391 lines (367 loc) • 12.1 kB
JavaScript
const Middleware = (util, commonUtil, validate) => {
const initializeAllVariablesInReq = (req, res, next) => {
req.error = null;
req.user = null;
req.incomingUser = null;
req.databaseUser = null;
req.jwtToken = null;
req.incomingJwtToken = null;
req.signatureVerifiedJwtToken = null;
req.jwtPayload = null;
req.jwtHeader = null;
req.jwtToken = null;
next();
};
/**
* Validates email and attaches to req.incomingUser.email
* @param req
* @param res
* @param next
*/
const validateEmailInReqBodyEmail = (req, res, next) => {
if ((!!req.body) && (!!req.body.email) && (validate.isEmail(req.body.email))) {
req.incomingUser = {
...req.incomingUser, email: req.body.email
};
req.body.email = null;
next();
} else {
req.error = {place: "validateEmailInReqBodyEmail"};
next('route');
}
}
/**
* Validates req.body.password and attaches to req.incomingUser.password
* consumes req.body.password
* @param req
* @param res
* @param next
*/
const validatePasswordInReqBodyPassword = (req, res, next) => {
if ((!!req.body) && (!!req.body.password) &&
validate.isStringOfPassword(req.body.password)) {
req.incomingUser = {
...req.incomingUser, password: req.body.password
};
req.body.password = null;
next();
} else {
req.error = {place: "validatePasswordInReqBodyPassword"};
next('route');
}
}
/**
* create hash and attach to req.incomingUser.hash
* @param req
* @param res
* @param next
* @returns {Promise<void>}
*/
const createIncomingUserHash = (req, res, next) => {
if ((!!req.incomingUser) && (!!req.incomingUser.password)) {
const hash = util.createPasswordHashStoreString(req.incomingUser.password, util.createRandomSalt());
req.incomingUser = {...req.incomingUser, hash}
req.incomingUser.password = null;
next();
} else {
req.error = {place: "createIncomingUserHash"};
next('route');
}
}
/**
* Create hash using salt stored in database
* @param req
* @param res
* @param next
*/
const createIncomingUserHashForLogin = (req, res, next) => {
if ((!!req.incomingUser) &&
(!!req.incomingUser.password) &&
(!!req.databaseUser) &&
(!!req.databaseUser.hash)) {
const decomposedPassword = commonUtil.decomposePasswordHashStoreString(req.databaseUser.hash);
const hash = util.createPasswordHashStoreString(req.incomingUser.password, decomposedPassword.salt);
req.incomingUser = {...req.incomingUser, hash}
req.incomingUser.password = null;
next();
} else {
req.error = {place: "createIncomingUserHashForLogin"};
next('route');
}
}
/**
* Creates req.header and req.payload object from the req.user
* @param req
* @param res
* @param next
* @returns {Promise<void>}
*/
const createJwtHeaderPayloadForJwtFromReqUserSHA512 = (req, res, next) => {
if ((!!req.user) &&
(!!req.user.user_id)) {
req.jwtHeader = {
"alg": "sha512",
"typ": "JWT"
};
req.jwtPayload = {
"user_id": req.user.user_id,
"time": Date.now(),
};
req.user = {...req.user, user_id: null};
next();
} else {
req.error = {place: "createJwtHeaderPayloadForJwtFromReqUserSHA512"};
next('route');
}
}
/**
* Creates a jwt token and attach to req.jwtToken
* consumes req.header and req.payload
* @param req
* @param res
* @param next
*/
const createJwtTokenSHA512 = (req, res, next) => {
if (req.jwtHeader || req.jwtPayload) {
req.jwtToken = util.jwtCreateSHA512(req.jwtHeader, req.jwtPayload);
req.jwtHeader = null;
req.jwtPayload = null;
next();
} else {
req.error = {place: "createJwtTokenSHA512"};
next('route');
}
}
/**
* Sends jwt to the user in reply
* @param req
* @param res
* @param next
*/
const sendJwtInReply = (req, res, next) => {
if ((!!req.jwtToken)) {
res.json({jwt: req.jwtToken});
} else {
req.error = {place: "sendJwtInReply"};
next('route');
}
}
/**
* Move req.databaseUser.user_id to req.user.user_id
* @param req
* @param res
* @param next
*/
const moveReqDatabaseUserIdToReqUserId = (req, res, next) => {
if ((!!req.databaseUser) && (!!req.databaseUser.user_id)) {
req.user = {
...req.user,
user_id: req.databaseUser.user_id
};
req.databaseUser = {...req.databaseUser, user_id: null};
next();
} else {
req.error = {place: "moveReqDatabaseUserIdToReqUserId"};
next('route');
}
}
/**
* Move req.databaseUser.email to req.user.email
* @param req
* @param res
* @param next
*/
const moveReqDatabaseUserEmailToReqUserEmail = (req, res, next) => {
if ((!!req.databaseUser) && (!!req.databaseUser.email)) {
req.user = {
...req.user,
email: req.databaseUser.email
};
req.databaseUser = {...req.databaseUser, email: null};
next();
} else {
req.error = {place: "moveReqDatabaseUserEmailToReqUserEmail"};
next('route');
}
}
/**
* If user logged in req.user contains user_id and email user is null otherwise
* @param req
* @param res
* @param next
*/
const loginUserUsingReqIncomingUserReqDatabaseUser = (req, res, next) => {
if ((!!req.incomingUser) &&
(!!req.databaseUser) &&
(!!req.incomingUser.hash) &&
(!!req.incomingUser.email) &&
(!!req.databaseUser.hash) &&
(!!req.databaseUser.email) &&
(!!req.databaseUser.user_id) &&
(req.incomingUser.hash === req.databaseUser.hash) &&
(req.incomingUser.email === req.databaseUser.email)) {
req.user = {
user_id: req.databaseUser.user_id,
email: req.databaseUser.email
};
req.incomingUser = {...req.incomingUser, hash: null, email: null};
req.databaseUser = {...req.databaseUser, hash: null, email: null, user_id: null};
next();
} else {
req.error = {place: "loginUserUsingReqIncomingUserReqDatabaseUser"};
next('route');
}
}
/**
* Validates and parses jwt from the params and attach to req.recoveryJwtToken
* @param req
* @param res
* @param next
*/
const parseJwtFromUrlParamJwtAndAttachToReq = (req, res, next) => {
if (!!req.params && !!req.params.jwt &&
(validate.validateStringForCharactersPermittedInJwt(req.params.jwt))) {
req.incomingJwtToken = req.params.jwt;
req.params.jwt = null;
next();
} else {
next();
}
}
/**
* Jwt comes in the body.jwt
* @param req
* @param res
* @param next
*/
const parseJwtFromBodyAndAttachToReq = (req, res, next) => {
if (!!req.body && !!req.body.jwt &&
(validate.validateStringForCharactersPermittedInJwt(req.body.jwt))) {
req.incomingJwtToken = req.body.jwt;
req.body.jwt = null;
next();
} else {
next();
}
};
/**
* Extract jwt from Authorization header with bearer schema
* @param req
* @param res
* @param next
*/
const parseJwtFromAuthenticationHeaderAndAttachToReq = (req, res, next) => {
if (!!req && !!req.get('authorization')) {
try {
const [schema, jwt] = req.get('authorization').split(' ')
if (!!schema &&
!!jwt &&
schema.toLowerCase() === 'bearer' &&
validate.validateStringForCharactersPermittedInJwt(jwt)) {
req.incomingJwtToken = jwt;
next();
}
} catch (err) {
next(err);
}
} else {
next();
}
};
/**
* verify jwt signatures are correct and attach to req.jwtToken
* @param req
* @param res
* @param next
*/
const verifyIncomingJwtTokenSignature = (req, res, next) => {
if (!!req.incomingJwtToken && util.jwtIsSignatureValid(req.incomingJwtToken)) {
req.signatureVerifiedJwtToken = req.incomingJwtToken;
req.incomingJwtToken = null;
next();
} else {
req.error = {place: "verifyIncomingJwtTokenSignature"};
next('route');
}
}
/**
* Parses jwt token from Authorization header and attach to req.user
* @param req
* @param res
* @param next
* @returns {Promise<void>}
*/
const readReqSignatureVerifiedJwtTokenAttachToReqUser = (req, res, next) => {
if ((!!req.signatureVerifiedJwtToken)) {
req.user = util.jwtRead(req.signatureVerifiedJwtToken);
req.signatureVerifiedJwtToken = null;
next();
} else {
req.error = {place: "readReqSignatureVerifiedJwtTokenAttachToReqUser"};
next('route');
}
};
/**
* Send password updated success message
* @param req
* @param res
* @param next
*/
const sendPasswordUpdatedReply = (req, res, next) => {
if ((!!req.user) && (!!req.user.updated)) {
req.user = null;
res.json({message: "update successful"})
next();
} else {
req.error = {place: "sendPasswordUpdatedReply"};
next('route');
}
}
/**
* Sends email for recovery
* @param req
* @param res
* @param next
*/
//Todo:: email sending to be implemented
const emailLinkForPasswordRecovery = (req, res, next) => {
res.json({
message: "Please check your mail",
jwt: req.jwtToken // Should go in the email
})
}
const validateIfUserIsExpired = validityInSeconds => (req, res, next) => {
if (!!req.user &&
!!req.user.payload &&
!!req.user.payload.time &&
(req.user.payload.time > (Date.now() - (validityInSeconds * 1000)))) {
next();
} else {
req.user = null;
req.error = {place: "validateIfUserIsExpired"};
next('route');
}
};
return {
parseJwtFromBodyAndAttachToReq,
initializeAllVariablesInReq,
validateEmailInReqBodyEmail,
validatePasswordInReqBodyPassword,
createIncomingUserHash,
createIncomingUserHashForLogin,
createJwtTokenSHA512,
createJwtHeaderPayloadForJwtFromReqUserSHA512,
moveReqDatabaseUserIdToReqUserId,
moveReqDatabaseUserEmailToReqUserEmail,
loginUserUsingReqIncomingUserReqDatabaseUser,
parseJwtFromUrlParamJwtAndAttachToReq,
parseJwtFromAuthenticationHeaderAndAttachToReq,
verifyIncomingJwtTokenSignature,
readReqSignatureVerifiedJwtTokenAttachToReqUser,
sendJwtInReply,
sendPasswordUpdatedReply,
emailLinkForPasswordRecovery,
validateIfUserIsExpired
};
}
module.exports = Middleware;