/** * @description Meshcentral MeshMail * @author Ylian Saint-Hilaire * @version v0.0.1 */ // Construct a MeshAgent object, called upon connection module.exports.CreateMeshMain = function (parent) { var obj = {}; obj.pendingMails = []; obj.parent = parent; obj.retry = 0; obj.sendingMail = false; obj.mailCookieEncryptionKey = null; const nodemailer = require('nodemailer'); // Default account email validation mail var accountCheckSubject = '[[[SERVERNAME]]] - Email Verification'; var accountCheckMailHtml = '
[[[SERVERNAME]]] - Verification

Hi [[[USERNAME]]], [[[SERVERNAME]]] is requesting email verification, click on the following link to complete the process.

Click here to verify your e-mail address.

If you did not initiate this request, please ignore this mail.
'; var accountCheckMailText = '[[[SERVERNAME]]] - Verification\r\n\r\nHi [[[USERNAME]]], [[[SERVERNAME]]] ([[[SERVERURL]]]) is performing an e-mail verification. Nagivate to the following link to complete the process: [[[CALLBACKURL]]]\r\nIf you did not initiate this request, please ignore this mail.\r\n'; // Default account reset mail var accountResetSubject = '[[[SERVERNAME]]] - Account Reset'; var accountResetMailHtml = '
[[[SERVERNAME]]] - Verification

Hi [[[USERNAME]]], [[[SERVERNAME]]] is requesting an account password reset, click on the following link to complete the process.

Click here to reset your account password.

If you did not initiate this request, please ignore this mail.
'; var accountResetMailText = '[[[SERVERNAME]]] - Account Reset\r\n\r\nHi [[[USERNAME]]], [[[SERVERNAME]]] ([[[SERVERURL]]]) is requesting an account password reset. Nagivate to the following link to complete the process: [[[CALLBACKURL]]]\r\nIf you did not initiate this request, please ignore this mail.\r\n'; // Setup mail server var options = { host: parent.config.smtp.host, secure: (parent.config.smtp.tls == true), tls: { rejectUnauthorized: false } }; if (parent.config.smtp.port != null) { options.port = parent.config.smtp.port; } if ((parent.config.smtp.user != null) && (parent.config.smtp.pass != null)) { options.auth = { user: parent.config.smtp.user, pass: parent.config.smtp.pass }; } obj.smtpServer = nodemailer.createTransport(options); // Perform all e-mail substitution function mailReplacements(text, domain, username, email, cookie) { var url = 'http' + ((obj.parent.args.notls == null) ? 's' : '') + '://' + parent.certificates.CommonName + ':' + obj.parent.args.port + domain.url; if (cookie != null) { text = text.split('[[[CALLBACKURL]]]').join(url + 'checkmail?c=' + cookie) } return text.split('[[[USERNAME]]]').join(username).split('[[[SERVERURL]]]').join(url).split('[[[SERVERNAME]]]').join(domain.title); } // Send a mail obj.sendMail = function (to, subject, text, html) { obj.pendingMails.push({ to: to, from: parent.config.smtp.from, subject: subject, text: text, html: html }); sendNextMail(); } // Send account check mail obj.sendAccountCheckMail = function (domain, username, email) { if ((parent.certificates == null) || (parent.certificates.CommonName == null)) return; // If the server name is not set, no reset possible. var cookie = obj.parent.encodeCookie({ u: domain.id + '/' + username, e: email, a: 1 }, obj.mailCookieEncryptionKey); obj.pendingMails.push({ to: email, from: parent.config.smtp.from, subject: mailReplacements(accountCheckSubject, domain, username, email), text: mailReplacements(accountCheckMailText, domain, username, email, cookie), html: mailReplacements(accountCheckMailHtml, domain, username, email, cookie) }); sendNextMail(); } // Send account reset mail obj.sendAccountResetMail = function (domain, username, email) { if ((parent.certificates == null) || (parent.certificates.CommonName == null)) return; // If the server name is not set, don't validate the email address. var cookie = obj.parent.encodeCookie({ u: domain.id + '/' + username, e: email, a: 2 }, obj.mailCookieEncryptionKey); obj.pendingMails.push({ to: email, from: parent.config.smtp.from, subject: mailReplacements(accountResetSubject, domain, username, email), text: mailReplacements(accountResetMailText, domain, username, email, cookie), html: mailReplacements(accountResetMailHtml, domain, username, email, cookie) }); sendNextMail(); } // Send out the next mail in the pending list function sendNextMail() { if ((obj.sendingMail == true) || (obj.pendingMails.length == 0)) { return; } var mailToSend = obj.pendingMails[0]; obj.sendingMail = true; //console.log('SMTP sending mail to ' + mailToSend.to + '.'); obj.smtpServer.sendMail(mailToSend, function (err, info) { //console.log(JSON.stringify(err), JSON.stringify(info)); obj.sendingMail = false; if (err == null) { obj.pendingMails.shift(); obj.retry = 0; sendNextMail(); // Send the next mail } else { obj.retry++; console.log('SMTP server failed: ' + JSON.stringify(err)); if (obj.retry < 6) { setTimeout(sendNextMail, 60000); } // Wait and try again } }); } // Send out the next mail in the pending list obj.verify = function() { obj.smtpServer.verify(function (err, info) { if (err == null) { console.log('SMTP mail server ' + parent.config.smtp.host + ' working as expected.'); } else { console.log('SMTP mail server ' + parent.config.smtp.host + ' failed: ' + JSON.stringify(err)); } }); } // Load the cookie encryption key from the database obj.parent.db.Get('MailCookieEncryptionKey', function (err, docs) { if ((docs.length > 0) && (docs[0].key != null)) { // Key is present, use it. obj.mailCookieEncryptionKey = Buffer.from(docs[0].key, 'hex'); } else { // Key is not present, generate one. obj.mailCookieEncryptionKey = obj.parent.generateCookieKey(); obj.parent.db.Set({ _id: 'MailCookieEncryptionKey', key: obj.mailCookieEncryptionKey.toString('hex'), time: Date.now() }); } }); return obj; }