diff --git a/meshmail.js b/meshmail.js index 5fbea5e9..c67a22e6 100644 --- a/meshmail.js +++ b/meshmail.js @@ -137,74 +137,103 @@ module.exports.CreateMeshMail = function (parent) { // Send account login mail / 2 factor token obj.sendAccountLoginMail = function (domain, email, token) { - var template = getTemplateEx('account-login', domain); - if ((template == null) || (template.htmlSubject == null) || (template.txtSubject == null) || (parent.certificates == null) || (parent.certificates.CommonName == null) || (parent.certificates.CommonName.indexOf('.') == -1)) return; // If the server name is not set, invitation not possible. + obj.checkEmail(email, function (checked) { + if (checked) { + parent.debug('email', "Sending login token to " + email); - // Set all the options. - var options = { email: email, servername: domain.title ? domain.title : 'MeshCentral', token: token }; + var template = getTemplateEx('account-login', domain); + if ((template == null) || (template.htmlSubject == null) || (template.txtSubject == null) || (parent.certificates == null) || (parent.certificates.CommonName == null) || (parent.certificates.CommonName.indexOf('.') == -1)) return; // If the server name is not set, invitation not possible. - // Send the email - obj.pendingMails.push({ to: email, from: parent.config.smtp.from, subject: mailReplacements(template.htmlSubject, domain, options), text: mailReplacements(template.txt, domain, options), html: mailReplacements(template.html, domain, options) }); - sendNextMail(); + // Set all the options. + var options = { email: email, servername: domain.title ? domain.title : 'MeshCentral', token: token }; + + // Send the email + obj.pendingMails.push({ to: email, from: parent.config.smtp.from, subject: mailReplacements(template.htmlSubject, domain, options), text: mailReplacements(template.txt, domain, options), html: mailReplacements(template.html, domain, options) }); + sendNextMail(); + } + }); }; // Send account invitation mail obj.sendAccountInviteMail = function (domain, username, accountname, email, password) { - var template = getTemplateEx('account-invite', domain); - if ((template == null) || (template.htmlSubject == null) || (template.txtSubject == null) || (parent.certificates == null) || (parent.certificates.CommonName == null) || (parent.certificates.CommonName.indexOf('.') == -1)) return; // If the server name is not set, invitation not possible. + obj.checkEmail(email, function (checked) { + if (checked) { + parent.debug('email', "Sending account invitation to " + email); - // Set all the options. - var options = { username: username, accountname: accountname, email: email, servername: domain.title ? domain.title : 'MeshCentral', password: password }; + var template = getTemplateEx('account-invite', domain); + if ((template == null) || (template.htmlSubject == null) || (template.txtSubject == null) || (parent.certificates == null) || (parent.certificates.CommonName == null) || (parent.certificates.CommonName.indexOf('.') == -1)) return; // If the server name is not set, invitation not possible. - // Send the email - obj.pendingMails.push({ to: email, from: parent.config.smtp.from, subject: mailReplacements(template.htmlSubject, domain, options), text: mailReplacements(template.txt, domain, options), html: mailReplacements(template.html, domain, options) }); - sendNextMail(); + // Set all the options. + var options = { username: username, accountname: accountname, email: email, servername: domain.title ? domain.title : 'MeshCentral', password: password }; + + // Send the email + obj.pendingMails.push({ to: email, from: parent.config.smtp.from, subject: mailReplacements(template.htmlSubject, domain, options), text: mailReplacements(template.txt, domain, options), html: mailReplacements(template.html, domain, options) }); + sendNextMail(); + } + }); }; // Send account check mail obj.sendAccountCheckMail = function (domain, username, email) { - var template = getTemplateEx('account-check', domain); - if ((template == null) || (template.htmlSubject == null) || (template.txtSubject == null) || (parent.certificates == null) || (parent.certificates.CommonName == null) || (parent.certificates.CommonName.indexOf('.') == -1)) return; // If the server name is not set, no reset possible. + obj.checkEmail(email, function (checked) { + if (checked) { + parent.debug('email', "Sending email verification to " + email); - // Set all the options. - var options = { username: username, email: email, servername: domain.title ? domain.title : 'MeshCentral' }; - options.cookie = obj.parent.encodeCookie({ u: domain.id + '/' + username.toLowerCase(), e: email, a: 1 }, obj.mailCookieEncryptionKey); + var template = getTemplateEx('account-check', domain); + if ((template == null) || (template.htmlSubject == null) || (template.txtSubject == null) || (parent.certificates == null) || (parent.certificates.CommonName == null) || (parent.certificates.CommonName.indexOf('.') == -1)) return; // If the server name is not set, no reset possible. - // Send the email - obj.pendingMails.push({ to: email, from: parent.config.smtp.from, subject: mailReplacements(template.htmlSubject, domain, options), text: mailReplacements(template.txt, domain, options), html: mailReplacements(template.html, domain, options) }); - sendNextMail(); + // Set all the options. + var options = { username: username, email: email, servername: domain.title ? domain.title : 'MeshCentral' }; + options.cookie = obj.parent.encodeCookie({ u: domain.id + '/' + username.toLowerCase(), e: email, a: 1 }, obj.mailCookieEncryptionKey); + + // Send the email + obj.pendingMails.push({ to: email, from: parent.config.smtp.from, subject: mailReplacements(template.htmlSubject, domain, options), text: mailReplacements(template.txt, domain, options), html: mailReplacements(template.html, domain, options) }); + sendNextMail(); + } + }); }; // Send account reset mail obj.sendAccountResetMail = function (domain, username, email) { - var template = getTemplateEx('account-reset', domain); - if ((template == null) || (template.htmlSubject == null) || (template.txtSubject == null) || (parent.certificates == null) || (parent.certificates.CommonName == null) || (parent.certificates.CommonName.indexOf('.') == -1)) return; // If the server name is not set, don't validate the email address. + obj.checkEmail(email, function (checked) { + if (checked) { + parent.debug('email', "Sending account password reset to " + email); - // Set all the options. - var options = { username: username, email: email, servername: domain.title ? domain.title : 'MeshCentral' }; - options.cookie = obj.parent.encodeCookie({ u: domain.id + '/' + username, e: email, a: 2 }, obj.mailCookieEncryptionKey); + var template = getTemplateEx('account-reset', domain); + if ((template == null) || (template.htmlSubject == null) || (template.txtSubject == null) || (parent.certificates == null) || (parent.certificates.CommonName == null) || (parent.certificates.CommonName.indexOf('.') == -1)) return; // If the server name is not set, don't validate the email address. - // Send the email - obj.pendingMails.push({ to: email, from: parent.config.smtp.from, subject: mailReplacements(template.htmlSubject, domain, options), text: mailReplacements(template.txt, domain, options), html: mailReplacements(template.html, domain, options) }); - sendNextMail(); + // Set all the options. + var options = { username: username, email: email, servername: domain.title ? domain.title : 'MeshCentral' }; + options.cookie = obj.parent.encodeCookie({ u: domain.id + '/' + username, e: email, a: 2 }, obj.mailCookieEncryptionKey); + + // Send the email + obj.pendingMails.push({ to: email, from: parent.config.smtp.from, subject: mailReplacements(template.htmlSubject, domain, options), text: mailReplacements(template.txt, domain, options), html: mailReplacements(template.html, domain, options) }); + sendNextMail(); + } + }); }; // Send agent invite mail obj.sendAgentInviteMail = function (domain, username, email, meshid, name, os, msg, flags, expirehours) { - var template = getTemplateEx('mesh-invite', domain); - if ((template == null) || (template.htmlSubject == null) || (template.txtSubject == null) || (parent.certificates == null) || (parent.certificates.CommonName == null) || (parent.certificates.CommonName.indexOf('.') == -1)) return; // If the server name is not set, don't validate the email address. + obj.checkEmail(email, function (checked) { + if (checked) { + parent.debug('email', "Sending agent install invitation to " + email); + var template = getTemplateEx('mesh-invite', domain); + if ((template == null) || (template.htmlSubject == null) || (template.txtSubject == null) || (parent.certificates == null) || (parent.certificates.CommonName == null) || (parent.certificates.CommonName.indexOf('.') == -1)) return; // If the server name is not set, don't validate the email address. - // Set all the template replacement options and generate the final email text (both in txt and html formats). - var options = { username: username, name: name, email: email, installflags: flags, msg: msg, meshid: meshid, meshidhex: meshid.split('/')[2], servername: domain.title ? domain.title : 'MeshCentral' }; - options.windows = ((os == 0) || (os == 1)) ? 1 : 0; - options.linux = ((os == 0) || (os == 2)) ? 1 : 0; - options.osx = ((os == 0) || (os == 3)) ? 1 : 0; - options.link = (os == 4) ? 1 : 0; - options.linkurl = createInviteLink(domain, meshid, flags, expirehours); + // Set all the template replacement options and generate the final email text (both in txt and html formats). + var options = { username: username, name: name, email: email, installflags: flags, msg: msg, meshid: meshid, meshidhex: meshid.split('/')[2], servername: domain.title ? domain.title : 'MeshCentral' }; + options.windows = ((os == 0) || (os == 1)) ? 1 : 0; + options.linux = ((os == 0) || (os == 2)) ? 1 : 0; + options.osx = ((os == 0) || (os == 3)) ? 1 : 0; + options.link = (os == 4) ? 1 : 0; + options.linkurl = createInviteLink(domain, meshid, flags, expirehours); - // Send the email - obj.pendingMails.push({ to: email, from: parent.config.smtp.from, subject: mailReplacements(template.htmlSubject, domain, options), text: mailReplacements(template.txt, domain, options), html: mailReplacements(template.html, domain, options) }); - sendNextMail(); + // Send the email + obj.pendingMails.push({ to: email, from: parent.config.smtp.from, subject: mailReplacements(template.htmlSubject, domain, options), text: mailReplacements(template.txt, domain, options), html: mailReplacements(template.html, domain, options) }); + sendNextMail(); + } + }); }; // Send out the next mail in the pending list @@ -223,6 +252,7 @@ module.exports.CreateMeshMail = function (parent) { sendNextMail(); // Send the next mail } else { obj.retry++; + parent.debug('email', 'SMTP server failed: ' + JSON.stringify(err)); console.log('SMTP server failed: ' + JSON.stringify(err)); if (obj.retry < 6) { setTimeout(sendNextMail, 60000); } // Wait and try again } @@ -238,6 +268,7 @@ module.exports.CreateMeshMail = function (parent) { // Remove all non-object types from error to avoid a JSON stringify error. var err2 = {}; for (var i in err) { if (typeof (err[i]) != 'object') { err2[i] = err[i]; } } + parent.debug('email', 'SMTP mail server ' + parent.config.smtp.host + ' failed: ' + JSON.stringify(err2)); console.log('SMTP mail server ' + parent.config.smtp.host + ' failed: ' + JSON.stringify(err2)); } }); @@ -260,5 +291,18 @@ module.exports.CreateMeshMail = function (parent) { return '/agentinvite?c=' + parent.encodeCookie({ a: 4, mid: meshid, f: flags, expire: expirehours * 60 }, parent.invitationLinkEncryptionKey); } + // Check the email domain DNS MX record. + obj.approvedEmailDomains = {}; + obj.checkEmail = function (email, func) { + var emailSplit = email.split('@'); + if (emailSplit.length != 2) { func(false); return; } + if (obj.approvedEmailDomains[emailSplit[1]] === true) { func(true); return; } + require('dns').resolveMx(emailSplit[1], function (err, addresses) { + parent.debug('email', "checkEmail: " + email + ", " + (err == null)); + if (err == null) { obj.approvedEmailDomains[emailSplit[1]] = true; } + func(err == null); + }); + } + return obj; }; \ No newline at end of file diff --git a/package.json b/package.json index ad0024ff..2bceaa40 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "meshcentral", - "version": "0.5.0-q", + "version": "0.5.0-r", "keywords": [ "Remote Management", "Intel AMT", diff --git a/translate/translate.json b/translate/translate.json index c89bf6af..a20d28a0 100644 --- a/translate/translate.json +++ b/translate/translate.json @@ -3764,7 +3764,7 @@ "pt": "Tem certeza de que deseja {0} o plug-in: {1}", "ru": "Вы уверенны, что {0} плагин: {1}", "xloc": [ - "default.handlebars->27->1553" + "default.handlebars->27->1554" ], "zh-chs": "您確定要{0}插件嗎:{1}" }, @@ -4408,7 +4408,7 @@ "pt": "Servidor CIRA", "ru": "CIRA Сервер", "xloc": [ - "default.handlebars->27->1544" + "default.handlebars->27->1545" ], "zh-chs": "CIRA服務器" }, @@ -4425,7 +4425,7 @@ "pt": "Comandos do servidor CIRA", "ru": "CIRA Сервер команды", "xloc": [ - "default.handlebars->27->1545" + "default.handlebars->27->1546" ], "zh-chs": "CIRA服務器命令" }, @@ -4548,7 +4548,7 @@ "pt": "Erro de chamada", "ru": "Ошибка вызова", "xloc": [ - "default.handlebars->27->1554" + "default.handlebars->27->1555" ], "zh-chs": "通話錯誤" }, @@ -4966,7 +4966,7 @@ "pt": "Verificando ...", "ru": "Проверка...", "xloc": [ - "default.handlebars->27->1550", + "default.handlebars->27->1551", "default.handlebars->27->778" ], "zh-chs": "檢查..." @@ -5824,7 +5824,7 @@ "pt": "Encaminhador de conexão", "ru": "Ретранслятор подключения", "xloc": [ - "default.handlebars->27->1543" + "default.handlebars->27->1544" ], "zh-chs": "連接繼電器" }, @@ -8723,6 +8723,12 @@ ], "zh-chs": "郵件認證" }, + { + "en": "Email Traffic", + "xloc": [ + "default.handlebars->27->1538" + ] + }, { "cs": "Ověření e-mailu", "de": "E-Mail-Verifizierung", @@ -11386,7 +11392,7 @@ "default.handlebars->27->1223", "default.handlebars->27->1229", "default.handlebars->27->1521", - "default.handlebars->27->1542" + "default.handlebars->27->1543" ], "zh-chs": "英特爾AMT" }, @@ -13186,7 +13192,7 @@ "pt": "Menos", "ru": "Меньше", "xloc": [ - "default.handlebars->27->1556" + "default.handlebars->27->1557" ], "zh-chs": "減" }, @@ -15252,7 +15258,7 @@ "pt": "Mais", "ru": "Еще", "xloc": [ - "default.handlebars->27->1555" + "default.handlebars->27->1556" ], "zh-chs": "更多" }, @@ -17996,7 +18002,7 @@ "pt": "Ação do Plugin", "ru": "Действие плагина", "xloc": [ - "default.handlebars->27->1552", + "default.handlebars->27->1553", "default.handlebars->27->159" ], "zh-chs": "插件動作" @@ -20738,7 +20744,7 @@ "pt": "Rastreamento de servidor", "ru": "Трассировка сервера", "xloc": [ - "default.handlebars->27->1546" + "default.handlebars->27->1547" ], "zh-chs": "服務器跟踪" }, @@ -24177,7 +24183,7 @@ "pt": "Atualizado", "ru": "Актуально", "xloc": [ - "default.handlebars->27->1551" + "default.handlebars->27->1552" ], "zh-chs": "最新" }, @@ -25251,8 +25257,8 @@ "pt": "Servidor web", "ru": "Веб-сервер", "xloc": [ - "default.handlebars->27->1538", - "default.handlebars->27->1539" + "default.handlebars->27->1539", + "default.handlebars->27->1540" ], "zh-chs": "網絡服務器" }, @@ -25269,7 +25275,7 @@ "pt": "Solicitações de servidor Web", "ru": "Запросы веб-сервера", "xloc": [ - "default.handlebars->27->1540" + "default.handlebars->27->1541" ], "zh-chs": "Web服務器請求" }, @@ -25286,7 +25292,7 @@ "pt": "Encaminhador de soquete da Web", "ru": "Ретранслятор Web Socket", "xloc": [ - "default.handlebars->27->1541" + "default.handlebars->27->1542" ], "zh-chs": "Web套接字中繼" }, @@ -26123,7 +26129,7 @@ "pt": "\\\\'", "ru": "\\\\'", "xloc": [ - "default.handlebars->27->1549" + "default.handlebars->27->1550" ], "zh-chs": "\\\\'" }, @@ -26656,7 +26662,7 @@ "pt": "servertrace.csv", "ru": "servertrace.csv", "xloc": [ - "default.handlebars->27->1548" + "default.handlebars->27->1549" ], "zh-chs": "servertrace.csv" }, @@ -26722,7 +26728,7 @@ "pt": "hora, fonte, mensagem", "ru": "time, source, message", "xloc": [ - "default.handlebars->27->1547" + "default.handlebars->27->1548" ], "zh-chs": "時間,來源,訊息" }, diff --git a/views/default.handlebars b/views/default.handlebars index 0795560a..87000a2d 100644 --- a/views/default.handlebars +++ b/views/default.handlebars @@ -10805,6 +10805,7 @@ x += '
'; x += ''; x += ''; + x += ''; x += '