mirror of
https://github.com/Ylianst/MeshCentral.git
synced 2024-09-11 08:55:32 +03:00
Added per-domain SMTP/SendGrid support.
This commit is contained in:
parent
ddf78e325c
commit
d96bf4b4f5
@ -506,6 +506,32 @@
|
|||||||
"required": [ "protocols" ]
|
"required": [ "protocols" ]
|
||||||
},
|
},
|
||||||
"showPasswordLogin": { "type": "boolean", "default": true, "description": "When set to false, hides the username and password prompt on login screen." },
|
"showPasswordLogin": { "type": "boolean", "default": true, "description": "When set to false, hides the username and password prompt on login screen." },
|
||||||
|
"sendgrid": {
|
||||||
|
"title" : "SendGrid.com Email server",
|
||||||
|
"description": "Connects MeshCentral to the SendGrid email server, allows MeshCentral to send email messages for 2FA or user notification.",
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"from": { "type": "string", "format": "email", "description": "Email address used in the messages from field." },
|
||||||
|
"apikey": { "type": "string", "description": "The SendGrid API key." },
|
||||||
|
"verifyemail": { "type": "boolean", "default": true, "description": "When set to false, the email format and DNS MX record are not checked." }
|
||||||
|
},
|
||||||
|
"required": [ "from", "apikey" ]
|
||||||
|
},
|
||||||
|
"smtp": {
|
||||||
|
"title" : "SMTP email server",
|
||||||
|
"description": "Connects MeshCentral to a SMTP email server, allows MeshCentral to send email messages for 2FA or user notification.",
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"host": { "type": "string", "format": "hostname" },
|
||||||
|
"port": { "type": "integer", "minimum": 1, "maximum": 65535 },
|
||||||
|
"from": { "type": "string", "format": "email", "description": "Email address used in the messages from field." },
|
||||||
|
"tls": { "type": "boolean" },
|
||||||
|
"tlscertcheck": { "type": "boolean" },
|
||||||
|
"tlsstrict": { "type": "boolean" },
|
||||||
|
"verifyemail": { "type": "boolean", "default": true, "description": "When set to false, the email format and DNS MX record are not checked." }
|
||||||
|
},
|
||||||
|
"required": [ "host", "port", "from", "tls" ]
|
||||||
|
},
|
||||||
"authStrategies": {
|
"authStrategies": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
|
@ -1525,7 +1525,7 @@ function CreateMeshCentralServer(config, args) {
|
|||||||
obj.swarmserver = require('./swarmserver.js').CreateSwarmServer(obj, obj.db, obj.args, obj.certificates);
|
obj.swarmserver = require('./swarmserver.js').CreateSwarmServer(obj, obj.db, obj.args, obj.certificates);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Setup email server
|
// Setup the main email server
|
||||||
if (obj.config.sendgrid != null) {
|
if (obj.config.sendgrid != null) {
|
||||||
// Sendgrid server
|
// Sendgrid server
|
||||||
obj.mailserver = require('./meshmail.js').CreateMeshMail(obj);
|
obj.mailserver = require('./meshmail.js').CreateMeshMail(obj);
|
||||||
@ -1538,6 +1538,24 @@ function CreateMeshCentralServer(config, args) {
|
|||||||
if (obj.args.lanonly == true) { addServerWarning("SMTP server has limited use in LAN mode."); }
|
if (obj.args.lanonly == true) { addServerWarning("SMTP server has limited use in LAN mode."); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Setup the email server for each domain
|
||||||
|
for (i in obj.config.domains) {
|
||||||
|
if (obj.config.domains[i].sendgrid != null) {
|
||||||
|
// Sendgrid server
|
||||||
|
obj.config.domains[i].mailserver = require('./meshmail.js').CreateMeshMail(obj, obj.config.domains[i]);
|
||||||
|
obj.config.domains[i].mailserver.verify();
|
||||||
|
if (obj.args.lanonly == true) { addServerWarning("SendGrid server has limited use in LAN mode."); }
|
||||||
|
} else if ((obj.config.domains[i].smtp != null) && (obj.config.domains[i].smtp.host != null) && (obj.config.domains[i].smtp.from != null)) {
|
||||||
|
// SMTP server
|
||||||
|
obj.config.domains[i].mailserver = require('./meshmail.js').CreateMeshMail(obj, obj.config.domains[i]);
|
||||||
|
obj.config.domains[i].mailserver.verify();
|
||||||
|
if (obj.args.lanonly == true) { addServerWarning("SMTP server has limited use in LAN mode."); }
|
||||||
|
} else {
|
||||||
|
// Setup the parent mail server for this domain
|
||||||
|
if (obj.mailserver != null) { obj.config.domains[i].mailserver = obj.mailserver; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Setup SMS gateway
|
// Setup SMS gateway
|
||||||
if (config.sms != null) {
|
if (config.sms != null) {
|
||||||
obj.smsserver = require('./meshsms.js').CreateMeshSMS(obj);
|
obj.smsserver = require('./meshsms.js').CreateMeshSMS(obj);
|
||||||
@ -2994,10 +3012,14 @@ function mainStart() {
|
|||||||
var recordingIndex = false;
|
var recordingIndex = false;
|
||||||
var domainCount = 0;
|
var domainCount = 0;
|
||||||
var wildleek = false;
|
var wildleek = false;
|
||||||
|
var nodemailer = false;
|
||||||
|
var sendgrid = false;
|
||||||
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; }
|
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; }
|
||||||
if (domainCount == 0) { allsspi = false; }
|
if (domainCount == 0) { allsspi = false; }
|
||||||
for (var i in config.domains) {
|
for (var i in config.domains) {
|
||||||
if (i.startsWith('_')) continue;
|
if (i.startsWith('_')) continue;
|
||||||
|
if (config.domains[i].smtp != null) { nodemailer = true; }
|
||||||
|
if (config.domains[i].sendgrid != null) { sendgrid = true; }
|
||||||
if (config.domains[i].yubikey != null) { yubikey = true; }
|
if (config.domains[i].yubikey != null) { yubikey = true; }
|
||||||
if (config.domains[i].auth == 'ldap') { ldap = true; }
|
if (config.domains[i].auth == 'ldap') { ldap = true; }
|
||||||
if (config.domains[i].mstsc === true) { mstsc = true; }
|
if (config.domains[i].mstsc === true) { mstsc = true; }
|
||||||
@ -3030,8 +3052,8 @@ function mainStart() {
|
|||||||
if (config.settings.plugins != null) { modules.push('semver'); } // Required for version compat testing and update checks
|
if (config.settings.plugins != null) { modules.push('semver'); } // Required for version compat testing and update checks
|
||||||
if ((config.settings.plugins != null) && (config.settings.plugins.proxy != null)) { modules.push('https-proxy-agent'); } // Required for HTTP/HTTPS proxy support
|
if ((config.settings.plugins != null) && (config.settings.plugins.proxy != null)) { modules.push('https-proxy-agent'); } // Required for HTTP/HTTPS proxy support
|
||||||
else if (config.settings.xmongodb != null) { modules.push('mongojs'); } // Add MongoJS, old driver.
|
else if (config.settings.xmongodb != null) { modules.push('mongojs'); } // Add MongoJS, old driver.
|
||||||
if (config.smtp != null) { modules.push('nodemailer'); } // Add SMTP support
|
if (nodemailer || (config.smtp != null)) { modules.push('nodemailer'); } // Add SMTP support
|
||||||
if (config.sendgrid != null) { modules.push('@sendgrid/mail'); } // Add SendGrid support
|
if (sendgrid || (config.sendgrid != null)) { modules.push('@sendgrid/mail'); } // Add SendGrid support
|
||||||
if (args.translate) { modules.push('jsdom'); modules.push('esprima'); modules.push('minify-js'); modules.push('html-minifier'); } // Translation support
|
if (args.translate) { modules.push('jsdom'); modules.push('esprima'); modules.push('minify-js'); modules.push('html-minifier'); } // Translation support
|
||||||
|
|
||||||
// If running NodeJS < 8, install "util.promisify"
|
// If running NodeJS < 8, install "util.promisify"
|
||||||
|
64
meshmail.js
64
meshmail.js
@ -17,32 +17,39 @@
|
|||||||
// TODO: Add NTML support with "nodemailer-ntlm-auth" https://github.com/nodemailer/nodemailer-ntlm-auth
|
// TODO: Add NTML support with "nodemailer-ntlm-auth" https://github.com/nodemailer/nodemailer-ntlm-auth
|
||||||
|
|
||||||
// Construct a MeshAgent object, called upon connection
|
// Construct a MeshAgent object, called upon connection
|
||||||
module.exports.CreateMeshMail = function (parent) {
|
module.exports.CreateMeshMail = function (parent, domain) {
|
||||||
var obj = {};
|
var obj = {};
|
||||||
obj.pendingMails = [];
|
obj.pendingMails = [];
|
||||||
obj.parent = parent;
|
obj.parent = parent;
|
||||||
obj.retry = 0;
|
obj.retry = 0;
|
||||||
obj.sendingMail = false;
|
obj.sendingMail = false;
|
||||||
obj.mailCookieEncryptionKey = null;
|
obj.mailCookieEncryptionKey = null;
|
||||||
|
obj.verifyemail = false;
|
||||||
|
obj.domain = domain;
|
||||||
//obj.mailTemplates = {};
|
//obj.mailTemplates = {};
|
||||||
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.
|
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.
|
||||||
|
|
||||||
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; }
|
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; }
|
||||||
//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; }
|
//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; }
|
||||||
|
|
||||||
if (parent.config.sendgrid != null) {
|
// Setup where we read our configuration from
|
||||||
|
if (obj.domain == null) { obj.config = parent.config; } else { obj.config = domain; }
|
||||||
|
|
||||||
|
if (obj.config.sendgrid != null) {
|
||||||
// Setup SendGrid mail server
|
// Setup SendGrid mail server
|
||||||
obj.sendGridServer = require('@sendgrid/mail');
|
obj.sendGridServer = require('@sendgrid/mail');
|
||||||
obj.sendGridServer.setApiKey(parent.config.sendgrid.apikey);
|
obj.sendGridServer.setApiKey(obj.config.sendgrid.apikey);
|
||||||
} else if (parent.config.smtp != null) {
|
if (obj.config.sendgrid.verifyemail == true) { obj.verifyemail = true; }
|
||||||
|
} else if (obj.config.smtp != null) {
|
||||||
// Setup SMTP mail server
|
// Setup SMTP mail server
|
||||||
const nodemailer = require('nodemailer');
|
const nodemailer = require('nodemailer');
|
||||||
var options = { host: parent.config.smtp.host, secure: (parent.config.smtp.tls == true), tls: {} };
|
var options = { host: obj.config.smtp.host, secure: (obj.config.smtp.tls == true), tls: {} };
|
||||||
//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 } };
|
//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 } };
|
||||||
if (parent.config.smtp.port != null) { options.port = parent.config.smtp.port; }
|
if (obj.config.smtp.port != null) { options.port = obj.config.smtp.port; }
|
||||||
if (parent.config.smtp.tlscertcheck === false) { options.tls.rejectUnauthorized = false; }
|
if (obj.config.smtp.tlscertcheck === false) { options.tls.rejectUnauthorized = false; }
|
||||||
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; }
|
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; }
|
||||||
if ((parent.config.smtp.user != null) && (parent.config.smtp.pass != null)) { options.auth = { user: parent.config.smtp.user, pass: parent.config.smtp.pass }; }
|
if ((obj.config.smtp.user != null) && (obj.config.smtp.pass != null)) { options.auth = { user: obj.config.smtp.user, pass: obj.config.smtp.pass }; }
|
||||||
|
if (obj.config.smtp.verifyemail == true) { obj.verifyemail = true; }
|
||||||
obj.smtpServer = nodemailer.createTransport(options);
|
obj.smtpServer = nodemailer.createTransport(options);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -149,10 +156,10 @@ module.exports.CreateMeshMail = function (parent) {
|
|||||||
|
|
||||||
// Send a generic email
|
// Send a generic email
|
||||||
obj.sendMail = function (to, subject, text, html) {
|
obj.sendMail = function (to, subject, text, html) {
|
||||||
if (parent.config.sendgrid != null) {
|
if (obj.config.sendgrid != null) {
|
||||||
obj.pendingMails.push({ to: to, from: parent.config.sendgrid.from, subject: subject, text: text, html: html });
|
obj.pendingMails.push({ to: to, from: obj.config.sendgrid.from, subject: subject, text: text, html: html });
|
||||||
} else if (parent.config.smtp != null) {
|
} else if (obj.config.smtp != null) {
|
||||||
obj.pendingMails.push({ to: to, from: parent.config.smtp.from, subject: subject, text: text, html: html });
|
obj.pendingMails.push({ to: to, from: obj.config.smtp.from, subject: subject, text: text, html: html });
|
||||||
}
|
}
|
||||||
sendNextMail();
|
sendNextMail();
|
||||||
};
|
};
|
||||||
@ -180,8 +187,8 @@ module.exports.CreateMeshMail = function (parent) {
|
|||||||
|
|
||||||
// Get from field
|
// Get from field
|
||||||
var from = null;
|
var from = null;
|
||||||
if (parent.config.sendgrid && (typeof parent.config.sendgrid.from == 'string')) { from = parent.config.sendgrid.from; }
|
if (obj.config.sendgrid && (typeof obj.config.sendgrid.from == 'string')) { from = obj.config.sendgrid.from; }
|
||||||
else if (parent.config.smtp && (typeof parent.config.smtp.from == 'string')) { from = parent.config.smtp.from; }
|
else if (obj.config.smtp && (typeof obj.config.smtp.from == 'string')) { from = obj.config.smtp.from; }
|
||||||
|
|
||||||
// Send the email
|
// Send the email
|
||||||
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) });
|
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) {
|
|||||||
|
|
||||||
// Get from field
|
// Get from field
|
||||||
var from = null;
|
var from = null;
|
||||||
if (parent.config.sendgrid && (typeof parent.config.sendgrid.from == 'string')) { from = parent.config.sendgrid.from; }
|
if (obj.config.sendgrid && (typeof obj.config.sendgrid.from == 'string')) { from = obj.config.sendgrid.from; }
|
||||||
else if (parent.config.smtp && (typeof parent.config.smtp.from == 'string')) { from = parent.config.smtp.from; }
|
else if (obj.config.smtp && (typeof obj.config.smtp.from == 'string')) { from = obj.config.smtp.from; }
|
||||||
|
|
||||||
// Send the email
|
// Send the email
|
||||||
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) });
|
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) {
|
|||||||
|
|
||||||
// Get from field
|
// Get from field
|
||||||
var from = null;
|
var from = null;
|
||||||
if (parent.config.sendgrid && (typeof parent.config.sendgrid.from == 'string')) { from = parent.config.sendgrid.from; }
|
if (obj.config.sendgrid && (typeof obj.config.sendgrid.from == 'string')) { from = obj.config.sendgrid.from; }
|
||||||
else if (parent.config.smtp && (typeof parent.config.smtp.from == 'string')) { from = parent.config.smtp.from; }
|
else if (obj.config.smtp && (typeof obj.config.smtp.from == 'string')) { from = obj.config.smtp.from; }
|
||||||
|
|
||||||
// Send the email
|
// Send the email
|
||||||
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) });
|
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) {
|
|||||||
|
|
||||||
// Get from field
|
// Get from field
|
||||||
var from = null;
|
var from = null;
|
||||||
if (parent.config.sendgrid && (typeof parent.config.sendgrid.from == 'string')) { from = parent.config.sendgrid.from; }
|
if (obj.config.sendgrid && (typeof obj.config.sendgrid.from == 'string')) { from = obj.config.sendgrid.from; }
|
||||||
else if (parent.config.smtp && (typeof parent.config.smtp.from == 'string')) { from = parent.config.smtp.from; }
|
else if (obj.config.smtp && (typeof obj.config.smtp.from == 'string')) { from = obj.config.smtp.from; }
|
||||||
|
|
||||||
// Send the email
|
// Send the email
|
||||||
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) });
|
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) {
|
|||||||
|
|
||||||
// Get from field
|
// Get from field
|
||||||
var from = null;
|
var from = null;
|
||||||
if (parent.config.sendgrid && (typeof parent.config.sendgrid.from == 'string')) { from = parent.config.sendgrid.from; }
|
if (obj.config.sendgrid && (typeof obj.config.sendgrid.from == 'string')) { from = obj.config.sendgrid.from; }
|
||||||
else if (parent.config.smtp && (typeof parent.config.smtp.from == 'string')) { from = parent.config.smtp.from; }
|
else if (obj.config.smtp && (typeof obj.config.smtp.from == 'string')) { from = obj.config.smtp.from; }
|
||||||
|
|
||||||
// Send the email
|
// Send the email
|
||||||
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) });
|
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) {
|
|||||||
if (obj.smtpServer == null) return;
|
if (obj.smtpServer == null) return;
|
||||||
obj.smtpServer.verify(function (err, info) {
|
obj.smtpServer.verify(function (err, info) {
|
||||||
if (err == null) {
|
if (err == null) {
|
||||||
console.log('SMTP mail server ' + parent.config.smtp.host + ' working as expected.');
|
console.log('SMTP mail server ' + obj.config.smtp.host + ' working as expected.');
|
||||||
} else {
|
} else {
|
||||||
// Remove all non-object types from error to avoid a JSON stringify error.
|
// Remove all non-object types from error to avoid a JSON stringify error.
|
||||||
var err2 = {};
|
var err2 = {};
|
||||||
for (var i in err) { if (typeof (err[i]) != 'object') { err2[i] = err[i]; } }
|
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));
|
parent.debug('email', 'SMTP mail server ' + obj.config.smtp.host + ' failed: ' + JSON.stringify(err2));
|
||||||
console.log('SMTP mail server ' + parent.config.smtp.host + ' failed: ' + JSON.stringify(err2));
|
console.log('SMTP mail server ' + obj.config.smtp.host + ' failed: ' + JSON.stringify(err2));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@ -430,8 +437,7 @@ module.exports.CreateMeshMail = function (parent) {
|
|||||||
// Check the email domain DNS MX record.
|
// Check the email domain DNS MX record.
|
||||||
obj.approvedEmailDomains = {};
|
obj.approvedEmailDomains = {};
|
||||||
obj.checkEmail = function (email, func) {
|
obj.checkEmail = function (email, func) {
|
||||||
if ((parent.config.smtp) && (parent.config.smtp.verifyemail === false)) { func(true); return; }
|
if (obj.verifyemail == false) { func(true); return; }
|
||||||
if ((parent.config.sendgrid) && (parent.config.sendgrid.verifyemail === false)) { func(true); return; }
|
|
||||||
var emailSplit = email.split('@');
|
var emailSplit = email.split('@');
|
||||||
if (emailSplit.length != 2) { func(false); return; }
|
if (emailSplit.length != 2) { func(false); return; }
|
||||||
if (obj.approvedEmailDomains[emailSplit[1]] === true) { func(true); return; }
|
if (obj.approvedEmailDomains[emailSplit[1]] === true) { func(true); return; }
|
||||||
|
30
meshuser.js
30
meshuser.js
@ -446,7 +446,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
|
|||||||
var httpport = ((args.aliasport != null) ? args.aliasport : args.port);
|
var httpport = ((args.aliasport != null) ? args.aliasport : args.port);
|
||||||
|
|
||||||
// Build server information object
|
// Build server information object
|
||||||
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() };
|
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() };
|
||||||
serverinfo.languages = parent.renderLanguages;
|
serverinfo.languages = parent.renderLanguages;
|
||||||
serverinfo.tlshash = Buffer.from(parent.webCertificateFullHashs[domain.id], 'binary').toString('hex').toUpperCase(); // SHA384 of server HTTPS certificate
|
serverinfo.tlshash = Buffer.from(parent.webCertificateFullHashs[domain.id], 'binary').toString('hex').toUpperCase(); // SHA384 of server HTTPS certificate
|
||||||
serverinfo.agentCertHash = parent.agentCertificateHashBase64;
|
serverinfo.agentCertHash = parent.agentCertificateHashBase64;
|
||||||
@ -978,13 +978,13 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'email': {
|
case 'email': {
|
||||||
if (parent.parent.mailserver == null) {
|
if (domain.mailserver == null) {
|
||||||
r = "No email service enabled.";
|
r = "No email service enabled.";
|
||||||
} else {
|
} else {
|
||||||
if (cmdargs['_'].length != 3) {
|
if (cmdargs['_'].length != 3) {
|
||||||
r = "Usage: email \"user@sample.com\" \"Subject\" \"Message\".";
|
r = "Usage: email \"user@sample.com\" \"Subject\" \"Message\".";
|
||||||
} else {
|
} else {
|
||||||
parent.parent.mailserver.sendMail(cmdargs['_'][0], cmdargs['_'][1], cmdargs['_'][2]);
|
domain.mailserver.sendMail(cmdargs['_'][0], cmdargs['_'][1], cmdargs['_'][2]);
|
||||||
r = "Done.";
|
r = "Done.";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1626,7 +1626,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
|
|||||||
if (parent.parent.authlog) { parent.parent.authLog('https', 'User ' + user.name + ' changed email from ' + oldemail + ' to ' + user.email); }
|
if (parent.parent.authlog) { parent.parent.authLog('https', 'User ' + user.name + ' changed email from ' + oldemail + ' to ' + user.email); }
|
||||||
|
|
||||||
// Send the verification email
|
// Send the verification email
|
||||||
if (parent.parent.mailserver != null) { parent.parent.mailserver.sendAccountCheckMail(domain, user.name, user._id, user.email, parent.getLanguageCodes(req)); }
|
if (domain.mailserver != null) { domain.mailserver.sendAccountCheckMail(domain, user.name, user._id, user.email, parent.getLanguageCodes(req)); }
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -1644,9 +1644,9 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
|
|||||||
// Always lowercase the email address
|
// Always lowercase the email address
|
||||||
command.email = command.email.toLowerCase();
|
command.email = command.email.toLowerCase();
|
||||||
|
|
||||||
if ((parent.parent.mailserver != null) && (obj.user.email.toLowerCase() == command.email)) {
|
if ((domain.mailserver != null) && (obj.user.email.toLowerCase() == command.email)) {
|
||||||
// Send the verification email
|
// Send the verification email
|
||||||
parent.parent.mailserver.sendAccountCheckMail(domain, user.name, user._id, user.email, parent.getLanguageCodes(req));
|
domain.mailserver.sendAccountCheckMail(domain, user.name, user._id, user.email, parent.getLanguageCodes(req));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -2039,8 +2039,8 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
|
|||||||
parent.parent.DispatchEvent(targets, obj, event);
|
parent.parent.DispatchEvent(targets, obj, event);
|
||||||
|
|
||||||
// Perform email invitation
|
// Perform email invitation
|
||||||
if ((command.emailInvitation == true) && (command.emailVerified == true) && command.email && parent.parent.mailserver) {
|
if ((command.emailInvitation == true) && (command.emailVerified == true) && command.email && domain.mailserver) {
|
||||||
parent.parent.mailserver.sendAccountInviteMail(newuserdomain, (user.realname ? user.realname : user.name), newusername, command.email.toLowerCase(), command.pass, parent.getLanguageCodes(req));
|
domain.mailserver.sendAccountInviteMail(newuserdomain, (user.realname ? user.realname : user.name), newusername, command.email.toLowerCase(), command.pass, parent.getLanguageCodes(req));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Log in the auth log
|
// Log in the auth log
|
||||||
@ -2237,7 +2237,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
|
|||||||
}
|
}
|
||||||
|
|
||||||
// In some situations, we need a verified email address to create a device group.
|
// In some situations, we need a verified email address to create a device group.
|
||||||
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.
|
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.
|
||||||
} catch (ex) { err = "Validation exception: " + ex; }
|
} catch (ex) { err = "Validation exception: " + ex; }
|
||||||
|
|
||||||
// Handle any errors
|
// Handle any errors
|
||||||
@ -2861,7 +2861,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
|
|||||||
if ((user.siteadmin != SITERIGHT_ADMIN) && ((user.siteadmin & 64) != 0)) { err = 'Permission denied'; }
|
if ((user.siteadmin != SITERIGHT_ADMIN) && ((user.siteadmin & 64) != 0)) { err = 'Permission denied'; }
|
||||||
|
|
||||||
// In some situations, we need a verified email address to create a device group.
|
// In some situations, we need a verified email address to create a device group.
|
||||||
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.
|
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.
|
||||||
|
|
||||||
// Create mesh
|
// Create mesh
|
||||||
else if (common.validateString(command.meshname, 1, 128) == false) { err = 'Invalid group name'; } // Meshname is between 1 and 64 characters
|
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
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if ((parent.parent.mailserver == null) || (args.lanonly == true)) { err = 'Unsupported feature'; } // This operation requires the email server
|
if ((domain.mailserver == null) || (args.lanonly == true)) { err = 'Unsupported feature'; } // This operation requires the email server
|
||||||
else if ((parent.parent.certificates.CommonName == null) || (parent.parent.certificates.CommonName.indexOf('.') == -1)) { err = 'Unsupported feature'; } // Server name must be configured
|
else if ((parent.parent.certificates.CommonName == null) || (parent.parent.certificates.CommonName.indexOf('.') == -1)) { err = 'Unsupported feature'; } // Server name must be configured
|
||||||
else if (common.validateString(command.meshid, 1, 1024) == false) { err = 'Invalid group identifier'; } // Check meshid
|
else if (common.validateString(command.meshid, 1, 1024) == false) { err = 'Invalid group identifier'; } // Check meshid
|
||||||
else {
|
else {
|
||||||
@ -4190,7 +4190,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Perform email invitation
|
// Perform email invitation
|
||||||
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);
|
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);
|
||||||
|
|
||||||
// Send a response if needed
|
// Send a response if needed
|
||||||
if (command.responseid != null) { try { ws.send(JSON.stringify({ action: 'inviteAgent', responseid: command.responseid, result: 'ok' })); } catch (ex) { } }
|
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
|
|||||||
}
|
}
|
||||||
case 'emailuser': { // Send a email message to a user
|
case 'emailuser': { // Send a email message to a user
|
||||||
var errMsg = null, emailuser = null;
|
var errMsg = null, emailuser = null;
|
||||||
if (parent.parent.mailserver == null) { errMsg = 'Email server not enabled'; }
|
if (domain.mailserver == null) { errMsg = 'Email server not enabled'; }
|
||||||
else if ((user.siteadmin & 2) == 0) { errMsg = 'No user management rights'; }
|
else if ((user.siteadmin & 2) == 0) { errMsg = 'No user management rights'; }
|
||||||
else if (common.validateString(command.userid, 1, 2048) == false) { errMsg = 'Invalid userid'; }
|
else if (common.validateString(command.userid, 1, 2048) == false) { errMsg = 'Invalid userid'; }
|
||||||
else if (common.validateString(command.subject, 1, 1000) == false) { errMsg = 'Invalid subject message'; }
|
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
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (errMsg != null) { displayNotificationMessage(errMsg); break; }
|
if (errMsg != null) { displayNotificationMessage(errMsg); break; }
|
||||||
parent.parent.mailserver.sendMail(emailuser.email, command.subject, command.msg);
|
domain.mailserver.sendMail(emailuser.email, command.subject, command.msg);
|
||||||
displayNotificationMessage("Email sent.", null, null, null, 14);
|
displayNotificationMessage("Email sent.", null, null, null, 14);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -5526,7 +5526,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
|
|||||||
|
|
||||||
// Return the number of 2nd factor for this account
|
// Return the number of 2nd factor for this account
|
||||||
function count2factoraAuths() {
|
function count2factoraAuths() {
|
||||||
var email2fa = (((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.email2factor != false)) && (parent.parent.mailserver != null));
|
var email2fa = (((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.email2factor != false)) && (domain.mailserver != null));
|
||||||
var sms2fa = ((parent.parent.smsserver != null) && ((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.sms2factor != false)));
|
var sms2fa = ((parent.parent.smsserver != null) && ((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.sms2factor != false)));
|
||||||
var authFactorCount = 0;
|
var authFactorCount = 0;
|
||||||
if (typeof user.otpsecret == 'string') { authFactorCount++; } // Authenticator time factor
|
if (typeof user.otpsecret == 'string') { authFactorCount++; } // Authenticator time factor
|
||||||
|
52
webserver.js
52
webserver.js
@ -706,7 +706,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
|||||||
var sms2fa = (((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.sms2factor != false)) && (parent.smsserver != null) && (user.phone != null));
|
var sms2fa = (((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.sms2factor != false)) && (parent.smsserver != null) && (user.phone != null));
|
||||||
|
|
||||||
// Check if a 2nd factor is present
|
// Check if a 2nd factor is present
|
||||||
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))));
|
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))));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check the 2-step auth token
|
// Check the 2-step auth token
|
||||||
@ -716,7 +716,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
|||||||
if (twoStepLoginSupported == false) { parent.debug('web', 'checkUserOneTimePassword: not supported.'); func(true); return; };
|
if (twoStepLoginSupported == false) { parent.debug('web', 'checkUserOneTimePassword: not supported.'); func(true); return; };
|
||||||
|
|
||||||
// Check if we can use OTP tokens with email
|
// Check if we can use OTP tokens with email
|
||||||
var otpemail = (parent.mailserver != null);
|
var otpemail = (domain.mailserver != null);
|
||||||
if ((typeof domain.passwordrequirements == 'object') && (domain.passwordrequirements.email2factor == false)) { otpemail = false; }
|
if ((typeof domain.passwordrequirements == 'object') && (domain.passwordrequirements.email2factor == false)) { otpemail = false; }
|
||||||
var otpsms = (parent.smsserver != null);
|
var otpsms = (parent.smsserver != null);
|
||||||
if ((typeof domain.passwordrequirements == 'object') && (domain.passwordrequirements.sms2factor == false)) { otpsms = false; }
|
if ((typeof domain.passwordrequirements == 'object') && (domain.passwordrequirements.sms2factor == false)) { otpsms = false; }
|
||||||
@ -919,7 +919,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var email2fa = (((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.email2factor != false)) && (parent.mailserver != null) && (user.email != null) && (user.emailVerified == true) && (user.otpekey != null));
|
var email2fa = (((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.email2factor != false)) && (domain.mailserver != null) && (user.email != null) && (user.emailVerified == true) && (user.otpekey != null));
|
||||||
var sms2fa = (((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.sms2factor != false)) && (parent.smsserver != null) && (user.phone != null));
|
var sms2fa = (((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.sms2factor != false)) && (parent.smsserver != null) && (user.phone != null));
|
||||||
|
|
||||||
// Check if this user has 2-step login active
|
// Check if this user has 2-step login active
|
||||||
@ -928,7 +928,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
|||||||
user.otpekey = { k: obj.common.zeroPad(getRandomEightDigitInteger(), 8), d: Date.now() };
|
user.otpekey = { k: obj.common.zeroPad(getRandomEightDigitInteger(), 8), d: Date.now() };
|
||||||
obj.db.SetUser(user);
|
obj.db.SetUser(user);
|
||||||
parent.debug('web', 'Sending 2FA email to: ' + user.email);
|
parent.debug('web', 'Sending 2FA email to: ' + user.email);
|
||||||
parent.mailserver.sendAccountLoginMail(domain, user.email, user.otpekey.k, obj.getLanguageCodes(req), req.query.key);
|
domain.mailserver.sendAccountLoginMail(domain, user.email, user.otpekey.k, obj.getLanguageCodes(req), req.query.key);
|
||||||
req.session.messageid = 2; // "Email sent" message
|
req.session.messageid = 2; // "Email sent" message
|
||||||
req.session.loginmode = '4';
|
req.session.loginmode = '4';
|
||||||
if (direct === true) { handleRootRequestEx(req, res, domain); } else { res.redirect(domain.url + getQueryPortion(req)); }
|
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) {
|
|||||||
// Wait and redirect the user
|
// Wait and redirect the user
|
||||||
setTimeout(function () {
|
setTimeout(function () {
|
||||||
req.session.loginmode = '4';
|
req.session.loginmode = '4';
|
||||||
req.session.tokenemail = ((user.email != null) && (user.emailVerified == true) && (parent.mailserver != null) && (user.otpekey != null));
|
req.session.tokenemail = ((user.email != null) && (user.emailVerified == true) && (domain.mailserver != null) && (user.otpekey != null));
|
||||||
req.session.tokensms = ((user.phone != null) && (parent.smsserver != null));
|
req.session.tokensms = ((user.phone != null) && (parent.smsserver != null));
|
||||||
req.session.tokenuserid = userid;
|
req.session.tokenuserid = userid;
|
||||||
req.session.tokenusername = xusername;
|
req.session.tokenusername = xusername;
|
||||||
@ -984,7 +984,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check if email address needs to be confirmed
|
// Check if email address needs to be confirmed
|
||||||
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'))
|
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'))
|
||||||
if (emailcheck && (user.emailVerified !== true)) {
|
if (emailcheck && (user.emailVerified !== true)) {
|
||||||
parent.debug('web', 'Redirecting using ' + user.name + ' to email check login page');
|
parent.debug('web', 'Redirecting using ' + user.name + ' to email check login page');
|
||||||
req.session.messageid = 3; // "Email verification required" message
|
req.session.messageid = 3; // "Email verification required" message
|
||||||
@ -1005,7 +1005,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check if email address needs to be confirmed
|
// Check if email address needs to be confirmed
|
||||||
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'))
|
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'))
|
||||||
if (emailcheck && (user.emailVerified !== true)) {
|
if (emailcheck && (user.emailVerified !== true)) {
|
||||||
parent.debug('web', 'Redirecting using ' + user.name + ' to email check login page');
|
parent.debug('web', 'Redirecting using ' + user.name + ' to email check login page');
|
||||||
req.session.messageid = 3; // "Email verification required" message
|
req.session.messageid = 3; // "Email verification required" message
|
||||||
@ -1261,7 +1261,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
|||||||
obj.db.SetUser(user);
|
obj.db.SetUser(user);
|
||||||
|
|
||||||
// Send the verification email
|
// Send the verification email
|
||||||
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); }
|
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); }
|
||||||
}, 0);
|
}, 0);
|
||||||
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 };
|
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 };
|
||||||
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.
|
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) {
|
|||||||
} else {
|
} else {
|
||||||
// Send email to perform recovery.
|
// Send email to perform recovery.
|
||||||
delete req.session.tokenemail;
|
delete req.session.tokenemail;
|
||||||
if (obj.parent.mailserver != null) {
|
if (domain.mailserver != null) {
|
||||||
obj.parent.mailserver.sendAccountResetMail(domain, user.name, user._id, user.email, obj.getLanguageCodes(req), req.query.key);
|
domain.mailserver.sendAccountResetMail(domain, user.name, user._id, user.email, obj.getLanguageCodes(req), req.query.key);
|
||||||
if (i == 0) {
|
if (i == 0) {
|
||||||
parent.debug('web', 'handleResetAccountRequest: Hold on, reset mail sent.');
|
parent.debug('web', 'handleResetAccountRequest: Hold on, reset mail sent.');
|
||||||
req.session.loginmode = '1';
|
req.session.loginmode = '1';
|
||||||
@ -1478,8 +1478,8 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
|||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// No second factor, send email to perform recovery.
|
// No second factor, send email to perform recovery.
|
||||||
if (obj.parent.mailserver != null) {
|
if (domain.mailserver != null) {
|
||||||
obj.parent.mailserver.sendAccountResetMail(domain, user.name, user._id, user.email, obj.getLanguageCodes(req), req.query.key);
|
domain.mailserver.sendAccountResetMail(domain, user.name, user._id, user.email, obj.getLanguageCodes(req), req.query.key);
|
||||||
if (i == 0) {
|
if (i == 0) {
|
||||||
parent.debug('web', 'handleResetAccountRequest: Hold on, reset mail sent.');
|
parent.debug('web', 'handleResetAccountRequest: Hold on, reset mail sent.');
|
||||||
req.session.loginmode = '1';
|
req.session.loginmode = '1';
|
||||||
@ -1505,7 +1505,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
|||||||
function handleCheckAccountEmailRequest(req, res, direct) {
|
function handleCheckAccountEmailRequest(req, res, direct) {
|
||||||
const domain = checkUserIpAddress(req, res);
|
const domain = checkUserIpAddress(req, res);
|
||||||
if (domain == null) { return; }
|
if (domain == null) { return; }
|
||||||
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; }
|
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; }
|
||||||
if ((domain.loginkey != null) && (domain.loginkey.indexOf(req.query.key) == -1)) { res.sendStatus(404); return; } // Check 3FA URL key
|
if ((domain.loginkey != null) && (domain.loginkey.indexOf(req.query.key) == -1)) { res.sendStatus(404); return; } // Check 3FA URL key
|
||||||
|
|
||||||
// Always lowercase the email address
|
// Always lowercase the email address
|
||||||
@ -1563,7 +1563,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Send the verification email
|
// Send the verification email
|
||||||
obj.parent.mailserver.sendAccountCheckMail(domain, user.name, user._id, user.email, obj.getLanguageCodes(req), req.query.key);
|
domain.mailserver.sendAccountCheckMail(domain, user.name, user._id, user.email, obj.getLanguageCodes(req), req.query.key);
|
||||||
|
|
||||||
// Send the response
|
// Send the response
|
||||||
req.session.messageid = 2; // Email sent.
|
req.session.messageid = 2; // Email sent.
|
||||||
@ -1579,11 +1579,11 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
|||||||
function handleCheckMailRequest(req, res) {
|
function handleCheckMailRequest(req, res) {
|
||||||
const domain = checkUserIpAddress(req, res);
|
const domain = checkUserIpAddress(req, res);
|
||||||
if (domain == null) { return; }
|
if (domain == null) { return; }
|
||||||
if ((domain.auth == 'sspi') || (domain.auth == 'ldap') || (obj.parent.mailserver == null)) { parent.debug('web', 'handleCheckMailRequest: failed checks.'); res.sendStatus(404); return; }
|
if ((domain.auth == 'sspi') || (domain.auth == 'ldap') || (domain.mailserver == null)) { parent.debug('web', 'handleCheckMailRequest: failed checks.'); res.sendStatus(404); return; }
|
||||||
if ((domain.loginkey != null) && (domain.loginkey.indexOf(req.query.key) == -1)) { res.sendStatus(404); return; } // Check 3FA URL key
|
if ((domain.loginkey != null) && (domain.loginkey.indexOf(req.query.key) == -1)) { res.sendStatus(404); return; } // Check 3FA URL key
|
||||||
|
|
||||||
if (req.query.c != null) {
|
if (req.query.c != null) {
|
||||||
var cookie = obj.parent.decodeCookie(req.query.c, obj.parent.mailserver.mailCookieEncryptionKey, 30);
|
var cookie = obj.parent.decodeCookie(req.query.c, domain.mailserver.mailCookieEncryptionKey, 30);
|
||||||
if ((cookie != null) && (cookie.u != null) && (cookie.u.startsWith('user/')) && (cookie.e != null)) {
|
if ((cookie != null) && (cookie.u != null) && (cookie.u.startsWith('user/')) && (cookie.e != null)) {
|
||||||
var idsplit = cookie.u.split('/');
|
var idsplit = cookie.u.split('/');
|
||||||
if ((idsplit.length != 3) || (idsplit[1] != domain.id)) {
|
if ((idsplit.length != 3) || (idsplit[1] != domain.id)) {
|
||||||
@ -2427,7 +2427,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
|||||||
if (domain.userQuota == -1) { features += 0x00000008; } // No server files mode
|
if (domain.userQuota == -1) { features += 0x00000008; } // No server files mode
|
||||||
if (obj.args.mpstlsoffload) { features += 0x00000010; } // No mutual-auth CIRA
|
if (obj.args.mpstlsoffload) { features += 0x00000010; } // No mutual-auth CIRA
|
||||||
if ((parent.config.settings.allowframing != null) || (domain.allowframing != null)) { features += 0x00000020; } // Allow site within iframe
|
if ((parent.config.settings.allowframing != null) || (domain.allowframing != null)) { features += 0x00000020; } // Allow site within iframe
|
||||||
if ((obj.parent.mailserver != null) && (obj.parent.certificates.CommonName != null) && (obj.parent.certificates.CommonName.indexOf('.') != -1) && (obj.args.lanonly != true)) { features += 0x00000040; } // Email invites
|
if ((domain.mailserver != null) && (obj.parent.certificates.CommonName != null) && (obj.parent.certificates.CommonName.indexOf('.') != -1) && (obj.args.lanonly != true)) { features += 0x00000040; } // Email invites
|
||||||
if (obj.args.webrtc == true) { features += 0x00000080; } // Enable WebRTC (Default false for now)
|
if (obj.args.webrtc == true) { features += 0x00000080; } // Enable WebRTC (Default false for now)
|
||||||
// 0x00000100 --> This feature flag is free for future use.
|
// 0x00000100 --> This feature flag is free for future use.
|
||||||
if (obj.args.allowhighqualitydesktop !== false) { features += 0x00000200; } // Enable AllowHighQualityDesktop (Default true)
|
if (obj.args.allowhighqualitydesktop !== false) { features += 0x00000200; } // Enable AllowHighQualityDesktop (Default true)
|
||||||
@ -2453,7 +2453,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
|||||||
if (domain.amtacmactivation) { features += 0x00100000; } // Intel AMT ACM activation/upgrade is possible
|
if (domain.amtacmactivation) { features += 0x00100000; } // Intel AMT ACM activation/upgrade is possible
|
||||||
if (domain.usernameisemail) { features += 0x00200000; } // Username is email address
|
if (domain.usernameisemail) { features += 0x00200000; } // Username is email address
|
||||||
if (parent.mqttbroker != null) { features += 0x00400000; } // This server supports MQTT channels
|
if (parent.mqttbroker != null) { features += 0x00400000; } // This server supports MQTT channels
|
||||||
if (((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.email2factor != false)) && (parent.mailserver != null)) { features += 0x00800000; } // using email for 2FA is allowed
|
if (((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.email2factor != false)) && (domain.mailserver != null)) { features += 0x00800000; } // using email for 2FA is allowed
|
||||||
if (domain.agentinvitecodes == true) { features += 0x01000000; } // Support for agent invite codes
|
if (domain.agentinvitecodes == true) { features += 0x01000000; } // Support for agent invite codes
|
||||||
if (parent.smsserver != null) { features += 0x02000000; } // SMS messaging is supported
|
if (parent.smsserver != null) { features += 0x02000000; } // SMS messaging is supported
|
||||||
if ((parent.smsserver != null) && ((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.sms2factor != false))) { features += 0x04000000; } // SMS 2FA is allowed
|
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) {
|
|||||||
delete req.session.messageid;
|
delete req.session.messageid;
|
||||||
delete req.session.passhint;
|
delete req.session.passhint;
|
||||||
}
|
}
|
||||||
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'))
|
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'))
|
||||||
|
|
||||||
// Check if we are allowed to create new users using the login screen
|
// Check if we are allowed to create new users using the login screen
|
||||||
var newAccountsAllowed = true;
|
var newAccountsAllowed = true;
|
||||||
@ -2613,7 +2613,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
|||||||
if (hardwareKeyChallenge) { hwstate = obj.parent.encodeCookie({ u: req.session.tokenusername, p: req.session.tokenpassword, c: req.session.u2fchallenge }, obj.parent.loginCookieEncryptionKey) }
|
if (hardwareKeyChallenge) { hwstate = obj.parent.encodeCookie({ u: req.session.tokenusername, p: req.session.tokenpassword, c: req.session.u2fchallenge }, obj.parent.loginCookieEncryptionKey) }
|
||||||
|
|
||||||
// Check if we can use OTP tokens with email. We can't use email for 2FA password recovery (loginmode 5).
|
// Check if we can use OTP tokens with email. We can't use email for 2FA password recovery (loginmode 5).
|
||||||
var otpemail = (loginmode != 5) && (parent.mailserver != null) && (req.session != null) && ((req.session.tokenemail == true) || (typeof req.session.tokenemail == 'string'));
|
var otpemail = (loginmode != 5) && (domain.mailserver != null) && (req.session != null) && ((req.session.tokenemail == true) || (typeof req.session.tokenemail == 'string'));
|
||||||
if ((typeof domain.passwordrequirements == 'object') && (domain.passwordrequirements.email2factor == false)) { otpemail = false; }
|
if ((typeof domain.passwordrequirements == 'object') && (domain.passwordrequirements.email2factor == false)) { otpemail = false; }
|
||||||
var otpsms = (parent.smsserver != null) && (req.session != null) && (req.session.tokensms == true);
|
var otpsms = (parent.smsserver != null) && (req.session != null) && (req.session.tokensms == true);
|
||||||
if ((typeof domain.passwordrequirements == 'object') && (domain.passwordrequirements.sms2factor == false)) { otpsms = false; }
|
if ((typeof domain.passwordrequirements == 'object') && (domain.passwordrequirements.sms2factor == false)) { otpsms = false; }
|
||||||
@ -5669,7 +5669,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
|||||||
if (domain == null) { parent.debug('web', 'WSERROR: Got no domain, user auth required.'); return; }
|
if (domain == null) { parent.debug('web', 'WSERROR: Got no domain, user auth required.'); return; }
|
||||||
}
|
}
|
||||||
|
|
||||||
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'))
|
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'))
|
||||||
|
|
||||||
// A web socket session can be authenticated in many ways (Default user, session, user/pass and cookie). Check authentication here.
|
// A web socket session can be authenticated in many ways (Default user, session, user/pass and cookie). Check authentication here.
|
||||||
if ((req.query.user != null) && (req.query.pass != null)) {
|
if ((req.query.user != null) && (req.query.pass != null)) {
|
||||||
@ -5685,7 +5685,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
|||||||
// Check if a 2nd factor is needed
|
// Check if a 2nd factor is needed
|
||||||
if (checkUserOneTimePasswordRequired(domain, user, req) == true) {
|
if (checkUserOneTimePasswordRequired(domain, user, req) == true) {
|
||||||
// Figure out if email 2FA is allowed
|
// Figure out if email 2FA is allowed
|
||||||
var email2fa = (((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.email2factor != false)) && (parent.mailserver != null) && (user.otpekey != null));
|
var email2fa = (((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.email2factor != false)) && (domain.mailserver != null) && (user.otpekey != null));
|
||||||
var sms2fa = (((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.sms2factor != false)) && (parent.smsserver != null) && (user.phone != null));
|
var sms2fa = (((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.sms2factor != false)) && (parent.smsserver != null) && (user.phone != null));
|
||||||
if ((typeof req.query.token != 'string') || (req.query.token == '**email**') || (req.query.token == '**sms**')) {
|
if ((typeof req.query.token != 'string') || (req.query.token == '**email**') || (req.query.token == '**sms**')) {
|
||||||
if ((req.query.token == '**email**') && (email2fa == true)) {
|
if ((req.query.token == '**email**') && (email2fa == true)) {
|
||||||
@ -5693,7 +5693,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
|||||||
user.otpekey = { k: obj.common.zeroPad(getRandomEightDigitInteger(), 8), d: Date.now() };
|
user.otpekey = { k: obj.common.zeroPad(getRandomEightDigitInteger(), 8), d: Date.now() };
|
||||||
obj.db.SetUser(user);
|
obj.db.SetUser(user);
|
||||||
parent.debug('web', 'Sending 2FA email to: ' + user.email);
|
parent.debug('web', 'Sending 2FA email to: ' + user.email);
|
||||||
parent.mailserver.sendAccountLoginMail(domain, user.email, user.otpekey.k, obj.getLanguageCodes(req), req.query.key);
|
domain.mailserver.sendAccountLoginMail(domain, user.email, user.otpekey.k, obj.getLanguageCodes(req), req.query.key);
|
||||||
// Ask for a login token & confirm email was sent
|
// Ask for a login token & confirm email was sent
|
||||||
try { ws.send(JSON.stringify({ action: 'close', cause: 'noauth', msg: 'tokenrequired', email2fa: email2fa, sms2fa: sms2fa, email2fasent: true, twoFactorCookieDays: twoFactorCookieDays })); ws.close(); } catch (e) { }
|
try { ws.send(JSON.stringify({ action: 'close', cause: 'noauth', msg: 'tokenrequired', email2fa: email2fa, sms2fa: sms2fa, email2fasent: true, twoFactorCookieDays: twoFactorCookieDays })); ws.close(); } catch (e) { }
|
||||||
} else if ((req.query.token == '**sms**') && (sms2fa == true)) {
|
} else if ((req.query.token == '**sms**') && (sms2fa == true)) {
|
||||||
@ -5731,7 +5731,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
|||||||
// Check email verification
|
// Check email verification
|
||||||
if (emailcheck && (user.email != null) && (user.emailVerified !== true)) {
|
if (emailcheck && (user.email != null) && (user.emailVerified !== true)) {
|
||||||
parent.debug('web', 'Invalid login, asking for email validation');
|
parent.debug('web', 'Invalid login, asking for email validation');
|
||||||
var email2fa = (((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.email2factor != false)) && (parent.mailserver != null) && (user.otpekey != null));
|
var email2fa = (((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.email2factor != false)) && (domain.mailserver != null) && (user.otpekey != null));
|
||||||
var sms2fa = (((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.sms2factor != false)) && (parent.smsserver != null) && (user.phone != null));
|
var sms2fa = (((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.sms2factor != false)) && (parent.smsserver != null) && (user.phone != null));
|
||||||
try { ws.send(JSON.stringify({ action: 'close', cause: 'emailvalidation', msg: 'emailvalidationrequired', email2fa: email2fa, sms2fa: sms2fa, email2fasent: true })); ws.close(); } catch (e) { }
|
try { ws.send(JSON.stringify({ action: 'close', cause: 'emailvalidation', msg: 'emailvalidationrequired', email2fa: email2fa, sms2fa: sms2fa, email2fasent: true })); ws.close(); } catch (e) { }
|
||||||
} else {
|
} else {
|
||||||
@ -5788,7 +5788,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
|||||||
if (typeof domain.twofactorcookiedurationdays == 'number') { twoFactorCookieDays = domain.twofactorcookiedurationdays; }
|
if (typeof domain.twofactorcookiedurationdays == 'number') { twoFactorCookieDays = domain.twofactorcookiedurationdays; }
|
||||||
|
|
||||||
// Figure out if email 2FA is allowed
|
// Figure out if email 2FA is allowed
|
||||||
var email2fa = (((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.email2factor != false)) && (parent.mailserver != null) && (user.otpekey != null));
|
var email2fa = (((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.email2factor != false)) && (domain.mailserver != null) && (user.otpekey != null));
|
||||||
var sms2fa = (((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.sms2factor != false)) && (parent.smsserver != null) && (user.phone != null));
|
var sms2fa = (((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.sms2factor != false)) && (parent.smsserver != null) && (user.phone != null));
|
||||||
if (s.length != 3) {
|
if (s.length != 3) {
|
||||||
try { ws.send(JSON.stringify({ action: 'close', cause: 'noauth', msg: 'tokenrequired', email2fa: email2fa, sms2fa: sms2fa, twoFactorCookieDays: twoFactorCookieDays })); ws.close(); } catch (e) { }
|
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) {
|
|||||||
user.otpekey = { k: obj.common.zeroPad(getRandomEightDigitInteger(), 8), d: Date.now() };
|
user.otpekey = { k: obj.common.zeroPad(getRandomEightDigitInteger(), 8), d: Date.now() };
|
||||||
obj.db.SetUser(user);
|
obj.db.SetUser(user);
|
||||||
parent.debug('web', 'Sending 2FA email to: ' + user.email);
|
parent.debug('web', 'Sending 2FA email to: ' + user.email);
|
||||||
parent.mailserver.sendAccountLoginMail(domain, user.email, user.otpekey.k, obj.getLanguageCodes(req), req.query.key);
|
domain.mailserver.sendAccountLoginMail(domain, user.email, user.otpekey.k, obj.getLanguageCodes(req), req.query.key);
|
||||||
// Ask for a login token & confirm email was sent
|
// Ask for a login token & confirm email was sent
|
||||||
try { ws.send(JSON.stringify({ action: 'close', cause: 'noauth', msg: 'tokenrequired', email2fa: email2fa, email2fasent: true, twoFactorCookieDays: twoFactorCookieDays })); ws.close(); } catch (e) { }
|
try { ws.send(JSON.stringify({ action: 'close', cause: 'noauth', msg: 'tokenrequired', email2fa: email2fa, email2fasent: true, twoFactorCookieDays: twoFactorCookieDays })); ws.close(); } catch (e) { }
|
||||||
} else if ((s[2] == '**sms**') && (sms2fa == true)) {
|
} else if ((s[2] == '**sms**') && (sms2fa == true)) {
|
||||||
|
Loading…
Reference in New Issue
Block a user