Skip to content

Commit

Permalink
Resolved Minor Bugs and Improved Performance in Server
Browse files Browse the repository at this point in the history
  • Loading branch information
stanleyowen committed May 8, 2021
1 parent 04e8e13 commit a9682d9
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 76 deletions.
127 changes: 54 additions & 73 deletions server/lib/passport.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ const GoogleStrategy = require('passport-google-oauth').OAuth2Strategy;

const { encrypt, decrypt } = require('../lib/crypto');
const MSG_DESC = require('./callback');

let User = require('../models/users.model');
let Todo = require('../models/todo.model');
let Token = require('../models/token.model');
Expand Down Expand Up @@ -127,7 +126,7 @@ passport.use('tokenData', new localStrategy({ usernameField: 'id', passwordField
else if(user && userId === decrypt(user.userId, 3) && token === decrypt(user.token, 3)){
User.findById(userId, (err, user) => {
if(err) done(err, false)
else if(user) return done(null, user, {
else if(user) return done(null, true, {
status: 200,
message: MSG_DESC[5],
credentials: {
Expand All @@ -145,79 +144,83 @@ passport.use('tokenData', new localStrategy({ usernameField: 'id', passwordField
passport.use('forgotPassword', new localStrategy({ usernameField: 'email', passwordField: 'email', session: false }, (email, token, done) => {
axios.get('https://api.ipify.org/?format=json')
.then(async res => {
const ip = res.data.ip;
const ip = res.data.ip
Token.find({ ipAddr: ip, 'type.passwordReset': true }, (err, data) => {
if(err) return done(err, false);
else if(data && data.length >= 5) return done(null, false, { status: 403, message: MSG_DESC[30] });
else if(!data || data.length < 5){
if(err) return done(err, false)
else if(data && data.length >= 5) return done(null, false, { status: 403, message: MSG_DESC[30] })
else if(!data || data.length < 5) {
User.findOne({ email }, (err, user) => {
if(err) return done(err, false);
if(err) return done(err, false)
else if(user) {
const id = user.id;
const token = crypto.randomBytes(60).toString("hex");
const id = user.id
const token = crypto.randomBytes(60).toString("hex")
new Token({ ipAddr: ip, 'type.passwordReset': true, userId: encrypt(id, 3), token: encrypt(token, 3) }).save((err, data) => {
if(err) return done(err, false);
if(err) return done(err, false)
else {
const mailOptions = {
to: email,
subject: '[TodoApp] Password Reset',
html: `<!DOCTYPE html><html xmlns="http://www.w3.org/1999/xhtml" xmlns:o="urn:schemas-microsoft-com:office:office"><head><meta charset="UTF-8"><meta content="width=device-width, initial-scale=1" name="viewport"><meta name="x-apple-disable-message-reformatting"><meta http-equiv="X-UA-Compatible" content="IE=edge"> <!--[if IE]><style type="text/css">a{text-decoration:none;color:black!important}</style><![endif]--> <!--[if (mso 16)]><style type="text/css">a{text-decoration:none}</style><![endif]--> <!--[if gte mso 9]><style>sup{font-size:100% !important}</style><![endif]--> <!--[if gte mso 9]> <xml> <o:OfficeDocumentSettings> <o:AllowPNG></o:AllowPNG> <o:PixelsPerInch>96</o:PixelsPerInch> </o:OfficeDocumentSettings> </xml> <![endif]--></head><body><div class="es-wrapper-color"> <!--[if gte mso 9]> <v:background xmlns:v="urn:schemas-microsoft-com:vml" fill="t"> <v:fill type="tile" color="#f4f4f4"></v:fill> </v:background> <![endif]--><table class="es-wrapper" width="100%" cellspacing="0" cellpadding="0"><tr><td class="esd-email-paddings" valign="top"><table class="es-header" cellspacing="0" cellpadding="0" align="center"><tr><td class="esd-stripe" esd-custom-block-id="6339" style="background-color: rgb(8 72 179); padding: 10px; border-radius: 10px;" bgcolor="#7c72dc" align="center"><table class="es-header-body" width="600" cellspacing="0" cellpadding="0" align="center"><tr><table width="100%" cellspacing="0" cellpadding="0"><tr><td class="esd-block-image es-p25t es-p25b es-p10r es-p10l" align="center" style="font-size: 0px;"><img src="https://raw.githubusercontent.com/stanleyowen/todo-application/v0.4.3/client/public/logo512.png" alt style="display: block;" width="40"></td></tr></table></tr></table></td></tr></table><table class="es-content" cellspacing="0" cellpadding="0" align="center"><tr><td class="esd-stripe" align="center"><table class="es-content-body" style="background-color: #ffffff;" width="600" cellspacing="0" cellpadding="10" bgcolor="#ffffff" align="center"><tr><td bgcolor="#ffffff" align="left"><p style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif">Need to reset your password? No problem! Just click the button below to reset your password!</p><div style="display: block; width: 100%; text-align: center; margin: 30px 0;"> <a href="${CLIENT_URL}/reset-password/${id}-${data.id}/${token}" style="padding: 15px 30px; background-color: rgb(8 72 179); color: white; text-decoration: none; border-radius: 5px; font-family: Cambria, Georgia, Times, 'Times New Roman', serif; font-weight: bold;">Reset your password</a></div><p style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif">This link will expires after one hour. To get a new password reset link, visit:<br>${CLIENT_URL}/reset-password</p><p style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif">Best Regards,<br>Todo Application</p></td></tr><tr><td align="center"><p style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif; color: gray; font-size: 15px;">You're receiving this email because a password reset was requested for your account.</p></td></tr></table></td></tr></table></td></tr></table></div></body></html>`
};
}
transporter.sendMail(mailOptions, (err) => {
if(err) return done(err, false);
else return done(null, user, { status: 200, message: MSG_DESC[29] });
});
})
}
});
}else return done(null, false, { status: 400, message: MSG_DESC[32] });
}else return done(null, false, { status: 400, message: MSG_DESC[32] })
})
}
})
})
.catch(err => { return done(err, false); })
}))

passport.use('resetPassword', new localStrategy({ usernameField: 'email', passwordField: 'password', passReqToCallback: true, session: false }, (req, email, password, done) => {
const {id, type, token, confirmPassword} = req.body;
if(!id || !token || !confirmPassword) return done(null, false, { status: 400, message: MSG_DESC[11] });
else if(EMAIL_VAL.test(String(email).toLocaleLowerCase()) === false || email.length < 6 || email.length > 60) return done(null, false, { status: 400, message: MSG_DESC[8] })
else if(password.length < 6 || password.length > 60 || confirmPassword.length < 6 || confirmPassword.length > 60) return done(null, false, { status: 400, message: MSG_DESC[9] });
else if(password !== confirmPassword) return done(null, false, { status: 400, message: MSG_DESC[7] })
else {
const userId = id.split('-')[0];
const tokenId = id.split('-')[1];
var query = {};
query['_id'] = tokenId; query['type.'.concat(type)] = true;
Token.findOne(query, (err, data) => {
if(err) done(err, false);
else if(data && token === decrypt(data.token, 3) && userId === decrypt(data.userId, 3)){
bcrypt.hash(password, SALT_WORK_FACTOR, (err, hash) => {
if(err) return done(err, false);
else {
User.findOneAndUpdate({_id: userId, email}, { password: hash }, (err, user) => {
if(err) done(err, false);
else if(user) {
data.remove();
const mailOptions = {
to: email,
replyTo: process.env.MAIL_REPLY_TO,
subject: '[TodoApp] Password Changed',
html: `Hi ${email},<br><br>We wanted to inform that your Todo Application password has changed.<br><br> If you did not perform this action, you can recover access by entering ${email} into the form at ${CLIENT_URL}/reset-password<br><br> Please do not reply to this email with your password. We will never ask for your password, and we strongly discourage you from sharing it with anyone.`
};
transporter.sendMail(mailOptions, (err) => {
if(err) return done(err, false);
else return done(null, user, { status: 200, message: MSG_DESC[6] });
});
}else return done(null, false, { status: 401, message: MSG_DESC[10] });
})
}
})
}else return done(null, false, { status: 400, message: MSG_DESC[32] });
})
passport.use('token', new localStrategy({ usernameField: 'id', passwordField: 'token', passReqToCallback: true, session: false }, (req, id, token, done) => {
const {type, email, password, confirmPassword} = req.body;
const userId = id.split('-')[0];
const tokenId = id.split('-')[1];
if(!type || !userId || !tokenId) return done(null, false, { status: 400, message: MSG_DESC[11] })
else if(type === 'passwordReset'){
if(!email || !password || !confirmPassword) return done(null, false, { status: 400, message: MSG_DESC[11] })
else if(EMAIL_VAL.test(String(email).toLocaleLowerCase()) === false || email.length < 6 || email.length > 60) return done(null, false, { status: 400, message: MSG_DESC[8] })
else if(password.length < 6 || password.length > 60 || confirmPassword.length < 6 || confirmPassword.length > 60) return done(null, false, { status: 400, message: MSG_DESC[9] })
else if(password !== confirmPassword) return done(null, false, { status: 400, message: MSG_DESC[7] })
}
var query = {}; query['_id'] = tokenId; query['type.'.concat(type)] = true;
Token.findOne(query, (err, data) => {
if(err) done(err, false)
else if(data && userId === decrypt(data.userId, 3) && token === decrypt(data.token, 3)){
var query = {}; query['_id'] = userId; email ? query['email'] = email : null;
var updateData = {};
if(type === 'passwordReset') bcrypt.hash(password, SALT_WORK_FACTOR, (err, hash) => {
if(err) done(err, false)
else updateData['password'] = hash
})
else updateData['verified'] = true
User.findOneAndUpdate(query, updateData, (err, user) => {
if(err) done(err, false)
else if(user) {
data.remove();
if(type === 'passwordReset'){
const mailOptions = {
to: email,
replyTo: process.env.MAIL_REPLY_TO,
subject: '[TodoApp] Password Changed',
html: `Hi ${email},<br><br>We wanted to inform that your Todo Application password has changed.<br><br> If you did not perform this action, you can recover access by entering ${email} into the form at ${CLIENT_URL}/reset-password<br><br> Please do not reply to this email with your password. We will never ask for your password, and we strongly discourage you from sharing it with anyone.`
}
transporter.sendMail(mailOptions, (err) => {
if(err) return done(err, false);
else return done(null, user, { status: 200, message: MSG_DESC[6] });
})
}else return done(null, user, { status: 200, message: MSG_DESC[5] })
}else return done(null, false, { status: 401, message: MSG_DESC[10] })
})
}else return done(null, false, { status: 400, message: MSG_DESC[32] })
})
}))

passport.use('verifyAccount', new localStrategy({ usernameField: 'email', passwordField: 'id', session: false }, (email, _id, done) => {
passport.use('verifyAccount', new localStrategy({ usernameField: 'email', passwordField: '_id', session: false }, (email, _id, done) => {
axios.get('https://api.ipify.org/?format=json')
.then(async res => {
const ip = res.data.ip
Expand Down Expand Up @@ -253,28 +256,6 @@ passport.use('verifyAccount', new localStrategy({ usernameField: 'email', passwo
.catch(err => { return done(err, false) })
}))

passport.use('verifyUser', new localStrategy({ usernameField: 'id', passwordField: 'token', passReqToCallback: true, session: false }, (req, id, token, done) => {
const {type} = req.params;
const userId = id.split('-')[0];
const tokenId = id.split('-')[1];
var query = {};
query['_id'] = tokenId; query['type.'.concat(type)] = true;
Token.findOne(query, (err, data) => {
if(err) return done(err, false);
else if(data && userId === decrypt(data.userId, 3) && token === decrypt(data.token, 3)){
User.findById(userId, (err, user) => {
if(err) done(err, false);
else if(user){
user.verified = true;
user.save(); data.remove();
return done(null, user, { status: 200, message: MSG_DESC[5] });
}
else return done(null, false, { status: 400, message: MSG_DESC[31] });
})
}else return done(null, false, { status: 400, message: MSG_DESC[31] });
})
}))

passport.use('github', new GitHubStrategy ({ clientID: process.env.GITHUB_ID, clientSecret: process.env.GITHUB_SECRET, callbackURL: process.env.GITHUB_CALLBACK }, (accessToken, refreshToken, profile, done) => {
const email = profile._json.email;
User.findOne({email}, (err, user) => {
Expand Down
7 changes: 4 additions & 3 deletions server/routes/users.route.js
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,8 @@ router.post('/forgot-password', async (req, res, next) => {
})

router.post('/reset-password', async (req, res, next) => {
passport.authenticate('resetPassword', { session: false }, (err, user, info) => {
passport.authenticate('token', { session: false }, (err, user, info) => {
console.log(err)
if(err) return res.status(500).send(JSON.stringify({status: 500, message: MSG_DESC[0]}, null, 2));
else if(info && (info.status ? info.status >= 300 ? true : false : true)) return res.status(info.status ? info.status : info.status = 400).send(JSON.stringify(info, null, 2));
else if(user) return res.cookie('jwt-token', jwt.sign({
Expand All @@ -196,8 +197,8 @@ router.post('/reset-password', async (req, res, next) => {
})

router.get('/verify', async (req, res, next) => {
req.params = req.query;
passport.authenticate('verifyUser', { session: false }, (err, user, info) => {
req.body = req.query;
passport.authenticate('token', { session: false }, (err, user, info) => {
if(err) return res.status(500).send(JSON.stringify({status: 500, message: MSG_DESC[0]}, null, 2));
else if(info && (info.status ? info.status >= 300 ? true : false : true)) return res.status(info.status ? info.status : info.status = 400).send(JSON.stringify(info, null, 2));
else if(user) return res.send(JSON.stringify(info, null, 2))
Expand Down

0 comments on commit a9682d9

Please sign in to comment.