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!'; 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 console.log(error); } console.log('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: 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" ', 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: '

Mandatory Password Reset

' + user.name.first + ',

A Timberland GCS Vendor Database Administrator has initiated a password reset on your account.

To complete the action you will need to reset your password.

If you have any questions, please contact a system administrator.

' }; sendMail(mail, (error, info) => { if (error) { console.log('[reset::forceReset] Message Send Error', { error: error }); forceResetMailResolve({ success: false, message: 'There was an error sending the message', error: error }); } if (info) { console.log('[reset::forceReset] Message sent', { messageId: info.messageId, response: info.response, resetLink: resetLink }); forceResetMailResolve({ success: true, message: 'Message ' + info.messageId + ' sent: ' + info.response + '.' }); } }); }) .catch((err) => { console.log('[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(result); } 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 { console.log('[ResetModel::markUsed] Password reset token used', { token: result }); } }) .catch((err) => { if (e) { e.emit('markUsed', err, null); } else { console.error('[ResetModel::markUsed] Error marking password reset token used', { token: result }); } }); }, 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" ', 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: '

New User Account Setup

' + user.name.first + ',

A new user has been created for you on the Timberland GCS Vendor Database.

Your username is: ' + user.userName + '.

To complete the setup you will need to create a password.

If you have any questions, please contact a system administrator.

' }; sendMail(mail, (error, info) => { if (error) { console.log('[reset::sendNewUser] Message Send Error', { error: error }); newUserMailResolve({ success: false, message: 'There was an error sending the message', error: error }); } if (info) { console.log('[reset::sendNewUser] Message %s sent: %s', info.messageId, info.response); newUserMailResolve({ success: true, message: 'Message ' + info.messageId + ' sent: ' + info.response + '.' }); } }); }) .catch((err) => { console.log('[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" ', 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: '

Password Reset Request

' + user.name.first + ',

A request has been received to reset your password. If you initiated this request, click here to reset your password.

If you did not initiate this request, you can safely ignore this email.

' }; sendMail(mail, (err, info) => { if (err) { var error = { msg: '[reset::sendReset] There was an error sending the reset email.', err: err }; console.log('[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 + '.'; console.log('[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 }; console.log(error.msg, { err: err }); e.emit('sendReset', null, { success: false, message: 'There was an error requesting the password reset.', error: error }); }); } };