Added email debug, DNS MX check on all outbound emails.
Ylian Saint-Hilaire committed
Mar 21, 2020 at 23:13 UTC
383f757e233395bfdce810eb0449d17558a81b28
4 files changed
+117
-66
meshmail.js
+88
-44
@@ -137,74 +137,103 @@ module.exports.CreateMeshMail = function (parent) {
137
138
// Send account login mail / 2 factor token
139
obj.sendAccountLoginMail = function (domain, email, token) {
140
- var template = getTemplateEx('account-login', domain);
141
- 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.
140
+ obj.checkEmail(email, function (checked) {
141
+ if (checked) {
142
+ parent.debug('email', "Sending login token to " + email);
143
143
- // Set all the options.
144
- var options = { email: email, servername: domain.title ? domain.title : 'MeshCentral', token: token };
144
+ var template = getTemplateEx('account-login', domain);
145
+ 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.
146
146
- // Send the email
147
- 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) });
148
- sendNextMail();
147
+ // Set all the options.
148
+ var options = { email: email, servername: domain.title ? domain.title : 'MeshCentral', token: token };
149
+
150
+ // Send the email
151
+ 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) });
152
+ sendNextMail();
153
+ }
154
+ });
155
};
156
157
// Send account invitation mail
158
obj.sendAccountInviteMail = function (domain, username, accountname, email, password) {
153
- var template = getTemplateEx('account-invite', domain);
154
- 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.
159
+ obj.checkEmail(email, function (checked) {
160
+ if (checked) {
161
+ parent.debug('email', "Sending account invitation to " + email);
162
156
- // Set all the options.
157
- var options = { username: username, accountname: accountname, email: email, servername: domain.title ? domain.title : 'MeshCentral', password: password };
163
+ var template = getTemplateEx('account-invite', domain);
164
+ 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.
165
159
- // Send the email
160
- 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) });
161
- sendNextMail();
166
+ // Set all the options.
167
+ var options = { username: username, accountname: accountname, email: email, servername: domain.title ? domain.title : 'MeshCentral', password: password };
168
+
169
+ // Send the email
170
+ 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) });
171
+ sendNextMail();
172
+ }
173
+ });
174
};
175
176
// Send account check mail
177
obj.sendAccountCheckMail = function (domain, username, email) {
166
- var template = getTemplateEx('account-check', domain);
167
- 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.
178
+ obj.checkEmail(email, function (checked) {
179
+ if (checked) {
180
+ parent.debug('email', "Sending email verification to " + email);
181
169
- // Set all the options.
170
- var options = { username: username, email: email, servername: domain.title ? domain.title : 'MeshCentral' };
171
- options.cookie = obj.parent.encodeCookie({ u: domain.id + '/' + username.toLowerCase(), e: email, a: 1 }, obj.mailCookieEncryptionKey);
182
+ var template = getTemplateEx('account-check', domain);
183
+ 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.
184
173
- // Send the email
174
- 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) });
175
- sendNextMail();
185
+ // Set all the options.
186
+ var options = { username: username, email: email, servername: domain.title ? domain.title : 'MeshCentral' };
187
+ options.cookie = obj.parent.encodeCookie({ u: domain.id + '/' + username.toLowerCase(), e: email, a: 1 }, obj.mailCookieEncryptionKey);
188
+
189
+ // Send the email
190
+ 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) });
191
+ sendNextMail();
192
+ }
193
+ });
194
};
195
196
// Send account reset mail
197
obj.sendAccountResetMail = function (domain, username, email) {
180
- var template = getTemplateEx('account-reset', domain);
181
- 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.
198
+ obj.checkEmail(email, function (checked) {
199
+ if (checked) {
200
+ parent.debug('email', "Sending account password reset to " + email);
201
183
- // Set all the options.
184
- var options = { username: username, email: email, servername: domain.title ? domain.title : 'MeshCentral' };
185
- options.cookie = obj.parent.encodeCookie({ u: domain.id + '/' + username, e: email, a: 2 }, obj.mailCookieEncryptionKey);
202
+ var template = getTemplateEx('account-reset', domain);
203
+ 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.
204
187
- // Send the email
188
- 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) });
189
- sendNextMail();
205
+ // Set all the options.
206
+ var options = { username: username, email: email, servername: domain.title ? domain.title : 'MeshCentral' };
207
+ options.cookie = obj.parent.encodeCookie({ u: domain.id + '/' + username, e: email, a: 2 }, obj.mailCookieEncryptionKey);
208
+
209
+ // Send the email
210
+ 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) });
211
+ sendNextMail();
212
+ }
213
+ });
214
};
215
216
// Send agent invite mail
217
obj.sendAgentInviteMail = function (domain, username, email, meshid, name, os, msg, flags, expirehours) {
194
- var template = getTemplateEx('mesh-invite', domain);
195
- 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.
196
-
197
- // Set all the template replacement options and generate the final email text (both in txt and html formats).
198
- var options = { username: username, name: name, email: email, installflags: flags, msg: msg, meshid: meshid, meshidhex: meshid.split('/')[2], servername: domain.title ? domain.title : 'MeshCentral' };
199
- options.windows = ((os == 0) || (os == 1)) ? 1 : 0;
200
- options.linux = ((os == 0) || (os == 2)) ? 1 : 0;
201
- options.osx = ((os == 0) || (os == 3)) ? 1 : 0;
202
- options.link = (os == 4) ? 1 : 0;
203
- options.linkurl = createInviteLink(domain, meshid, flags, expirehours);
204
-
205
- // Send the email
206
- 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) });
207
- sendNextMail();
218
+ obj.checkEmail(email, function (checked) {
219
+ if (checked) {
220
+ parent.debug('email', "Sending agent install invitation to " + email);
221
+ var template = getTemplateEx('mesh-invite', domain);
222
+ 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.
223
+
224
+ // Set all the template replacement options and generate the final email text (both in txt and html formats).
225
+ var options = { username: username, name: name, email: email, installflags: flags, msg: msg, meshid: meshid, meshidhex: meshid.split('/')[2], servername: domain.title ? domain.title : 'MeshCentral' };
226
+ options.windows = ((os == 0) || (os == 1)) ? 1 : 0;
227
+ options.linux = ((os == 0) || (os == 2)) ? 1 : 0;
228
+ options.osx = ((os == 0) || (os == 3)) ? 1 : 0;
229
+ options.link = (os == 4) ? 1 : 0;
230
+ options.linkurl = createInviteLink(domain, meshid, flags, expirehours);
231
+
232
+ // Send the email
233
+ 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) });
234
+ sendNextMail();
235
+ }
236
+ });
237
};
238
239
// Send out the next mail in the pending list
@@ -223,6 +252,7 @@ module.exports.CreateMeshMail = function (parent) {
252
sendNextMail(); // Send the next mail
253
} else {
254
obj.retry++;
255
+ parent.debug('email', 'SMTP server failed: ' + JSON.stringify(err));
256
console.log('SMTP server failed: ' + JSON.stringify(err));
257
if (obj.retry < 6) { setTimeout(sendNextMail, 60000); } // Wait and try again
258
}
@@ -238,6 +268,7 @@ module.exports.CreateMeshMail = function (parent) {
268
// Remove all non-object types from error to avoid a JSON stringify error.
269
var err2 = {};
270
for (var i in err) { if (typeof (err[i]) != 'object') { err2[i] = err[i]; } }
271
+ parent.debug('email', 'SMTP mail server ' + parent.config.smtp.host + ' failed: ' + JSON.stringify(err2));
272
console.log('SMTP mail server ' + parent.config.smtp.host + ' failed: ' + JSON.stringify(err2));
273
}
274
});
@@ -260,5 +291,18 @@ module.exports.CreateMeshMail = function (parent) {
291
return '/agentinvite?c=' + parent.encodeCookie({ a: 4, mid: meshid, f: flags, expire: expirehours * 60 }, parent.invitationLinkEncryptionKey);
292
}
293
294
+ // Check the email domain DNS MX record.
295
+ obj.approvedEmailDomains = {};
296
+ obj.checkEmail = function (email, func) {
297
+ var emailSplit = email.split('@');
298
+ if (emailSplit.length != 2) { func(false); return; }
299
+ if (obj.approvedEmailDomains[emailSplit[1]] === true) { func(true); return; }
300
+ require('dns').resolveMx(emailSplit[1], function (err, addresses) {
301
+ parent.debug('email', "checkEmail: " + email + ", " + (err == null));
302
+ if (err == null) { obj.approvedEmailDomains[emailSplit[1]] = true; }
303
+ func(err == null);
304
+ });
305
+ }
306
+
307
return obj;
308
};
\ No newline at end of file
package.json
+1
-1
@@ -1,6 +1,6 @@
1
{
2
"name": "meshcentral",
3
- "version": "0.5.0-q",
3
+ "version": "0.5.0-r",
4
"keywords": [
5
"Remote Management",
6
"Intel AMT",
translate/translate.json
+25
-19
@@ -3764,7 +3764,7 @@
3764
"pt": "Tem certeza de que deseja {0} o plug-in: {1}",
3765
"ru": "Вы уверенны, что {0} плагин: {1}",
3766
"xloc": [
3767
- "default.handlebars->27->1553"
3767
+ "default.handlebars->27->1554"
3768
],
3769
"zh-chs": "您確定要{0}插件嗎:{1}"
3770
},
@@ -4408,7 +4408,7 @@
4408
"pt": "Servidor CIRA",
4409
"ru": "CIRA Сервер",
4410
"xloc": [
4411
- "default.handlebars->27->1544"
4411
+ "default.handlebars->27->1545"
4412
],
4413
"zh-chs": "CIRA服務器"
4414
},
@@ -4425,7 +4425,7 @@
4425
"pt": "Comandos do servidor CIRA",
4426
"ru": "CIRA Сервер команды",
4427
"xloc": [
4428
- "default.handlebars->27->1545"
4428
+ "default.handlebars->27->1546"
4429
],
4430
"zh-chs": "CIRA服務器命令"
4431
},
@@ -4548,7 +4548,7 @@
4548
"pt": "Erro de chamada",
4549
"ru": "Ошибка вызова",
4550
"xloc": [
4551
- "default.handlebars->27->1554"
4551
+ "default.handlebars->27->1555"
4552
],
4553
"zh-chs": "通話錯誤"
4554
},
@@ -4966,7 +4966,7 @@
4966
"pt": "Verificando ...",
4967
"ru": "Проверка...",
4968
"xloc": [
4969
- "default.handlebars->27->1550",
4969
+ "default.handlebars->27->1551",
4970
"default.handlebars->27->778"
4971
],
4972
"zh-chs": "檢查..."
@@ -5824,7 +5824,7 @@
5824
"pt": "Encaminhador de conexão",
5825
"ru": "Ретранслятор подключения",
5826
"xloc": [
5827
- "default.handlebars->27->1543"
5827
+ "default.handlebars->27->1544"
5828
],
5829
"zh-chs": "連接繼電器"
5830
},
@@ -8723,6 +8723,12 @@
8723
],
8724
"zh-chs": "郵件認證"
8725
},
8726
+ {
8727
+ "en": "Email Traffic",
8728
+ "xloc": [
8729
+ "default.handlebars->27->1538"
8730
+ ]
8731
+ },
8732
{
8733
"cs": "Ověření e-mailu",
8734
"de": "E-Mail-Verifizierung",
@@ -11386,7 +11392,7 @@
11392
"default.handlebars->27->1223",
11393
"default.handlebars->27->1229",
11394
"default.handlebars->27->1521",
11389
- "default.handlebars->27->1542"
11395
+ "default.handlebars->27->1543"
11396
],
11397
"zh-chs": "英特爾AMT"
11398
},
@@ -13186,7 +13192,7 @@
13192
"pt": "Menos",
13193
"ru": "Меньше",
13194
"xloc": [
13189
- "default.handlebars->27->1556"
13195
+ "default.handlebars->27->1557"
13196
],
13197
"zh-chs": "減"
13198
},
@@ -15252,7 +15258,7 @@
15258
"pt": "Mais",
15259
"ru": "Еще",
15260
"xloc": [
15255
- "default.handlebars->27->1555"
15261
+ "default.handlebars->27->1556"
15262
],
15263
"zh-chs": "更多"
15264
},
@@ -17996,7 +18002,7 @@
18002
"pt": "Ação do Plugin",
18003
"ru": "Действие плагина",
18004
"xloc": [
17999
- "default.handlebars->27->1552",
18005
+ "default.handlebars->27->1553",
18006
"default.handlebars->27->159"
18007
],
18008
"zh-chs": "插件動作"
@@ -20738,7 +20744,7 @@
20744
"pt": "Rastreamento de servidor",
20745
"ru": "Трассировка сервера",
20746
"xloc": [
20741
- "default.handlebars->27->1546"
20747
+ "default.handlebars->27->1547"
20748
],
20749
"zh-chs": "服務器跟踪"
20750
},
@@ -24177,7 +24183,7 @@
24183
"pt": "Atualizado",
24184
"ru": "Актуально",
24185
"xloc": [
24180
- "default.handlebars->27->1551"
24186
+ "default.handlebars->27->1552"
24187
],
24188
"zh-chs": "最新"
24189
},
@@ -25251,8 +25257,8 @@
25257
"pt": "Servidor web",
25258
"ru": "Веб-сервер",
25259
"xloc": [
25254
- "default.handlebars->27->1538",
25255
- "default.handlebars->27->1539"
25260
+ "default.handlebars->27->1539",
25261
+ "default.handlebars->27->1540"
25262
],
25263
"zh-chs": "網絡服務器"
25264
},
@@ -25269,7 +25275,7 @@
25275
"pt": "Solicitações de servidor Web",
25276
"ru": "Запросы веб-сервера",
25277
"xloc": [
25272
- "default.handlebars->27->1540"
25278
+ "default.handlebars->27->1541"
25279
],
25280
"zh-chs": "Web服務器請求"
25281
},
@@ -25286,7 +25292,7 @@
25292
"pt": "Encaminhador de soquete da Web",
25293
"ru": "Ретранслятор Web Socket",
25294
"xloc": [
25289
- "default.handlebars->27->1541"
25295
+ "default.handlebars->27->1542"
25296
],
25297
"zh-chs": "Web套接字中繼"
25298
},
@@ -26123,7 +26129,7 @@
26129
"pt": "\\\\'",
26130
"ru": "\\\\'",
26131
"xloc": [
26126
- "default.handlebars->27->1549"
26132
+ "default.handlebars->27->1550"
26133
],
26134
"zh-chs": "\\\\'"
26135
},
@@ -26656,7 +26662,7 @@
26662
"pt": "servertrace.csv",
26663
"ru": "servertrace.csv",
26664
"xloc": [
26659
- "default.handlebars->27->1548"
26665
+ "default.handlebars->27->1549"
26666
],
26667
"zh-chs": "servertrace.csv"
26668
},
@@ -26722,7 +26728,7 @@
26728
"pt": "hora, fonte, mensagem",
26729
"ru": "time, source, message",
26730
"xloc": [
26725
- "default.handlebars->27->1547"
26731
+ "default.handlebars->27->1548"
26732
],
26733
"zh-chs": "時間,來源,訊息"
26734
},
views/default.handlebars
+3
-2
@@ -10805,6 +10805,7 @@
10805
x += '<div><label><input type=checkbox id=p41c14 ' + ((serverTraceSources.indexOf('agentupdate') >= 0) ? 'checked' : '') + '>' + "MeshAgent update" + '</label></div>';
10806
x += '<div><label><input type=checkbox id=p41c16 ' + ((serverTraceSources.indexOf('cert') >= 0) ? 'checked' : '') + '>' + "Server Certificate" + '</label></div>';
10807
x += '<div><label><input type=checkbox id=p41c17 ' + ((serverTraceSources.indexOf('db') >= 0) ? 'checked' : '') + '>' + "Server Database" + '</label></div>';
10808
+ x += '<div><label><input type=checkbox id=p41c18 ' + ((serverTraceSources.indexOf('email') >= 0) ? 'checked' : '') + '>' + "Email Traffic" + '</label></div>';
10809
x += '<div style="width:100%;border-bottom:1px solid gray;margin-bottom:5px;margin-top:5px"><b>' + "Web Server" + '</b></div>';
10810
x += '<div><label><input type=checkbox id=p41c5 ' + ((serverTraceSources.indexOf('web') >= 0) ? 'checked' : '') + '>' + "Web Server" + '</label></div>';
10811
x += '<div><label><input type=checkbox id=p41c6 ' + ((serverTraceSources.indexOf('webrequest') >= 0) ? 'checked' : '') + '>' + "Web Server Requests" + '</label></div>';
@@ -10821,8 +10822,8 @@
10822
}
10823
10824
function setServerTracingEx(b) {
10824
- var sources = [], allsources = ['cookie', 'dispatch', 'main', 'peer', 'web', 'webrequest', 'relay', 'webrelaydata', 'webrelay', 'mps', 'mpscmd', 'swarm', 'swarmcmd', 'agentupdate', 'agent', 'cert', 'db'];
10825
- if (b == 1) { for (var i = 1; i < 18; i++) { try { if (Q('p41c' + i).checked) { sources.push(allsources[i - 1]); } } catch (ex) { } } }
10825
+ var sources = [], allsources = ['cookie', 'dispatch', 'main', 'peer', 'web', 'webrequest', 'relay', 'webrelaydata', 'webrelay', 'mps', 'mpscmd', 'swarm', 'swarmcmd', 'agentupdate', 'agent', 'cert', 'db', 'email'];
10826
+ if (b == 1) { for (var i = 1; i < 19; i++) { try { if (Q('p41c' + i).checked) { sources.push(allsources[i - 1]); } } catch (ex) { } } }
10827
meshserver.send({ action: 'traceinfo', traceSources: sources });
10828
}
10829