Files
looking-monorepo/models/reset.js
2018-03-03 13:07:07 -05:00

326 lines
12 KiB
JavaScript

const Authentication = require('../modules/authentication');
const Crypto = require('crypto');
const Mongoose = require('mongoose');
const Mailer = require('nodemailer');
const Token = require('../modules/token');
const secret = 'Creepily hooking the gays up since 2008!';
var logger = require('../modules/logger');
function generateHmac (userId, expires) {
var string = String(userId) + '|' + String(expires);
return Crypto.createHmac('sha1', secret).update(string).digest('hex');
}
function sendMail (options, callback) {
// create reusable transporter object using the default SMTP transport
let transporter = Mailer.createTransport({
host: 'mail.fitz.guru',
port: 587,
secure: false, // secure:true for port 465, secure:false for port 587
auth: {
user: 'support@fitz.guru',
pass: 'NotSt@ff3d!'
}
});
callback = typeof callback === 'function' ? callback : (error, info) => {
if (error) {
return logger.error(error);
}
logger.debug('Message %s sent: %s', info.messageId, info.response);
};
// send mail with defined transport object
transporter.sendMail(options, callback);
}
const ResetSchema = new Mongoose.Schema({
user: { type: Mongoose.Schema.Types.ObjectId, required: true },
expires: { type: Date, default: Date.now },
used: { type: Boolean, default: false },
updated_at: { type: Date, default: Date.now }
});
const ResetModel = Mongoose.model('resets', ResetSchema);
module.exports = {
checkReset: (e, id, token, callback) => {
const promise = new Promise((resolve, reject) => {
ResetModel.findOne({ _id: id }, (err, result) => {
if (err) {
reject(err);
}
if (result && (token === generateHmac(result.user, result.expires)) && (Date.now() <= result.expires)) {
resolve({ user: String(result.user), err: null });
} else {
resolve({ user: false, err: 'The reset link has expired. Please request a new reset link from the login page.'});
}
});
});
promise.then((result) => {
if (e) {
e.emit('checkReset', null, result);
} else if (callback) {
callback(null, result.user);
} else {
return true;
}
})
.catch((err) => {
if (e) {
e.emit('checkReset', err, null);
} else if (callback) {
callback(err, null);
} else {
return false;
}
});
},
forceReset: (e, user, callback) => {
const promise = new Promise((forceResetMailResolve, forceResetMailReject) => {
const forceResetTokenPromise = new Promise((forceResetTokenResolve, forceResetTokenReject) => {
var tokenInstance = new ResetModel({ user: user._id, expires: (Date.now() + (72 * 60 * 60 * 1000)) });
tokenInstance.save((err, result) => {
if (err) {
forceResetTokenReject(err);
}
if (result) {
forceResetTokenResolve(result);
}
});
});
forceResetTokenPromise.then((result) => {
let resetLink = 'https://timberland.bizdex.cloud/reset/' + encodeURIComponent(result._id) + '/' + encodeURIComponent(generateHmac(result.user, result.expires));
// setup email data with unicode symbols
let mail = {
from: '"GCS Vendor Database" <system@timberland.bizdex.cloud>',
to: user.email,
subject: 'Mandatory Password Reset',
text: 'Mandatory Password Reset\r\r\r\r' + user.name.first + ',\r\rA Timberland GCS Vendor Database Administrator has initiated a password reset on your account.\r\rTo complete the action you will need to reset you password <<' + resetLink + '>>.\r\rIf you have any questions, please contact a system administrator.',
html: '<h2>Mandatory Password Reset</h2><p>' + user.name.first + ',</p><p>A Timberland GCS Vendor Database Administrator has initiated a password reset on your account.</p>To complete the action you will need to <a href="' + resetLink + '">reset your password</a>.</p><p><b>If you have any questions, please contact a system administrator.</b></p>'
};
sendMail(mail, (error, info) => {
if (error) {
logger.debug('[reset::forceReset] Message Send Error', { error: error });
forceResetMailResolve({ success: false, message: 'There was an error sending the message', error: error });
}
if (info) {
logger.debug('[reset::forceReset] Message sent', { messageId: info.messageId, response: info.response, resetLink: resetLink });
forceResetMailResolve({ success: true, message: 'Message ' + info.messageId + ' sent: ' + info.response + '.' });
}
});
})
.catch((err) => {
logger.debug('[reset::forceReset] There was an error creating the reset token.', { err: err });
forceResetMailReject(err);
});
});
promise.then((result) => {
if (e) {
e.emit('forceReset', null, result);
} else if (callback) {
callback(result);
} else {
return true;
}
})
.catch((err) => {
if (e) {
e.emit('forceReset', err, null);
} else if (callback) {
callback(err);
} else {
return false;
}
});
},
getResets: (e) => {
const promise = new Promise((resolve, reject) => {
ResetModel.find({}, (err, results) => {
if (err) {
reject(err);
}
if (results) {
resolve(results);
}
});
});
promise.then((results) => {
e.emit('getResets', null, results);
})
.catch((err) => {
e.emit('getResets', err, null);
});
},
markUsed: (e, id) => {
const promise = new Promise((resolve, reject) => {
ResetModel.findByIdAndUpdate(id, { $set: { used: true } }, (err, result) => {
if (err) {
reject(err);
}
if (result) {
resolve(result);
}
});
});
promise.then((result) => {
if (e) {
e.emit('markUsed', null, result);
} else {
logger.debug('[ResetModel::markUsed] Password reset token used', { token: result });
}
})
.catch((err) => {
if (e) {
e.emit('markUsed', err, null);
} else {
logger.error('[ResetModel::markUsed] Error marking password reset token used', { token: err });
}
});
},
sendNewUser: (e, user) => {
const promise = new Promise((newUserMailResolve, newUserMailReject) => {
const newUserTokenPromise = new Promise((newUserTokenResolve, newUserTokenReject) => {
var tokenInstance = new ResetModel({ user: user._id, expires: (Date.now() + (72 * 60 * 60 * 1000)) });
tokenInstance.save((err, result) => {
if (err) {
newUserTokenReject(err);
}
if (result) {
newUserTokenResolve(result);
}
});
});
newUserTokenPromise.then((result) => {
let setPasswordLink = 'https://timberland.bizdex.cloud/reset/' + encodeURIComponent(result._id) + '/' + encodeURIComponent(generateHmac(result.user, result.expires));
// setup email data with unicode symbols
let mail = {
from: '"GCS Vendor Database" <system@timberland.bizdex.cloud>',
to: user.email,
subject: 'New User Account Setup',
text: 'New User Account Setup\r\r\r\r' + user.name.first + ',\r\rA new user has been created for you on the Timberland GCS Vendor Database.\r\rYour username is: <<' + user.userName + '>>.\r\r To complete the setup you will need to create a password <<' + setPasswordLink + '>>.\r\rIf you have any questions, please contact a system administrator.',
html: '<h2>New User Account Setup</h2><p>' + user.name.first + ',</p><p>A new user has been created for you on the Timberland GCS Vendor Database.</p><p>Your username is: <b>' + user.userName + '</b>.</p>To complete the setup you will need to <a href="' + setPasswordLink + '">create a password</a>.</p><p><b>If you have any questions, please contact a system administrator.</b></p>'
};
sendMail(mail, (error, info) => {
if (error) {
logger.error('[reset::sendNewUser] Message Send Error', { error: error });
newUserMailResolve({ success: false, message: 'There was an error sending the message', error: error });
}
if (info) {
logger.debug('[reset::sendNewUser] Message %s sent: %s', info.messageId, info.response);
newUserMailResolve({ success: true, message: 'Message ' + info.messageId + ' sent: ' + info.response + '.' });
}
});
})
.catch((err) => {
logger.error('[reset::sendNewUser] There was an error creating the reset token.', { err: err });
newUserMailReject(err);
});
});
promise.then((result) => {
if (e) {
e.emit('sendNewUser', null, result);
} else {
return true;
}
})
.catch((err) => {
if (e) {
e.emit('sendNewUser', err, null);
} else {
return false;
}
});
},
sendReset: (e, user) => {
const resetTokenPromise = new Promise((resetTokenResolve, resetTokenReject) => {
var tokenInstance = new ResetModel({ user: user._id, expires: (Date.now() + (30 * 60 * 1000)) });
tokenInstance.save((err, result) => {
if (err) {
resetTokenReject(err);
}
if (result) {
resetTokenResolve(result);
}
});
});
resetTokenPromise.then((data) => {
var token = generateHmac(data.user, data.expires);
var tokenId = data._id;
const sendMailPromise = new Promise((sendMailResolve, sendMailReset) => {
var resetLink = 'https://timberland.bizdex.cloud/reset/' + encodeURIComponent(tokenId) + '/' + encodeURIComponent(token);
// setup email data with unicode symbols
var mail = {
from: '"GCS Vendor Database" <system@timberland.bizdex.cloud>',
to: user.email,
subject: 'Password Reset Request',
text: user.name.first + ',\r\rA request has been received to reset your password. If you initiated please visit <<' + resetLink + '>>.\r\rIf you did not initiate this request, you can safely ignore this email.',
html: '<h2>Password Reset Request</h2><p>' + user.name.first + ',</p><p>A request has been received to reset your password. If you initiated this request, <a href="' + resetLink + '">click here to reset your password</a>.</p><p><b>If you did not initiate this request, you can safely ignore this email.</b></p>'
};
sendMail(mail, (err, info) => {
if (err) {
var error = { msg: '[reset::sendReset] There was an error sending the reset email.', err: err };
logger.error('[reset::sendReset] Message Send Error', { err: err });
sendMailResolve({ success: false, message: 'There was an error requesting the password reset.', error: error });
}
if (info) {
var message = 'Message ' + info.messageId + ' sent: ' + info.response + '.';
logger.debug('[reset::sendReset] ' + message);
sendMailResolve({ success: true, message: 'The password reset request was successfully completed.', response: message });
}
});
});
sendMailPromise.then((result) => {
e.emit('sendReset', null, result);
})
.catch((err) => {
e.emit('sendReset', err, null);
});
})
.catch((err) => {
var error = { msg: '[reset::sendReset] There was an error creating the reset token.', err: err };
logger.debug(error.msg, { err: err });
e.emit('sendReset', null, { success: false, message: 'There was an error requesting the password reset.', error: error });
});
}
};