/** * @description MeshCentral e-mail server communication modules * @author Ylian Saint-Hilaire * @copyright Intel Corporation 2018 * @license Apache-2.0 * @version v0.0.1 */ /*xjslint node: true */ /*xjslint plusplus: true */ /*xjslint maxlen: 256 */ /*jshint node: true */ /*jshint strict: false */ /*jshint esversion: 6 */ "use strict"; // Construct a MeshAgent object, called upon connection module.exports.CreateMeshMail = 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 const accountCheckSubject = '[[[SERVERNAME]]] - Email Verification'; const 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.
'; const 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 const accountResetSubject = '[[[SERVERNAME]]] - Account Reset'; const 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.
'; const 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'; // Default account invite mail const accountInviteSubject = '[[[SERVERNAME]]] - Invitation'; const accountInviteMailHtml = '
[[[SERVERNAME]]] - Agent Installation

[[[INTROHTML]]]User [[[USERNAME]]] on server [[[SERVERNAME]]] is requesting you to download the following software to start the remote control session.

[[[MSGHTML]]][[[AGENTHTML]]]

If you did not initiate this request, please ignore this mail.

Best regards,
[[[USERNAME]]]
'; const accountInviteMailText = '[[[SERVERNAME]]] - Agent Installation Invitation\r\n\r\n[[[INTROTEXT]]]User [[[USERNAME]]] on server [[[SERVERNAME]]] ([[[SERVERURL]]]) is requesting you to download the following software to start the remote control session. [[[MSGTEXT]]][[[AGENTTEXT]]]If you did not initiate this request, please ignore this mail.\r\n\r\nBest regards,\r\n[[[USERNAME]]]\r\n'; function EscapeHtml(x) { if (typeof x == "string") return x.replace(/&/g, '&').replace(/>/g, '>').replace(//g, '>').replace(/').replace(/\n/g, '').replace(/\t/g, '  '); if (typeof x == "boolean") return x; if (typeof x == "number") return x; } // 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, options) { var url; if (domain.dns == null) { // Default domain or subdomain of the default. url = 'http' + ((obj.parent.args.notls == null) ? 's' : '') + '://' + parent.certificates.CommonName + ':' + obj.parent.args.port + domain.url; } else { // Domain with a DNS name. url = 'http' + ((obj.parent.args.notls == null) ? 's' : '') + '://' + domain.dns + ':' + obj.parent.args.port + domain.url; } if (options) { if (options.cookie == null) { options.cookie = ''; } if (options.agentlinkhtml == null) { options.agentlinkhtml = ''; } if (options.agentlinktext == null) { options.agentlinktext = ''; } if (options.meshid == null) { options.meshid = ''; } if (options.introtext == null) { options.introtext = ''; } if (options.introhtml == null) { options.introhtml = ''; } if (options.msgtext == null) { options.msgtext = ''; } if (options.msghtml == null) { options.msghtml = ''; } text = text.split('[[[CALLBACKURL]]]').join(url + 'checkmail?c=' + options.cookie); text = text.split('[[[AGENTHTML]]]').join(options.agentlinkhtml); text = text.split('[[[AGENTTEXT]]]').join(options.agentlinktext); text = text.split('[[[MESHID]]]').join(options.meshid); text = text.split('[[[INTROTEXT]]]').join(options.introtext); text = text.split('[[[INTROHTML]]]').join(options.introhtml); text = text.split('[[[MSGTEXT]]]').join(options.msgtext); text = text.split('[[[MSGHTML]]]').join(options.msghtml); } return text.split('[[[USERNAME]]]').join(username).split('[[[SERVERURL]]]').join(url).split('[[[SERVERNAME]]]').join(domain.title).split('[[[EMAIL]]]').join(EscapeHtml(email)).split('[[[URL]]]').join(url); } // 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) || (parent.certificates.CommonName == 'un-configured')) 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: cookie }), html: mailReplacements(accountCheckMailHtml, domain, username, email, { cookie: cookie }) }); sendNextMail(); }; // Send account reset mail obj.sendAccountResetMail = function (domain, username, email) { if ((parent.certificates == null) || (parent.certificates.CommonName == null) || (parent.certificates.CommonName == 'un-configured')) 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: cookie }), html: mailReplacements(accountResetMailHtml, domain, username, email, { cookie: cookie }) }); sendNextMail(); }; // Send agent invite mail obj.sendAgentInviteMail = function (domain, username, email, meshid, name, os, msg) { if ((parent.certificates == null) || (parent.certificates.CommonName == null) || (parent.certificates.CommonName == 'un-configured')) return; // If the server name is not set, can't do this. var options = { meshid: meshid.split('/')[2] }; var agentLinkHtml = ''; var agentLinkText = ''; if (os == 0 || os == 1) { // All OS or Windows agentLinkHtml += '

Click here to download the MeshAgent for Windows.

'; agentLinkText += 'For Windows, nagivate to the following link to complete the process:\r\n\r\n[[[SERVERURL]]]/meshagents?id=3&meshid=[[[MESHID]]]&tag=mailto:[[[EMAIL]]]\r\n\r\n'; } if (os == 0 || os == 2) { // All OS or Linux agentLinkHtml += '

For Linux, cut & paste the following in a terminal to install the agent:

wget -q [[[SERVERURL]]]/meshagents?script=1 --no-check-certificate -O ./meshinstall.sh && chmod 755 ./meshinstall.sh && sudo ./meshinstall.sh [[[SERVERURL]]] \'[[[MESHID]]]\'

'; agentLinkText += 'For Linux, cut & paste the following in a terminal to install the agent:\r\n\r\nwget -q [[[SERVERURL]]]/meshagents?script=1 --no-check-certificate -O ./meshinstall.sh && chmod 755 ./meshinstall.sh && sudo ./meshinstall.sh [[[SERVERURL]]] \'[[[MESHID]]]\'\r\n\r\n'; } options.agentlinkhtml = agentLinkHtml; options.agentlinktext = agentLinkText; if ((name != null) && (name != '')) { options.introtext = 'Hello ' + name + ',\r\n\r\n'; options.introhtml = '

Hello ' + name + ',

'; } if ((msg != null) && (msg != '')) { options.msgtext = '\r\n\r\nMessage: ' + msg + '\r\n\r\n'; options.msghtml = '

Message: ' + msg + '

'; } var mail = { to: email, from: parent.config.smtp.from, subject: mailReplacements(accountInviteSubject, domain, username, email), text: mailReplacements(accountInviteMailText, domain, username, email, options), html: mailReplacements(accountInviteMailHtml, domain, username, email, options) }; obj.pendingMails.push(mail); 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) && (obj.parent.mailtokengen == 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; };