Added per-domain SMTP/SendGrid support.
Ylian Saint-Hilaire committed
Feb 10, 2021 at 11:28 UTC
d96bf4b4f51de0715af64941dd0c9266e6f6d9e4
5 files changed
+127
-73
meshcentral-config-schema.json
+26
@@ -506,6 +506,32 @@
506
"required": [ "protocols" ]
507
},
508
"showPasswordLogin": { "type": "boolean", "default": true, "description": "When set to false, hides the username and password prompt on login screen." },
509
+ "sendgrid": {
510
+ "title" : "SendGrid.com Email server",
511
+ "description": "Connects MeshCentral to the SendGrid email server, allows MeshCentral to send email messages for 2FA or user notification.",
512
+ "type": "object",
513
+ "properties": {
514
+ "from": { "type": "string", "format": "email", "description": "Email address used in the messages from field." },
515
+ "apikey": { "type": "string", "description": "The SendGrid API key." },
516
+ "verifyemail": { "type": "boolean", "default": true, "description": "When set to false, the email format and DNS MX record are not checked." }
517
+ },
518
+ "required": [ "from", "apikey" ]
519
+ },
520
+ "smtp": {
521
+ "title" : "SMTP email server",
522
+ "description": "Connects MeshCentral to a SMTP email server, allows MeshCentral to send email messages for 2FA or user notification.",
523
+ "type": "object",
524
+ "properties": {
525
+ "host": { "type": "string", "format": "hostname" },
526
+ "port": { "type": "integer", "minimum": 1, "maximum": 65535 },
527
+ "from": { "type": "string", "format": "email", "description": "Email address used in the messages from field." },
528
+ "tls": { "type": "boolean" },
529
+ "tlscertcheck": { "type": "boolean" },
530
+ "tlsstrict": { "type": "boolean" },
531
+ "verifyemail": { "type": "boolean", "default": true, "description": "When set to false, the email format and DNS MX record are not checked." }
532
+ },
533
+ "required": [ "host", "port", "from", "tls" ]
534
+ },
535
"authStrategies": {
536
"type": "object",
537
"additionalProperties": false,
meshcentral.js
+25
-3
@@ -1525,7 +1525,7 @@ function CreateMeshCentralServer(config, args) {
1525
obj.swarmserver = require('./swarmserver.js').CreateSwarmServer(obj, obj.db, obj.args, obj.certificates);
1526
}
1527
1528
- // Setup email server
1528
+ // Setup the main email server
1529
if (obj.config.sendgrid != null) {
1530
// Sendgrid server
1531
obj.mailserver = require('./meshmail.js').CreateMeshMail(obj);
@@ -1538,6 +1538,24 @@ function CreateMeshCentralServer(config, args) {
1538
if (obj.args.lanonly == true) { addServerWarning("SMTP server has limited use in LAN mode."); }
1539
}
1540
1541
+ // Setup the email server for each domain
1542
+ for (i in obj.config.domains) {
1543
+ if (obj.config.domains[i].sendgrid != null) {
1544
+ // Sendgrid server
1545
+ obj.config.domains[i].mailserver = require('./meshmail.js').CreateMeshMail(obj, obj.config.domains[i]);
1546
+ obj.config.domains[i].mailserver.verify();
1547
+ if (obj.args.lanonly == true) { addServerWarning("SendGrid server has limited use in LAN mode."); }
1548
+ } else if ((obj.config.domains[i].smtp != null) && (obj.config.domains[i].smtp.host != null) && (obj.config.domains[i].smtp.from != null)) {
1549
+ // SMTP server
1550
+ obj.config.domains[i].mailserver = require('./meshmail.js').CreateMeshMail(obj, obj.config.domains[i]);
1551
+ obj.config.domains[i].mailserver.verify();
1552
+ if (obj.args.lanonly == true) { addServerWarning("SMTP server has limited use in LAN mode."); }
1553
+ } else {
1554
+ // Setup the parent mail server for this domain
1555
+ if (obj.mailserver != null) { obj.config.domains[i].mailserver = obj.mailserver; }
1556
+ }
1557
+ }
1558
+
1559
// Setup SMS gateway
1560
if (config.sms != null) {
1561
obj.smsserver = require('./meshsms.js').CreateMeshSMS(obj);
@@ -2994,10 +3012,14 @@ function mainStart() {
3012
var recordingIndex = false;
3013
var domainCount = 0;
3014
var wildleek = false;
3015
+ var nodemailer = false;
3016
+ var sendgrid = false;
3017
if (require('os').platform() == 'win32') { for (var i in config.domains) { domainCount++; if (config.domains[i].auth == 'sspi') { sspi = true; } else { allsspi = false; } } } else { allsspi = false; }
3018
if (domainCount == 0) { allsspi = false; }
3019
for (var i in config.domains) {
3020
if (i.startsWith('_')) continue;
3021
+ if (config.domains[i].smtp != null) { nodemailer = true; }
3022
+ if (config.domains[i].sendgrid != null) { sendgrid = true; }
3023
if (config.domains[i].yubikey != null) { yubikey = true; }
3024
if (config.domains[i].auth == 'ldap') { ldap = true; }
3025
if (config.domains[i].mstsc === true) { mstsc = true; }
@@ -3030,8 +3052,8 @@ function mainStart() {
3052
if (config.settings.plugins != null) { modules.push('semver'); } // Required for version compat testing and update checks
3053
if ((config.settings.plugins != null) && (config.settings.plugins.proxy != null)) { modules.push('https-proxy-agent'); } // Required for HTTP/HTTPS proxy support
3054
else if (config.settings.xmongodb != null) { modules.push('mongojs'); } // Add MongoJS, old driver.
3033
- if (config.smtp != null) { modules.push('nodemailer'); } // Add SMTP support
3034
- if (config.sendgrid != null) { modules.push('@sendgrid/mail'); } // Add SendGrid support
3055
+ if (nodemailer || (config.smtp != null)) { modules.push('nodemailer'); } // Add SMTP support
3056
+ if (sendgrid || (config.sendgrid != null)) { modules.push('@sendgrid/mail'); } // Add SendGrid support
3057
if (args.translate) { modules.push('jsdom'); modules.push('esprima'); modules.push('minify-js'); modules.push('html-minifier'); } // Translation support
3058
3059
// If running NodeJS < 8, install "util.promisify"
meshmail.js
+35
-29
@@ -17,32 +17,39 @@
17
// TODO: Add NTML support with "nodemailer-ntlm-auth" https://github.com/nodemailer/nodemailer-ntlm-auth
18
19
// Construct a MeshAgent object, called upon connection
20
-module.exports.CreateMeshMail = function (parent) {
20
+module.exports.CreateMeshMail = function (parent, domain) {
21
var obj = {};
22
obj.pendingMails = [];
23
obj.parent = parent;
24
obj.retry = 0;
25
obj.sendingMail = false;
26
obj.mailCookieEncryptionKey = null;
27
+ obj.verifyemail = false;
28
+ obj.domain = domain;
29
//obj.mailTemplates = {};
30
const constants = (obj.parent.crypto.constants ? obj.parent.crypto.constants : require('constants')); // require('constants') is deprecated in Node 11.10, use require('crypto').constants instead.
31
32
function EscapeHtml(x) { if (typeof x == "string") return x.replace(/&/g, '&').replace(/>/g, '>').replace(/</g, '<').replace(/"/g, '"').replace(/'/g, '''); if (typeof x == "boolean") return x; if (typeof x == "number") return x; }
33
//function EscapeHtmlBreaks(x) { if (typeof x == "string") return x.replace(/&/g, '&').replace(/>/g, '>').replace(/</g, '<').replace(/"/g, '"').replace(/'/g, ''').replace(/\r/g, '<br />').replace(/\n/g, '').replace(/\t/g, ' '); if (typeof x == "boolean") return x; if (typeof x == "number") return x; }
34
33
- if (parent.config.sendgrid != null) {
35
+ // Setup where we read our configuration from
36
+ if (obj.domain == null) { obj.config = parent.config; } else { obj.config = domain; }
37
+
38
+ if (obj.config.sendgrid != null) {
39
// Setup SendGrid mail server
40
obj.sendGridServer = require('@sendgrid/mail');
36
- obj.sendGridServer.setApiKey(parent.config.sendgrid.apikey);
37
- } else if (parent.config.smtp != null) {
41
+ obj.sendGridServer.setApiKey(obj.config.sendgrid.apikey);
42
+ if (obj.config.sendgrid.verifyemail == true) { obj.verifyemail = true; }
43
+ } else if (obj.config.smtp != null) {
44
// Setup SMTP mail server
45
const nodemailer = require('nodemailer');
40
- var options = { host: parent.config.smtp.host, secure: (parent.config.smtp.tls == true), tls: {} };
41
- //var options = { host: parent.config.smtp.host, secure: (parent.config.smtp.tls == true), tls: { secureProtocol: 'SSLv23_method', ciphers: 'RSA+AES:!aNULL:!MD5:!DSS', secureOptions: constants.SSL_OP_NO_SSLv2 | constants.SSL_OP_NO_SSLv3 | constants.SSL_OP_NO_COMPRESSION | constants.SSL_OP_CIPHER_SERVER_PREFERENCE, rejectUnauthorized: false } };
42
- if (parent.config.smtp.port != null) { options.port = parent.config.smtp.port; }
43
- if (parent.config.smtp.tlscertcheck === false) { options.tls.rejectUnauthorized = false; }
44
- if (parent.config.smtp.tlsstrict === true) { options.tls.secureProtocol = 'SSLv23_method'; options.tls.ciphers = 'RSA+AES:!aNULL:!MD5:!DSS'; options.tls.secureOptions = constants.SSL_OP_NO_SSLv2 | constants.SSL_OP_NO_SSLv3 | constants.SSL_OP_NO_COMPRESSION | constants.SSL_OP_CIPHER_SERVER_PREFERENCE; }
45
- if ((parent.config.smtp.user != null) && (parent.config.smtp.pass != null)) { options.auth = { user: parent.config.smtp.user, pass: parent.config.smtp.pass }; }
46
+ var options = { host: obj.config.smtp.host, secure: (obj.config.smtp.tls == true), tls: {} };
47
+ //var options = { host: obj.config.smtp.host, secure: (obj.config.smtp.tls == true), tls: { secureProtocol: 'SSLv23_method', ciphers: 'RSA+AES:!aNULL:!MD5:!DSS', secureOptions: constants.SSL_OP_NO_SSLv2 | constants.SSL_OP_NO_SSLv3 | constants.SSL_OP_NO_COMPRESSION | constants.SSL_OP_CIPHER_SERVER_PREFERENCE, rejectUnauthorized: false } };
48
+ if (obj.config.smtp.port != null) { options.port = obj.config.smtp.port; }
49
+ if (obj.config.smtp.tlscertcheck === false) { options.tls.rejectUnauthorized = false; }
50
+ if (obj.config.smtp.tlsstrict === true) { options.tls.secureProtocol = 'SSLv23_method'; options.tls.ciphers = 'RSA+AES:!aNULL:!MD5:!DSS'; options.tls.secureOptions = constants.SSL_OP_NO_SSLv2 | constants.SSL_OP_NO_SSLv3 | constants.SSL_OP_NO_COMPRESSION | constants.SSL_OP_CIPHER_SERVER_PREFERENCE; }
51
+ if ((obj.config.smtp.user != null) && (obj.config.smtp.pass != null)) { options.auth = { user: obj.config.smtp.user, pass: obj.config.smtp.pass }; }
52
+ if (obj.config.smtp.verifyemail == true) { obj.verifyemail = true; }
53
obj.smtpServer = nodemailer.createTransport(options);
54
}
55
@@ -149,10 +156,10 @@ module.exports.CreateMeshMail = function (parent) {
156
157
// Send a generic email
158
obj.sendMail = function (to, subject, text, html) {
152
- if (parent.config.sendgrid != null) {
153
- obj.pendingMails.push({ to: to, from: parent.config.sendgrid.from, subject: subject, text: text, html: html });
154
- } else if (parent.config.smtp != null) {
155
- obj.pendingMails.push({ to: to, from: parent.config.smtp.from, subject: subject, text: text, html: html });
159
+ if (obj.config.sendgrid != null) {
160
+ obj.pendingMails.push({ to: to, from: obj.config.sendgrid.from, subject: subject, text: text, html: html });
161
+ } else if (obj.config.smtp != null) {
162
+ obj.pendingMails.push({ to: to, from: obj.config.smtp.from, subject: subject, text: text, html: html });
163
}
164
sendNextMail();
165
};
@@ -180,8 +187,8 @@ module.exports.CreateMeshMail = function (parent) {
187
188
// Get from field
189
var from = null;
183
- if (parent.config.sendgrid && (typeof parent.config.sendgrid.from == 'string')) { from = parent.config.sendgrid.from; }
184
- else if (parent.config.smtp && (typeof parent.config.smtp.from == 'string')) { from = parent.config.smtp.from; }
190
+ if (obj.config.sendgrid && (typeof obj.config.sendgrid.from == 'string')) { from = obj.config.sendgrid.from; }
191
+ else if (obj.config.smtp && (typeof obj.config.smtp.from == 'string')) { from = obj.config.smtp.from; }
192
193
// Send the email
194
obj.pendingMails.push({ to: email, from: from, subject: mailReplacements(template.htmlSubject, domain, options), text: mailReplacements(template.txt, domain, options), html: mailReplacements(template.html, domain, options) });
@@ -213,8 +220,8 @@ module.exports.CreateMeshMail = function (parent) {
220
221
// Get from field
222
var from = null;
216
- if (parent.config.sendgrid && (typeof parent.config.sendgrid.from == 'string')) { from = parent.config.sendgrid.from; }
217
- else if (parent.config.smtp && (typeof parent.config.smtp.from == 'string')) { from = parent.config.smtp.from; }
223
+ if (obj.config.sendgrid && (typeof obj.config.sendgrid.from == 'string')) { from = obj.config.sendgrid.from; }
224
+ else if (obj.config.smtp && (typeof obj.config.smtp.from == 'string')) { from = obj.config.smtp.from; }
225
226
// Send the email
227
obj.pendingMails.push({ to: email, from: from, subject: mailReplacements(template.htmlSubject, domain, options), text: mailReplacements(template.txt, domain, options), html: mailReplacements(template.html, domain, options) });
@@ -247,8 +254,8 @@ module.exports.CreateMeshMail = function (parent) {
254
255
// Get from field
256
var from = null;
250
- if (parent.config.sendgrid && (typeof parent.config.sendgrid.from == 'string')) { from = parent.config.sendgrid.from; }
251
- else if (parent.config.smtp && (typeof parent.config.smtp.from == 'string')) { from = parent.config.smtp.from; }
257
+ if (obj.config.sendgrid && (typeof obj.config.sendgrid.from == 'string')) { from = obj.config.sendgrid.from; }
258
+ else if (obj.config.smtp && (typeof obj.config.smtp.from == 'string')) { from = obj.config.smtp.from; }
259
260
// Send the email
261
obj.pendingMails.push({ to: email, from: from, subject: mailReplacements(template.htmlSubject, domain, options), text: mailReplacements(template.txt, domain, options), html: mailReplacements(template.html, domain, options) });
@@ -281,8 +288,8 @@ module.exports.CreateMeshMail = function (parent) {
288
289
// Get from field
290
var from = null;
284
- if (parent.config.sendgrid && (typeof parent.config.sendgrid.from == 'string')) { from = parent.config.sendgrid.from; }
285
- else if (parent.config.smtp && (typeof parent.config.smtp.from == 'string')) { from = parent.config.smtp.from; }
291
+ if (obj.config.sendgrid && (typeof obj.config.sendgrid.from == 'string')) { from = obj.config.sendgrid.from; }
292
+ else if (obj.config.smtp && (typeof obj.config.smtp.from == 'string')) { from = obj.config.smtp.from; }
293
294
// Send the email
295
obj.pendingMails.push({ to: email, from: from, subject: mailReplacements(template.htmlSubject, domain, options), text: mailReplacements(template.txt, domain, options), html: mailReplacements(template.html, domain, options) });
@@ -319,8 +326,8 @@ module.exports.CreateMeshMail = function (parent) {
326
327
// Get from field
328
var from = null;
322
- if (parent.config.sendgrid && (typeof parent.config.sendgrid.from == 'string')) { from = parent.config.sendgrid.from; }
323
- else if (parent.config.smtp && (typeof parent.config.smtp.from == 'string')) { from = parent.config.smtp.from; }
329
+ if (obj.config.sendgrid && (typeof obj.config.sendgrid.from == 'string')) { from = obj.config.sendgrid.from; }
330
+ else if (obj.config.smtp && (typeof obj.config.smtp.from == 'string')) { from = obj.config.smtp.from; }
331
332
// Send the email
333
obj.pendingMails.push({ to: email, from: from, subject: mailReplacements(template.htmlSubject, domain, options), text: mailReplacements(template.txt, domain, options), html: mailReplacements(template.html, domain, options) });
@@ -399,13 +406,13 @@ module.exports.CreateMeshMail = function (parent) {
406
if (obj.smtpServer == null) return;
407
obj.smtpServer.verify(function (err, info) {
408
if (err == null) {
402
- console.log('SMTP mail server ' + parent.config.smtp.host + ' working as expected.');
409
+ console.log('SMTP mail server ' + obj.config.smtp.host + ' working as expected.');
410
} else {
411
// Remove all non-object types from error to avoid a JSON stringify error.
412
var err2 = {};
413
for (var i in err) { if (typeof (err[i]) != 'object') { err2[i] = err[i]; } }
407
- parent.debug('email', 'SMTP mail server ' + parent.config.smtp.host + ' failed: ' + JSON.stringify(err2));
408
- console.log('SMTP mail server ' + parent.config.smtp.host + ' failed: ' + JSON.stringify(err2));
414
+ parent.debug('email', 'SMTP mail server ' + obj.config.smtp.host + ' failed: ' + JSON.stringify(err2));
415
+ console.log('SMTP mail server ' + obj.config.smtp.host + ' failed: ' + JSON.stringify(err2));
416
}
417
});
418
};
@@ -430,8 +437,7 @@ module.exports.CreateMeshMail = function (parent) {
437
// Check the email domain DNS MX record.
438
obj.approvedEmailDomains = {};
439
obj.checkEmail = function (email, func) {
433
- if ((parent.config.smtp) && (parent.config.smtp.verifyemail === false)) { func(true); return; }
434
- if ((parent.config.sendgrid) && (parent.config.sendgrid.verifyemail === false)) { func(true); return; }
440
+ if (obj.verifyemail == false) { func(true); return; }
441
var emailSplit = email.split('@');
442
if (emailSplit.length != 2) { func(false); return; }
443
if (obj.approvedEmailDomains[emailSplit[1]] === true) { func(true); return; }
meshuser.js
+15
-15
@@ -446,7 +446,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
446
var httpport = ((args.aliasport != null) ? args.aliasport : args.port);
447
448
// Build server information object
449
- var serverinfo = { domain: domain.id, name: domain.dns ? domain.dns : parent.certificates.CommonName, mpsname: parent.certificates.AmtMpsName, mpsport: mpsport, mpspass: args.mpspass, port: httpport, emailcheck: ((parent.parent.mailserver != null) && (domain.auth != 'sspi') && (domain.auth != 'ldap') && (args.lanonly != true) && (parent.certificates.CommonName != null) && (parent.certificates.CommonName.indexOf('.') != -1) && (user._id.split('/')[2].startsWith('~') == false)), domainauth: (domain.auth == 'sspi'), serverTime: Date.now() };
449
+ var serverinfo = { domain: domain.id, name: domain.dns ? domain.dns : parent.certificates.CommonName, mpsname: parent.certificates.AmtMpsName, mpsport: mpsport, mpspass: args.mpspass, port: httpport, emailcheck: ((domain.mailserver != null) && (domain.auth != 'sspi') && (domain.auth != 'ldap') && (args.lanonly != true) && (parent.certificates.CommonName != null) && (parent.certificates.CommonName.indexOf('.') != -1) && (user._id.split('/')[2].startsWith('~') == false)), domainauth: (domain.auth == 'sspi'), serverTime: Date.now() };
450
serverinfo.languages = parent.renderLanguages;
451
serverinfo.tlshash = Buffer.from(parent.webCertificateFullHashs[domain.id], 'binary').toString('hex').toUpperCase(); // SHA384 of server HTTPS certificate
452
serverinfo.agentCertHash = parent.agentCertificateHashBase64;
@@ -978,13 +978,13 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
978
break;
979
}
980
case 'email': {
981
- if (parent.parent.mailserver == null) {
981
+ if (domain.mailserver == null) {
982
r = "No email service enabled.";
983
} else {
984
if (cmdargs['_'].length != 3) {
985
r = "Usage: email \"user@sample.com\" \"Subject\" \"Message\".";
986
} else {
987
- parent.parent.mailserver.sendMail(cmdargs['_'][0], cmdargs['_'][1], cmdargs['_'][2]);
987
+ domain.mailserver.sendMail(cmdargs['_'][0], cmdargs['_'][1], cmdargs['_'][2]);
988
r = "Done.";
989
}
990
}
@@ -1626,7 +1626,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
1626
if (parent.parent.authlog) { parent.parent.authLog('https', 'User ' + user.name + ' changed email from ' + oldemail + ' to ' + user.email); }
1627
1628
// Send the verification email
1629
- if (parent.parent.mailserver != null) { parent.parent.mailserver.sendAccountCheckMail(domain, user.name, user._id, user.email, parent.getLanguageCodes(req)); }
1629
+ if (domain.mailserver != null) { domain.mailserver.sendAccountCheckMail(domain, user.name, user._id, user.email, parent.getLanguageCodes(req)); }
1630
}
1631
});
1632
}
@@ -1644,9 +1644,9 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
1644
// Always lowercase the email address
1645
command.email = command.email.toLowerCase();
1646
1647
- if ((parent.parent.mailserver != null) && (obj.user.email.toLowerCase() == command.email)) {
1647
+ if ((domain.mailserver != null) && (obj.user.email.toLowerCase() == command.email)) {
1648
// Send the verification email
1649
- parent.parent.mailserver.sendAccountCheckMail(domain, user.name, user._id, user.email, parent.getLanguageCodes(req));
1649
+ domain.mailserver.sendAccountCheckMail(domain, user.name, user._id, user.email, parent.getLanguageCodes(req));
1650
}
1651
break;
1652
}
@@ -2039,8 +2039,8 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
2039
parent.parent.DispatchEvent(targets, obj, event);
2040
2041
// Perform email invitation
2042
- if ((command.emailInvitation == true) && (command.emailVerified == true) && command.email && parent.parent.mailserver) {
2043
- parent.parent.mailserver.sendAccountInviteMail(newuserdomain, (user.realname ? user.realname : user.name), newusername, command.email.toLowerCase(), command.pass, parent.getLanguageCodes(req));
2042
+ if ((command.emailInvitation == true) && (command.emailVerified == true) && command.email && domain.mailserver) {
2043
+ domain.mailserver.sendAccountInviteMail(newuserdomain, (user.realname ? user.realname : user.name), newusername, command.email.toLowerCase(), command.pass, parent.getLanguageCodes(req));
2044
}
2045
2046
// Log in the auth log
@@ -2237,7 +2237,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
2237
}
2238
2239
// In some situations, we need a verified email address to create a device group.
2240
- if ((err == null) && (parent.parent.mailserver != null) && (ugrpdomain.auth != 'sspi') && (ugrpdomain.auth != 'ldap') && (user.emailVerified !== true) && (user.siteadmin != SITERIGHT_ADMIN)) { err = "Email verification required"; } // User must verify it's email first.
2240
+ if ((err == null) && (domain.mailserver != null) && (ugrpdomain.auth != 'sspi') && (ugrpdomain.auth != 'ldap') && (user.emailVerified !== true) && (user.siteadmin != SITERIGHT_ADMIN)) { err = "Email verification required"; } // User must verify it's email first.
2241
} catch (ex) { err = "Validation exception: " + ex; }
2242
2243
// Handle any errors
@@ -2861,7 +2861,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
2861
if ((user.siteadmin != SITERIGHT_ADMIN) && ((user.siteadmin & 64) != 0)) { err = 'Permission denied'; }
2862
2863
// In some situations, we need a verified email address to create a device group.
2864
- else if ((parent.parent.mailserver != null) && (domain.auth != 'sspi') && (domain.auth != 'ldap') && (user.emailVerified !== true) && (user.siteadmin != SITERIGHT_ADMIN)) { err = 'Email verification required'; } // User must verify it's email first.
2864
+ else if ((domain.mailserver != null) && (domain.auth != 'sspi') && (domain.auth != 'ldap') && (user.emailVerified !== true) && (user.siteadmin != SITERIGHT_ADMIN)) { err = 'Email verification required'; } // User must verify it's email first.
2865
2866
// Create mesh
2867
else if (common.validateString(command.meshname, 1, 128) == false) { err = 'Invalid group name'; } // Meshname is between 1 and 64 characters
@@ -4166,7 +4166,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
4166
}
4167
4168
try {
4169
- if ((parent.parent.mailserver == null) || (args.lanonly == true)) { err = 'Unsupported feature'; } // This operation requires the email server
4169
+ if ((domain.mailserver == null) || (args.lanonly == true)) { err = 'Unsupported feature'; } // This operation requires the email server
4170
else if ((parent.parent.certificates.CommonName == null) || (parent.parent.certificates.CommonName.indexOf('.') == -1)) { err = 'Unsupported feature'; } // Server name must be configured
4171
else if (common.validateString(command.meshid, 1, 1024) == false) { err = 'Invalid group identifier'; } // Check meshid
4172
else {
@@ -4190,7 +4190,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
4190
}
4191
4192
// Perform email invitation
4193
- parent.parent.mailserver.sendAgentInviteMail(domain, (user.realname ? user.realname : user.name), command.email.toLowerCase(), command.meshid, command.name, command.os, command.msg, command.flags, command.expire, parent.getLanguageCodes(req), req.query.key);
4193
+ domain.mailserver.sendAgentInviteMail(domain, (user.realname ? user.realname : user.name), command.email.toLowerCase(), command.meshid, command.name, command.os, command.msg, command.flags, command.expire, parent.getLanguageCodes(req), req.query.key);
4194
4195
// Send a response if needed
4196
if (command.responseid != null) { try { ws.send(JSON.stringify({ action: 'inviteAgent', responseid: command.responseid, result: 'ok' })); } catch (ex) { } }
@@ -4632,7 +4632,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
4632
}
4633
case 'emailuser': { // Send a email message to a user
4634
var errMsg = null, emailuser = null;
4635
- if (parent.parent.mailserver == null) { errMsg = 'Email server not enabled'; }
4635
+ if (domain.mailserver == null) { errMsg = 'Email server not enabled'; }
4636
else if ((user.siteadmin & 2) == 0) { errMsg = 'No user management rights'; }
4637
else if (common.validateString(command.userid, 1, 2048) == false) { errMsg = 'Invalid userid'; }
4638
else if (common.validateString(command.subject, 1, 1000) == false) { errMsg = 'Invalid subject message'; }
@@ -4645,7 +4645,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
4645
}
4646
4647
if (errMsg != null) { displayNotificationMessage(errMsg); break; }
4648
- parent.parent.mailserver.sendMail(emailuser.email, command.subject, command.msg);
4648
+ domain.mailserver.sendMail(emailuser.email, command.subject, command.msg);
4649
displayNotificationMessage("Email sent.", null, null, null, 14);
4650
break;
4651
}
@@ -5526,7 +5526,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
5526
5527
// Return the number of 2nd factor for this account
5528
function count2factoraAuths() {
5529
- var email2fa = (((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.email2factor != false)) && (parent.parent.mailserver != null));
5529
+ var email2fa = (((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.email2factor != false)) && (domain.mailserver != null));
5530
var sms2fa = ((parent.parent.smsserver != null) && ((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.sms2factor != false)));
5531
var authFactorCount = 0;
5532
if (typeof user.otpsecret == 'string') { authFactorCount++; } // Authenticator time factor
webserver.js
+26
-26
@@ -706,7 +706,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
706
var sms2fa = (((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.sms2factor != false)) && (parent.smsserver != null) && (user.phone != null));
707
708
// Check if a 2nd factor is present
709
- return ((parent.config.settings.no2factorauth !== true) && (sms2fa || (user.otpsecret != null) || ((user.email != null) && (user.emailVerified == true) && (parent.mailserver != null) && (user.otpekey != null)) || ((user.otphkeys != null) && (user.otphkeys.length > 0))));
709
+ return ((parent.config.settings.no2factorauth !== true) && (sms2fa || (user.otpsecret != null) || ((user.email != null) && (user.emailVerified == true) && (domain.mailserver != null) && (user.otpekey != null)) || ((user.otphkeys != null) && (user.otphkeys.length > 0))));
710
}
711
712
// Check the 2-step auth token
@@ -716,7 +716,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
716
if (twoStepLoginSupported == false) { parent.debug('web', 'checkUserOneTimePassword: not supported.'); func(true); return; };
717
718
// Check if we can use OTP tokens with email
719
- var otpemail = (parent.mailserver != null);
719
+ var otpemail = (domain.mailserver != null);
720
if ((typeof domain.passwordrequirements == 'object') && (domain.passwordrequirements.email2factor == false)) { otpemail = false; }
721
var otpsms = (parent.smsserver != null);
722
if ((typeof domain.passwordrequirements == 'object') && (domain.passwordrequirements.sms2factor == false)) { otpsms = false; }
@@ -919,7 +919,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
919
return;
920
}
921
922
- var email2fa = (((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.email2factor != false)) && (parent.mailserver != null) && (user.email != null) && (user.emailVerified == true) && (user.otpekey != null));
922
+ var email2fa = (((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.email2factor != false)) && (domain.mailserver != null) && (user.email != null) && (user.emailVerified == true) && (user.otpekey != null));
923
var sms2fa = (((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.sms2factor != false)) && (parent.smsserver != null) && (user.phone != null));
924
925
// Check if this user has 2-step login active
@@ -928,7 +928,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
928
user.otpekey = { k: obj.common.zeroPad(getRandomEightDigitInteger(), 8), d: Date.now() };
929
obj.db.SetUser(user);
930
parent.debug('web', 'Sending 2FA email to: ' + user.email);
931
- parent.mailserver.sendAccountLoginMail(domain, user.email, user.otpekey.k, obj.getLanguageCodes(req), req.query.key);
931
+ domain.mailserver.sendAccountLoginMail(domain, user.email, user.otpekey.k, obj.getLanguageCodes(req), req.query.key);
932
req.session.messageid = 2; // "Email sent" message
933
req.session.loginmode = '4';
934
if (direct === true) { handleRootRequestEx(req, res, domain); } else { res.redirect(domain.url + getQueryPortion(req)); }
@@ -967,7 +967,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
967
// Wait and redirect the user
968
setTimeout(function () {
969
req.session.loginmode = '4';
970
- req.session.tokenemail = ((user.email != null) && (user.emailVerified == true) && (parent.mailserver != null) && (user.otpekey != null));
970
+ req.session.tokenemail = ((user.email != null) && (user.emailVerified == true) && (domain.mailserver != null) && (user.otpekey != null));
971
req.session.tokensms = ((user.phone != null) && (parent.smsserver != null));
972
req.session.tokenuserid = userid;
973
req.session.tokenusername = xusername;
@@ -984,7 +984,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
984
}
985
986
// Check if email address needs to be confirmed
987
- var emailcheck = ((obj.parent.mailserver != null) && (obj.parent.certificates.CommonName != null) && (obj.parent.certificates.CommonName.indexOf('.') != -1) && (obj.args.lanonly != true) && (domain.auth != 'sspi') && (domain.auth != 'ldap'))
987
+ var emailcheck = ((domain.mailserver != null) && (obj.parent.certificates.CommonName != null) && (obj.parent.certificates.CommonName.indexOf('.') != -1) && (obj.args.lanonly != true) && (domain.auth != 'sspi') && (domain.auth != 'ldap'))
988
if (emailcheck && (user.emailVerified !== true)) {
989
parent.debug('web', 'Redirecting using ' + user.name + ' to email check login page');
990
req.session.messageid = 3; // "Email verification required" message
@@ -1005,7 +1005,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1005
}
1006
1007
// Check if email address needs to be confirmed
1008
- var emailcheck = ((obj.parent.mailserver != null) && (obj.parent.certificates.CommonName != null) && (obj.parent.certificates.CommonName.indexOf('.') != -1) && (obj.args.lanonly != true) && (domain.auth != 'sspi') && (domain.auth != 'ldap'))
1008
+ var emailcheck = ((domain.mailserver != null) && (obj.parent.certificates.CommonName != null) && (obj.parent.certificates.CommonName.indexOf('.') != -1) && (obj.args.lanonly != true) && (domain.auth != 'sspi') && (domain.auth != 'ldap'))
1009
if (emailcheck && (user.emailVerified !== true)) {
1010
parent.debug('web', 'Redirecting using ' + user.name + ' to email check login page');
1011
req.session.messageid = 3; // "Email verification required" message
@@ -1261,7 +1261,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1261
obj.db.SetUser(user);
1262
1263
// Send the verification email
1264
- if ((obj.parent.mailserver != null) && (domain.auth != 'sspi') && (domain.auth != 'ldap') && (obj.common.validateEmail(user.email, 1, 256) == true)) { obj.parent.mailserver.sendAccountCheckMail(domain, user.name, user._id, user.email, obj.getLanguageCodes(req), req.query.key); }
1264
+ if ((domain.mailserver != null) && (domain.auth != 'sspi') && (domain.auth != 'ldap') && (obj.common.validateEmail(user.email, 1, 256) == true)) { domain.mailserver.sendAccountCheckMail(domain, user.name, user._id, user.email, obj.getLanguageCodes(req), req.query.key); }
1265
}, 0);
1266
var event = { etype: 'user', userid: user._id, username: user.name, account: obj.CloneSafeUser(user), action: 'accountcreate', msg: 'Account created, email is ' + req.body.email, domain: domain.id };
1267
if (obj.db.changeStream) { event.noact = 1; } // If DB change stream is active, don't use this event to create the user. Another event will come.
@@ -1458,8 +1458,8 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1458
} else {
1459
// Send email to perform recovery.
1460
delete req.session.tokenemail;
1461
- if (obj.parent.mailserver != null) {
1462
- obj.parent.mailserver.sendAccountResetMail(domain, user.name, user._id, user.email, obj.getLanguageCodes(req), req.query.key);
1461
+ if (domain.mailserver != null) {
1462
+ domain.mailserver.sendAccountResetMail(domain, user.name, user._id, user.email, obj.getLanguageCodes(req), req.query.key);
1463
if (i == 0) {
1464
parent.debug('web', 'handleResetAccountRequest: Hold on, reset mail sent.');
1465
req.session.loginmode = '1';
@@ -1478,8 +1478,8 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1478
});
1479
} else {
1480
// No second factor, send email to perform recovery.
1481
- if (obj.parent.mailserver != null) {
1482
- obj.parent.mailserver.sendAccountResetMail(domain, user.name, user._id, user.email, obj.getLanguageCodes(req), req.query.key);
1481
+ if (domain.mailserver != null) {
1482
+ domain.mailserver.sendAccountResetMail(domain, user.name, user._id, user.email, obj.getLanguageCodes(req), req.query.key);
1483
if (i == 0) {
1484
parent.debug('web', 'handleResetAccountRequest: Hold on, reset mail sent.');
1485
req.session.loginmode = '1';
@@ -1505,7 +1505,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1505
function handleCheckAccountEmailRequest(req, res, direct) {
1506
const domain = checkUserIpAddress(req, res);
1507
if (domain == null) { return; }
1508
- if ((obj.parent.mailserver == null) || (domain.auth == 'sspi') || (domain.auth == 'ldap') || (typeof req.session.cuserid != 'string') || (obj.users[req.session.cuserid] == null) || (!obj.common.validateEmail(req.body.email, 1, 256))) { parent.debug('web', 'handleCheckAccountEmailRequest: failed checks.'); res.sendStatus(404); return; }
1508
+ if ((domain.mailserver == null) || (domain.auth == 'sspi') || (domain.auth == 'ldap') || (typeof req.session.cuserid != 'string') || (obj.users[req.session.cuserid] == null) || (!obj.common.validateEmail(req.body.email, 1, 256))) { parent.debug('web', 'handleCheckAccountEmailRequest: failed checks.'); res.sendStatus(404); return; }
1509
if ((domain.loginkey != null) && (domain.loginkey.indexOf(req.query.key) == -1)) { res.sendStatus(404); return; } // Check 3FA URL key
1510
1511
// Always lowercase the email address
@@ -1563,7 +1563,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1563
}
1564
1565
// Send the verification email
1566
- obj.parent.mailserver.sendAccountCheckMail(domain, user.name, user._id, user.email, obj.getLanguageCodes(req), req.query.key);
1566
+ domain.mailserver.sendAccountCheckMail(domain, user.name, user._id, user.email, obj.getLanguageCodes(req), req.query.key);
1567
1568
// Send the response
1569
req.session.messageid = 2; // Email sent.
@@ -1579,11 +1579,11 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1579
function handleCheckMailRequest(req, res) {
1580
const domain = checkUserIpAddress(req, res);
1581
if (domain == null) { return; }
1582
- if ((domain.auth == 'sspi') || (domain.auth == 'ldap') || (obj.parent.mailserver == null)) { parent.debug('web', 'handleCheckMailRequest: failed checks.'); res.sendStatus(404); return; }
1582
+ if ((domain.auth == 'sspi') || (domain.auth == 'ldap') || (domain.mailserver == null)) { parent.debug('web', 'handleCheckMailRequest: failed checks.'); res.sendStatus(404); return; }
1583
if ((domain.loginkey != null) && (domain.loginkey.indexOf(req.query.key) == -1)) { res.sendStatus(404); return; } // Check 3FA URL key
1584
1585
if (req.query.c != null) {
1586
- var cookie = obj.parent.decodeCookie(req.query.c, obj.parent.mailserver.mailCookieEncryptionKey, 30);
1586
+ var cookie = obj.parent.decodeCookie(req.query.c, domain.mailserver.mailCookieEncryptionKey, 30);
1587
if ((cookie != null) && (cookie.u != null) && (cookie.u.startsWith('user/')) && (cookie.e != null)) {
1588
var idsplit = cookie.u.split('/');
1589
if ((idsplit.length != 3) || (idsplit[1] != domain.id)) {
@@ -2427,7 +2427,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
2427
if (domain.userQuota == -1) { features += 0x00000008; } // No server files mode
2428
if (obj.args.mpstlsoffload) { features += 0x00000010; } // No mutual-auth CIRA
2429
if ((parent.config.settings.allowframing != null) || (domain.allowframing != null)) { features += 0x00000020; } // Allow site within iframe
2430
- if ((obj.parent.mailserver != null) && (obj.parent.certificates.CommonName != null) && (obj.parent.certificates.CommonName.indexOf('.') != -1) && (obj.args.lanonly != true)) { features += 0x00000040; } // Email invites
2430
+ if ((domain.mailserver != null) && (obj.parent.certificates.CommonName != null) && (obj.parent.certificates.CommonName.indexOf('.') != -1) && (obj.args.lanonly != true)) { features += 0x00000040; } // Email invites
2431
if (obj.args.webrtc == true) { features += 0x00000080; } // Enable WebRTC (Default false for now)
2432
// 0x00000100 --> This feature flag is free for future use.
2433
if (obj.args.allowhighqualitydesktop !== false) { features += 0x00000200; } // Enable AllowHighQualityDesktop (Default true)
@@ -2453,7 +2453,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
2453
if (domain.amtacmactivation) { features += 0x00100000; } // Intel AMT ACM activation/upgrade is possible
2454
if (domain.usernameisemail) { features += 0x00200000; } // Username is email address
2455
if (parent.mqttbroker != null) { features += 0x00400000; } // This server supports MQTT channels
2456
- if (((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.email2factor != false)) && (parent.mailserver != null)) { features += 0x00800000; } // using email for 2FA is allowed
2456
+ if (((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.email2factor != false)) && (domain.mailserver != null)) { features += 0x00800000; } // using email for 2FA is allowed
2457
if (domain.agentinvitecodes == true) { features += 0x01000000; } // Support for agent invite codes
2458
if (parent.smsserver != null) { features += 0x02000000; } // SMS messaging is supported
2459
if ((parent.smsserver != null) && ((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.sms2factor != false))) { features += 0x04000000; } // SMS 2FA is allowed
@@ -2601,7 +2601,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
2601
delete req.session.messageid;
2602
delete req.session.passhint;
2603
}
2604
- var emailcheck = ((obj.parent.mailserver != null) && (obj.parent.certificates.CommonName != null) && (obj.parent.certificates.CommonName.indexOf('.') != -1) && (obj.args.lanonly != true) && (domain.auth != 'sspi') && (domain.auth != 'ldap'))
2604
+ var emailcheck = ((domain.mailserver != null) && (obj.parent.certificates.CommonName != null) && (obj.parent.certificates.CommonName.indexOf('.') != -1) && (obj.args.lanonly != true) && (domain.auth != 'sspi') && (domain.auth != 'ldap'))
2605
2606
// Check if we are allowed to create new users using the login screen
2607
var newAccountsAllowed = true;
@@ -2613,7 +2613,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
2613
if (hardwareKeyChallenge) { hwstate = obj.parent.encodeCookie({ u: req.session.tokenusername, p: req.session.tokenpassword, c: req.session.u2fchallenge }, obj.parent.loginCookieEncryptionKey) }
2614
2615
// Check if we can use OTP tokens with email. We can't use email for 2FA password recovery (loginmode 5).
2616
- var otpemail = (loginmode != 5) && (parent.mailserver != null) && (req.session != null) && ((req.session.tokenemail == true) || (typeof req.session.tokenemail == 'string'));
2616
+ var otpemail = (loginmode != 5) && (domain.mailserver != null) && (req.session != null) && ((req.session.tokenemail == true) || (typeof req.session.tokenemail == 'string'));
2617
if ((typeof domain.passwordrequirements == 'object') && (domain.passwordrequirements.email2factor == false)) { otpemail = false; }
2618
var otpsms = (parent.smsserver != null) && (req.session != null) && (req.session.tokensms == true);
2619
if ((typeof domain.passwordrequirements == 'object') && (domain.passwordrequirements.sms2factor == false)) { otpsms = false; }
@@ -5669,7 +5669,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
5669
if (domain == null) { parent.debug('web', 'WSERROR: Got no domain, user auth required.'); return; }
5670
}
5671
5672
- var emailcheck = ((obj.parent.mailserver != null) && (obj.parent.certificates.CommonName != null) && (obj.parent.certificates.CommonName.indexOf('.') != -1) && (obj.args.lanonly != true) && (domain.auth != 'sspi') && (domain.auth != 'ldap'))
5672
+ var emailcheck = ((domain.mailserver != null) && (obj.parent.certificates.CommonName != null) && (obj.parent.certificates.CommonName.indexOf('.') != -1) && (obj.args.lanonly != true) && (domain.auth != 'sspi') && (domain.auth != 'ldap'))
5673
5674
// A web socket session can be authenticated in many ways (Default user, session, user/pass and cookie). Check authentication here.
5675
if ((req.query.user != null) && (req.query.pass != null)) {
@@ -5685,7 +5685,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
5685
// Check if a 2nd factor is needed
5686
if (checkUserOneTimePasswordRequired(domain, user, req) == true) {
5687
// Figure out if email 2FA is allowed
5688
- var email2fa = (((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.email2factor != false)) && (parent.mailserver != null) && (user.otpekey != null));
5688
+ var email2fa = (((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.email2factor != false)) && (domain.mailserver != null) && (user.otpekey != null));
5689
var sms2fa = (((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.sms2factor != false)) && (parent.smsserver != null) && (user.phone != null));
5690
if ((typeof req.query.token != 'string') || (req.query.token == '**email**') || (req.query.token == '**sms**')) {
5691
if ((req.query.token == '**email**') && (email2fa == true)) {
@@ -5693,7 +5693,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
5693
user.otpekey = { k: obj.common.zeroPad(getRandomEightDigitInteger(), 8), d: Date.now() };
5694
obj.db.SetUser(user);
5695
parent.debug('web', 'Sending 2FA email to: ' + user.email);
5696
- parent.mailserver.sendAccountLoginMail(domain, user.email, user.otpekey.k, obj.getLanguageCodes(req), req.query.key);
5696
+ domain.mailserver.sendAccountLoginMail(domain, user.email, user.otpekey.k, obj.getLanguageCodes(req), req.query.key);
5697
// Ask for a login token & confirm email was sent
5698
try { ws.send(JSON.stringify({ action: 'close', cause: 'noauth', msg: 'tokenrequired', email2fa: email2fa, sms2fa: sms2fa, email2fasent: true, twoFactorCookieDays: twoFactorCookieDays })); ws.close(); } catch (e) { }
5699
} else if ((req.query.token == '**sms**') && (sms2fa == true)) {
@@ -5731,7 +5731,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
5731
// Check email verification
5732
if (emailcheck && (user.email != null) && (user.emailVerified !== true)) {
5733
parent.debug('web', 'Invalid login, asking for email validation');
5734
- var email2fa = (((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.email2factor != false)) && (parent.mailserver != null) && (user.otpekey != null));
5734
+ var email2fa = (((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.email2factor != false)) && (domain.mailserver != null) && (user.otpekey != null));
5735
var sms2fa = (((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.sms2factor != false)) && (parent.smsserver != null) && (user.phone != null));
5736
try { ws.send(JSON.stringify({ action: 'close', cause: 'emailvalidation', msg: 'emailvalidationrequired', email2fa: email2fa, sms2fa: sms2fa, email2fasent: true })); ws.close(); } catch (e) { }
5737
} else {
@@ -5788,7 +5788,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
5788
if (typeof domain.twofactorcookiedurationdays == 'number') { twoFactorCookieDays = domain.twofactorcookiedurationdays; }
5789
5790
// Figure out if email 2FA is allowed
5791
- var email2fa = (((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.email2factor != false)) && (parent.mailserver != null) && (user.otpekey != null));
5791
+ var email2fa = (((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.email2factor != false)) && (domain.mailserver != null) && (user.otpekey != null));
5792
var sms2fa = (((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.sms2factor != false)) && (parent.smsserver != null) && (user.phone != null));
5793
if (s.length != 3) {
5794
try { ws.send(JSON.stringify({ action: 'close', cause: 'noauth', msg: 'tokenrequired', email2fa: email2fa, sms2fa: sms2fa, twoFactorCookieDays: twoFactorCookieDays })); ws.close(); } catch (e) { }
@@ -5800,7 +5800,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
5800
user.otpekey = { k: obj.common.zeroPad(getRandomEightDigitInteger(), 8), d: Date.now() };
5801
obj.db.SetUser(user);
5802
parent.debug('web', 'Sending 2FA email to: ' + user.email);
5803
- parent.mailserver.sendAccountLoginMail(domain, user.email, user.otpekey.k, obj.getLanguageCodes(req), req.query.key);
5803
+ domain.mailserver.sendAccountLoginMail(domain, user.email, user.otpekey.k, obj.getLanguageCodes(req), req.query.key);
5804
// Ask for a login token & confirm email was sent
5805
try { ws.send(JSON.stringify({ action: 'close', cause: 'noauth', msg: 'tokenrequired', email2fa: email2fa, email2fasent: true, twoFactorCookieDays: twoFactorCookieDays })); ws.close(); } catch (e) { }
5806
} else if ((s[2] == '**sms**') && (sms2fa == true)) {