mirror of
https://github.com/Ylianst/MeshCentral.git
synced 2024-11-22 22:17:31 +03:00
Merge branch 'master' into plugin-admin
This commit is contained in:
commit
8e35f432c8
3
.greenlockrc
Normal file
3
.greenlockrc
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"manager": "C:\\Users\\Default.DESKTOP-M9I88C9\\Desktop\\AmtWebApp\\meshcentral\\letsencrypt.js"
|
||||||
|
}
|
Binary file not shown.
@ -1788,6 +1788,78 @@ function createMeshCore(agent) {
|
|||||||
response = 'Available commands: \r\n' + fin + '.';
|
response = 'Available commands: \r\n' + fin + '.';
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case 'wallpaper':
|
||||||
|
if (process.platform != 'win32' && !(process.platform == 'linux' && require('linux-gnome-helpers').available))
|
||||||
|
{
|
||||||
|
response = 'wallpaper command not supported on this platform'
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (args['_'].length != 1)
|
||||||
|
{
|
||||||
|
response = 'Proper usage: wallpaper (GET|TOGGLE)'; // Display usage
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
switch (args['_'][0].toUpperCase())
|
||||||
|
{
|
||||||
|
default:
|
||||||
|
response = 'Proper usage: wallpaper (GET|TOGGLE)'; // Display usage
|
||||||
|
break;
|
||||||
|
case 'GET':
|
||||||
|
case 'TOGGLE':
|
||||||
|
if (process.platform == 'win32')
|
||||||
|
{
|
||||||
|
var id = require('user-sessions').getProcessOwnerName(process.pid).tsid == 0 ? 1 : 0;
|
||||||
|
var child = require('child_process').execFile(process.execPath, [process.execPath.split('\\').pop(), '-b64exec', 'dmFyIFNQSV9HRVRERVNLV0FMTFBBUEVSID0gMHgwMDczOwp2YXIgU1BJX1NFVERFU0tXQUxMUEFQRVIgPSAweDAwMTQ7CnZhciBHTSA9IHJlcXVpcmUoJ19HZW5lcmljTWFyc2hhbCcpOwp2YXIgdXNlcjMyID0gR00uQ3JlYXRlTmF0aXZlUHJveHkoJ3VzZXIzMi5kbGwnKTsKdXNlcjMyLkNyZWF0ZU1ldGhvZCgnU3lzdGVtUGFyYW1ldGVyc0luZm9BJyk7CgppZiAocHJvY2Vzcy5hcmd2Lmxlbmd0aCA9PSAzKQp7CiAgICB2YXIgdiA9IEdNLkNyZWF0ZVZhcmlhYmxlKDEwMjQpOwogICAgdXNlcjMyLlN5c3RlbVBhcmFtZXRlcnNJbmZvQShTUElfR0VUREVTS1dBTExQQVBFUiwgdi5fc2l6ZSwgdiwgMCk7CiAgICBjb25zb2xlLmxvZyh2LlN0cmluZyk7CiAgICBwcm9jZXNzLmV4aXQoKTsKfQplbHNlCnsKICAgIHZhciBuYiA9IEdNLkNyZWF0ZVZhcmlhYmxlKHByb2Nlc3MuYXJndlszXSk7CiAgICB1c2VyMzIuU3lzdGVtUGFyYW1ldGVyc0luZm9BKFNQSV9TRVRERVNLV0FMTFBBUEVSLCBuYi5fc2l6ZSwgbmIsIDApOwogICAgcHJvY2Vzcy5leGl0KCk7Cn0='], { type: id });
|
||||||
|
child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); });
|
||||||
|
child.stderr.on('data', function () { });
|
||||||
|
child.waitExit();
|
||||||
|
var current = child.stdout.str.trim();
|
||||||
|
if (args['_'][0].toUpperCase() == 'GET')
|
||||||
|
{
|
||||||
|
response = current;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (current != '')
|
||||||
|
{
|
||||||
|
require('MeshAgent')._wallpaper = current;
|
||||||
|
response = 'Wallpaper cleared';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
response = 'Wallpaper restored';
|
||||||
|
}
|
||||||
|
child = require('child_process').execFile(process.execPath, [process.execPath.split('\\').pop(), '-b64exec', 'dmFyIFNQSV9HRVRERVNLV0FMTFBBUEVSID0gMHgwMDczOwp2YXIgU1BJX1NFVERFU0tXQUxMUEFQRVIgPSAweDAwMTQ7CnZhciBHTSA9IHJlcXVpcmUoJ19HZW5lcmljTWFyc2hhbCcpOwp2YXIgdXNlcjMyID0gR00uQ3JlYXRlTmF0aXZlUHJveHkoJ3VzZXIzMi5kbGwnKTsKdXNlcjMyLkNyZWF0ZU1ldGhvZCgnU3lzdGVtUGFyYW1ldGVyc0luZm9BJyk7CgppZiAocHJvY2Vzcy5hcmd2Lmxlbmd0aCA9PSAzKQp7CiAgICB2YXIgdiA9IEdNLkNyZWF0ZVZhcmlhYmxlKDEwMjQpOwogICAgdXNlcjMyLlN5c3RlbVBhcmFtZXRlcnNJbmZvQShTUElfR0VUREVTS1dBTExQQVBFUiwgdi5fc2l6ZSwgdiwgMCk7CiAgICBjb25zb2xlLmxvZyh2LlN0cmluZyk7CiAgICBwcm9jZXNzLmV4aXQoKTsKfQplbHNlCnsKICAgIHZhciBuYiA9IEdNLkNyZWF0ZVZhcmlhYmxlKHByb2Nlc3MuYXJndlszXSk7CiAgICB1c2VyMzIuU3lzdGVtUGFyYW1ldGVyc0luZm9BKFNQSV9TRVRERVNLV0FMTFBBUEVSLCBuYi5fc2l6ZSwgbmIsIDApOwogICAgcHJvY2Vzcy5leGl0KCk7Cn0=', current != '' ? '""' : require('MeshAgent')._wallpaper], { type: id });
|
||||||
|
child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); });
|
||||||
|
child.stderr.on('data', function () { });
|
||||||
|
child.waitExit();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var id = require('user-sessions').consoleUid();
|
||||||
|
var current = require('linux-gnome-helpers').getDesktopWallpaper(id);
|
||||||
|
if (args['_'][0].toUpperCase() == 'GET')
|
||||||
|
{
|
||||||
|
response = current;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (current != '/dev/null')
|
||||||
|
{
|
||||||
|
require('MeshAgent')._wallpaper = current;
|
||||||
|
response = 'Wallpaper cleared';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
response = 'Wallpaper restored';
|
||||||
|
}
|
||||||
|
require('linux-gnome-helpers').setDesktopWallpaper(id, current != '/dev/null' ? undefined : require('MeshAgent')._wallpaper);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
case 'safemode':
|
case 'safemode':
|
||||||
if (process.platform != 'win32')
|
if (process.platform != 'win32')
|
||||||
{
|
{
|
||||||
|
@ -313,7 +313,7 @@ module.exports.CertificateOperations = function (parent) {
|
|||||||
cert.setIssuer(attrs);
|
cert.setIssuer(attrs);
|
||||||
// Create a root certificate
|
// Create a root certificate
|
||||||
//cert.setExtensions([{ name: "basicConstraints", cA: true }, { name: "nsCertType", sslCA: true, emailCA: true, objCA: true }, { name: "subjectKeyIdentifier" }]);
|
//cert.setExtensions([{ name: "basicConstraints", cA: true }, { name: "nsCertType", sslCA: true, emailCA: true, objCA: true }, { name: "subjectKeyIdentifier" }]);
|
||||||
cert.setExtensions([{ name: "basicConstraints", cA: true }, { name: "subjectKeyIdentifier" }]);
|
cert.setExtensions([{ name: "basicConstraints", cA: true }, { name: "subjectKeyIdentifier" }, { name: "keyUsage", keyCertSign: true }]);
|
||||||
cert.sign(keys.privateKey, obj.forge.md.sha384.create());
|
cert.sign(keys.privateKey, obj.forge.md.sha384.create());
|
||||||
|
|
||||||
return { cert: cert, key: keys.privateKey };
|
return { cert: cert, key: keys.privateKey };
|
||||||
@ -418,6 +418,21 @@ module.exports.CertificateOperations = function (parent) {
|
|||||||
var rootPrivateKey = obj.fileLoad("root-cert-private.key", "utf8");
|
var rootPrivateKey = obj.fileLoad("root-cert-private.key", "utf8");
|
||||||
r.root = { cert: rootCertificate, key: rootPrivateKey };
|
r.root = { cert: rootCertificate, key: rootPrivateKey };
|
||||||
rcount++;
|
rcount++;
|
||||||
|
|
||||||
|
// Check if the root certificate has the "Certificate Signing (04)" Key usage.
|
||||||
|
// This option is required for newer versions of Intel AMT for CIRA/WS-EVENTS.
|
||||||
|
var xroot = obj.pki.certificateFromPem(rootCertificate);
|
||||||
|
var xext = xroot.getExtension("keyUsage");
|
||||||
|
if ((xext == null) || (xext.keyCertSign !== true)) {
|
||||||
|
// We need to fix this certificate
|
||||||
|
console.log('Fixing root certificate to add signing key usage...');
|
||||||
|
obj.fs.writeFileSync(parent.getConfigFilePath("root-cert-public-backup.crt"), rootCertificate);
|
||||||
|
xroot.setExtensions([{ name: "basicConstraints", cA: true }, { name: "subjectKeyIdentifier" }, { name: "keyUsage", keyCertSign: true }]);
|
||||||
|
var xrootPrivateKey = obj.pki.privateKeyFromPem(rootPrivateKey);
|
||||||
|
xroot.sign(xrootPrivateKey, obj.forge.md.sha384.create());
|
||||||
|
r.root.cert = obj.pki.certificateToPem(xroot);
|
||||||
|
try { obj.fs.writeFileSync(parent.getConfigFilePath("root-cert-public.crt"), r.root.cert); } catch (ex) { }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (args.tlsoffload) {
|
if (args.tlsoffload) {
|
||||||
|
16
db.js
16
db.js
@ -687,7 +687,13 @@ module.exports.CreateDB = function (parent, func) {
|
|||||||
// TODO: Starting in MongoDB 4.0.3, you should use countDocuments() instead of count() that is deprecated. We should detect MongoDB version and switch.
|
// TODO: Starting in MongoDB 4.0.3, you should use countDocuments() instead of count() that is deprecated. We should detect MongoDB version and switch.
|
||||||
// https://docs.mongodb.com/manual/reference/method/db.collection.countDocuments/
|
// https://docs.mongodb.com/manual/reference/method/db.collection.countDocuments/
|
||||||
//obj.isMaxType = function (max, type, domainid, func) { if (max == null) { func(false); } else { obj.file.countDocuments({ type: type, domain: domainid }, function (err, count) { func((err != null) || (count > max)); }); } }
|
//obj.isMaxType = function (max, type, domainid, func) { if (max == null) { func(false); } else { obj.file.countDocuments({ type: type, domain: domainid }, function (err, count) { func((err != null) || (count > max)); }); } }
|
||||||
obj.isMaxType = function (max, type, domainid, func) { if (max == null) { func(false); } else { obj.file.count({ type: type, domain: domainid }, function (err, count) { func((err != null) || (count > max), count); }); } }
|
obj.isMaxType = function (max, type, domainid, func) {
|
||||||
|
if (obj.eventsfile.countDocuments) {
|
||||||
|
if (max == null) { func(false); } else { obj.file.countDocuments({ type: type, domain: domainid }, function (err, count) { func((err != null) || (count > max), count); }); }
|
||||||
|
} else {
|
||||||
|
if (max == null) { func(false); } else { obj.file.count({ type: type, domain: domainid }, function (err, count) { func((err != null) || (count > max), count); }); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Database actions on the events collection
|
// Database actions on the events collection
|
||||||
obj.GetAllEvents = function (func) { obj.eventsfile.find({}).toArray(func); };
|
obj.GetAllEvents = function (func) { obj.eventsfile.find({}).toArray(func); };
|
||||||
@ -703,6 +709,13 @@ module.exports.CreateDB = function (parent, func) {
|
|||||||
obj.GetNodeEventsSelfWithLimit = function (nodeid, domain, userid, limit, func) { obj.eventsfile.find({ domain: domain, nodeid: nodeid, userid: { $in: [userid, null] } }).project({ type: 0, etype: 0, _id: 0, domain: 0, ids: 0, node: 0, nodeid: 0 }).sort({ time: -1 }).limit(limit).toArray(func); };
|
obj.GetNodeEventsSelfWithLimit = function (nodeid, domain, userid, limit, func) { obj.eventsfile.find({ domain: domain, nodeid: nodeid, userid: { $in: [userid, null] } }).project({ type: 0, etype: 0, _id: 0, domain: 0, ids: 0, node: 0, nodeid: 0 }).sort({ time: -1 }).limit(limit).toArray(func); };
|
||||||
obj.RemoveAllEvents = function (domain) { obj.eventsfile.deleteMany({ domain: domain }, { multi: true }); };
|
obj.RemoveAllEvents = function (domain) { obj.eventsfile.deleteMany({ domain: domain }, { multi: true }); };
|
||||||
obj.RemoveAllNodeEvents = function (domain, nodeid) { obj.eventsfile.deleteMany({ domain: domain, nodeid: nodeid }, { multi: true }); };
|
obj.RemoveAllNodeEvents = function (domain, nodeid) { obj.eventsfile.deleteMany({ domain: domain, nodeid: nodeid }, { multi: true }); };
|
||||||
|
obj.GetFailedLoginCount = function (username, domainid, lastlogin, func) {
|
||||||
|
if (obj.eventsfile.countDocuments) {
|
||||||
|
obj.eventsfile.countDocuments({ action: 'authfail', username: username, domain: domainid, time: { "$gte": lastlogin } }, function (err, count) { func((err == null) ? count : 0); });
|
||||||
|
} else {
|
||||||
|
obj.eventsfile.count({ action: 'authfail', username: username, domain: domainid, time: { "$gte": lastlogin } }, function (err, count) { func((err == null) ? count : 0); });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Database actions on the power collection
|
// Database actions on the power collection
|
||||||
obj.getAllPower = function (func) { obj.powerfile.find({}).toArray(func); };
|
obj.getAllPower = function (func) { obj.powerfile.find({}).toArray(func); };
|
||||||
@ -852,6 +865,7 @@ module.exports.CreateDB = function (parent, func) {
|
|||||||
obj.GetNodeEventsSelfWithLimit = function (nodeid, domain, userid, limit, func) { if (obj.databaseType == 1) { obj.eventsfile.find({ domain: domain, nodeid: nodeid, userid: { $in: [userid, null] } }, { type: 0, etype: 0, _id: 0, domain: 0, ids: 0, node: 0, nodeid: 0 }).sort({ time: -1 }).limit(limit).exec(func); } else { obj.eventsfile.find({ domain: domain, nodeid: nodeid }, { type: 0, etype: 0, _id: 0, domain: 0, ids: 0, node: 0, nodeid: 0 }).sort({ time: -1 }).limit(limit, func); } };
|
obj.GetNodeEventsSelfWithLimit = function (nodeid, domain, userid, limit, func) { if (obj.databaseType == 1) { obj.eventsfile.find({ domain: domain, nodeid: nodeid, userid: { $in: [userid, null] } }, { type: 0, etype: 0, _id: 0, domain: 0, ids: 0, node: 0, nodeid: 0 }).sort({ time: -1 }).limit(limit).exec(func); } else { obj.eventsfile.find({ domain: domain, nodeid: nodeid }, { type: 0, etype: 0, _id: 0, domain: 0, ids: 0, node: 0, nodeid: 0 }).sort({ time: -1 }).limit(limit, func); } };
|
||||||
obj.RemoveAllEvents = function (domain) { obj.eventsfile.remove({ domain: domain }, { multi: true }); };
|
obj.RemoveAllEvents = function (domain) { obj.eventsfile.remove({ domain: domain }, { multi: true }); };
|
||||||
obj.RemoveAllNodeEvents = function (domain, nodeid) { obj.eventsfile.remove({ domain: domain, nodeid: nodeid }, { multi: true }); };
|
obj.RemoveAllNodeEvents = function (domain, nodeid) { obj.eventsfile.remove({ domain: domain, nodeid: nodeid }, { multi: true }); };
|
||||||
|
obj.GetFailedLoginCount = function (username, domainid, lastlogin, func) { obj.eventsfile.count({ action: 'authfail', username: username, domain: domainid, time: { "$gte": lastlogin } }, function (err, count) { func((err == null) ? count : 0); }); }
|
||||||
|
|
||||||
// Database actions on the power collection
|
// Database actions on the power collection
|
||||||
obj.getAllPower = function (func) { obj.powerfile.find({}, func); };
|
obj.getAllPower = function (func) { obj.powerfile.find({}, func); };
|
||||||
|
288
letsEncrypt.js
288
letsEncrypt.js
@ -12,62 +12,128 @@
|
|||||||
/*jshint node: true */
|
/*jshint node: true */
|
||||||
/*jshint strict: false */
|
/*jshint strict: false */
|
||||||
/*jshint esversion: 6 */
|
/*jshint esversion: 6 */
|
||||||
"use strict";
|
'use strict';
|
||||||
|
|
||||||
module.exports.CreateLetsEncrypt = function (parent) {
|
module.exports.CreateLetsEncrypt = function (parent) {
|
||||||
try {
|
try {
|
||||||
|
// Get the GreenLock version
|
||||||
|
var greenLockVersion = null;
|
||||||
|
try { greenLockVersion = require('greenlock/package.json').version; } catch (ex) { }
|
||||||
|
if (greenLockVersion == null) {
|
||||||
|
parent.debug('cert', "Initializing Let's Encrypt support");
|
||||||
|
} else {
|
||||||
|
parent.debug('cert', "Initializing Let's Encrypt support, using GreenLock v" + greenLockVersion);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check the current node version and support for generateKeyPair
|
||||||
|
if (require('crypto').generateKeyPair == null) { return null; }
|
||||||
|
if (Number(process.version.match(/^v(\d+\.\d+)/)[1]) < 10) { return null; }
|
||||||
|
|
||||||
// Try to delete the "./ursa-optional" or "./node_modules/ursa-optional" folder if present.
|
// Try to delete the "./ursa-optional" or "./node_modules/ursa-optional" folder if present.
|
||||||
// This is an optional module that GreenLock uses that causes issues.
|
// This is an optional module that GreenLock uses that causes issues.
|
||||||
try {
|
try {
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
if (fs.existsSync(obj.path.join(__dirname, 'ursa-optional'))) { fs.unlinkSync(obj.path.join(__dirname, 'ursa-optional')); }
|
if (fs.existsSync(parent.path.join(__dirname, 'ursa-optional'))) { fs.unlinkSync(obj.path.join(__dirname, 'ursa-optional')); }
|
||||||
if (fs.existsSync(obj.path.join(__dirname, 'node_modules', 'ursa-optional'))) { fs.unlinkSync(obj.path.join(__dirname, 'node_modules', 'ursa-optional')); }
|
if (fs.existsSync(parent.path.join(__dirname, 'node_modules', 'ursa-optional'))) { fs.unlinkSync(obj.path.join(__dirname, 'node_modules', 'ursa-optional')); }
|
||||||
} catch (ex) { }
|
} catch (ex) { }
|
||||||
|
|
||||||
// Get GreenLock setup and running.
|
// Get GreenLock setup and running.
|
||||||
const greenlock = require('greenlock');
|
const greenlock = require('greenlock');
|
||||||
var obj = {};
|
var obj = {};
|
||||||
obj.parent = parent;
|
obj.parent = parent;
|
||||||
|
obj.path = require('path');
|
||||||
obj.redirWebServerHooked = false;
|
obj.redirWebServerHooked = false;
|
||||||
obj.leDomains = null;
|
obj.leDomains = null;
|
||||||
obj.leResults = null;
|
obj.leResults = null;
|
||||||
|
obj.leResultsStaging = null;
|
||||||
|
obj.performRestart = false; // Indicates we need to restart the server
|
||||||
|
obj.performMoveToProduction = false; // Indicates we just got a staging certificate and need to move to production
|
||||||
|
obj.runAsProduction = false; // This starts at false and moves to true if staging cert is ok.
|
||||||
|
|
||||||
// Setup the certificate storage paths
|
// Setup the certificate storage paths
|
||||||
obj.configPath = obj.parent.path.join(obj.parent.datapath, 'letsencrypt');
|
obj.configPath = obj.path.join(obj.parent.datapath, 'letsencrypt3');
|
||||||
obj.webrootPath = obj.parent.path.join(obj.parent.datapath, 'letsencrypt', 'webroot');
|
|
||||||
try { obj.parent.fs.mkdirSync(obj.configPath); } catch (e) { }
|
try { obj.parent.fs.mkdirSync(obj.configPath); } catch (e) { }
|
||||||
try { obj.parent.fs.mkdirSync(obj.webrootPath); } catch (e) { }
|
obj.configPathStaging = obj.path.join(obj.parent.datapath, 'letsencrypt3-staging');
|
||||||
|
try { obj.parent.fs.mkdirSync(obj.configPathStaging); } catch (e) { }
|
||||||
|
|
||||||
// Storage Backend, store data in the "meshcentral-data/letencrypt" folder.
|
// Setup Let's Encrypt default configuration
|
||||||
var leStore = require('le-store-certbot').create({ configDir: obj.configPath, webrootPath: obj.webrootPath, debug: obj.parent.args.debug > 0 });
|
obj.leDefaults = { agreeToTerms: true, store: { module: 'greenlock-store-fs', basePath: obj.configPath } };
|
||||||
|
obj.leDefaultsStaging = { agreeToTerms: true, store: { module: 'greenlock-store-fs', basePath: obj.configPathStaging } };
|
||||||
|
|
||||||
// ACME Challenge Handlers
|
// Get package and maintainer email
|
||||||
var leHttpChallenge = require('le-challenge-fs').create({ webrootPath: obj.webrootPath, debug: obj.parent.args.debug > 0 });
|
const pkg = require('./package.json');
|
||||||
|
var maintainerEmail = null;
|
||||||
|
if (typeof pkg.author == 'string') {
|
||||||
|
// Older NodeJS
|
||||||
|
maintainerEmail = pkg.author;
|
||||||
|
var i = maintainerEmail.indexOf('<');
|
||||||
|
if (i >= 0) { maintainerEmail = maintainerEmail.substring(i + 1); }
|
||||||
|
var i = maintainerEmail.indexOf('>');
|
||||||
|
if (i >= 0) { maintainerEmail = maintainerEmail.substring(0, i); }
|
||||||
|
} else if (typeof pkg.author == 'object') {
|
||||||
|
// Latest NodeJS
|
||||||
|
maintainerEmail = pkg.author.email;
|
||||||
|
}
|
||||||
|
|
||||||
// Function to agree to terms of service
|
// Check if we need to be in debug mode
|
||||||
function leAgree(opts, agreeCb) { agreeCb(null, opts.tosUrl); }
|
var ledebug = false;
|
||||||
|
try { ledebug = ((obj.parent.args.debug != null) || (obj.parent.args.debug.indexOf('cert'))); } catch (ex) { }
|
||||||
|
|
||||||
// Create the main GreenLock code module.
|
// Create the main GreenLock code module for production.
|
||||||
var greenlockargs = {
|
var greenlockargs = {
|
||||||
version: 'draft-12',
|
parent: obj,
|
||||||
server: (obj.parent.config.letsencrypt.production === true) ? 'https://acme-v02.api.letsencrypt.org/directory' : 'https://acme-staging-v02.api.letsencrypt.org/directory',
|
packageRoot: __dirname,
|
||||||
store: leStore,
|
packageAgent: pkg.name + '/' + pkg.version,
|
||||||
challenges: { 'http-01': leHttpChallenge },
|
manager: obj.path.join(__dirname, 'letsencrypt.js'),
|
||||||
challengeType: 'http-01',
|
maintainerEmail: maintainerEmail,
|
||||||
agreeToTerms: leAgree,
|
notify: function (ev, args) { if (typeof args == 'string') { parent.debug('cert', ev + ': ' + args); } else { parent.debug('cert', ev + ': ' + JSON.stringify(args)); } },
|
||||||
debug: obj.parent.args.debug > 0
|
staging: false,
|
||||||
|
debug: ledebug
|
||||||
};
|
};
|
||||||
if (obj.parent.args.debug == null) { greenlockargs.log = function (debug) { }; } // If not in debug mode, ignore all console output from greenlock (makes things clean).
|
if (obj.parent.args.debug == null) { greenlockargs.log = function (debug) { }; } // If not in debug mode, ignore all console output from greenlock (makes things clean).
|
||||||
obj.le = greenlock.create(greenlockargs);
|
obj.le = greenlock.create(greenlockargs);
|
||||||
|
|
||||||
|
// Create the main GreenLock code module for staging.
|
||||||
|
var greenlockargsstaging = {
|
||||||
|
parent: obj,
|
||||||
|
packageRoot: __dirname,
|
||||||
|
packageAgent: pkg.name + '/' + pkg.version,
|
||||||
|
manager: obj.path.join(__dirname, 'letsencrypt.js'),
|
||||||
|
maintainerEmail: maintainerEmail,
|
||||||
|
notify: function (ev, args) { if (typeof args == 'string') { parent.debug('cert', 'Notify: ' + ev + ': ' + args); } else { parent.debug('cert', 'Notify: ' + ev + ': ' + JSON.stringify(args)); } },
|
||||||
|
staging: true,
|
||||||
|
debug: ledebug
|
||||||
|
};
|
||||||
|
if (obj.parent.args.debug == null) { greenlockargsstaging.log = function (debug) { }; } // If not in debug mode, ignore all console output from greenlock (makes things clean).
|
||||||
|
obj.leStaging = greenlock.create(greenlockargsstaging);
|
||||||
|
|
||||||
// Hook up GreenLock to the redirection server
|
// Hook up GreenLock to the redirection server
|
||||||
if (obj.parent.redirserver.port == 80) { obj.parent.redirserver.app.use('/', obj.le.middleware()); obj.redirWebServerHooked = true; }
|
if (obj.parent.config.settings.rediraliasport === 80) { obj.redirWebServerHooked = true; }
|
||||||
|
else if ((obj.parent.config.settings.rediraliasport == null) && (obj.parent.redirserver.port == 80)) { obj.redirWebServerHooked = true; }
|
||||||
|
|
||||||
|
// Respond to a challenge
|
||||||
|
obj.challenge = function (token, hostname, func) {
|
||||||
|
if (obj.runAsProduction === true) {
|
||||||
|
// Production
|
||||||
|
parent.debug('cert', "Challenge " + hostname + "/" + token);
|
||||||
|
obj.le.challenges.get({ type: 'http-01', servername: hostname, token: token })
|
||||||
|
.then(function (results) { func(results.keyAuthorization); })
|
||||||
|
.catch(function (e) { console.log('LE-ERROR', e); func(null); }); // unexpected error, not related to renewal
|
||||||
|
} else {
|
||||||
|
// Staging
|
||||||
|
parent.debug('cert', "Challenge " + hostname + "/" + token);
|
||||||
|
obj.leStaging.challenges.get({ type: 'http-01', servername: hostname, token: token })
|
||||||
|
.then(function (results) { func(results.keyAuthorization); })
|
||||||
|
.catch(function (e) { console.log('LE-ERROR', e); func(null); }); // unexpected error, not related to renewal
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
obj.getCertificate = function(certs, func) {
|
obj.getCertificate = function(certs, func) {
|
||||||
|
parent.debug('cert', "Getting certs from local store");
|
||||||
if (certs.CommonName.indexOf('.') == -1) { console.log("ERROR: Use --cert to setup the default server name before using Let's Encrypt."); func(certs); return; }
|
if (certs.CommonName.indexOf('.') == -1) { console.log("ERROR: Use --cert to setup the default server name before using Let's Encrypt."); func(certs); return; }
|
||||||
if (obj.parent.config.letsencrypt == null) { func(certs); return; }
|
if (obj.parent.config.letsencrypt == null) { func(certs); return; }
|
||||||
if (obj.parent.config.letsencrypt.email == null) { console.log("ERROR: Let's Encrypt email address not specified."); func(certs); return; }
|
if (obj.parent.config.letsencrypt.email == null) { console.log("ERROR: Let's Encrypt email address not specified."); func(certs); return; }
|
||||||
if ((obj.parent.redirserver == null) || (obj.parent.redirserver.port !== 80)) { console.log("ERROR: Redirection web server must be active on port 80 for Let's Encrypt to work."); func(certs); return; }
|
if ((obj.parent.redirserver == null) || ((typeof obj.parent.config.settings.rediraliasport === 'number') && (obj.parent.config.settings.rediraliasport !== 80)) || ((obj.parent.config.settings.rediraliasport == null) && (obj.parent.redirserver.port !== 80))) { console.log("ERROR: Redirection web server must be active on port 80 for Let's Encrypt to work."); func(certs); return; }
|
||||||
if (obj.redirWebServerHooked !== true) { console.log("ERROR: Redirection web server not setup for Let's Encrypt to work."); func(certs); return; }
|
if (obj.redirWebServerHooked !== true) { console.log("ERROR: Redirection web server not setup for Let's Encrypt to work."); func(certs); return; }
|
||||||
if ((obj.parent.config.letsencrypt.rsakeysize != null) && (obj.parent.config.letsencrypt.rsakeysize !== 2048) && (obj.parent.config.letsencrypt.rsakeysize !== 3072)) { console.log("ERROR: Invalid Let's Encrypt certificate key size, must be 2048 or 3072."); func(certs); return; }
|
if ((obj.parent.config.letsencrypt.rsakeysize != null) && (obj.parent.config.letsencrypt.rsakeysize !== 2048) && (obj.parent.config.letsencrypt.rsakeysize !== 3072)) { console.log("ERROR: Invalid Let's Encrypt certificate key size, must be 2048 or 3072."); func(certs); return; }
|
||||||
|
|
||||||
@ -78,70 +144,160 @@ module.exports.CreateLetsEncrypt = function (parent) {
|
|||||||
obj.parent.config.letsencrypt.names.map(function (s) { return s.trim(); }); // Trim each name
|
obj.parent.config.letsencrypt.names.map(function (s) { return s.trim(); }); // Trim each name
|
||||||
if ((typeof obj.parent.config.letsencrypt.names != 'object') || (obj.parent.config.letsencrypt.names.length == null)) { console.log("ERROR: Let's Encrypt names must be an array in config.json."); func(certs); return; }
|
if ((typeof obj.parent.config.letsencrypt.names != 'object') || (obj.parent.config.letsencrypt.names.length == null)) { console.log("ERROR: Let's Encrypt names must be an array in config.json."); func(certs); return; }
|
||||||
obj.leDomains = obj.parent.config.letsencrypt.names;
|
obj.leDomains = obj.parent.config.letsencrypt.names;
|
||||||
obj.leDomains.sort(); // Sort the array so it's always going to be in the same order.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
obj.le.check({ domains: obj.leDomains }).then(function (results) {
|
if (obj.parent.config.letsencrypt.production !== true) {
|
||||||
if (results) {
|
// We are in staging mode, just go ahead
|
||||||
obj.leResults = results;
|
obj.getCertificateEx(certs, func);
|
||||||
|
} else {
|
||||||
|
// We are really in production mode
|
||||||
|
if (obj.runAsProduction === true) {
|
||||||
|
// Staging cert check must have been done already, move to production
|
||||||
|
obj.getCertificateEx(certs, func);
|
||||||
|
} else {
|
||||||
|
// Perform staging certificate check
|
||||||
|
parent.debug('cert', "Checking staging certificate " + obj.leDomains[0] + "...");
|
||||||
|
obj.leStaging.get({ servername: obj.leDomains[0] })
|
||||||
|
.then(function (results) {
|
||||||
|
if (results != null) {
|
||||||
|
// We have a staging certificate, move to production for real
|
||||||
|
parent.debug('cert', "Staging certificate is present, moving to production...");
|
||||||
|
obj.runAsProduction = true;
|
||||||
|
obj.getCertificateEx(certs, func);
|
||||||
|
} else {
|
||||||
|
// No staging certificate
|
||||||
|
parent.debug('cert', "No staging certificate present");
|
||||||
|
func(certs);
|
||||||
|
setTimeout(obj.checkRenewCertificate, 10000); // Check the certificate in 10 seconds.
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(function (e) {
|
||||||
|
// No staging certificate
|
||||||
|
parent.debug('cert', "No staging certificate present");
|
||||||
|
func(certs);
|
||||||
|
setTimeout(obj.checkRenewCertificate, 10000); // Check the certificate in 10 seconds.
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// If we already have real certificates, use them.
|
obj.getCertificateEx = function (certs, func) {
|
||||||
if (results.altnames.indexOf(certs.CommonName) >= 0) {
|
// Get the Let's Encrypt certificate from our own storage
|
||||||
certs.web.cert = results.cert;
|
const xle = (obj.runAsProduction === true)? obj.le : obj.leStaging;
|
||||||
certs.web.key = results.privkey;
|
xle.get({ servername: obj.leDomains[0] })
|
||||||
certs.web.ca = [results.chain];
|
.then(function (results) {
|
||||||
|
// If we already have real certificates, use them
|
||||||
|
if (results) {
|
||||||
|
if (results.site.altnames.indexOf(certs.CommonName) >= 0) {
|
||||||
|
certs.web.cert = results.pems.cert;
|
||||||
|
certs.web.key = results.pems.privkey;
|
||||||
|
certs.web.ca = [results.pems.chain];
|
||||||
}
|
}
|
||||||
for (var i in obj.parent.config.domains) {
|
for (var i in obj.parent.config.domains) {
|
||||||
if ((obj.parent.config.domains[i].dns != null) && (obj.parent.certificateOperations.compareCertificateNames(results.altnames, obj.parent.config.domains[i].dns))) {
|
if ((obj.parent.config.domains[i].dns != null) && (obj.parent.certificateOperations.compareCertificateNames(results.site.altnames, obj.parent.config.domains[i].dns))) {
|
||||||
certs.dns[i].cert = results.cert;
|
certs.dns[i].cert = results.pems.cert;
|
||||||
certs.dns[i].key = results.privkey;
|
certs.dns[i].key = results.pems.privkey;
|
||||||
certs.dns[i].ca = [results.chain];
|
certs.dns[i].ca = [results.pems.chain];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
parent.debug('cert', "Got certs from local store (" + (obj.runAsProduction ? "Production" : "Staging") + ")");
|
||||||
func(certs);
|
func(certs);
|
||||||
|
|
||||||
// Check if the Let's Encrypt certificate needs to be renewed.
|
// Check if the Let's Encrypt certificate needs to be renewed.
|
||||||
setTimeout(obj.checkRenewCertificate, 60000); // Check in 1 minute.
|
setTimeout(obj.checkRenewCertificate, 60000); // Check in 1 minute.
|
||||||
setInterval(obj.checkRenewCertificate, 86400000); // Check again in 24 hours and every 24 hours.
|
setInterval(obj.checkRenewCertificate, 86400000); // Check again in 24 hours and every 24 hours.
|
||||||
return;
|
return;
|
||||||
} else {
|
})
|
||||||
// Otherwise return default certificates and try to get a real one
|
.catch(function (e) {
|
||||||
|
parent.debug('cert', "Unable to get certs from local store (" + (obj.runAsProduction ? "Production" : "Staging") + ")");
|
||||||
|
setTimeout(obj.checkRenewCertificate, 10000); // Check the certificate in 10 seconds.
|
||||||
func(certs);
|
func(certs);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
console.log("Attempting to get Let's Encrypt certificate, may take a few minutes...");
|
|
||||||
|
|
||||||
// Figure out the RSA key size
|
|
||||||
var rsaKeySize = (obj.parent.config.letsencrypt.rsakeysize === 2048) ? 2048 : 3072;
|
|
||||||
|
|
||||||
// TODO: Only register on one of the peers if multi-peers are active.
|
|
||||||
// Register Certificate manually
|
|
||||||
obj.le.register({
|
|
||||||
domains: obj.leDomains,
|
|
||||||
email: obj.parent.config.letsencrypt.email,
|
|
||||||
agreeTos: true,
|
|
||||||
rsaKeySize: rsaKeySize,
|
|
||||||
challengeType: 'http-01',
|
|
||||||
renewWithin: 45 * 24 * 60 * 60 * 1000, // Certificate renewal may begin at this time (45 days)
|
|
||||||
renewBy: 60 * 24 * 60 * 60 * 1000 // Certificate renewal should happen by this time (60 days)
|
|
||||||
}).then(function (xresults) {
|
|
||||||
obj.parent.performServerCertUpdate(); // Reset the server, TODO: Reset all peers
|
|
||||||
}, function (err) {
|
|
||||||
console.error("ERROR: Let's encrypt error: ", err);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// Check if we need to renew the certificate, call this every day.
|
// Check if we need to renew the certificate, call this every day.
|
||||||
obj.checkRenewCertificate = function () {
|
obj.checkRenewCertificate = function () {
|
||||||
if (obj.leResults == null) { return; }
|
parent.debug('cert', "Checking certificate for " + obj.leDomains[0] + " (" + (obj.runAsProduction ? "Production" : "Staging") + ")");
|
||||||
// TODO: Only renew on one of the peers if multi-peers are active.
|
|
||||||
// Check if we need to renew the certificate
|
// Setup renew options
|
||||||
obj.le.renew({ duplicate: false, domains: obj.leDomains, email: obj.parent.config.letsencrypt.email }, obj.leResults).then(function (xresults) {
|
obj.certCheckStart = Date.now();
|
||||||
obj.parent.performServerCertUpdate(); // Reset the server, TODO: Reset all peers
|
const xle = (obj.runAsProduction === true) ? obj.le : obj.leStaging;
|
||||||
}, function (err) { }); // If we can't renew, ignore.
|
var renewOptions = { servername: obj.leDomains[0], altnames: obj.leDomains };
|
||||||
};
|
try {
|
||||||
|
xle.renew(renewOptions)
|
||||||
|
.then(function (results) {
|
||||||
|
if ((results == null) || (typeof results != 'object') || (results.length == 0) || (results[0].error != null)) {
|
||||||
|
parent.debug('cert', "Unable to get a certificate (" + (obj.runAsProduction ? "Production" : "Staging") + ", " + (Date.now() - obj.certCheckStart) + "ms): " + JSON.stringify(results));
|
||||||
|
} else {
|
||||||
|
parent.debug('cert', "Checks completed (" + (obj.runAsProduction ? "Production" : "Staging") + ", " + (Date.now() - obj.certCheckStart) + "ms): " + JSON.stringify(results));
|
||||||
|
if (obj.performRestart === true) { parent.debug('cert', "Certs changed, restarting..."); obj.parent.performServerCertUpdate(); } // Reset the server, TODO: Reset all peers
|
||||||
|
else if (obj.performMoveToProduction == true) {
|
||||||
|
parent.debug('cert', "Staging certificate received, moving to production...");
|
||||||
|
obj.runAsProduction = true;
|
||||||
|
obj.performMoveToProduction = false;
|
||||||
|
obj.performRestart = true;
|
||||||
|
setTimeout(obj.checkRenewCertificate, 10000); // Check the certificate in 10 seconds.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(function (ex) {
|
||||||
|
parent.debug('cert', "checkCertificate exception: (" + JSON.stringify(ex) + ")");
|
||||||
|
console.log(ex);
|
||||||
|
});
|
||||||
|
} catch (ex) {
|
||||||
|
parent.debug('cert', "checkCertificate main exception: (" + JSON.stringify(ex) + ")");
|
||||||
|
console.log(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return obj;
|
return obj;
|
||||||
} catch (ex) { console.log(ex); } // Unable to start Let's Encrypt
|
} catch (ex) { console.log(ex); } // Unable to start Let's Encrypt
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// GreenLock v3 Manager
|
||||||
|
module.exports.create = function (options) {
|
||||||
|
var manager = { parent: options.parent };
|
||||||
|
manager.find = async function (options) {
|
||||||
|
//console.log('LE-FIND', options);
|
||||||
|
return Promise.resolve([{ subject: options.servername, altnames: options.altnames }]);
|
||||||
|
};
|
||||||
|
|
||||||
|
manager.set = function (options) {
|
||||||
|
manager.parent.parent.debug('cert', "Certificate has been set: " + JSON.stringify(options));
|
||||||
|
if (manager.parent.parent.config.letsencrypt.production == manager.parent.runAsProduction) { manager.parent.performRestart = true; }
|
||||||
|
else if ((manager.parent.parent.config.letsencrypt.production === true) && (manager.parent.runAsProduction === false)) { manager.parent.performMoveToProduction = true; }
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
manager.remove = function (options) {
|
||||||
|
manager.parent.parent.debug('cert', "Certificate has been removed: " + JSON.stringify(options));
|
||||||
|
if (manager.parent.parent.config.letsencrypt.production == manager.parent.runAsProduction) { manager.parent.performRestart = true; }
|
||||||
|
else if ((manager.parent.parent.config.letsencrypt.production === true) && (manager.parent.runAsProduction === false)) { manager.parent.performMoveToProduction = true; }
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
// set the global config
|
||||||
|
manager.defaults = async function (options) {
|
||||||
|
var r;
|
||||||
|
if (manager.parent.runAsProduction === true) {
|
||||||
|
// Production
|
||||||
|
//console.log('LE-DEFAULTS-Production', options);
|
||||||
|
if (options != null) { for (var i in options) { if (manager.parent.leDefaults[i] == null) { manager.parent.leDefaults[i] = options[i]; } } }
|
||||||
|
r = manager.parent.leDefaults;
|
||||||
|
r.subscriberEmail = manager.parent.parent.config.letsencrypt.email;
|
||||||
|
r.sites = { mainsite: { subject: manager.parent.leDomains[0], altnames: manager.parent.leDomains } };
|
||||||
|
} else {
|
||||||
|
// Staging
|
||||||
|
//console.log('LE-DEFAULTS-Staging', options);
|
||||||
|
if (options != null) { for (var i in options) { if (manager.parent.leDefaultsStaging[i] == null) { manager.parent.leDefaultsStaging[i] = options[i]; } } }
|
||||||
|
r = manager.parent.leDefaultsStaging;
|
||||||
|
r.subscriberEmail = manager.parent.parent.config.letsencrypt.email;
|
||||||
|
r.sites = { mainsite: { subject: manager.parent.leDomains[0], altnames: manager.parent.leDomains } };
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
};
|
||||||
|
|
||||||
|
return manager;
|
||||||
|
};
|
@ -117,7 +117,7 @@ function CreateMeshCentralServer(config, args) {
|
|||||||
try { require('./pass').hash('test', function () { }, 0); } catch (e) { console.log('Old version of node, must upgrade.'); return; } // TODO: Not sure if this test works or not.
|
try { require('./pass').hash('test', function () { }, 0); } catch (e) { console.log('Old version of node, must upgrade.'); return; } // TODO: Not sure if this test works or not.
|
||||||
|
|
||||||
// Check for invalid arguments
|
// Check for invalid arguments
|
||||||
var validArguments = ['_', 'notls', 'user', 'port', 'aliasport', 'mpsport', 'mpsaliasport', 'redirport', 'cert', 'mpscert', 'deletedomain', 'deletedefaultdomain', 'showall', 'showusers', 'shownodes', 'showmeshes', 'showevents', 'showpower', 'clearpower', 'showiplocations', 'help', 'exactports', 'install', 'uninstall', 'start', 'stop', 'restart', 'debug', 'filespath', 'datapath', 'noagentupdate', 'launch', 'noserverbackup', 'mongodb', 'mongodbcol', 'wanonly', 'lanonly', 'nousers', 'mpspass', 'ciralocalfqdn', 'dbexport', 'dbexportmin', 'dbimport', 'dbmerge', 'dbencryptkey', 'selfupdate', 'tlsoffload', 'userallowedip', 'userblockedip', 'swarmallowedip', 'agentallowedip', 'agentblockedip', 'fastcert', 'swarmport', 'logintoken', 'logintokenkey', 'logintokengen', 'logintokengen', 'mailtokengen', 'admin', 'unadmin', 'sessionkey', 'sessiontime', 'minify', 'minifycore', 'dblistconfigfiles', 'dbshowconfigfile', 'dbpushconfigfiles', 'dbpullconfigfiles', 'dbdeleteconfigfiles', 'vaultpushconfigfiles', 'vaultpullconfigfiles', 'vaultdeleteconfigfiles', 'configkey', 'loadconfigfromdb', 'npmpath', 'memorytracking', 'serverid', 'recordencryptionrecode', 'vault', 'token', 'unsealkey', 'name'];
|
var validArguments = ['_', 'notls', 'user', 'port', 'aliasport', 'mpsport', 'mpsaliasport', 'redirport', 'rediraliasport', 'cert', 'mpscert', 'deletedomain', 'deletedefaultdomain', 'showall', 'showusers', 'shownodes', 'showmeshes', 'showevents', 'showpower', 'clearpower', 'showiplocations', 'help', 'exactports', 'xinstall', 'xuninstall', 'install', 'uninstall', 'start', 'stop', 'restart', 'debug', 'filespath', 'datapath', 'noagentupdate', 'launch', 'noserverbackup', 'mongodb', 'mongodbcol', 'wanonly', 'lanonly', 'nousers', 'mpspass', 'ciralocalfqdn', 'dbexport', 'dbexportmin', 'dbimport', 'dbmerge', 'dbencryptkey', 'selfupdate', 'tlsoffload', 'userallowedip', 'userblockedip', 'swarmallowedip', 'agentallowedip', 'agentblockedip', 'fastcert', 'swarmport', 'logintoken', 'logintokenkey', 'logintokengen', 'logintokengen', 'mailtokengen', 'admin', 'unadmin', 'sessionkey', 'sessiontime', 'minify', 'minifycore', 'dblistconfigfiles', 'dbshowconfigfile', 'dbpushconfigfiles', 'dbpullconfigfiles', 'dbdeleteconfigfiles', 'vaultpushconfigfiles', 'vaultpullconfigfiles', 'vaultdeleteconfigfiles', 'configkey', 'loadconfigfromdb', 'npmpath', 'memorytracking', 'serverid', 'recordencryptionrecode', 'vault', 'token', 'unsealkey', 'name', 'log'];
|
||||||
for (var arg in obj.args) { obj.args[arg.toLocaleLowerCase()] = obj.args[arg]; if (validArguments.indexOf(arg.toLocaleLowerCase()) == -1) { console.log('Invalid argument "' + arg + '", use --help.'); return; } }
|
for (var arg in obj.args) { obj.args[arg.toLocaleLowerCase()] = obj.args[arg]; if (validArguments.indexOf(arg.toLocaleLowerCase()) == -1) { console.log('Invalid argument "' + arg + '", use --help.'); return; } }
|
||||||
if (obj.args.mongodb == true) { console.log('Must specify: --mongodb [connectionstring] \r\nSee https://docs.mongodb.com/manual/reference/connection-string/ for MongoDB connection string.'); return; }
|
if (obj.args.mongodb == true) { console.log('Must specify: --mongodb [connectionstring] \r\nSee https://docs.mongodb.com/manual/reference/connection-string/ for MongoDB connection string.'); return; }
|
||||||
for (i in obj.config.settings) { obj.args[i] = obj.config.settings[i]; } // Place all settings into arguments, arguments have already been placed into settings so arguments take precedence.
|
for (i in obj.config.settings) { obj.args[i] = obj.config.settings[i]; } // Place all settings into arguments, arguments have already been placed into settings so arguments take precedence.
|
||||||
@ -144,9 +144,10 @@ function CreateMeshCentralServer(config, args) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (obj.service != null) {
|
||||||
// Check if we need to install, start, stop, remove ourself as a background service
|
// Check if we need to install, start, stop, remove ourself as a background service
|
||||||
if ((obj.service != null) && ((obj.args.install == true) || (obj.args.uninstall == true) || (obj.args.start == true) || (obj.args.stop == true) || (obj.args.restart == true))) {
|
if (((obj.args.xinstall == true) || (obj.args.xuninstall == true) || (obj.args.start == true) || (obj.args.stop == true) || (obj.args.restart == true))) {
|
||||||
var env = [], xenv = ['user', 'port', 'aliasport', 'mpsport', 'mpsaliasport', 'redirport', 'exactport', 'debug'];
|
var env = [], xenv = ['user', 'port', 'aliasport', 'mpsport', 'mpsaliasport', 'redirport', 'exactport', 'rediraliasport', 'debug'];
|
||||||
for (i in xenv) { if (obj.args[xenv[i]] != null) { env.push({ name: 'mesh' + xenv[i], value: obj.args[xenv[i]] }); } } // Set some args as service environement variables.
|
for (i in xenv) { if (obj.args[xenv[i]] != null) { env.push({ name: 'mesh' + xenv[i], value: obj.args[xenv[i]] }); } } // Set some args as service environement variables.
|
||||||
var svc = new obj.service({ name: 'MeshCentral', description: 'MeshCentral Remote Management Server', script: obj.path.join(__dirname, 'winservice.js'), env: env, wait: 2, grow: 0.5 });
|
var svc = new obj.service({ name: 'MeshCentral', description: 'MeshCentral Remote Management Server', script: obj.path.join(__dirname, 'winservice.js'), env: env, wait: 2, grow: 0.5 });
|
||||||
svc.on('install', function () { console.log('MeshCentral service installed.'); svc.start(); });
|
svc.on('install', function () { console.log('MeshCentral service installed.'); svc.start(); });
|
||||||
@ -156,13 +157,42 @@ function CreateMeshCentralServer(config, args) {
|
|||||||
svc.on('alreadyinstalled', function () { console.log('MeshCentral service already installed.'); process.exit(); });
|
svc.on('alreadyinstalled', function () { console.log('MeshCentral service already installed.'); process.exit(); });
|
||||||
svc.on('invalidinstallation', function () { console.log('Invalid MeshCentral service installation.'); process.exit(); });
|
svc.on('invalidinstallation', function () { console.log('Invalid MeshCentral service installation.'); process.exit(); });
|
||||||
|
|
||||||
if (obj.args.install == true) { try { svc.install(); } catch (e) { logException(e); } }
|
if (obj.args.xinstall == true) { try { svc.install(); } catch (e) { logException(e); } }
|
||||||
if (obj.args.stop == true || obj.args.restart == true) { try { svc.stop(); } catch (e) { logException(e); } }
|
if (obj.args.stop == true || obj.args.restart == true) { try { svc.stop(); } catch (e) { logException(e); } }
|
||||||
if (obj.args.start == true || obj.args.restart == true) { try { svc.start(); } catch (e) { logException(e); } }
|
if (obj.args.start == true || obj.args.restart == true) { try { svc.start(); } catch (e) { logException(e); } }
|
||||||
if (obj.args.uninstall == true) { try { svc.uninstall(); } catch (e) { logException(e); } }
|
if (obj.args.xuninstall == true) { try { svc.uninstall(); } catch (e) { logException(e); } }
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Windows service install using the external winservice.js
|
||||||
|
if (obj.args.install == true) {
|
||||||
|
console.log('Installing MeshCentral as Windows Service...');
|
||||||
|
if (obj.fs.existsSync(obj.path.join(__dirname, '../WinService')) == false) { try { obj.fs.mkdirSync(obj.path.join(__dirname, '../WinService')); } catch (ex) { console.log('ERROR: Unable to create WinService folder: ' + ex); process.exit(); return; } }
|
||||||
|
try { obj.fs.createReadStream(obj.path.join(__dirname, 'winservice.js')).pipe(obj.fs.createWriteStream(obj.path.join(__dirname, '../WinService/winservice.js'))); } catch (ex) { console.log('ERROR: Unable to copy winservice.js: ' + ex); process.exit(); return; }
|
||||||
|
require('child_process').exec('node winservice.js --install', { maxBuffer: 512000, timeout: 120000, cwd: obj.path.join(__dirname, '../WinService') }, function (error, stdout, stderr) {
|
||||||
|
if ((error != null) && (error != '')) { console.log('ERROR: Unable to install MeshCentral as a service: ' + error); process.exit(); return; }
|
||||||
|
console.log(stdout);
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
} else if (obj.args.uninstall == true) {
|
||||||
|
console.log('Uninstalling MeshCentral Windows Service...');
|
||||||
|
if (obj.fs.existsSync(obj.path.join(__dirname, '../WinService')) == true) {
|
||||||
|
require('child_process').exec('node winservice.js --uninstall', { maxBuffer: 512000, timeout: 120000, cwd: obj.path.join(__dirname, '../WinService') }, function (error, stdout, stderr) {
|
||||||
|
if ((error != null) && (error != '')) { console.log('ERROR: Unable to uninstall MeshCentral service: ' + error); process.exit(); return; }
|
||||||
|
console.log(stdout);
|
||||||
|
try { obj.fs.unlinkSync(obj.path.join(__dirname, '../WinService/winservice.js')); } catch (ex) { }
|
||||||
|
try { obj.fs.rmdirSync(obj.path.join(__dirname, '../WinService')); } catch (ex) { }
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
require('child_process').exec('node winservice.js --uninstall', { maxBuffer: 512000, timeout: 120000, cwd: __dirname }, function (error, stdout, stderr) {
|
||||||
|
if ((error != null) && (error != '')) { console.log('ERROR: Unable to uninstall MeshCentral service: ' + error); process.exit(); return; }
|
||||||
|
console.log(stdout);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// If "--launch" is in the arguments, launch now
|
// If "--launch" is in the arguments, launch now
|
||||||
if (obj.args.launch) {
|
if (obj.args.launch) {
|
||||||
if (obj.args.vault) { obj.StartVault(); } else { obj.StartEx(); }
|
if (obj.args.vault) { obj.StartVault(); } else { obj.StartEx(); }
|
||||||
@ -677,7 +707,7 @@ function CreateMeshCentralServer(config, args) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Read environment variables. For a subset of arguments, we allow them to be read from environment variables.
|
// Read environment variables. For a subset of arguments, we allow them to be read from environment variables.
|
||||||
var xenv = ['user', 'port', 'mpsport', 'mpsaliasport', 'redirport', 'exactport', 'debug'];
|
var xenv = ['user', 'port', 'mpsport', 'mpsaliasport', 'redirport', 'rediraliasport', 'exactport', 'debug'];
|
||||||
for (i in xenv) { if ((obj.args[xenv[i]] == null) && (process.env['mesh' + xenv[i]])) { obj.args[xenv[i]] = obj.common.toNumber(process.env['mesh' + xenv[i]]); } }
|
for (i in xenv) { if ((obj.args[xenv[i]] == null) && (process.env['mesh' + xenv[i]])) { obj.args[xenv[i]] = obj.common.toNumber(process.env['mesh' + xenv[i]]); } }
|
||||||
|
|
||||||
// Validate the domains, this is used for multi-hosting
|
// Validate the domains, this is used for multi-hosting
|
||||||
@ -735,6 +765,7 @@ function CreateMeshCentralServer(config, args) {
|
|||||||
if (obj.args.aliasport != null && (typeof obj.args.aliasport != 'number')) obj.args.aliasport = null;
|
if (obj.args.aliasport != null && (typeof obj.args.aliasport != 'number')) obj.args.aliasport = null;
|
||||||
if (obj.args.mpsport == null || typeof obj.args.mpsport != 'number') obj.args.mpsport = 4433;
|
if (obj.args.mpsport == null || typeof obj.args.mpsport != 'number') obj.args.mpsport = 4433;
|
||||||
if (obj.args.mpsaliasport != null && (typeof obj.args.mpsaliasport != 'number')) obj.args.mpsaliasport = null;
|
if (obj.args.mpsaliasport != null && (typeof obj.args.mpsaliasport != 'number')) obj.args.mpsaliasport = null;
|
||||||
|
if (obj.args.rediraliasport != null && (typeof obj.args.rediraliasport != 'number')) obj.args.rediraliasport = null;
|
||||||
if (obj.args.notls == null && obj.args.redirport == null) obj.args.redirport = 80;
|
if (obj.args.notls == null && obj.args.redirport == null) obj.args.redirport = 80;
|
||||||
if (obj.args.minifycore === 0) obj.args.minifycore = false;
|
if (obj.args.minifycore === 0) obj.args.minifycore = false;
|
||||||
if (typeof args.agentidletimeout != 'number') { args.agentidletimeout = 150000; } else { args.agentidletimeout *= 1000 } // Default agent idle timeout is 2m, 30sec.
|
if (typeof args.agentidletimeout != 'number') { args.agentidletimeout = 150000; } else { args.agentidletimeout *= 1000 } // Default agent idle timeout is 2m, 30sec.
|
||||||
@ -830,7 +861,9 @@ function CreateMeshCentralServer(config, args) {
|
|||||||
// Load server certificates
|
// Load server certificates
|
||||||
obj.certificateOperations = require('./certoperations.js').CertificateOperations(obj);
|
obj.certificateOperations = require('./certoperations.js').CertificateOperations(obj);
|
||||||
obj.certificateOperations.GetMeshServerCertificate(obj.args, obj.config, function (certs) {
|
obj.certificateOperations.GetMeshServerCertificate(obj.args, obj.config, function (certs) {
|
||||||
if ((obj.config.letsencrypt == null) || (obj.redirserver == null)) {
|
// Get the current node version
|
||||||
|
const nodeVersion = Number(process.version.match(/^v(\d+\.\d+)/)[1]);
|
||||||
|
if ((nodeVersion < 8) || (require('crypto').generateKeyPair == null) || (obj.config.letsencrypt == null) || (obj.redirserver == null)) {
|
||||||
obj.StartEx3(certs); // Just use the configured certificates
|
obj.StartEx3(certs); // Just use the configured certificates
|
||||||
} else {
|
} else {
|
||||||
var le = require('./letsencrypt.js');
|
var le = require('./letsencrypt.js');
|
||||||
@ -1831,6 +1864,27 @@ function CreateMeshCentralServer(config, args) {
|
|||||||
// Send event to console
|
// Send event to console
|
||||||
if ((obj.debugSources != null) && ((obj.debugSources == '*') || (obj.debugSources.indexOf(source) >= 0))) { console.log(source.toUpperCase() + ':', ...args); }
|
if ((obj.debugSources != null) && ((obj.debugSources == '*') || (obj.debugSources.indexOf(source) >= 0))) { console.log(source.toUpperCase() + ':', ...args); }
|
||||||
|
|
||||||
|
// Send event to log file
|
||||||
|
if (obj.config.settings && obj.config.settings.log) {
|
||||||
|
if (typeof obj.args.log == 'string') { obj.args.log = obj.args.log.split(','); }
|
||||||
|
if (obj.args.log.indexOf(source) >= 0) {
|
||||||
|
const d = new Date();
|
||||||
|
if (obj.xxLogFile == null) {
|
||||||
|
try {
|
||||||
|
obj.xxLogFile = obj.fs.openSync(obj.getConfigFilePath('log.txt'), 'a+', 666);
|
||||||
|
obj.fs.writeSync(obj.xxLogFile, '---- Log start at ' + new Date().toLocaleString() + ' ----\r\n');
|
||||||
|
obj.xxLogDateStr = d.toLocaleDateString();
|
||||||
|
} catch (ex) { }
|
||||||
|
}
|
||||||
|
if (obj.xxLogFile != null) {
|
||||||
|
try {
|
||||||
|
if (obj.xxLogDateStr != d.toLocaleDateString()) { obj.xxLogDateStr = d.toLocaleDateString(); obj.fs.writeSync(obj.xxLogFile, '---- ' + d.toLocaleDateString() + ' ----\r\n'); }
|
||||||
|
obj.fs.writeSync(obj.xxLogFile, new Date().toLocaleTimeString() + ' - ' + source + ': ' + Array.prototype.slice.call(...args).join('') + '\r\n');
|
||||||
|
} catch (ex) { }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Send the event to logged in administrators
|
// Send the event to logged in administrators
|
||||||
if ((obj.debugRemoteSources != null) && ((obj.debugRemoteSources == '*') || (obj.debugRemoteSources.indexOf(source) >= 0))) {
|
if ((obj.debugRemoteSources != null) && ((obj.debugRemoteSources == '*') || (obj.debugRemoteSources.indexOf(source) >= 0))) {
|
||||||
var sendcount = 0;
|
var sendcount = 0;
|
||||||
@ -1932,8 +1986,17 @@ function InstallModules(modules, func) {
|
|||||||
var missingModules = [];
|
var missingModules = [];
|
||||||
if (modules.length > 0) {
|
if (modules.length > 0) {
|
||||||
for (var i in modules) {
|
for (var i in modules) {
|
||||||
|
// Modules may contain a version tag (foobar@1.0.0), remove it so the module can be found using require
|
||||||
|
var moduleName = modules[i].split("@", 1)[0];
|
||||||
try {
|
try {
|
||||||
var xxmodule = require(modules[i]);
|
if (moduleName == 'greenlock') {
|
||||||
|
// Check if we have GreenLock v3
|
||||||
|
delete require.cache[require.resolve('greenlock')]; // Clear the require cache
|
||||||
|
if (typeof require('greenlock').challengeType == 'string') { missingModules.push(modules[i]); }
|
||||||
|
} else {
|
||||||
|
// For all other modules, do the check here.
|
||||||
|
require(moduleName);
|
||||||
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (previouslyInstalledModules[modules[i]] !== true) { missingModules.push(modules[i]); }
|
if (previouslyInstalledModules[modules[i]] !== true) { missingModules.push(modules[i]); }
|
||||||
}
|
}
|
||||||
@ -1943,7 +2006,6 @@ function InstallModules(modules, func) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check if a module is present and install it if missing
|
// Check if a module is present and install it if missing
|
||||||
var InstallModuleChildProcess = null;
|
|
||||||
function InstallModule(modulename, func, tag1, tag2) {
|
function InstallModule(modulename, func, tag1, tag2) {
|
||||||
console.log('Installing ' + modulename + '...');
|
console.log('Installing ' + modulename + '...');
|
||||||
var child_process = require('child_process');
|
var child_process = require('child_process');
|
||||||
@ -1952,9 +2014,7 @@ function InstallModule(modulename, func, tag1, tag2) {
|
|||||||
// Get the working directory
|
// Get the working directory
|
||||||
if ((__dirname.endsWith('/node_modules/meshcentral')) || (__dirname.endsWith('\\node_modules\\meshcentral')) || (__dirname.endsWith('/node_modules/meshcentral/')) || (__dirname.endsWith('\\node_modules\\meshcentral\\'))) { parentpath = require('path').join(__dirname, '../..'); }
|
if ((__dirname.endsWith('/node_modules/meshcentral')) || (__dirname.endsWith('\\node_modules\\meshcentral')) || (__dirname.endsWith('/node_modules/meshcentral/')) || (__dirname.endsWith('\\node_modules\\meshcentral\\'))) { parentpath = require('path').join(__dirname, '../..'); }
|
||||||
|
|
||||||
// Looks like we need to keep a global reference to the child process object for this to work correctly.
|
child_process.exec(`npm install --no-optional ${modulename}`, { maxBuffer: 512000, timeout: 120000, cwd: parentpath }, function (error, stdout, stderr) {
|
||||||
InstallModuleChildProcess = child_process.exec('npm install --no-optional --save ' + modulename, { maxBuffer: 512000, timeout: 10000, cwd: parentpath }, function (error, stdout, stderr) {
|
|
||||||
InstallModuleChildProcess = null;
|
|
||||||
if ((error != null) && (error != '')) {
|
if ((error != null) && (error != '')) {
|
||||||
console.log('ERROR: Unable to install required module "' + modulename + '". MeshCentral may not have access to npm, or npm may not have suffisent rights to load the new module. Try "npm install ' + modulename + '" to manualy install this module.\r\n');
|
console.log('ERROR: Unable to install required module "' + modulename + '". MeshCentral may not have access to npm, or npm may not have suffisent rights to load the new module. Try "npm install ' + modulename + '" to manualy install this module.\r\n');
|
||||||
process.exit();
|
process.exit();
|
||||||
@ -2002,20 +2062,20 @@ function mainStart() {
|
|||||||
if (config.domains[i].auth == 'ldap') { ldap = true; }
|
if (config.domains[i].auth == 'ldap') { ldap = true; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get the current node version
|
||||||
|
var nodeVersion = Number(process.version.match(/^v(\d+\.\d+)/)[1]);
|
||||||
|
|
||||||
// Build the list of required modules
|
// Build the list of required modules
|
||||||
var modules = ['ws', 'cbor', 'nedb', 'https', 'yauzl', 'xmldom', 'ipcheck', 'express', 'archiver', 'multiparty', 'node-forge', 'express-ws', 'compression', 'body-parser', 'connect-redis', 'cookie-session', 'express-handlebars'];
|
var modules = ['ws', 'cbor', 'nedb', 'https', 'yauzl', 'xmldom', 'ipcheck', 'express', 'archiver', 'multiparty', 'node-forge', 'express-ws', 'compression', 'body-parser', 'connect-redis', 'cookie-session', 'express-handlebars'];
|
||||||
if (require('os').platform() == 'win32') { modules.push('node-windows'); if (sspi == true) { modules.push('node-sspi'); } } // Add Windows modules
|
if (require('os').platform() == 'win32') { modules.push('node-windows'); if (sspi == true) { modules.push('node-sspi'); } } // Add Windows modules
|
||||||
if (ldap == true) { modules.push('ldapauth-fork'); }
|
if (ldap == true) { modules.push('ldapauth-fork'); }
|
||||||
if (config.letsencrypt != null) { modules.push('greenlock'); modules.push('le-store-certbot'); modules.push('le-challenge-fs'); modules.push('le-acme-core'); } // Add Greenlock Modules
|
if (config.letsencrypt != null) { if ((nodeVersion < 10) || (require('crypto').generateKeyPair == null)) { if (!args.launch) { console.log("WARNING: Let's Encrypt support requires Node v10.12.0 or higher."); } } else { modules.push('greenlock'); } } // Add Greenlock Module
|
||||||
if (config.settings.mqtt != null) { modules.push('aedes'); } // Add MQTT Modules
|
if (config.settings.mqtt != null) { modules.push('aedes'); } // Add MQTT Modules
|
||||||
if (config.settings.mongodb != null) { modules.push('mongodb'); } // Add MongoDB, official driver.
|
if (config.settings.mongodb != null) { modules.push('mongodb'); } // Add MongoDB, official driver.
|
||||||
if (config.settings.vault != null) { modules.push('node-vault'); } // Add official HashiCorp's Vault module.
|
if (config.settings.vault != null) { modules.push('node-vault'); } // Add official HashiCorp's Vault module.
|
||||||
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 (config.smtp != null) { modules.push('nodemailer'); } // Add SMTP support
|
||||||
|
|
||||||
// Get the current node version
|
|
||||||
var nodeVersion = Number(process.version.match(/^v(\d+\.\d+)/)[1]);
|
|
||||||
|
|
||||||
// If running NodeJS < 8, install "util.promisify"
|
// If running NodeJS < 8, install "util.promisify"
|
||||||
if (nodeVersion < 8) { modules.push('util.promisify'); }
|
if (nodeVersion < 8) { modules.push('util.promisify'); }
|
||||||
|
|
||||||
|
33
meshuser.js
33
meshuser.js
@ -360,6 +360,14 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
|
|||||||
try { ws.send(JSON.stringify({ action: 'traceinfo', traceSources: parent.parent.debugRemoteSources })); } catch (ex) { }
|
try { ws.send(JSON.stringify({ action: 'traceinfo', traceSources: parent.parent.debugRemoteSources })); } catch (ex) { }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// See how many times bad login attempts where made since the last login
|
||||||
|
const lastLoginTime = parent.users[user._id].pastlogin;
|
||||||
|
if (lastLoginTime != null) {
|
||||||
|
db.GetFailedLoginCount(user.name, user.domain, new Date(lastLoginTime * 1000), function (count) {
|
||||||
|
if (count > 0) { try { ws.send(JSON.stringify({ action: 'msg', type: 'notify', title: "Security Warning", tag: 'ServerNotify', value: "There has been " + count + " failed login attempts on this account since the last login." })); } catch (ex) { } delete user.pastlogin; }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// We are all set, start receiving data
|
// We are all set, start receiving data
|
||||||
ws._socket.resume();
|
ws._socket.resume();
|
||||||
});
|
});
|
||||||
@ -681,14 +689,31 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
|
|||||||
case 'help': {
|
case 'help': {
|
||||||
r = 'Available commands: help, info, versions, args, resetserver, showconfig, usersessions, tasklimiter, setmaxtasks, cores,\r\n'
|
r = 'Available commands: help, info, versions, args, resetserver, showconfig, usersessions, tasklimiter, setmaxtasks, cores,\r\n'
|
||||||
r += 'migrationagents, agentstats, webstats, mpsstats, swarmstats, acceleratorsstats, updatecheck, serverupdate, nodeconfig,\r\n';
|
r += 'migrationagents, agentstats, webstats, mpsstats, swarmstats, acceleratorsstats, updatecheck, serverupdate, nodeconfig,\r\n';
|
||||||
r += 'heapdump, relays, autobackup, backupconfig, dupagents, dispatchtable.';
|
r += 'heapdump, relays, autobackup, backupconfig, dupagents, dispatchtable, badlogins.';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'badlogins': {
|
||||||
|
if (typeof parent.parent.config.settings.maxinvalidlogin.coolofftime == 'number') {
|
||||||
|
r = "Max is " + parent.parent.config.settings.maxinvalidlogin.count + " bad login(s) in " + parent.parent.config.settings.maxinvalidlogin.time + " minute(s), " + parent.parent.config.settings.maxinvalidlogin.coolofftime + " minute(s) cooloff.\r\n";
|
||||||
|
} else {
|
||||||
|
r = "Max is " + parent.parent.config.settings.maxinvalidlogin.count + " bad login(s) in " + parent.parent.config.settings.maxinvalidlogin.time + " minute(s).\r\n";
|
||||||
|
}
|
||||||
|
var badLoginCount = 0;
|
||||||
|
parent.cleanBadLoginTable();
|
||||||
|
for (var i in parent.badLoginTable) {
|
||||||
|
badLoginCount++;
|
||||||
|
if (typeof parent.badLoginTable[i] == 'number') {
|
||||||
|
r += "Cooloff for " + Math.floor((parent.badLoginTable[i] - Date.now()) / 60000) + " minute(s)\r\n";
|
||||||
|
} else {
|
||||||
|
r += (i + ' - ' + parent.badLoginTable[i].length + " entries\r\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (badLoginCount == 0) { r += 'No bad logins.'; }
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'dispatchtable': {
|
case 'dispatchtable': {
|
||||||
r = '';
|
r = '';
|
||||||
for (var i in parent.parent.eventsDispatch) {
|
for (var i in parent.parent.eventsDispatch) { r += (i + ', ' + parent.parent.eventsDispatch[i].length + '\r\n'); }
|
||||||
r += (i + ', ' + parent.parent.eventsDispatch[i].length + '\r\n');
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'dupagents': {
|
case 'dupagents': {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "meshcentral",
|
"name": "meshcentral",
|
||||||
"version": "0.4.3-s",
|
"version": "0.4.4-r",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"Remote Management",
|
"Remote Management",
|
||||||
"Intel AMT",
|
"Intel AMT",
|
||||||
@ -30,22 +30,19 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"archiver": "^3.0.0",
|
"archiver": "^3.0.0",
|
||||||
"body-parser": "^1.19.0",
|
"body-parser": "^1.19.0",
|
||||||
"cbor": "4.1.5",
|
"cbor": "^4.1.5",
|
||||||
"compression": "^1.7.4",
|
"compression": "^1.7.4",
|
||||||
"connect-redis": "^3.4.1",
|
"connect-redis": "^3.4.1",
|
||||||
"cookie-session": "^2.0.0-beta.3",
|
"cookie-session": "^2.0.0-beta.3",
|
||||||
"express": "^4.17.0",
|
"express": "^4.17.0",
|
||||||
"express-handlebars": "^3.1.0",
|
"express-handlebars": "^3.1.0",
|
||||||
"express-ws": "^4.0.0",
|
"express-ws": "^4.0.0",
|
||||||
"html-minifier": "^4.0.0",
|
|
||||||
"ipcheck": "^0.1.0",
|
"ipcheck": "^0.1.0",
|
||||||
"meshcentral": "*",
|
"meshcentral": "*",
|
||||||
"minify-js": "0.0.4",
|
|
||||||
"minimist": "^1.2.0",
|
"minimist": "^1.2.0",
|
||||||
"multiparty": "^4.2.1",
|
"multiparty": "^4.2.1",
|
||||||
"nedb": "^1.8.0",
|
"nedb": "^1.8.0",
|
||||||
"node-forge": "^0.8.4",
|
"node-forge": "^0.8.4",
|
||||||
"node-vault": "^0.9.11",
|
|
||||||
"ws": "^6.2.1",
|
"ws": "^6.2.1",
|
||||||
"xmldom": "^0.1.27",
|
"xmldom": "^0.1.27",
|
||||||
"yauzl": "^2.10.0"
|
"yauzl": "^2.10.0"
|
||||||
|
File diff suppressed because one or more lines are too long
@ -23,11 +23,12 @@ module.exports.CreateRedirServer = function (parent, db, args, func) {
|
|||||||
obj.db = db;
|
obj.db = db;
|
||||||
obj.args = args;
|
obj.args = args;
|
||||||
obj.certificates = null;
|
obj.certificates = null;
|
||||||
obj.express = require("express");
|
obj.express = require('express');
|
||||||
obj.net = require("net");
|
obj.net = require('net');
|
||||||
obj.app = obj.express();
|
obj.app = obj.express();
|
||||||
obj.tcpServer = null;
|
obj.tcpServer = null;
|
||||||
obj.port = null;
|
obj.port = null;
|
||||||
|
const leChallengePrefix = '/.well-known/acme-challenge/';
|
||||||
|
|
||||||
// Perform an HTTP to HTTPS redirection
|
// Perform an HTTP to HTTPS redirection
|
||||||
function performRedirection(req, res) {
|
function performRedirection(req, res) {
|
||||||
@ -49,14 +50,14 @@ module.exports.CreateRedirServer = function (parent, db, args, func) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// Renter the terms of service.
|
// Renter the terms of service.
|
||||||
obj.app.get("/MeshServerRootCert.cer", function (req, res) {
|
obj.app.get('/MeshServerRootCert.cer', function (req, res) {
|
||||||
// The redirection server starts before certificates are loaded, make sure to handle the case where no certificate is loaded now.
|
// The redirection server starts before certificates are loaded, make sure to handle the case where no certificate is loaded now.
|
||||||
if (obj.certificates != null) {
|
if (obj.certificates != null) {
|
||||||
res.set({ "Cache-Control": "no-cache, no-store, must-revalidate", "Pragma": "no-cache", "Expires": "0", "Content-Type": "application/octet-stream", "Content-Disposition": "attachment; filename=\"" + obj.certificates.RootName + ".cer\"" });
|
res.set({ 'Cache-Control': "no-cache, no-store, must-revalidate", "Pragma": "no-cache", "Expires": "0", "Content-Type": "application/octet-stream", "Content-Disposition": "attachment; filename=\"" + obj.certificates.RootName + ".cer\"" });
|
||||||
var rootcert = obj.certificates.root.cert;
|
var rootcert = obj.certificates.root.cert;
|
||||||
var i = rootcert.indexOf("-----BEGIN CERTIFICATE-----\r\n");
|
var i = rootcert.indexOf('-----BEGIN CERTIFICATE-----\r\n');
|
||||||
if (i >= 0) { rootcert = rootcert.substring(i + 29); }
|
if (i >= 0) { rootcert = rootcert.substring(i + 29); }
|
||||||
i = rootcert.indexOf("-----END CERTIFICATE-----");
|
i = rootcert.indexOf('-----END CERTIFICATE-----');
|
||||||
if (i >= 0) { rootcert = rootcert.substring(i, 0); }
|
if (i >= 0) { rootcert = rootcert.substring(i, 0); }
|
||||||
res.send(Buffer.from(rootcert, "base64"));
|
res.send(Buffer.from(rootcert, "base64"));
|
||||||
} else {
|
} else {
|
||||||
@ -66,9 +67,17 @@ module.exports.CreateRedirServer = function (parent, db, args, func) {
|
|||||||
|
|
||||||
// Add HTTP security headers to all responses
|
// Add HTTP security headers to all responses
|
||||||
obj.app.use(function (req, res, next) {
|
obj.app.use(function (req, res, next) {
|
||||||
res.removeHeader("X-Powered-By");
|
parent.debug('webrequest', req.url + ' (RedirServer)');
|
||||||
res.set({ "strict-transport-security": "max-age=60000; includeSubDomains", "Referrer-Policy": "no-referrer", "x-frame-options": "SAMEORIGIN", "X-XSS-Protection": "1; mode=block", "X-Content-Type-Options": "nosniff", "Content-Security-Policy": "default-src http: ws: \"self\" \"unsafe-inline\"" });
|
res.removeHeader('X-Powered-By');
|
||||||
|
|
||||||
|
if ((parent.letsencrypt != null) && (req.url.startsWith(leChallengePrefix))) {
|
||||||
|
// Let's Encrypt Support
|
||||||
|
parent.letsencrypt.challenge(req.url.slice(leChallengePrefix.length), getCleanHostname(req), function (response) { if (response == null) { res.sendStatus(404); } else { res.send(response); } });
|
||||||
|
} else {
|
||||||
|
// Everything else
|
||||||
|
res.set({ 'strict-transport-security': "max-age=60000; includeSubDomains", "Referrer-Policy": "no-referrer", "x-frame-options": "SAMEORIGIN", "X-XSS-Protection": "1; mode=block", "X-Content-Type-Options": "nosniff", "Content-Security-Policy": "default-src http: ws: \"self\" \"unsafe-inline\"" });
|
||||||
return next();
|
return next();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Once the main web server is started, call this to hookup additional handlers
|
// Once the main web server is started, call this to hookup additional handlers
|
||||||
@ -125,6 +134,17 @@ module.exports.CreateRedirServer = function (parent, db, args, func) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get the remote hostname correctly
|
||||||
|
const servernameRe = /^[a-z0-9\.\-]+$/i;
|
||||||
|
function getHostname(req) { return req.hostname || req.headers['x-forwarded-host'] || (req.headers.host || ''); };
|
||||||
|
function getCleanHostname(req) {
|
||||||
|
var servername = getHostname(req).toLowerCase().replace(/:.*/, '');
|
||||||
|
try { req.hostname = servername; } catch (e) { } // read-only express property
|
||||||
|
if (req.headers['x-forwarded-host']) { req.headers['x-forwarded-host'] = servername; }
|
||||||
|
try { req.headers.host = servername; } catch (e) { }
|
||||||
|
return (servernameRe.test(servername) && -1 === servername.indexOf('..') && servername) || '';
|
||||||
|
};
|
||||||
|
|
||||||
CheckListenPort(args.redirport, StartRedirServer);
|
CheckListenPort(args.redirport, StartRedirServer);
|
||||||
|
|
||||||
return obj;
|
return obj;
|
||||||
|
@ -44,6 +44,7 @@
|
|||||||
"_TlsOffload": true,
|
"_TlsOffload": true,
|
||||||
"_MpsTlsOffload": true,
|
"_MpsTlsOffload": true,
|
||||||
"_No2FactorAuth": true,
|
"_No2FactorAuth": true,
|
||||||
|
"_Log": "main,web,webrequest,cert",
|
||||||
"_WebRtConfig": {
|
"_WebRtConfig": {
|
||||||
"iceServers": [
|
"iceServers": [
|
||||||
{ "urls": "stun:stun.services.mozilla.com" },
|
{ "urls": "stun:stun.services.mozilla.com" },
|
||||||
@ -58,7 +59,9 @@
|
|||||||
},
|
},
|
||||||
"_Redirects": {
|
"_Redirects": {
|
||||||
"meshcommander": "https://www.meshcommander.com/"
|
"meshcommander": "https://www.meshcommander.com/"
|
||||||
}
|
},
|
||||||
|
"__MaxInvalidLogin": "Time in minutes, max amount of bad logins from a source IP in the time before logins are rejected.",
|
||||||
|
"MaxInvalidLogin": { "time": 10, "count": 10, "coolofftime": 10 }
|
||||||
},
|
},
|
||||||
"_domains": {
|
"_domains": {
|
||||||
"": {
|
"": {
|
||||||
|
@ -462,7 +462,7 @@ function InstallModule(modulename, func, tag1, tag2) {
|
|||||||
if ((__dirname.endsWith('/node_modules/meshcentral')) || (__dirname.endsWith('\\node_modules\\meshcentral')) || (__dirname.endsWith('/node_modules/meshcentral/')) || (__dirname.endsWith('\\node_modules\\meshcentral\\'))) { parentpath = require('path').join(__dirname, '../..'); }
|
if ((__dirname.endsWith('/node_modules/meshcentral')) || (__dirname.endsWith('\\node_modules\\meshcentral')) || (__dirname.endsWith('/node_modules/meshcentral/')) || (__dirname.endsWith('\\node_modules\\meshcentral\\'))) { parentpath = require('path').join(__dirname, '../..'); }
|
||||||
|
|
||||||
// Looks like we need to keep a global reference to the child process object for this to work correctly.
|
// Looks like we need to keep a global reference to the child process object for this to work correctly.
|
||||||
InstallModuleChildProcess = child_process.exec('npm install --no-optional --save ' + modulename, { maxBuffer: 512000, timeout: 10000, cwd: parentpath }, function (error, stdout, stderr) {
|
InstallModuleChildProcess = child_process.exec('npm install --no-optional --save ' + modulename, { maxBuffer: 512000, timeout: 120000, cwd: parentpath }, function (error, stdout, stderr) {
|
||||||
InstallModuleChildProcess = null;
|
InstallModuleChildProcess = null;
|
||||||
if ((error != null) && (error != '')) {
|
if ((error != null) && (error != '')) {
|
||||||
console.log('ERROR: Unable to install required module "' + modulename + '". May not have access to npm, or npm may not have suffisent rights to load the new module. Try "npm install ' + modulename + '" to manualy install this module.\r\n');
|
console.log('ERROR: Unable to install required module "' + modulename + '". May not have access to npm, or npm may not have suffisent rights to load the new module. Try "npm install ' + modulename + '" to manualy install this module.\r\n');
|
||||||
|
@ -6498,10 +6498,10 @@
|
|||||||
if (meshrights & 8) {
|
if (meshrights & 8) {
|
||||||
Q('p20remotecontrol').checked = true;
|
Q('p20remotecontrol').checked = true;
|
||||||
if (meshrights & 256) { Q('p20remoteview').checked = true; }
|
if (meshrights & 256) { Q('p20remoteview').checked = true; }
|
||||||
if (meshrights & 512) { Q('p20remotelimitedinput').checked = true; }
|
if (meshrights & 512) { Q('p20noterminal').checked = true; }
|
||||||
if (meshrights & 1024) { Q('p20noterminal').checked = true; }
|
if (meshrights & 1024) { Q('p20nofiles').checked = true; }
|
||||||
if (meshrights & 2048) { Q('p20nofiles').checked = true; }
|
if (meshrights & 2048) { Q('p20noamt').checked = true; }
|
||||||
if (meshrights & 4096) { Q('p20noamt').checked = true; }
|
if (meshrights & 4096) { Q('p20remotelimitedinput').checked = true; }
|
||||||
}
|
}
|
||||||
if (meshrights & 16) { Q('p20meshagentconsole').checked = true; }
|
if (meshrights & 16) { Q('p20meshagentconsole').checked = true; }
|
||||||
if (meshrights & 32) { Q('p20meshserverfiles').checked = true; }
|
if (meshrights & 32) { Q('p20meshserverfiles').checked = true; }
|
||||||
@ -8197,6 +8197,7 @@
|
|||||||
x += '<div><label><input type=checkbox id=p41c4 ' + ((serverTraceSources.indexOf('peer') >= 0) ? 'checked' : '') + '>' + "MeshCentral Server Peering" + '</label></div>';
|
x += '<div><label><input type=checkbox id=p41c4 ' + ((serverTraceSources.indexOf('peer') >= 0) ? 'checked' : '') + '>' + "MeshCentral Server Peering" + '</label></div>';
|
||||||
x += '<div><label><input type=checkbox id=p41c15 ' + ((serverTraceSources.indexOf('agent') >= 0) ? 'checked' : '') + '>' + "MeshAgent traffic" + '</label></div>';
|
x += '<div><label><input type=checkbox id=p41c15 ' + ((serverTraceSources.indexOf('agent') >= 0) ? 'checked' : '') + '>' + "MeshAgent traffic" + '</label></div>';
|
||||||
x += '<div><label><input type=checkbox id=p41c14 ' + ((serverTraceSources.indexOf('agentupdate') >= 0) ? 'checked' : '') + '>' + "MeshAgent update" + '</label></div>';
|
x += '<div><label><input type=checkbox id=p41c14 ' + ((serverTraceSources.indexOf('agentupdate') >= 0) ? 'checked' : '') + '>' + "MeshAgent update" + '</label></div>';
|
||||||
|
x += '<div><label><input type=checkbox id=p41c16 ' + ((serverTraceSources.indexOf('cert') >= 0) ? 'checked' : '') + '>' + "Server Certificate" + '</label></div>';
|
||||||
x += '<div style="width:100%;border-bottom:1px solid gray;margin-bottom:5px;margin-top:5px"><b>' + "Web Server" + '</b></div>';
|
x += '<div style="width:100%;border-bottom:1px solid gray;margin-bottom:5px;margin-top:5px"><b>' + "Web Server" + '</b></div>';
|
||||||
x += '<div><label><input type=checkbox id=p41c5 ' + ((serverTraceSources.indexOf('web') >= 0) ? 'checked' : '') + '>' + "Web Server" + '</label></div>';
|
x += '<div><label><input type=checkbox id=p41c5 ' + ((serverTraceSources.indexOf('web') >= 0) ? 'checked' : '') + '>' + "Web Server" + '</label></div>';
|
||||||
x += '<div><label><input type=checkbox id=p41c6 ' + ((serverTraceSources.indexOf('webrequest') >= 0) ? 'checked' : '') + '>' + "Web Server Requests" + '</label></div>';
|
x += '<div><label><input type=checkbox id=p41c6 ' + ((serverTraceSources.indexOf('webrequest') >= 0) ? 'checked' : '') + '>' + "Web Server Requests" + '</label></div>';
|
||||||
@ -8213,8 +8214,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function setServerTracingEx(b) {
|
function setServerTracingEx(b) {
|
||||||
var sources = [], allsources = ['cookie', 'dispatch', 'main', 'peer', 'web', 'webrequest', 'relay', 'webrelaydata', 'webrelay', 'mps', 'mpscmd', 'swarm', 'swarmcmd', 'agentupdate', 'agent'];
|
var sources = [], allsources = ['cookie', 'dispatch', 'main', 'peer', 'web', 'webrequest', 'relay', 'webrelaydata', 'webrelay', 'mps', 'mpscmd', 'swarm', 'swarmcmd', 'agentupdate', 'agent', 'cert'];
|
||||||
if (b == 1) { for (var i = 1; i < 16; i++) { try { if (Q('p41c' + i).checked) { sources.push(allsources[i - 1]); } } catch (ex) { } } }
|
if (b == 1) { for (var i = 1; i < 17; i++) { try { if (Q('p41c' + i).checked) { sources.push(allsources[i - 1]); } } catch (ex) { } } }
|
||||||
meshserver.send({ action: 'traceinfo', traceSources: sources });
|
meshserver.send({ action: 'traceinfo', traceSources: sources });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
File diff suppressed because one or more lines are too long
@ -3221,6 +3221,7 @@
|
|||||||
x += '<label><input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20editnotes>' + "Edit Device Notes" + '</label><br>';
|
x += '<label><input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20editnotes>' + "Edit Device Notes" + '</label><br>';
|
||||||
x += '<label><input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20limitevents>' + "Show Only Own Events" + '</label><br>';
|
x += '<label><input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20limitevents>' + "Show Only Own Events" + '</label><br>';
|
||||||
x += '<label><input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20chatnotify>' + "Chat & Notify" + '</label><br>';
|
x += '<label><input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20chatnotify>' + "Chat & Notify" + '</label><br>';
|
||||||
|
x += '<label><input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20uninstall>' + "Uninstall Agent" + '</label><br>';
|
||||||
x += '</div>';
|
x += '</div>';
|
||||||
setDialogMode(2, "Add User to Mesh", 3, p20showAddMeshUserDialogEx, x);
|
setDialogMode(2, "Add User to Mesh", 3, p20showAddMeshUserDialogEx, x);
|
||||||
p20validateAddMeshUserDialog();
|
p20validateAddMeshUserDialog();
|
||||||
@ -3229,20 +3230,24 @@
|
|||||||
|
|
||||||
function p20validateAddMeshUserDialog() {
|
function p20validateAddMeshUserDialog() {
|
||||||
var meshrights = currentMesh.links[userinfo._id].rights;
|
var meshrights = currentMesh.links[userinfo._id].rights;
|
||||||
QE('idx_dlgOkButton', (Q('dp20username').value.length > 0));
|
var nc = !Q('p20fulladmin').checked;
|
||||||
QE('p20fulladmin', meshrights == 0xFFFFFFFF);
|
QE('p20fulladmin', meshrights == 0xFFFFFFFF);
|
||||||
QE('p20editmesh', (!Q('p20fulladmin').checked) && (meshrights == 0xFFFFFFFF));
|
QE('p20editmesh', nc && (meshrights == 0xFFFFFFFF));
|
||||||
QE('p20manageusers', !Q('p20fulladmin').checked);
|
QE('p20manageusers', nc);
|
||||||
QE('p20managecomputers', !Q('p20fulladmin').checked);
|
QE('p20managecomputers', nc);
|
||||||
QE('p20remotecontrol', !Q('p20fulladmin').checked);
|
QE('p20remotecontrol', nc);
|
||||||
QE('p20meshagentconsole', !Q('p20fulladmin').checked);
|
QE('p20meshagentconsole', nc);
|
||||||
QE('p20meshserverfiles', !Q('p20fulladmin').checked);
|
QE('p20meshserverfiles', nc);
|
||||||
QE('p20wakedevices', !Q('p20fulladmin').checked);
|
QE('p20wakedevices', nc);
|
||||||
QE('p20editnotes', !Q('p20fulladmin').checked);
|
QE('p20editnotes', nc);
|
||||||
QE('p20remoteview', !Q('p20fulladmin').checked && Q('p20remotecontrol').checked);
|
QE('p20limitevents', nc);
|
||||||
QE('p20noterminal', !Q('p20fulladmin').checked && Q('p20remotecontrol').checked);
|
QE('p20remoteview', nc && Q('p20remotecontrol').checked);
|
||||||
QE('p20nofiles', !Q('p20fulladmin').checked && Q('p20remotecontrol').checked);
|
QE('p20remotelimitedinput', nc && Q('p20remotecontrol').checked && !Q('p20remoteview').checked);
|
||||||
QE('p20noamt', !Q('p20fulladmin').checked && Q('p20remotecontrol').checked);
|
QE('p20noterminal', nc && Q('p20remotecontrol').checked);
|
||||||
|
QE('p20nofiles', nc && Q('p20remotecontrol').checked);
|
||||||
|
QE('p20noamt', nc && Q('p20remotecontrol').checked);
|
||||||
|
QE('p20chatnotify', nc);
|
||||||
|
QE('p20uninstall', nc);
|
||||||
}
|
}
|
||||||
|
|
||||||
function p20showAddMeshUserDialogEx() {
|
function p20showAddMeshUserDialogEx() {
|
||||||
@ -3260,8 +3265,14 @@
|
|||||||
if (Q('p20noterminal').checked == true) meshadmin += 512;
|
if (Q('p20noterminal').checked == true) meshadmin += 512;
|
||||||
if (Q('p20nofiles').checked == true) meshadmin += 1024;
|
if (Q('p20nofiles').checked == true) meshadmin += 1024;
|
||||||
if (Q('p20noamt').checked == true) meshadmin += 2048;
|
if (Q('p20noamt').checked == true) meshadmin += 2048;
|
||||||
|
if (Q('p20remotelimitedinput').checked == true) meshadmin += 4096;
|
||||||
|
if (Q('p20limitevents').checked == true) meshadmin += 8192;
|
||||||
|
if (Q('p20chatnotify').checked == true) meshadmin += 16384;
|
||||||
|
if (Q('p20uninstall').checked == true) meshadmin += 32768;
|
||||||
}
|
}
|
||||||
meshserver.send({ action: 'addmeshuser', meshid: currentMesh._id, meshname: currentMesh.name, username: Q('dp20username').value, meshadmin: meshadmin });
|
var users = Q('dp20username').value.split(','), users2 = [];
|
||||||
|
for (var i in users) { users2.push(users[i].trim()); }
|
||||||
|
meshserver.send({ action: 'addmeshuser', meshid: currentMesh._id, meshname: currentMesh.name, usernames: users2, meshadmin: meshadmin });
|
||||||
}
|
}
|
||||||
|
|
||||||
function p20viewuser(userid) {
|
function p20viewuser(userid) {
|
||||||
@ -3284,6 +3295,7 @@
|
|||||||
if (((meshrights & 8) != 0) && ((meshrights & 4096) != 0) && ((meshrights & 256) == 0)) r.push("Limited Input");
|
if (((meshrights & 8) != 0) && ((meshrights & 4096) != 0) && ((meshrights & 256) == 0)) r.push("Limited Input");
|
||||||
if ((meshrights & 8192) != 0) r.push("Self Events Only");
|
if ((meshrights & 8192) != 0) r.push("Self Events Only");
|
||||||
if ((meshrights & 16384) != 0) r.push("Chat & Notify");
|
if ((meshrights & 16384) != 0) r.push("Chat & Notify");
|
||||||
|
if ((meshrights & 32768) != 0) r.push("Uninstall");
|
||||||
}
|
}
|
||||||
if (r.length == 0) { r.push("No Rights"); }
|
if (r.length == 0) { r.push("No Rights"); }
|
||||||
var buttons = 1, x = addHtmlValue("User", EscapeHtml(decodeURIComponent(userid.split('/')[2])));
|
var buttons = 1, x = addHtmlValue("User", EscapeHtml(decodeURIComponent(userid.split('/')[2])));
|
||||||
|
@ -7555,10 +7555,10 @@
|
|||||||
if (meshrights & 8) {
|
if (meshrights & 8) {
|
||||||
Q('p20remotecontrol').checked = true;
|
Q('p20remotecontrol').checked = true;
|
||||||
if (meshrights & 256) { Q('p20remoteview').checked = true; }
|
if (meshrights & 256) { Q('p20remoteview').checked = true; }
|
||||||
if (meshrights & 512) { Q('p20remotelimitedinput').checked = true; }
|
if (meshrights & 512) { Q('p20noterminal').checked = true; }
|
||||||
if (meshrights & 1024) { Q('p20noterminal').checked = true; }
|
if (meshrights & 1024) { Q('p20nofiles').checked = true; }
|
||||||
if (meshrights & 2048) { Q('p20nofiles').checked = true; }
|
if (meshrights & 2048) { Q('p20noamt').checked = true; }
|
||||||
if (meshrights & 4096) { Q('p20noamt').checked = true; }
|
if (meshrights & 4096) { Q('p20remotelimitedinput').checked = true; }
|
||||||
}
|
}
|
||||||
if (meshrights & 16) { Q('p20meshagentconsole').checked = true; }
|
if (meshrights & 16) { Q('p20meshagentconsole').checked = true; }
|
||||||
if (meshrights & 32) { Q('p20meshserverfiles').checked = true; }
|
if (meshrights & 32) { Q('p20meshserverfiles').checked = true; }
|
||||||
@ -9254,6 +9254,7 @@
|
|||||||
x += '<div><label><input type=checkbox id=p41c4 ' + ((serverTraceSources.indexOf('peer') >= 0) ? 'checked' : '') + '>' + "MeshCentral Server Peering" + '</label></div>';
|
x += '<div><label><input type=checkbox id=p41c4 ' + ((serverTraceSources.indexOf('peer') >= 0) ? 'checked' : '') + '>' + "MeshCentral Server Peering" + '</label></div>';
|
||||||
x += '<div><label><input type=checkbox id=p41c15 ' + ((serverTraceSources.indexOf('agent') >= 0) ? 'checked' : '') + '>' + "MeshAgent traffic" + '</label></div>';
|
x += '<div><label><input type=checkbox id=p41c15 ' + ((serverTraceSources.indexOf('agent') >= 0) ? 'checked' : '') + '>' + "MeshAgent traffic" + '</label></div>';
|
||||||
x += '<div><label><input type=checkbox id=p41c14 ' + ((serverTraceSources.indexOf('agentupdate') >= 0) ? 'checked' : '') + '>' + "MeshAgent update" + '</label></div>';
|
x += '<div><label><input type=checkbox id=p41c14 ' + ((serverTraceSources.indexOf('agentupdate') >= 0) ? 'checked' : '') + '>' + "MeshAgent update" + '</label></div>';
|
||||||
|
x += '<div><label><input type=checkbox id=p41c16 ' + ((serverTraceSources.indexOf('cert') >= 0) ? 'checked' : '') + '>' + "Server Certificate" + '</label></div>';
|
||||||
x += '<div style="width:100%;border-bottom:1px solid gray;margin-bottom:5px;margin-top:5px"><b>' + "Web Server" + '</b></div>';
|
x += '<div style="width:100%;border-bottom:1px solid gray;margin-bottom:5px;margin-top:5px"><b>' + "Web Server" + '</b></div>';
|
||||||
x += '<div><label><input type=checkbox id=p41c5 ' + ((serverTraceSources.indexOf('web') >= 0) ? 'checked' : '') + '>' + "Web Server" + '</label></div>';
|
x += '<div><label><input type=checkbox id=p41c5 ' + ((serverTraceSources.indexOf('web') >= 0) ? 'checked' : '') + '>' + "Web Server" + '</label></div>';
|
||||||
x += '<div><label><input type=checkbox id=p41c6 ' + ((serverTraceSources.indexOf('webrequest') >= 0) ? 'checked' : '') + '>' + "Web Server Requests" + '</label></div>';
|
x += '<div><label><input type=checkbox id=p41c6 ' + ((serverTraceSources.indexOf('webrequest') >= 0) ? 'checked' : '') + '>' + "Web Server Requests" + '</label></div>';
|
||||||
@ -9270,8 +9271,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function setServerTracingEx(b) {
|
function setServerTracingEx(b) {
|
||||||
var sources = [], allsources = ['cookie', 'dispatch', 'main', 'peer', 'web', 'webrequest', 'relay', 'webrelaydata', 'webrelay', 'mps', 'mpscmd', 'swarm', 'swarmcmd', 'agentupdate', 'agent'];
|
var sources = [], allsources = ['cookie', 'dispatch', 'main', 'peer', 'web', 'webrequest', 'relay', 'webrelaydata', 'webrelay', 'mps', 'mpscmd', 'swarm', 'swarmcmd', 'agentupdate', 'agent', 'cert'];
|
||||||
if (b == 1) { for (var i = 1; i < 16; i++) { try { if (Q('p41c' + i).checked) { sources.push(allsources[i - 1]); } } catch (ex) { } } }
|
if (b == 1) { for (var i = 1; i < 17; i++) { try { if (Q('p41c' + i).checked) { sources.push(allsources[i - 1]); } } catch (ex) { } } }
|
||||||
meshserver.send({ action: 'traceinfo', traceSources: sources });
|
meshserver.send({ action: 'traceinfo', traceSources: sources });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -46,9 +46,7 @@
|
|||||||
<div id=loginpanel style="background-color:#979797;border-radius:16px;width:260px;padding:16px;text-align:center;clear:both;display:none">
|
<div id=loginpanel style="background-color:#979797;border-radius:16px;width:260px;padding:16px;text-align:center;clear:both;display:none">
|
||||||
<form method=post>
|
<form method=post>
|
||||||
<input type=hidden name=action value=login />
|
<input type=hidden name=action value=login />
|
||||||
<div id=message1>
|
<div id=message1></div>
|
||||||
{{{message}}}
|
|
||||||
</div>
|
|
||||||
<div>
|
<div>
|
||||||
<b>Log In</b>
|
<b>Log In</b>
|
||||||
</div>
|
</div>
|
||||||
@ -80,9 +78,7 @@
|
|||||||
<div style="background-color:#979797;border-radius:16px;width:260px;padding:16px;text-align:center;clear:both;position:relative">
|
<div style="background-color:#979797;border-radius:16px;width:260px;padding:16px;text-align:center;clear:both;position:relative">
|
||||||
<form method=post>
|
<form method=post>
|
||||||
<input type=hidden name=action value=createaccount />
|
<input type=hidden name=action value=createaccount />
|
||||||
<div id=message2>
|
<div id=message2></div>
|
||||||
{{{message}}}
|
|
||||||
</div>
|
|
||||||
<div>
|
<div>
|
||||||
<b>Account Creation</b>
|
<b>Account Creation</b>
|
||||||
</div>
|
</div>
|
||||||
@ -127,9 +123,7 @@
|
|||||||
<div id=resetpanel style="background-color:#979797;border-radius:16px;width:260px;padding:16px;text-align:center;display:none;clear:both">
|
<div id=resetpanel style="background-color:#979797;border-radius:16px;width:260px;padding:16px;text-align:center;display:none;clear:both">
|
||||||
<form method=post>
|
<form method=post>
|
||||||
<input type=hidden name=action value=resetaccount />
|
<input type=hidden name=action value=resetaccount />
|
||||||
<div id=message3>
|
<div id=message3></div>
|
||||||
{{{message}}}
|
|
||||||
</div>
|
|
||||||
<div>
|
<div>
|
||||||
<b>Account Reset</b>
|
<b>Account Reset</b>
|
||||||
</div>
|
</div>
|
||||||
@ -153,9 +147,7 @@
|
|||||||
<form method=post autocomplete=off>
|
<form method=post autocomplete=off>
|
||||||
<input type=hidden name=action value=tokenlogin />
|
<input type=hidden name=action value=tokenlogin />
|
||||||
<input type=hidden name=hwstate value="{{{hwstate}}}" />
|
<input type=hidden name=hwstate value="{{{hwstate}}}" />
|
||||||
<div id=message4>
|
<div id=message4></div>
|
||||||
{{{message}}}
|
|
||||||
</div>
|
|
||||||
<table>
|
<table>
|
||||||
<tr>
|
<tr>
|
||||||
<td align=right width=100>Login token:</td>
|
<td align=right width=100>Login token:</td>
|
||||||
@ -178,9 +170,7 @@
|
|||||||
<div id=resettokenpanel style="background-color:#979797;border-radius:16px;width:260px;padding:16px;text-align:center;display:none;clear:both">
|
<div id=resettokenpanel style="background-color:#979797;border-radius:16px;width:260px;padding:16px;text-align:center;display:none;clear:both">
|
||||||
<form method=post autocomplete=off>
|
<form method=post autocomplete=off>
|
||||||
<input type=hidden name=action value=resetaccount />
|
<input type=hidden name=action value=resetaccount />
|
||||||
<div id=message5>
|
<div id=message5></div>
|
||||||
{{{message}}}
|
|
||||||
</div>
|
|
||||||
<table>
|
<table>
|
||||||
<tr>
|
<tr>
|
||||||
<td align=right width=100>Login token:</td>
|
<td align=right width=100>Login token:</td>
|
||||||
@ -203,9 +193,7 @@
|
|||||||
<div id=resetpasswordpanel style="position:relative;background-color:#979797;border-radius:16px;width:300px;padding:16px;text-align:center;display:none">
|
<div id=resetpasswordpanel style="position:relative;background-color:#979797;border-radius:16px;width:300px;padding:16px;text-align:center;display:none">
|
||||||
<form method=post>
|
<form method=post>
|
||||||
<input type=hidden name=action value=resetpassword />
|
<input type=hidden name=action value=resetpassword />
|
||||||
<div id=message6>
|
<div id=message6></div>
|
||||||
{{{message}}}
|
|
||||||
</div>
|
|
||||||
<div id="rpasswordPolicyCallout" style="left:-10px;width:100px;display:none;position:absolute;background-color:#FFC;border-radius:5px;padding:5px;box-shadow:0px 0px 15px #666;font-size:10px"></div>
|
<div id="rpasswordPolicyCallout" style="left:-10px;width:100px;display:none;position:absolute;background-color:#FFC;border-radius:5px;padding:5px;box-shadow:0px 0px 15px #666;font-size:10px"></div>
|
||||||
<table>
|
<table>
|
||||||
<tr>
|
<tr>
|
||||||
@ -279,6 +267,20 @@
|
|||||||
var hardwareKeyChallenge = decodeURIComponent('{{{hkey}}}');
|
var hardwareKeyChallenge = decodeURIComponent('{{{hkey}}}');
|
||||||
var currentpanel = 0;
|
var currentpanel = 0;
|
||||||
|
|
||||||
|
// Display the right server message
|
||||||
|
var messageid = parseInt('{{{messageid}}}');
|
||||||
|
var okmessages = ['', "Hold on, reset mail sent."];
|
||||||
|
var failmessages = ["Unable to create account.", "Account limit reached.", "Existing account with this email address.", "Invalid account creation token.", "Username already exists.", "Password rejected, use a different one.", "Invalid email.", "Account not found.", "Invalid token, try again.", "Unable to sent email.", "Account locked.", "Access denied.", "Login failed, check username and password.", "Password change requested.", "IP address blocked, try again later."];
|
||||||
|
if (messageid > 0) {
|
||||||
|
var msg = '';
|
||||||
|
if ((messageid < 100) && (messageid < okmessages.length)) { msg = okmessages[messageid]; }
|
||||||
|
else if ((messageid >= 100) && ((messageid - 100) < failmessages.length)) { msg = failmessages[messageid - 100]; }
|
||||||
|
if (msg != '') {
|
||||||
|
if (messageid >= 100) { msg = ('<span class="msg error"><b style=color:#8C001A>' + msg + '<b></span><br /><br />'); } else { msg = ('<span class="msg success"><b>' + msg + '</b></span><br /><br />'); }
|
||||||
|
for (var i = 1; i < 7; i++) { QH('message' + i, msg); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// If URL arguments are provided, add them to form posts
|
// If URL arguments are provided, add them to form posts
|
||||||
if (window.location.href.indexOf('?') > 0) {
|
if (window.location.href.indexOf('?') > 0) {
|
||||||
var urlargs = window.location.href.substring(window.location.href.indexOf('?'));
|
var urlargs = window.location.href.substring(window.location.href.indexOf('?'));
|
||||||
|
@ -43,9 +43,7 @@
|
|||||||
<div id=loginpanel style="display:none">
|
<div id=loginpanel style="display:none">
|
||||||
<form method=post>
|
<form method=post>
|
||||||
<input type=hidden name=action value=login />
|
<input type=hidden name=action value=login />
|
||||||
<div id=message1>
|
<div id=message1></div>
|
||||||
{{{message}}}
|
|
||||||
</div>
|
|
||||||
<div>
|
<div>
|
||||||
<b>Log In</b>
|
<b>Log In</b>
|
||||||
</div>
|
</div>
|
||||||
@ -76,9 +74,7 @@
|
|||||||
<div id=createpanel style="display:none;position:relative">
|
<div id=createpanel style="display:none;position:relative">
|
||||||
<form method=post>
|
<form method=post>
|
||||||
<input type=hidden name=action value=createaccount />
|
<input type=hidden name=action value=createaccount />
|
||||||
<div id=message2>
|
<div id=message2></div>
|
||||||
{{{message}}}
|
|
||||||
</div>
|
|
||||||
<div>
|
<div>
|
||||||
<b>Account Creation</b>
|
<b>Account Creation</b>
|
||||||
</div>
|
</div>
|
||||||
@ -122,9 +118,7 @@
|
|||||||
<div id=resetpanel style="display:none">
|
<div id=resetpanel style="display:none">
|
||||||
<form method=post>
|
<form method=post>
|
||||||
<input type=hidden name=action value=resetaccount />
|
<input type=hidden name=action value=resetaccount />
|
||||||
<div id=message3>
|
<div id=message3></div>
|
||||||
{{{message}}}
|
|
||||||
</div>
|
|
||||||
<div>
|
<div>
|
||||||
<b>Account Reset</b>
|
<b>Account Reset</b>
|
||||||
</div>
|
</div>
|
||||||
@ -148,9 +142,7 @@
|
|||||||
<form method=post autocomplete=off>
|
<form method=post autocomplete=off>
|
||||||
<input type=hidden name=action value=tokenlogin />
|
<input type=hidden name=action value=tokenlogin />
|
||||||
<input type=hidden name=hwstate value="{{{hwstate}}}" />
|
<input type=hidden name=hwstate value="{{{hwstate}}}" />
|
||||||
<div id=message4>
|
<div id=message4></div>
|
||||||
{{{message}}}
|
|
||||||
</div>
|
|
||||||
<table>
|
<table>
|
||||||
<tr>
|
<tr>
|
||||||
<td align=right width=100>Login token:</td>
|
<td align=right width=100>Login token:</td>
|
||||||
@ -172,9 +164,7 @@
|
|||||||
<div id=resettokenpanel style="display:none">
|
<div id=resettokenpanel style="display:none">
|
||||||
<form method=post>
|
<form method=post>
|
||||||
<input type=hidden name=action value=resetaccount />
|
<input type=hidden name=action value=resetaccount />
|
||||||
<div id=message5>
|
<div id=message5></div>
|
||||||
{{{message}}}
|
|
||||||
</div>
|
|
||||||
<table>
|
<table>
|
||||||
<tr>
|
<tr>
|
||||||
<td align=right width=100>Login token:</td>
|
<td align=right width=100>Login token:</td>
|
||||||
@ -196,9 +186,7 @@
|
|||||||
<div id=resetpasswordpanel style="display:none;position:relative">
|
<div id=resetpasswordpanel style="display:none;position:relative">
|
||||||
<form method=post>
|
<form method=post>
|
||||||
<input type=hidden name=action value=resetpassword />
|
<input type=hidden name=action value=resetpassword />
|
||||||
<div id=message6>
|
<div id=message6></div>
|
||||||
{{{message}}}
|
|
||||||
</div>
|
|
||||||
<div id="rpasswordPolicyCallout" style="display:none"></div>
|
<div id="rpasswordPolicyCallout" style="display:none"></div>
|
||||||
<table>
|
<table>
|
||||||
<tr>
|
<tr>
|
||||||
@ -276,6 +264,20 @@
|
|||||||
var nightMode = (getstore('_nightMode', '0') == '1');
|
var nightMode = (getstore('_nightMode', '0') == '1');
|
||||||
var publicKeyCredentialRequestOptions = null;
|
var publicKeyCredentialRequestOptions = null;
|
||||||
|
|
||||||
|
// Display the right server message
|
||||||
|
var messageid = parseInt('{{{messageid}}}');
|
||||||
|
var okmessages = ['', "Hold on, reset mail sent."];
|
||||||
|
var failmessages = ["Unable to create account.", "Account limit reached.", "Existing account with this email address.", "Invalid account creation token.", "Username already exists.", "Password rejected, use a different one.", "Invalid email.", "Account not found.", "Invalid token, try again.", "Unable to sent email.", "Account locked.", "Access denied.", "Login failed, check username and password.", "Password change requested.", "IP address blocked, try again later."];
|
||||||
|
if (messageid > 0) {
|
||||||
|
var msg = '';
|
||||||
|
if ((messageid < 100) && (messageid < okmessages.length)) { msg = okmessages[messageid]; }
|
||||||
|
else if ((messageid >= 100) && ((messageid - 100) < failmessages.length)) { msg = failmessages[messageid - 100]; }
|
||||||
|
if (msg != '') {
|
||||||
|
if (messageid >= 100) { msg = ('<span class="msg error"><b style=color:#8C001A>' + msg + '<b></span><br /><br />'); } else { msg = ('<span class="msg success"><b>' + msg + '</b></span><br /><br />'); }
|
||||||
|
for (var i = 1; i < 7; i++) { QH('message' + i, msg); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// If URL arguments are provided, add them to form posts
|
// If URL arguments are provided, add them to form posts
|
||||||
if (window.location.href.indexOf('?') > 0) {
|
if (window.location.href.indexOf('?') > 0) {
|
||||||
var urlargs = window.location.href.substring(window.location.href.indexOf('?'));
|
var urlargs = window.location.href.substring(window.location.href.indexOf('?'));
|
||||||
@ -353,9 +355,7 @@
|
|||||||
QE('tokenOkButton', true);
|
QE('tokenOkButton', true);
|
||||||
Q('tokenOkButton').click();
|
Q('tokenOkButton').click();
|
||||||
},
|
},
|
||||||
function (error) {
|
function (error) { console.log('credentials-get error', error); }
|
||||||
console.log('credentials-get error', error);
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6498,10 +6498,10 @@
|
|||||||
if (meshrights & 8) {
|
if (meshrights & 8) {
|
||||||
Q('p20remotecontrol').checked = true;
|
Q('p20remotecontrol').checked = true;
|
||||||
if (meshrights & 256) { Q('p20remoteview').checked = true; }
|
if (meshrights & 256) { Q('p20remoteview').checked = true; }
|
||||||
if (meshrights & 512) { Q('p20remotelimitedinput').checked = true; }
|
if (meshrights & 512) { Q('p20noterminal').checked = true; }
|
||||||
if (meshrights & 1024) { Q('p20noterminal').checked = true; }
|
if (meshrights & 1024) { Q('p20nofiles').checked = true; }
|
||||||
if (meshrights & 2048) { Q('p20nofiles').checked = true; }
|
if (meshrights & 2048) { Q('p20noamt').checked = true; }
|
||||||
if (meshrights & 4096) { Q('p20noamt').checked = true; }
|
if (meshrights & 4096) { Q('p20remotelimitedinput').checked = true; }
|
||||||
}
|
}
|
||||||
if (meshrights & 16) { Q('p20meshagentconsole').checked = true; }
|
if (meshrights & 16) { Q('p20meshagentconsole').checked = true; }
|
||||||
if (meshrights & 32) { Q('p20meshserverfiles').checked = true; }
|
if (meshrights & 32) { Q('p20meshserverfiles').checked = true; }
|
||||||
@ -8197,6 +8197,7 @@
|
|||||||
x += '<div><label><input type=checkbox id=p41c4 ' + ((serverTraceSources.indexOf('peer') >= 0) ? 'checked' : '') + '>' + "MeshCentral Server Peering" + '</label></div>';
|
x += '<div><label><input type=checkbox id=p41c4 ' + ((serverTraceSources.indexOf('peer') >= 0) ? 'checked' : '') + '>' + "MeshCentral Server Peering" + '</label></div>';
|
||||||
x += '<div><label><input type=checkbox id=p41c15 ' + ((serverTraceSources.indexOf('agent') >= 0) ? 'checked' : '') + '>' + "MeshAgent traffic" + '</label></div>';
|
x += '<div><label><input type=checkbox id=p41c15 ' + ((serverTraceSources.indexOf('agent') >= 0) ? 'checked' : '') + '>' + "MeshAgent traffic" + '</label></div>';
|
||||||
x += '<div><label><input type=checkbox id=p41c14 ' + ((serverTraceSources.indexOf('agentupdate') >= 0) ? 'checked' : '') + '>' + "MeshAgent update" + '</label></div>';
|
x += '<div><label><input type=checkbox id=p41c14 ' + ((serverTraceSources.indexOf('agentupdate') >= 0) ? 'checked' : '') + '>' + "MeshAgent update" + '</label></div>';
|
||||||
|
x += '<div><label><input type=checkbox id=p41c16 ' + ((serverTraceSources.indexOf('cert') >= 0) ? 'checked' : '') + '>' + "Server Certificate" + '</label></div>';
|
||||||
x += '<div style="width:100%;border-bottom:1px solid gray;margin-bottom:5px;margin-top:5px"><b>' + "Serveur Web" + '</b></div>';
|
x += '<div style="width:100%;border-bottom:1px solid gray;margin-bottom:5px;margin-top:5px"><b>' + "Serveur Web" + '</b></div>';
|
||||||
x += '<div><label><input type=checkbox id=p41c5 ' + ((serverTraceSources.indexOf('web') >= 0) ? 'checked' : '') + '>' + "Serveur Web" + '</label></div>';
|
x += '<div><label><input type=checkbox id=p41c5 ' + ((serverTraceSources.indexOf('web') >= 0) ? 'checked' : '') + '>' + "Serveur Web" + '</label></div>';
|
||||||
x += '<div><label><input type=checkbox id=p41c6 ' + ((serverTraceSources.indexOf('webrequest') >= 0) ? 'checked' : '') + '>' + "Demandes de serveur Web" + '</label></div>';
|
x += '<div><label><input type=checkbox id=p41c6 ' + ((serverTraceSources.indexOf('webrequest') >= 0) ? 'checked' : '') + '>' + "Demandes de serveur Web" + '</label></div>';
|
||||||
@ -8213,8 +8214,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function setServerTracingEx(b) {
|
function setServerTracingEx(b) {
|
||||||
var sources = [], allsources = ['cookie', 'dispatch', 'main', 'peer', 'web', 'webrequest', 'relay', 'webrelaydata', 'webrelay', 'mps', 'mpscmd', 'swarm', 'swarmcmd', 'agentupdate', 'agent'];
|
var sources = [], allsources = ['cookie', 'dispatch', 'main', 'peer', 'web', 'webrequest', 'relay', 'webrelaydata', 'webrelay', 'mps', 'mpscmd', 'swarm', 'swarmcmd', 'agentupdate', 'agent', 'cert'];
|
||||||
if (b == 1) { for (var i = 1; i < 16; i++) { try { if (Q('p41c' + i).checked) { sources.push(allsources[i - 1]); } } catch (ex) { } } }
|
if (b == 1) { for (var i = 1; i < 17; i++) { try { if (Q('p41c' + i).checked) { sources.push(allsources[i - 1]); } } catch (ex) { } } }
|
||||||
meshserver.send({ action: 'traceinfo', traceSources: sources });
|
meshserver.send({ action: 'traceinfo', traceSources: sources });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
File diff suppressed because one or more lines are too long
@ -3219,6 +3219,7 @@
|
|||||||
x += '<label><input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20editnotes>' + "Edit Device Notes" + '</label><br>';
|
x += '<label><input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20editnotes>' + "Edit Device Notes" + '</label><br>';
|
||||||
x += '<label><input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20limitevents>' + "Show Only Own Events" + '</label><br>';
|
x += '<label><input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20limitevents>' + "Show Only Own Events" + '</label><br>';
|
||||||
x += '<label><input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20chatnotify>' + "Chat & Notify" + '</label><br>';
|
x += '<label><input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20chatnotify>' + "Chat & Notify" + '</label><br>';
|
||||||
|
x += '<label><input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20uninstall>' + "Uninstall Agent" + '</label><br>';
|
||||||
x += '</div>';
|
x += '</div>';
|
||||||
setDialogMode(2, "Ajouter un utilisateur au groupe", 3, p20showAddMeshUserDialogEx, x);
|
setDialogMode(2, "Ajouter un utilisateur au groupe", 3, p20showAddMeshUserDialogEx, x);
|
||||||
p20validateAddMeshUserDialog();
|
p20validateAddMeshUserDialog();
|
||||||
@ -3227,20 +3228,24 @@
|
|||||||
|
|
||||||
function p20validateAddMeshUserDialog() {
|
function p20validateAddMeshUserDialog() {
|
||||||
var meshrights = currentMesh.links[userinfo._id].rights;
|
var meshrights = currentMesh.links[userinfo._id].rights;
|
||||||
QE('idx_dlgOkButton', (Q('dp20username').value.length > 0));
|
var nc = !Q('p20fulladmin').checked;
|
||||||
QE('p20fulladmin', meshrights == 0xFFFFFFFF);
|
QE('p20fulladmin', meshrights == 0xFFFFFFFF);
|
||||||
QE('p20editmesh', (!Q('p20fulladmin').checked) && (meshrights == 0xFFFFFFFF));
|
QE('p20editmesh', nc && (meshrights == 0xFFFFFFFF));
|
||||||
QE('p20manageusers', !Q('p20fulladmin').checked);
|
QE('p20manageusers', nc);
|
||||||
QE('p20managecomputers', !Q('p20fulladmin').checked);
|
QE('p20managecomputers', nc);
|
||||||
QE('p20remotecontrol', !Q('p20fulladmin').checked);
|
QE('p20remotecontrol', nc);
|
||||||
QE('p20meshagentconsole', !Q('p20fulladmin').checked);
|
QE('p20meshagentconsole', nc);
|
||||||
QE('p20meshserverfiles', !Q('p20fulladmin').checked);
|
QE('p20meshserverfiles', nc);
|
||||||
QE('p20wakedevices', !Q('p20fulladmin').checked);
|
QE('p20wakedevices', nc);
|
||||||
QE('p20editnotes', !Q('p20fulladmin').checked);
|
QE('p20editnotes', nc);
|
||||||
QE('p20remoteview', !Q('p20fulladmin').checked && Q('p20remotecontrol').checked);
|
QE('p20limitevents', nc);
|
||||||
QE('p20noterminal', !Q('p20fulladmin').checked && Q('p20remotecontrol').checked);
|
QE('p20remoteview', nc && Q('p20remotecontrol').checked);
|
||||||
QE('p20nofiles', !Q('p20fulladmin').checked && Q('p20remotecontrol').checked);
|
QE('p20remotelimitedinput', nc && Q('p20remotecontrol').checked && !Q('p20remoteview').checked);
|
||||||
QE('p20noamt', !Q('p20fulladmin').checked && Q('p20remotecontrol').checked);
|
QE('p20noterminal', nc && Q('p20remotecontrol').checked);
|
||||||
|
QE('p20nofiles', nc && Q('p20remotecontrol').checked);
|
||||||
|
QE('p20noamt', nc && Q('p20remotecontrol').checked);
|
||||||
|
QE('p20chatnotify', nc);
|
||||||
|
QE('p20uninstall', nc);
|
||||||
}
|
}
|
||||||
|
|
||||||
function p20showAddMeshUserDialogEx() {
|
function p20showAddMeshUserDialogEx() {
|
||||||
@ -3258,8 +3263,14 @@
|
|||||||
if (Q('p20noterminal').checked == true) meshadmin += 512;
|
if (Q('p20noterminal').checked == true) meshadmin += 512;
|
||||||
if (Q('p20nofiles').checked == true) meshadmin += 1024;
|
if (Q('p20nofiles').checked == true) meshadmin += 1024;
|
||||||
if (Q('p20noamt').checked == true) meshadmin += 2048;
|
if (Q('p20noamt').checked == true) meshadmin += 2048;
|
||||||
|
if (Q('p20remotelimitedinput').checked == true) meshadmin += 4096;
|
||||||
|
if (Q('p20limitevents').checked == true) meshadmin += 8192;
|
||||||
|
if (Q('p20chatnotify').checked == true) meshadmin += 16384;
|
||||||
|
if (Q('p20uninstall').checked == true) meshadmin += 32768;
|
||||||
}
|
}
|
||||||
meshserver.send({ action: 'addmeshuser', meshid: currentMesh._id, meshname: currentMesh.name, username: Q('dp20username').value, meshadmin: meshadmin });
|
var users = Q('dp20username').value.split(','), users2 = [];
|
||||||
|
for (var i in users) { users2.push(users[i].trim()); }
|
||||||
|
meshserver.send({ action: 'addmeshuser', meshid: currentMesh._id, meshname: currentMesh.name, usernames: users2, meshadmin: meshadmin });
|
||||||
}
|
}
|
||||||
|
|
||||||
function p20viewuser(userid) {
|
function p20viewuser(userid) {
|
||||||
@ -3282,6 +3293,7 @@
|
|||||||
if (((meshrights & 8) != 0) && ((meshrights & 4096) != 0) && ((meshrights & 256) == 0)) r.push("Limited Input");
|
if (((meshrights & 8) != 0) && ((meshrights & 4096) != 0) && ((meshrights & 256) == 0)) r.push("Limited Input");
|
||||||
if ((meshrights & 8192) != 0) r.push("Self Events Only");
|
if ((meshrights & 8192) != 0) r.push("Self Events Only");
|
||||||
if ((meshrights & 16384) != 0) r.push("Chat & Notify");
|
if ((meshrights & 16384) != 0) r.push("Chat & Notify");
|
||||||
|
if ((meshrights & 32768) != 0) r.push("Uninstall");
|
||||||
}
|
}
|
||||||
if (r.length == 0) { r.push("No Rights"); }
|
if (r.length == 0) { r.push("No Rights"); }
|
||||||
var buttons = 1, x = addHtmlValue("User", EscapeHtml(decodeURIComponent(userid.split('/')[2])));
|
var buttons = 1, x = addHtmlValue("User", EscapeHtml(decodeURIComponent(userid.split('/')[2])));
|
||||||
|
@ -7478,10 +7478,10 @@
|
|||||||
if (meshrights & 8) {
|
if (meshrights & 8) {
|
||||||
Q('p20remotecontrol').checked = true;
|
Q('p20remotecontrol').checked = true;
|
||||||
if (meshrights & 256) { Q('p20remoteview').checked = true; }
|
if (meshrights & 256) { Q('p20remoteview').checked = true; }
|
||||||
if (meshrights & 512) { Q('p20remotelimitedinput').checked = true; }
|
if (meshrights & 512) { Q('p20noterminal').checked = true; }
|
||||||
if (meshrights & 1024) { Q('p20noterminal').checked = true; }
|
if (meshrights & 1024) { Q('p20nofiles').checked = true; }
|
||||||
if (meshrights & 2048) { Q('p20nofiles').checked = true; }
|
if (meshrights & 2048) { Q('p20noamt').checked = true; }
|
||||||
if (meshrights & 4096) { Q('p20noamt').checked = true; }
|
if (meshrights & 4096) { Q('p20remotelimitedinput').checked = true; }
|
||||||
}
|
}
|
||||||
if (meshrights & 16) { Q('p20meshagentconsole').checked = true; }
|
if (meshrights & 16) { Q('p20meshagentconsole').checked = true; }
|
||||||
if (meshrights & 32) { Q('p20meshserverfiles').checked = true; }
|
if (meshrights & 32) { Q('p20meshserverfiles').checked = true; }
|
||||||
@ -9177,6 +9177,7 @@
|
|||||||
x += '<div><label><input type=checkbox id=p41c4 ' + ((serverTraceSources.indexOf('peer') >= 0) ? 'checked' : '') + '>' + "MeshCentral Server Peering" + '</label></div>';
|
x += '<div><label><input type=checkbox id=p41c4 ' + ((serverTraceSources.indexOf('peer') >= 0) ? 'checked' : '') + '>' + "MeshCentral Server Peering" + '</label></div>';
|
||||||
x += '<div><label><input type=checkbox id=p41c15 ' + ((serverTraceSources.indexOf('agent') >= 0) ? 'checked' : '') + '>' + "MeshAgent traffic" + '</label></div>';
|
x += '<div><label><input type=checkbox id=p41c15 ' + ((serverTraceSources.indexOf('agent') >= 0) ? 'checked' : '') + '>' + "MeshAgent traffic" + '</label></div>';
|
||||||
x += '<div><label><input type=checkbox id=p41c14 ' + ((serverTraceSources.indexOf('agentupdate') >= 0) ? 'checked' : '') + '>' + "MeshAgent update" + '</label></div>';
|
x += '<div><label><input type=checkbox id=p41c14 ' + ((serverTraceSources.indexOf('agentupdate') >= 0) ? 'checked' : '') + '>' + "MeshAgent update" + '</label></div>';
|
||||||
|
x += '<div><label><input type=checkbox id=p41c16 ' + ((serverTraceSources.indexOf('cert') >= 0) ? 'checked' : '') + '>' + "Server Certificate" + '</label></div>';
|
||||||
x += '<div style="width:100%;border-bottom:1px solid gray;margin-bottom:5px;margin-top:5px"><b>' + "Serveur Web" + '</b></div>';
|
x += '<div style="width:100%;border-bottom:1px solid gray;margin-bottom:5px;margin-top:5px"><b>' + "Serveur Web" + '</b></div>';
|
||||||
x += '<div><label><input type=checkbox id=p41c5 ' + ((serverTraceSources.indexOf('web') >= 0) ? 'checked' : '') + '>' + "Serveur Web" + '</label></div>';
|
x += '<div><label><input type=checkbox id=p41c5 ' + ((serverTraceSources.indexOf('web') >= 0) ? 'checked' : '') + '>' + "Serveur Web" + '</label></div>';
|
||||||
x += '<div><label><input type=checkbox id=p41c6 ' + ((serverTraceSources.indexOf('webrequest') >= 0) ? 'checked' : '') + '>' + "Demandes de serveur Web" + '</label></div>';
|
x += '<div><label><input type=checkbox id=p41c6 ' + ((serverTraceSources.indexOf('webrequest') >= 0) ? 'checked' : '') + '>' + "Demandes de serveur Web" + '</label></div>';
|
||||||
@ -9193,8 +9194,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function setServerTracingEx(b) {
|
function setServerTracingEx(b) {
|
||||||
var sources = [], allsources = ['cookie', 'dispatch', 'main', 'peer', 'web', 'webrequest', 'relay', 'webrelaydata', 'webrelay', 'mps', 'mpscmd', 'swarm', 'swarmcmd', 'agentupdate', 'agent'];
|
var sources = [], allsources = ['cookie', 'dispatch', 'main', 'peer', 'web', 'webrequest', 'relay', 'webrelaydata', 'webrelay', 'mps', 'mpscmd', 'swarm', 'swarmcmd', 'agentupdate', 'agent', 'cert'];
|
||||||
if (b == 1) { for (var i = 1; i < 16; i++) { try { if (Q('p41c' + i).checked) { sources.push(allsources[i - 1]); } } catch (ex) { } } }
|
if (b == 1) { for (var i = 1; i < 17; i++) { try { if (Q('p41c' + i).checked) { sources.push(allsources[i - 1]); } } catch (ex) { } } }
|
||||||
meshserver.send({ action: 'traceinfo', traceSources: sources });
|
meshserver.send({ action: 'traceinfo', traceSources: sources });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -44,9 +44,7 @@
|
|||||||
<div id="loginpanel" style="background-color:#979797;border-radius:16px;width:260px;padding:16px;text-align:center;clear:both;display:none">
|
<div id="loginpanel" style="background-color:#979797;border-radius:16px;width:260px;padding:16px;text-align:center;clear:both;display:none">
|
||||||
<form method="post">
|
<form method="post">
|
||||||
<input type="hidden" name="action" value="login">
|
<input type="hidden" name="action" value="login">
|
||||||
<div id="message1">
|
<div id="message1"></div>
|
||||||
{{{message}}}
|
|
||||||
</div>
|
|
||||||
<div>
|
<div>
|
||||||
<b>Log In</b>
|
<b>Log In</b>
|
||||||
</div>
|
</div>
|
||||||
@ -78,9 +76,7 @@
|
|||||||
<div style="background-color:#979797;border-radius:16px;width:260px;padding:16px;text-align:center;clear:both;position:relative">
|
<div style="background-color:#979797;border-radius:16px;width:260px;padding:16px;text-align:center;clear:both;position:relative">
|
||||||
<form method="post">
|
<form method="post">
|
||||||
<input type="hidden" name="action" value="createaccount">
|
<input type="hidden" name="action" value="createaccount">
|
||||||
<div id="message2">
|
<div id="message2"></div>
|
||||||
{{{message}}}
|
|
||||||
</div>
|
|
||||||
<div>
|
<div>
|
||||||
<b>Account Creation</b>
|
<b>Account Creation</b>
|
||||||
</div>
|
</div>
|
||||||
@ -125,9 +121,7 @@
|
|||||||
<div id="resetpanel" style="background-color:#979797;border-radius:16px;width:260px;padding:16px;text-align:center;display:none;clear:both">
|
<div id="resetpanel" style="background-color:#979797;border-radius:16px;width:260px;padding:16px;text-align:center;display:none;clear:both">
|
||||||
<form method="post">
|
<form method="post">
|
||||||
<input type="hidden" name="action" value="resetaccount">
|
<input type="hidden" name="action" value="resetaccount">
|
||||||
<div id="message3">
|
<div id="message3"></div>
|
||||||
{{{message}}}
|
|
||||||
</div>
|
|
||||||
<div>
|
<div>
|
||||||
<b>Account Reset</b>
|
<b>Account Reset</b>
|
||||||
</div>
|
</div>
|
||||||
@ -151,9 +145,7 @@
|
|||||||
<form method="post" autocomplete="off">
|
<form method="post" autocomplete="off">
|
||||||
<input type="hidden" name="action" value="tokenlogin">
|
<input type="hidden" name="action" value="tokenlogin">
|
||||||
<input type="hidden" name="hwstate" value="{{{hwstate}}}">
|
<input type="hidden" name="hwstate" value="{{{hwstate}}}">
|
||||||
<div id="message4">
|
<div id="message4"></div>
|
||||||
{{{message}}}
|
|
||||||
</div>
|
|
||||||
<table>
|
<table>
|
||||||
<tbody><tr>
|
<tbody><tr>
|
||||||
<td align="right" width="100">Login token:</td>
|
<td align="right" width="100">Login token:</td>
|
||||||
@ -176,9 +168,7 @@
|
|||||||
<div id="resettokenpanel" style="background-color:#979797;border-radius:16px;width:260px;padding:16px;text-align:center;display:none;clear:both">
|
<div id="resettokenpanel" style="background-color:#979797;border-radius:16px;width:260px;padding:16px;text-align:center;display:none;clear:both">
|
||||||
<form method="post" autocomplete="off">
|
<form method="post" autocomplete="off">
|
||||||
<input type="hidden" name="action" value="resetaccount">
|
<input type="hidden" name="action" value="resetaccount">
|
||||||
<div id="message5">
|
<div id="message5"></div>
|
||||||
{{{message}}}
|
|
||||||
</div>
|
|
||||||
<table>
|
<table>
|
||||||
<tbody><tr>
|
<tbody><tr>
|
||||||
<td align="right" width="100">Login token:</td>
|
<td align="right" width="100">Login token:</td>
|
||||||
@ -201,9 +191,7 @@
|
|||||||
<div id="resetpasswordpanel" style="position:relative;background-color:#979797;border-radius:16px;width:300px;padding:16px;text-align:center;display:none">
|
<div id="resetpasswordpanel" style="position:relative;background-color:#979797;border-radius:16px;width:300px;padding:16px;text-align:center;display:none">
|
||||||
<form method="post">
|
<form method="post">
|
||||||
<input type="hidden" name="action" value="resetpassword">
|
<input type="hidden" name="action" value="resetpassword">
|
||||||
<div id="message6">
|
<div id="message6"></div>
|
||||||
{{{message}}}
|
|
||||||
</div>
|
|
||||||
<div id="rpasswordPolicyCallout" style="left:-10px;width:100px;display:none;position:absolute;background-color:#FFC;border-radius:5px;padding:5px;box-shadow:0px 0px 15px #666;font-size:10px"></div>
|
<div id="rpasswordPolicyCallout" style="left:-10px;width:100px;display:none;position:absolute;background-color:#FFC;border-radius:5px;padding:5px;box-shadow:0px 0px 15px #666;font-size:10px"></div>
|
||||||
<table>
|
<table>
|
||||||
<tbody><tr>
|
<tbody><tr>
|
||||||
@ -277,6 +265,20 @@
|
|||||||
var hardwareKeyChallenge = decodeURIComponent('{{{hkey}}}');
|
var hardwareKeyChallenge = decodeURIComponent('{{{hkey}}}');
|
||||||
var currentpanel = 0;
|
var currentpanel = 0;
|
||||||
|
|
||||||
|
// Display the right server message
|
||||||
|
var messageid = parseInt('{{{messageid}}}');
|
||||||
|
var okmessages = ['', "Hold on, reset mail sent."];
|
||||||
|
var failmessages = ["Unable to create account.", "Account limit reached.", "Existing account with this email address.", "Invalid account creation token.", "Username already exists.", "Password rejected, use a different one.", "Invalid email.", "Account not found.", "Invalid token, try again.", "Unable to sent email.", "Account locked.", "Access denied.", "Login failed, check username and password.", "Password change requested.", "IP address blocked, try again later."];
|
||||||
|
if (messageid > 0) {
|
||||||
|
var msg = '';
|
||||||
|
if ((messageid < 100) && (messageid < okmessages.length)) { msg = okmessages[messageid]; }
|
||||||
|
else if ((messageid >= 100) && ((messageid - 100) < failmessages.length)) { msg = failmessages[messageid - 100]; }
|
||||||
|
if (msg != '') {
|
||||||
|
if (messageid >= 100) { msg = ('<span class="msg error"><b style=color:#8C001A>' + msg + '<b></span><br /><br />'); } else { msg = ('<span class="msg success"><b>' + msg + '</b></span><br /><br />'); }
|
||||||
|
for (var i = 1; i < 7; i++) { QH('message' + i, msg); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// If URL arguments are provided, add them to form posts
|
// If URL arguments are provided, add them to form posts
|
||||||
if (window.location.href.indexOf('?') > 0) {
|
if (window.location.href.indexOf('?') > 0) {
|
||||||
var urlargs = window.location.href.substring(window.location.href.indexOf('?'));
|
var urlargs = window.location.href.substring(window.location.href.indexOf('?'));
|
||||||
|
@ -41,9 +41,7 @@
|
|||||||
<div id="loginpanel" style="display:none">
|
<div id="loginpanel" style="display:none">
|
||||||
<form method="post">
|
<form method="post">
|
||||||
<input type="hidden" name="action" value="login">
|
<input type="hidden" name="action" value="login">
|
||||||
<div id="message1">
|
<div id="message1"></div>
|
||||||
{{{message}}}
|
|
||||||
</div>
|
|
||||||
<div>
|
<div>
|
||||||
<b>Log In</b>
|
<b>Log In</b>
|
||||||
</div>
|
</div>
|
||||||
@ -74,9 +72,7 @@
|
|||||||
<div id="createpanel" style="display:none;position:relative">
|
<div id="createpanel" style="display:none;position:relative">
|
||||||
<form method="post">
|
<form method="post">
|
||||||
<input type="hidden" name="action" value="createaccount">
|
<input type="hidden" name="action" value="createaccount">
|
||||||
<div id="message2">
|
<div id="message2"></div>
|
||||||
{{{message}}}
|
|
||||||
</div>
|
|
||||||
<div>
|
<div>
|
||||||
<b>Account Creation</b>
|
<b>Account Creation</b>
|
||||||
</div>
|
</div>
|
||||||
@ -120,9 +116,7 @@
|
|||||||
<div id="resetpanel" style="display:none">
|
<div id="resetpanel" style="display:none">
|
||||||
<form method="post">
|
<form method="post">
|
||||||
<input type="hidden" name="action" value="resetaccount">
|
<input type="hidden" name="action" value="resetaccount">
|
||||||
<div id="message3">
|
<div id="message3"></div>
|
||||||
{{{message}}}
|
|
||||||
</div>
|
|
||||||
<div>
|
<div>
|
||||||
<b>Account Reset</b>
|
<b>Account Reset</b>
|
||||||
</div>
|
</div>
|
||||||
@ -146,9 +140,7 @@
|
|||||||
<form method="post" autocomplete="off">
|
<form method="post" autocomplete="off">
|
||||||
<input type="hidden" name="action" value="tokenlogin">
|
<input type="hidden" name="action" value="tokenlogin">
|
||||||
<input type="hidden" name="hwstate" value="{{{hwstate}}}">
|
<input type="hidden" name="hwstate" value="{{{hwstate}}}">
|
||||||
<div id="message4">
|
<div id="message4"></div>
|
||||||
{{{message}}}
|
|
||||||
</div>
|
|
||||||
<table>
|
<table>
|
||||||
<tbody><tr>
|
<tbody><tr>
|
||||||
<td align="right" width="100">Login token:</td>
|
<td align="right" width="100">Login token:</td>
|
||||||
@ -170,9 +162,7 @@
|
|||||||
<div id="resettokenpanel" style="display:none">
|
<div id="resettokenpanel" style="display:none">
|
||||||
<form method="post">
|
<form method="post">
|
||||||
<input type="hidden" name="action" value="resetaccount">
|
<input type="hidden" name="action" value="resetaccount">
|
||||||
<div id="message5">
|
<div id="message5"></div>
|
||||||
{{{message}}}
|
|
||||||
</div>
|
|
||||||
<table>
|
<table>
|
||||||
<tbody><tr>
|
<tbody><tr>
|
||||||
<td align="right" width="100">Login token:</td>
|
<td align="right" width="100">Login token:</td>
|
||||||
@ -194,9 +184,7 @@
|
|||||||
<div id="resetpasswordpanel" style="display:none;position:relative">
|
<div id="resetpasswordpanel" style="display:none;position:relative">
|
||||||
<form method="post">
|
<form method="post">
|
||||||
<input type="hidden" name="action" value="resetpassword">
|
<input type="hidden" name="action" value="resetpassword">
|
||||||
<div id="message6">
|
<div id="message6"></div>
|
||||||
{{{message}}}
|
|
||||||
</div>
|
|
||||||
<div id="rpasswordPolicyCallout" style="display:none"></div>
|
<div id="rpasswordPolicyCallout" style="display:none"></div>
|
||||||
<table>
|
<table>
|
||||||
<tbody><tr>
|
<tbody><tr>
|
||||||
@ -274,6 +262,20 @@
|
|||||||
var nightMode = (getstore('_nightMode', '0') == '1');
|
var nightMode = (getstore('_nightMode', '0') == '1');
|
||||||
var publicKeyCredentialRequestOptions = null;
|
var publicKeyCredentialRequestOptions = null;
|
||||||
|
|
||||||
|
// Display the right server message
|
||||||
|
var messageid = parseInt('{{{messageid}}}');
|
||||||
|
var okmessages = ['', "Hold on, reset mail sent."];
|
||||||
|
var failmessages = ["Unable to create account.", "Account limit reached.", "Existing account with this email address.", "Invalid account creation token.", "Username already exists.", "Password rejected, use a different one.", "Invalid email.", "Account not found.", "Invalid token, try again.", "Unable to sent email.", "Account locked.", "Access denied.", "Login failed, check username and password.", "Password change requested.", "IP address blocked, try again later."];
|
||||||
|
if (messageid > 0) {
|
||||||
|
var msg = '';
|
||||||
|
if ((messageid < 100) && (messageid < okmessages.length)) { msg = okmessages[messageid]; }
|
||||||
|
else if ((messageid >= 100) && ((messageid - 100) < failmessages.length)) { msg = failmessages[messageid - 100]; }
|
||||||
|
if (msg != '') {
|
||||||
|
if (messageid >= 100) { msg = ('<span class="msg error"><b style=color:#8C001A>' + msg + '<b></span><br /><br />'); } else { msg = ('<span class="msg success"><b>' + msg + '</b></span><br /><br />'); }
|
||||||
|
for (var i = 1; i < 7; i++) { QH('message' + i, msg); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// If URL arguments are provided, add them to form posts
|
// If URL arguments are provided, add them to form posts
|
||||||
if (window.location.href.indexOf('?') > 0) {
|
if (window.location.href.indexOf('?') > 0) {
|
||||||
var urlargs = window.location.href.substring(window.location.href.indexOf('?'));
|
var urlargs = window.location.href.substring(window.location.href.indexOf('?'));
|
||||||
@ -351,9 +353,7 @@
|
|||||||
QE('tokenOkButton', true);
|
QE('tokenOkButton', true);
|
||||||
Q('tokenOkButton').click();
|
Q('tokenOkButton').click();
|
||||||
},
|
},
|
||||||
function (error) {
|
function (error) { console.log('credentials-get error', error); }
|
||||||
console.log('credentials-get error', error);
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
246
webserver.js
246
webserver.js
@ -434,7 +434,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
|||||||
if (req.session.userid) {
|
if (req.session.userid) {
|
||||||
next();
|
next();
|
||||||
} else {
|
} else {
|
||||||
req.session.error = 'Access denied!';
|
req.session.messageid = 111; // Access denied.
|
||||||
res.redirect(domain.url + 'login');
|
res.redirect(domain.url + 'login');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -496,11 +496,8 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
|||||||
|
|
||||||
function handleLogoutRequest(req, res) {
|
function handleLogoutRequest(req, res) {
|
||||||
const domain = checkUserIpAddress(req, res);
|
const domain = checkUserIpAddress(req, res);
|
||||||
if ((domain == null) || (domain.auth == 'sspi')) {
|
if ((domain == null) || (domain.auth == 'sspi')) { parent.debug('web', 'handleLogoutRequest: failed checks.'); res.sendStatus(404); return; }
|
||||||
parent.debug('web', 'handleLogoutRequest: failed checks.');
|
if ((domain.loginkey != null) && (domain.loginkey != req.query.key)) { res.sendStatus(404); return; } // Check 3FA URL key
|
||||||
res.sendStatus(404);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
res.set({ 'Cache-Control': 'no-cache, no-store, must-revalidate', 'Pragma': 'no-cache', 'Expires': '0' });
|
res.set({ 'Cache-Control': 'no-cache, no-store, must-revalidate', 'Pragma': 'no-cache', 'Expires': '0' });
|
||||||
// Destroy the user's session to log them out will be re-created next request
|
// Destroy the user's session to log them out will be re-created next request
|
||||||
@ -509,7 +506,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
|||||||
if (user != null) { obj.parent.DispatchEvent(['*'], obj, { etype: 'user', userid: user._id, username: user.name, action: 'logout', msg: 'Account logout', domain: domain.id }); }
|
if (user != null) { obj.parent.DispatchEvent(['*'], obj, { etype: 'user', userid: user._id, username: user.name, action: 'logout', msg: 'Account logout', domain: domain.id }); }
|
||||||
}
|
}
|
||||||
req.session = null;
|
req.session = null;
|
||||||
res.redirect(domain.url);
|
if (req.query.key != null) { res.redirect(domain.url + "?key=" + req.query.key); } else { res.redirect(domain.url); }
|
||||||
parent.debug('web', 'handleLogoutRequest: success.');
|
parent.debug('web', 'handleLogoutRequest: success.');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -638,6 +635,17 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
|||||||
function handleLoginRequest(req, res, direct) {
|
function handleLoginRequest(req, res, direct) {
|
||||||
const domain = checkUserIpAddress(req, res);
|
const domain = checkUserIpAddress(req, res);
|
||||||
if (domain == null) { parent.debug('web', 'handleLoginRequest: invalid domain'); res.sendStatus(404); return; }
|
if (domain == null) { parent.debug('web', 'handleLoginRequest: invalid domain'); res.sendStatus(404); return; }
|
||||||
|
if ((domain.loginkey != null) && (domain.loginkey != req.query.key)) { res.sendStatus(404); return; } // Check 3FA URL key
|
||||||
|
|
||||||
|
// Check if this is a banned ip address
|
||||||
|
if (obj.checkAllowLogin(req) == false) {
|
||||||
|
// Wait and redirect the user
|
||||||
|
setTimeout(function () {
|
||||||
|
req.session.messageid = 114; // IP address blocked, try again later.
|
||||||
|
if (direct === true) { handleRootRequestEx(req, res, domain); } else { res.redirect(domain.url + getQueryPortion(req)); }
|
||||||
|
}, 2000 + (obj.crypto.randomBytes(2).readUInt16BE(0) % 4095));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Normally, use the body username/password. If this is a token, use the username/password in the session.
|
// Normally, use the body username/password. If this is a token, use the username/password in the session.
|
||||||
var xusername = req.body.username, xpassword = req.body.password;
|
var xusername = req.body.username, xpassword = req.body.password;
|
||||||
@ -657,8 +665,10 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
|||||||
// 2-step auth is required, but the token is not present or not valid.
|
// 2-step auth is required, but the token is not present or not valid.
|
||||||
if ((req.body.token != null) || (req.body.hwtoken != null)) {
|
if ((req.body.token != null) || (req.body.hwtoken != null)) {
|
||||||
randomWaitTime = 2000 + (obj.crypto.randomBytes(2).readUInt16BE(0) % 4095); // This is a fail, wait a random time. 2 to 6 seconds.
|
randomWaitTime = 2000 + (obj.crypto.randomBytes(2).readUInt16BE(0) % 4095); // This is a fail, wait a random time. 2 to 6 seconds.
|
||||||
req.session.error = '<b style=color:#8C001A>Invalid token, try again.</b>';
|
req.session.messageid = 108; // Invalid token, try again.
|
||||||
parent.debug('web', 'handleLoginRequest: invalid 2FA token');
|
parent.debug('web', 'handleLoginRequest: invalid 2FA token');
|
||||||
|
obj.parent.DispatchEvent(['*', 'server-users', 'user/' + domain.id + '/' + user.name], obj, { action: 'authfail', username: user.name, userid: 'user/' + domain.id + '/' + user.name, domain: domain.id, msg: 'User login attempt with incorrect 2nd factor from ' + cleanRemoteAddr(req.ip) });
|
||||||
|
obj.setbadLogin(req);
|
||||||
} else {
|
} else {
|
||||||
parent.debug('web', 'handleLoginRequest: 2FA token required');
|
parent.debug('web', 'handleLoginRequest: 2FA token required');
|
||||||
}
|
}
|
||||||
@ -686,12 +696,19 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
|||||||
// Login failed, wait a random delay
|
// Login failed, wait a random delay
|
||||||
setTimeout(function () {
|
setTimeout(function () {
|
||||||
// If the account is locked, display that.
|
// If the account is locked, display that.
|
||||||
|
if (typeof xusername == 'string') {
|
||||||
|
var xuserid = 'user/' + domain.id + '/' + xusername.toLowerCase();
|
||||||
if (err == 'locked') {
|
if (err == 'locked') {
|
||||||
parent.debug('web', 'handleLoginRequest: login failed, locked account');
|
parent.debug('web', 'handleLoginRequest: login failed, locked account');
|
||||||
req.session.error = '<b style=color:#8C001A>Account locked.</b>';
|
req.session.messageid = 110; // Account locked.
|
||||||
|
obj.parent.DispatchEvent(['*', 'server-users', xuserid], obj, { action: 'authfail', userid: xuserid, username: xusername, domain: domain.id, msg: 'User login attempt on locked account from ' + cleanRemoteAddr(req.ip) });
|
||||||
|
obj.setbadLogin(req);
|
||||||
} else {
|
} else {
|
||||||
parent.debug('web', 'handleLoginRequest: login failed, bad username and password');
|
parent.debug('web', 'handleLoginRequest: login failed, bad username and password');
|
||||||
req.session.error = '<b style=color:#8C001A>Login failed, check username and password.</b>';
|
req.session.messageid = 112; // Login failed, check username and password.
|
||||||
|
obj.parent.DispatchEvent(['*', 'server-users', xuserid], obj, { action: 'authfail', userid: xuserid, username: xusername, domain: domain.id, msg: 'Invalid user login attempt from ' + cleanRemoteAddr(req.ip) });
|
||||||
|
obj.setbadLogin(req);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clean up login mode and display password hint if present.
|
// Clean up login mode and display password hint if present.
|
||||||
@ -714,7 +731,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
|||||||
// Request a password change
|
// Request a password change
|
||||||
parent.debug('web', 'handleLoginRequest: login ok, password change requested');
|
parent.debug('web', 'handleLoginRequest: login ok, password change requested');
|
||||||
req.session.loginmode = '6';
|
req.session.loginmode = '6';
|
||||||
req.session.error = '<b style=color:#8C001A>Password change requested.</b>';
|
req.session.messageid = 113; // Password change requested.
|
||||||
req.session.resettokenusername = xusername;
|
req.session.resettokenusername = xusername;
|
||||||
req.session.resettokenpassword = xpassword;
|
req.session.resettokenpassword = xpassword;
|
||||||
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)); }
|
||||||
@ -722,6 +739,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Save login time
|
// Save login time
|
||||||
|
user.pastlogin = user.login;
|
||||||
user.login = Math.floor(Date.now() / 1000);
|
user.login = Math.floor(Date.now() / 1000);
|
||||||
obj.db.SetUser(user);
|
obj.db.SetUser(user);
|
||||||
|
|
||||||
@ -733,13 +751,11 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
|||||||
// Regenerate session when signing in to prevent fixation
|
// Regenerate session when signing in to prevent fixation
|
||||||
//req.session.regenerate(function () {
|
//req.session.regenerate(function () {
|
||||||
// Store the user's primary key in the session store to be retrieved, or in this case the entire user object
|
// Store the user's primary key in the session store to be retrieved, or in this case the entire user object
|
||||||
// req.session.success = 'Authenticated as ' + user.name + 'click to <a href="/logout">logout</a>. You may now access <a href="/restricted">/restricted</a>.';
|
|
||||||
delete req.session.loginmode;
|
delete req.session.loginmode;
|
||||||
delete req.session.tokenusername;
|
delete req.session.tokenusername;
|
||||||
delete req.session.tokenpassword;
|
delete req.session.tokenpassword;
|
||||||
delete req.session.tokenemail;
|
delete req.session.tokenemail;
|
||||||
delete req.session.success;
|
delete req.session.messageid;
|
||||||
delete req.session.error;
|
|
||||||
delete req.session.passhint;
|
delete req.session.passhint;
|
||||||
req.session.userid = userid;
|
req.session.userid = userid;
|
||||||
req.session.domainid = domain.id;
|
req.session.domainid = domain.id;
|
||||||
@ -772,11 +788,8 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
|||||||
|
|
||||||
function handleCreateAccountRequest(req, res, direct) {
|
function handleCreateAccountRequest(req, res, direct) {
|
||||||
const domain = checkUserIpAddress(req, res);
|
const domain = checkUserIpAddress(req, res);
|
||||||
if ((domain == null) || (domain.auth == 'sspi') || (domain.auth == 'ldap')) {
|
if ((domain == null) || (domain.auth == 'sspi') || (domain.auth == 'ldap')) { parent.debug('web', 'handleCreateAccountRequest: failed checks.'); res.sendStatus(404); return; }
|
||||||
parent.debug('web', 'handleCreateAccountRequest: failed checks.');
|
if ((domain.loginkey != null) && (domain.loginkey != req.query.key)) { res.sendStatus(404); return; } // Check 3FA URL key
|
||||||
res.sendStatus(404);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Always lowercase the email address
|
// Always lowercase the email address
|
||||||
if (req.body.email) { req.body.email = req.body.email.toLowerCase(); }
|
if (req.body.email) { req.body.email = req.body.email.toLowerCase(); }
|
||||||
@ -802,7 +815,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
|||||||
if (i == -1) {
|
if (i == -1) {
|
||||||
parent.debug('web', 'handleCreateAccountRequest: unable to create account (1)');
|
parent.debug('web', 'handleCreateAccountRequest: unable to create account (1)');
|
||||||
req.session.loginmode = '2';
|
req.session.loginmode = '2';
|
||||||
req.session.error = '<b style=color:#8C001A>Unable to create account.</b>';
|
req.session.messageid = 100; // Unable to create account.
|
||||||
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)); }
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -811,7 +824,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
|||||||
if (emailok == false) {
|
if (emailok == false) {
|
||||||
parent.debug('web', 'handleCreateAccountRequest: unable to create account (2)');
|
parent.debug('web', 'handleCreateAccountRequest: unable to create account (2)');
|
||||||
req.session.loginmode = '2';
|
req.session.loginmode = '2';
|
||||||
req.session.error = '<b style=color:#8C001A>Unable to create account.</b>';
|
req.session.messageid = 100; // Unable to create account.
|
||||||
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)); }
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -822,13 +835,13 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
|||||||
if (maxExceed) {
|
if (maxExceed) {
|
||||||
parent.debug('web', 'handleCreateAccountRequest: account limit reached');
|
parent.debug('web', 'handleCreateAccountRequest: account limit reached');
|
||||||
req.session.loginmode = '2';
|
req.session.loginmode = '2';
|
||||||
req.session.error = '<b style=color:#8C001A>Account limit reached.</b>';
|
req.session.messageid = 101; // Account limit reached.
|
||||||
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)); }
|
||||||
} else {
|
} else {
|
||||||
if (!obj.common.validateUsername(req.body.username, 1, 64) || !obj.common.validateEmail(req.body.email, 1, 256) || !obj.common.validateString(req.body.password1, 1, 256) || !obj.common.validateString(req.body.password2, 1, 256) || (req.body.password1 != req.body.password2) || req.body.username == '~' || !obj.common.checkPasswordRequirements(req.body.password1, domain.passwordrequirements)) {
|
if (!obj.common.validateUsername(req.body.username, 1, 64) || !obj.common.validateEmail(req.body.email, 1, 256) || !obj.common.validateString(req.body.password1, 1, 256) || !obj.common.validateString(req.body.password2, 1, 256) || (req.body.password1 != req.body.password2) || req.body.username == '~' || !obj.common.checkPasswordRequirements(req.body.password1, domain.passwordrequirements)) {
|
||||||
parent.debug('web', 'handleCreateAccountRequest: unable to create account (3)');
|
parent.debug('web', 'handleCreateAccountRequest: unable to create account (3)');
|
||||||
req.session.loginmode = '2';
|
req.session.loginmode = '2';
|
||||||
req.session.error = '<b style=color:#8C001A>Unable to create account.</b>';
|
req.session.messageid = 100; // Unable to create account.
|
||||||
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)); }
|
||||||
} else {
|
} else {
|
||||||
// Check if this email was already verified
|
// Check if this email was already verified
|
||||||
@ -836,14 +849,14 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
|||||||
if (docs.length > 0) {
|
if (docs.length > 0) {
|
||||||
parent.debug('web', 'handleCreateAccountRequest: Existing account with this email address');
|
parent.debug('web', 'handleCreateAccountRequest: Existing account with this email address');
|
||||||
req.session.loginmode = '2';
|
req.session.loginmode = '2';
|
||||||
req.session.error = '<b style=color:#8C001A>Existing account with this email address.</b>';
|
req.session.messageid = 102; // Existing account with this email address.
|
||||||
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)); }
|
||||||
} else {
|
} else {
|
||||||
// Check if there is domain.newAccountToken, check if supplied token is valid
|
// Check if there is domain.newAccountToken, check if supplied token is valid
|
||||||
if ((domain.newaccountspass != null) && (domain.newaccountspass != '') && (req.body.anewaccountpass != domain.newaccountspass)) {
|
if ((domain.newaccountspass != null) && (domain.newaccountspass != '') && (req.body.anewaccountpass != domain.newaccountspass)) {
|
||||||
parent.debug('web', 'handleCreateAccountRequest: Invalid account creation token');
|
parent.debug('web', 'handleCreateAccountRequest: Invalid account creation token');
|
||||||
req.session.loginmode = '2';
|
req.session.loginmode = '2';
|
||||||
req.session.error = '<b style=color:#8C001A>Invalid account creation token.</b>';
|
req.session.messageid = 103; // Invalid account creation token.
|
||||||
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)); }
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -851,7 +864,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
|||||||
if (obj.users['user/' + domain.id + '/' + req.body.username.toLowerCase()]) {
|
if (obj.users['user/' + domain.id + '/' + req.body.username.toLowerCase()]) {
|
||||||
parent.debug('web', 'handleCreateAccountRequest: Username already exists');
|
parent.debug('web', 'handleCreateAccountRequest: Username already exists');
|
||||||
req.session.loginmode = '2';
|
req.session.loginmode = '2';
|
||||||
req.session.error = '<b style=color:#8C001A>Username already exists.</b>';
|
req.session.messageid = 104; // Username already exists.
|
||||||
} else {
|
} else {
|
||||||
var user = { type: 'user', _id: 'user/' + domain.id + '/' + req.body.username.toLowerCase(), name: req.body.username, email: req.body.email, creation: Math.floor(Date.now() / 1000), login: Math.floor(Date.now() / 1000), domain: domain.id };
|
var user = { type: 'user', _id: 'user/' + domain.id + '/' + req.body.username.toLowerCase(), name: req.body.username, email: req.body.email, creation: Math.floor(Date.now() / 1000), login: Math.floor(Date.now() / 1000), domain: domain.id };
|
||||||
if (domain.newaccountsrights) { user.siteadmin = domain.newaccountsrights; }
|
if (domain.newaccountsrights) { user.siteadmin = domain.newaccountsrights; }
|
||||||
@ -887,6 +900,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
|||||||
// Called to process an account password reset
|
// Called to process an account password reset
|
||||||
function handleResetPasswordRequest(req, res, direct) {
|
function handleResetPasswordRequest(req, res, direct) {
|
||||||
const domain = checkUserIpAddress(req, res);
|
const domain = checkUserIpAddress(req, res);
|
||||||
|
if ((domain.loginkey != null) && (domain.loginkey != req.query.key)) { res.sendStatus(404); return; } // Check 3FA URL key
|
||||||
|
|
||||||
// Check everything is ok
|
// Check everything is ok
|
||||||
if ((domain == null) || (domain.auth == 'sspi') || (domain.auth == 'ldap') || (typeof req.body.rpassword1 != 'string') || (typeof req.body.rpassword2 != 'string') || (req.body.rpassword1 != req.body.rpassword2) || (typeof req.body.rpasswordhint != 'string') || (req.session == null) || (typeof req.session.resettokenusername != 'string') || (typeof req.session.resettokenpassword != 'string')) {
|
if ((domain == null) || (domain.auth == 'sspi') || (domain.auth == 'ldap') || (typeof req.body.rpassword1 != 'string') || (typeof req.body.rpassword2 != 'string') || (req.body.rpassword1 != req.body.rpassword2) || (typeof req.body.rpasswordhint != 'string') || (req.session == null) || (typeof req.session.resettokenusername != 'string') || (typeof req.session.resettokenpassword != 'string')) {
|
||||||
@ -897,8 +911,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
|||||||
delete req.session.resettokenusername;
|
delete req.session.resettokenusername;
|
||||||
delete req.session.resettokenpassword;
|
delete req.session.resettokenpassword;
|
||||||
delete req.session.tokenemail;
|
delete req.session.tokenemail;
|
||||||
delete req.session.success;
|
delete req.session.messageid;
|
||||||
delete req.session.error;
|
|
||||||
delete req.session.passhint;
|
delete req.session.passhint;
|
||||||
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)); }
|
||||||
return;
|
return;
|
||||||
@ -914,7 +927,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
|||||||
if (!obj.common.checkPasswordRequirements(req.body.rpassword1, domain.passwordrequirements)) {
|
if (!obj.common.checkPasswordRequirements(req.body.rpassword1, domain.passwordrequirements)) {
|
||||||
parent.debug('web', 'handleResetPasswordRequest: password rejected, use a different one (1)');
|
parent.debug('web', 'handleResetPasswordRequest: password rejected, use a different one (1)');
|
||||||
req.session.loginmode = '6';
|
req.session.loginmode = '6';
|
||||||
req.session.error = '<b style=color:#8C001A>Password rejected, use a different one.</b>';
|
req.session.messageid = 105; // Password rejected, use a different one.
|
||||||
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)); }
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -925,7 +938,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
|||||||
// This is the same password, request a password change again
|
// This is the same password, request a password change again
|
||||||
parent.debug('web', 'handleResetPasswordRequest: password rejected, use a different one (2)');
|
parent.debug('web', 'handleResetPasswordRequest: password rejected, use a different one (2)');
|
||||||
req.session.loginmode = '6';
|
req.session.loginmode = '6';
|
||||||
req.session.error = '<b style=color:#8C001A>Password rejected, use a different one.</b>';
|
req.session.messageid = 105; // Password rejected, use a different one.
|
||||||
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)); }
|
||||||
} else {
|
} else {
|
||||||
// Update the password, use a different salt.
|
// Update the password, use a different salt.
|
||||||
@ -959,8 +972,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
|||||||
delete req.session.resettokenusername;
|
delete req.session.resettokenusername;
|
||||||
delete req.session.resettokenpassword;
|
delete req.session.resettokenpassword;
|
||||||
delete req.session.tokenemail;
|
delete req.session.tokenemail;
|
||||||
delete req.session.success;
|
delete req.session.messageid;
|
||||||
delete req.session.error;
|
|
||||||
delete req.session.passhint;
|
delete req.session.passhint;
|
||||||
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)); }
|
||||||
return;
|
return;
|
||||||
@ -971,11 +983,8 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
|||||||
// Called to process an account reset request
|
// Called to process an account reset request
|
||||||
function handleResetAccountRequest(req, res, direct) {
|
function handleResetAccountRequest(req, res, direct) {
|
||||||
const domain = checkUserIpAddress(req, res);
|
const domain = checkUserIpAddress(req, res);
|
||||||
if ((domain == null) || (domain.auth == 'sspi') || (domain.auth == 'ldap') || (obj.args.lanonly == true) || (obj.parent.certificates.CommonName == null) || (obj.parent.certificates.CommonName.indexOf('.') == -1)) {
|
if ((domain == null) || (domain.auth == 'sspi') || (domain.auth == 'ldap') || (obj.args.lanonly == true) || (obj.parent.certificates.CommonName == null) || (obj.parent.certificates.CommonName.indexOf('.') == -1)) { parent.debug('web', 'handleResetAccountRequest: check failed'); res.sendStatus(404); return; }
|
||||||
parent.debug('web', 'handleResetAccountRequest: check failed');
|
if ((domain.loginkey != null) && (domain.loginkey != req.query.key)) { res.sendStatus(404); return; } // Check 3FA URL key
|
||||||
res.sendStatus(404);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Always lowercase the email address
|
// Always lowercase the email address
|
||||||
if (req.body.email) { req.body.email = req.body.email.toLowerCase(); }
|
if (req.body.email) { req.body.email = req.body.email.toLowerCase(); }
|
||||||
@ -988,14 +997,14 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
|||||||
if (!email || checkEmail(email) == false) {
|
if (!email || checkEmail(email) == false) {
|
||||||
parent.debug('web', 'handleResetAccountRequest: Invalid email');
|
parent.debug('web', 'handleResetAccountRequest: Invalid email');
|
||||||
req.session.loginmode = '3';
|
req.session.loginmode = '3';
|
||||||
req.session.error = '<b style=color:#8C001A>Invalid email.</b>';
|
req.session.messageid = 106; // Invalid email.
|
||||||
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)); }
|
||||||
} else {
|
} else {
|
||||||
obj.db.GetUserWithVerifiedEmail(domain.id, email, function (err, docs) {
|
obj.db.GetUserWithVerifiedEmail(domain.id, email, function (err, docs) {
|
||||||
if ((err != null) || (docs.length == 0)) {
|
if ((err != null) || (docs.length == 0)) {
|
||||||
parent.debug('web', 'handleResetAccountRequest: Account not found');
|
parent.debug('web', 'handleResetAccountRequest: Account not found');
|
||||||
req.session.loginmode = '3';
|
req.session.loginmode = '3';
|
||||||
req.session.error = '<b style=color:#8C001A>Account not found.</b>';
|
req.session.messageid = 107; // Account not found.
|
||||||
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)); }
|
||||||
} else {
|
} else {
|
||||||
// If many accounts have the same validated e-mail, we are going to use the first one for display, but sent a reset email for all accounts.
|
// If many accounts have the same validated e-mail, we are going to use the first one for display, but sent a reset email for all accounts.
|
||||||
@ -1009,7 +1018,11 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
|||||||
if (i == 0) {
|
if (i == 0) {
|
||||||
// 2-step auth is required, but the token is not present or not valid.
|
// 2-step auth is required, but the token is not present or not valid.
|
||||||
parent.debug('web', 'handleResetAccountRequest: Invalid 2FA token, try again');
|
parent.debug('web', 'handleResetAccountRequest: Invalid 2FA token, try again');
|
||||||
if ((req.body.token != null) || (req.body.hwtoken != null)) { req.session.error = '<b style=color:#8C001A>Invalid token, try again.</b>'; }
|
if ((req.body.token != null) || (req.body.hwtoken != null)) {
|
||||||
|
req.session.messageid = 108; // Invalid token, try again.
|
||||||
|
obj.parent.DispatchEvent(['*', 'server-users', 'user/' + domain.id + '/' + user.name], obj, { action: 'authfail', username: user.name, userid: 'user/' + domain.id + '/' + user.name, domain: domain.id, msg: 'User login attempt with incorrect 2nd factor from ' + cleanRemoteAddr(req.ip) });
|
||||||
|
obj.setbadLogin(req);
|
||||||
|
}
|
||||||
req.session.loginmode = '5';
|
req.session.loginmode = '5';
|
||||||
req.session.tokenemail = email;
|
req.session.tokenemail = email;
|
||||||
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)); }
|
||||||
@ -1022,14 +1035,14 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
|||||||
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';
|
||||||
req.session.error = '<b style=color:darkgreen>Hold on, reset mail sent.</b>';
|
req.session.messageid = 1; // Hold on, reset mail sent.
|
||||||
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)); }
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (i == 0) {
|
if (i == 0) {
|
||||||
parent.debug('web', 'handleResetAccountRequest: Unable to sent email.');
|
parent.debug('web', 'handleResetAccountRequest: Unable to sent email.');
|
||||||
req.session.loginmode = '3';
|
req.session.loginmode = '3';
|
||||||
req.session.error = '<b style=color:#8C001A>Unable to sent email.</b>';
|
req.session.messageid = 109; // Unable to sent email.
|
||||||
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)); }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1042,14 +1055,14 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
|||||||
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';
|
||||||
req.session.error = '<b style=color:darkgreen>Hold on, reset mail sent.</b>';
|
req.session.messageid = 1; // Hold on, reset mail sent.
|
||||||
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)); }
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (i == 0) {
|
if (i == 0) {
|
||||||
parent.debug('web', 'handleResetAccountRequest: Unable to sent email.');
|
parent.debug('web', 'handleResetAccountRequest: Unable to sent email.');
|
||||||
req.session.loginmode = '3';
|
req.session.loginmode = '3';
|
||||||
req.session.error = '<b style=color:#8C001A>Unable to sent email.</b>';
|
req.session.messageid = 109; // Unable to sent email.
|
||||||
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)); }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1063,11 +1076,8 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
|||||||
// Called to process a web based email verification request
|
// Called to process a web based email verification request
|
||||||
function handleCheckMailRequest(req, res) {
|
function handleCheckMailRequest(req, res) {
|
||||||
const domain = checkUserIpAddress(req, res);
|
const domain = checkUserIpAddress(req, res);
|
||||||
if ((domain == null) || (domain.auth == 'sspi') || (domain.auth == 'ldap')) {
|
if ((domain == null) || (domain.auth == 'sspi') || (domain.auth == 'ldap')) { parent.debug('web', 'handleCheckMailRequest: failed checks.'); res.sendStatus(404); return; }
|
||||||
parent.debug('web', 'handleCheckMailRequest: failed checks.');
|
if ((domain.loginkey != null) && (domain.loginkey != req.query.key)) { res.sendStatus(404); return; } // Check 3FA URL key
|
||||||
res.sendStatus(404);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
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, obj.parent.mailserver.mailCookieEncryptionKey, 30);
|
||||||
@ -1168,11 +1178,9 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
|||||||
// Called to process an agent invite request
|
// Called to process an agent invite request
|
||||||
function handleAgentInviteRequest(req, res) {
|
function handleAgentInviteRequest(req, res) {
|
||||||
const domain = getDomain(req);
|
const domain = getDomain(req);
|
||||||
if ((domain == null) || ((req.query.m == null) && (req.query.c == null))) {
|
if ((domain == null) || ((req.query.m == null) && (req.query.c == null))) { parent.debug('web', 'handleAgentInviteRequest: failed checks.'); res.sendStatus(404); return; }
|
||||||
parent.debug('web', 'handleAgentInviteRequest: failed checks.');
|
if ((domain.loginkey != null) && (domain.loginkey != req.query.key)) { res.sendStatus(404); return; } // Check 3FA URL key
|
||||||
res.sendStatus(404);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (req.query.c != null) {
|
if (req.query.c != null) {
|
||||||
// A cookie is specified in the query string, use that
|
// A cookie is specified in the query string, use that
|
||||||
var cookie = obj.parent.decodeCookie(req.query.c, obj.parent.invitationLinkEncryptionKey);
|
var cookie = obj.parent.decodeCookie(req.query.c, obj.parent.invitationLinkEncryptionKey);
|
||||||
@ -1198,11 +1206,8 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
|||||||
function handleDeleteAccountRequest(req, res, direct) {
|
function handleDeleteAccountRequest(req, res, direct) {
|
||||||
parent.debug('web', 'handleDeleteAccountRequest()');
|
parent.debug('web', 'handleDeleteAccountRequest()');
|
||||||
const domain = checkUserIpAddress(req, res);
|
const domain = checkUserIpAddress(req, res);
|
||||||
if ((domain == null) || (domain.auth == 'sspi') || (domain.auth == 'ldap')) {
|
if ((domain == null) || (domain.auth == 'sspi') || (domain.auth == 'ldap')) { parent.debug('web', 'handleDeleteAccountRequest: failed checks.'); res.sendStatus(404); return; }
|
||||||
parent.debug('web', 'handleDeleteAccountRequest: failed checks.');
|
if ((domain.loginkey != null) && (domain.loginkey != req.query.key)) { res.sendStatus(404); return; } // Check 3FA URL key
|
||||||
res.sendStatus(404);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var user = null;
|
var user = null;
|
||||||
if (req.body.authcookie) {
|
if (req.body.authcookie) {
|
||||||
@ -1288,11 +1293,8 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
|||||||
// Handle password changes
|
// Handle password changes
|
||||||
function handlePasswordChangeRequest(req, res, direct) {
|
function handlePasswordChangeRequest(req, res, direct) {
|
||||||
const domain = checkUserIpAddress(req, res);
|
const domain = checkUserIpAddress(req, res);
|
||||||
if ((domain == null) || (domain.auth == 'sspi') || (domain.auth == 'ldap')) {
|
if ((domain == null) || (domain.auth == 'sspi') || (domain.auth == 'ldap')) { parent.debug('web', 'handlePasswordChangeRequest: failed checks (1).'); res.sendStatus(404); return; }
|
||||||
parent.debug('web', 'handlePasswordChangeRequest: failed checks (1).');
|
if ((domain.loginkey != null) && (domain.loginkey != req.query.key)) { res.sendStatus(404); return; } // Check 3FA URL key
|
||||||
res.sendStatus(404);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if the user is logged and we have all required parameters
|
// Check if the user is logged and we have all required parameters
|
||||||
if (!req.session || !req.session.userid || !req.body.apassword0 || !req.body.apassword1 || (req.body.apassword1 != req.body.apassword2) || (req.session.domainid != domain.id)) {
|
if (!req.session || !req.session.userid || !req.body.apassword0 || !req.body.apassword1 || (req.body.apassword1 != req.body.apassword2) || (req.session.domainid != domain.id)) {
|
||||||
@ -1333,6 +1335,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
|||||||
function handleRootRequest(req, res, direct) {
|
function handleRootRequest(req, res, direct) {
|
||||||
const domain = checkUserIpAddress(req, res);
|
const domain = checkUserIpAddress(req, res);
|
||||||
if (domain == null) { parent.debug('web', 'handleRootRequest: invalid domain.'); res.sendStatus(404); return; }
|
if (domain == null) { parent.debug('web', 'handleRootRequest: invalid domain.'); res.sendStatus(404); return; }
|
||||||
|
if ((domain.loginkey != null) && (domain.loginkey != req.query.key)) { res.sendStatus(404); return; } // Check 3FA URL key
|
||||||
if (!obj.args) { parent.debug('web', 'handleRootRequest: no obj.args.'); res.sendStatus(500); return; }
|
if (!obj.args) { parent.debug('web', 'handleRootRequest: no obj.args.'); res.sendStatus(500); return; }
|
||||||
|
|
||||||
if ((domain.sspi != null) && ((req.query.login == null) || (obj.parent.loginCookieEncryptionKey == null))) {
|
if ((domain.sspi != null) && ((req.query.login == null) || (obj.parent.loginCookieEncryptionKey == null))) {
|
||||||
@ -1466,7 +1469,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
|||||||
delete req.session.domainid;
|
delete req.session.domainid;
|
||||||
delete req.session.currentNode;
|
delete req.session.currentNode;
|
||||||
delete req.session.passhint;
|
delete req.session.passhint;
|
||||||
req.session.error = '<b style=color:#8C001A>Account locked.</b>';
|
req.session.messageid = 110; // Account locked.
|
||||||
res.redirect(domain.url + getQueryPortion(req)); // BAD***
|
res.redirect(domain.url + getQueryPortion(req)); // BAD***
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1519,7 +1522,8 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
|||||||
const authRelayCookie = obj.parent.encodeCookie({ ruserid: user._id, domainid: domain.id }, obj.parent.loginCookieEncryptionKey);
|
const authRelayCookie = obj.parent.encodeCookie({ ruserid: user._id, domainid: domain.id }, obj.parent.loginCookieEncryptionKey);
|
||||||
|
|
||||||
// Send the master web application
|
// Send the master web application
|
||||||
if ((!obj.args.user) && (obj.args.nousers != true) && (nologout == false)) { logoutcontrol += ' <a href=' + domain.url + 'logout?' + Math.random() + ' style=color:white>Logout</a>'; } // If a default user is in use or no user mode, don't display the logout button
|
var extras = (req.query.key != null) ? ('&key=' + req.query.key) : '';
|
||||||
|
if ((!obj.args.user) && (obj.args.nousers != true) && (nologout == false)) { logoutcontrol += ' <a href=' + domain.url + 'logout?' + Math.random() + extras + ' style=color:white>Logout</a>'; } // If a default user is in use or no user mode, don't display the logout button
|
||||||
var httpsPort = ((obj.args.aliasport == null) ? obj.args.port : obj.args.aliasport); // Use HTTPS alias port is specified
|
var httpsPort = ((obj.args.aliasport == null) ? obj.args.port : obj.args.aliasport); // Use HTTPS alias port is specified
|
||||||
|
|
||||||
// Clean up the U2F challenge if needed
|
// Clean up the U2F challenge if needed
|
||||||
@ -1578,18 +1582,13 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
|||||||
if (req.session) { loginmode = req.session.loginmode; delete req.session.loginmode; } // Clear this state, if the user hits refresh, we want to go back to the login page.
|
if (req.session) { loginmode = req.session.loginmode; delete req.session.loginmode; } // Clear this state, if the user hits refresh, we want to go back to the login page.
|
||||||
|
|
||||||
// Format an error message if needed
|
// Format an error message if needed
|
||||||
var err = null, msg = null, passhint = null;
|
var passhint = null, msgid = 0;
|
||||||
if (req.session != null) {
|
if (req.session != null) {
|
||||||
err = req.session.error;
|
msgid = req.session.messageid;
|
||||||
msg = req.session.success;
|
|
||||||
if ((domain.passwordrequirements != null) && (domain.passwordrequirements.hint === true)) { passhint = EscapeHtml(req.session.passhint); }
|
if ((domain.passwordrequirements != null) && (domain.passwordrequirements.hint === true)) { passhint = EscapeHtml(req.session.passhint); }
|
||||||
delete req.session.error;
|
delete req.session.messageid;
|
||||||
delete req.session.success;
|
|
||||||
delete req.session.passhint;
|
delete req.session.passhint;
|
||||||
}
|
}
|
||||||
var message = '';
|
|
||||||
if (err != null) message = '<p class="msg error">' + err + '</p>';
|
|
||||||
if (msg != null) message = '<p class="msg success">' + msg + '</p>';
|
|
||||||
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 = ((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'))
|
||||||
|
|
||||||
// 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
|
||||||
@ -1601,12 +1600,16 @@ 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) }
|
||||||
|
|
||||||
// Render the login page
|
// Render the login page
|
||||||
render(req, res, getRenderPage('login', req), { loginmode: loginmode, rootCertLink: getRootCertLink(), domainurl: domain.url, title: domain.title, title2: domain.title2, newAccount: newAccountsAllowed, newAccountPass: (((domain.newaccountspass == null) || (domain.newaccountspass == '')) ? 0 : 1), serverDnsName: obj.getWebServerName(domain), serverPublicPort: httpsPort, emailcheck: emailcheck, features: features, sessiontime: args.sessiontime, passRequirements: passRequirements, footer: (domain.footer == null) ? '' : domain.footer, hkey: encodeURIComponent(hardwareKeyChallenge), message: message, passhint: passhint, welcometext: domain.welcometext ? encodeURIComponent(domain.welcometext).split('\'').join('\\\'') : null, hwstate: hwstate });
|
render(req, res, getRenderPage('login', req), { loginmode: loginmode, rootCertLink: getRootCertLink(), domainurl: domain.url, title: domain.title, title2: domain.title2, newAccount: newAccountsAllowed, newAccountPass: (((domain.newaccountspass == null) || (domain.newaccountspass == '')) ? 0 : 1), serverDnsName: obj.getWebServerName(domain), serverPublicPort: httpsPort, emailcheck: emailcheck, features: features, sessiontime: args.sessiontime, passRequirements: passRequirements, footer: (domain.footer == null) ? '' : domain.footer, hkey: encodeURIComponent(hardwareKeyChallenge), messageid: msgid, passhint: passhint, welcometext: domain.welcometext ? encodeURIComponent(domain.welcometext).split('\'').join('\\\'') : null, hwstate: hwstate });
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle a post request on the root
|
// Handle a post request on the root
|
||||||
function handleRootPostRequest(req, res) {
|
function handleRootPostRequest(req, res) {
|
||||||
|
const domain = checkUserIpAddress(req, res);
|
||||||
|
if (domain == null) { parent.debug('web', 'handleTermsRequest: Bad domain'); res.sendStatus(404); return; }
|
||||||
|
if ((domain.loginkey != null) && (domain.loginkey != req.query.key)) { res.sendStatus(404); return; } // Check 3FA URL key
|
||||||
parent.debug('web', 'handleRootPostRequest, action: ' + req.body.action);
|
parent.debug('web', 'handleRootPostRequest, action: ' + req.body.action);
|
||||||
|
|
||||||
switch (req.body.action) {
|
switch (req.body.action) {
|
||||||
case 'login': { handleLoginRequest(req, res, true); break; }
|
case 'login': { handleLoginRequest(req, res, true); break; }
|
||||||
case 'tokenlogin': {
|
case 'tokenlogin': {
|
||||||
@ -1647,11 +1650,8 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
|||||||
// Render the terms of service.
|
// Render the terms of service.
|
||||||
function handleTermsRequest(req, res) {
|
function handleTermsRequest(req, res) {
|
||||||
const domain = checkUserIpAddress(req, res);
|
const domain = checkUserIpAddress(req, res);
|
||||||
if (domain == null) {
|
if (domain == null) { parent.debug('web', 'handleTermsRequest: Bad domain'); res.sendStatus(404); return; }
|
||||||
parent.debug('web', 'handleTermsRequest: Bad domain');
|
if ((domain.loginkey != null) && (domain.loginkey != req.query.key)) { res.sendStatus(404); return; } // Check 3FA URL key
|
||||||
res.sendStatus(404);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// See if term.txt was loaded from the database
|
// See if term.txt was loaded from the database
|
||||||
if ((parent.configurationFiles != null) && (parent.configurationFiles['terms.txt'] != null)) {
|
if ((parent.configurationFiles != null) && (parent.configurationFiles['terms.txt'] != null)) {
|
||||||
@ -1661,7 +1661,8 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
|||||||
if (req.session.domainid != domain.id) { req.session = null; res.redirect(domain.url + getQueryPortion(req)); return; } // Check is the session is for the correct domain
|
if (req.session.domainid != domain.id) { req.session = null; res.redirect(domain.url + getQueryPortion(req)); return; } // Check is the session is for the correct domain
|
||||||
var user = obj.users[req.session.userid];
|
var user = obj.users[req.session.userid];
|
||||||
var logoutcontrol = 'Welcome ' + user.name + '.';
|
var logoutcontrol = 'Welcome ' + user.name + '.';
|
||||||
if ((domain.ldap == null) && (domain.sspi == null) && (obj.args.user == null) && (obj.args.nousers != true)) { logoutcontrol += ' <a href=' + domain.url + 'logout?' + Math.random() + ' style=color:white>Logout</a>'; } // If a default user is in use or no user mode, don't display the logout button
|
var extras = (req.query.key != null) ? ('&key=' + req.query.key) : '';
|
||||||
|
if ((domain.ldap == null) && (domain.sspi == null) && (obj.args.user == null) && (obj.args.nousers != true)) { logoutcontrol += ' <a href=' + domain.url + 'logout?' + Math.random() + extras + ' style=color:white>Logout</a>'; } // If a default user is in use or no user mode, don't display the logout button
|
||||||
render(req, res, getRenderPage('terms', req), { title: domain.title, title2: domain.title2, domainurl: domain.url, terms: encodeURIComponent(parent.configurationFiles['terms.txt'].toString()), logoutControl: logoutcontrol });
|
render(req, res, getRenderPage('terms', req), { title: domain.title, title2: domain.title2, domainurl: domain.url, terms: encodeURIComponent(parent.configurationFiles['terms.txt'].toString()), logoutControl: logoutcontrol });
|
||||||
} else {
|
} else {
|
||||||
render(req, res, getRenderPage('terms', req), { title: domain.title, title2: domain.title2, domainurl: domain.url, terms: encodeURIComponent(parent.configurationFiles['terms.txt'].toString()) });
|
render(req, res, getRenderPage('terms', req), { title: domain.title, title2: domain.title2, domainurl: domain.url, terms: encodeURIComponent(parent.configurationFiles['terms.txt'].toString()) });
|
||||||
@ -1679,7 +1680,8 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
|||||||
if (req.session.domainid != domain.id) { req.session = null; res.redirect(domain.url + getQueryPortion(req)); return; } // Check is the session is for the correct domain
|
if (req.session.domainid != domain.id) { req.session = null; res.redirect(domain.url + getQueryPortion(req)); return; } // Check is the session is for the correct domain
|
||||||
var user = obj.users[req.session.userid];
|
var user = obj.users[req.session.userid];
|
||||||
var logoutcontrol = 'Welcome ' + user.name + '.';
|
var logoutcontrol = 'Welcome ' + user.name + '.';
|
||||||
if ((domain.ldap == null) && (domain.sspi == null) && (obj.args.user == null) && (obj.args.nousers != true)) { logoutcontrol += ' <a href=' + domain.url + 'logout?' + Math.random() + ' style=color:white>Logout</a>'; } // If a default user is in use or no user mode, don't display the logout button
|
var extras = (req.query.key != null) ? ('&key=' + req.query.key) : '';
|
||||||
|
if ((domain.ldap == null) && (domain.sspi == null) && (obj.args.user == null) && (obj.args.nousers != true)) { logoutcontrol += ' <a href=' + domain.url + 'logout?' + Math.random() + extras + ' style=color:white>Logout</a>'; } // If a default user is in use or no user mode, don't display the logout button
|
||||||
render(req, res, getRenderPage('terms', req), { title: domain.title, title2: domain.title2, domainurl: domain.url, terms: encodeURIComponent(data), logoutControl: logoutcontrol });
|
render(req, res, getRenderPage('terms', req), { title: domain.title, title2: domain.title2, domainurl: domain.url, terms: encodeURIComponent(data), logoutControl: logoutcontrol });
|
||||||
} else {
|
} else {
|
||||||
render(req, res, getRenderPage('terms', req), { title: domain.title, title2: domain.title2, domainurl: domain.url, terms: encodeURIComponent(data) });
|
render(req, res, getRenderPage('terms', req), { title: domain.title, title2: domain.title2, domainurl: domain.url, terms: encodeURIComponent(data) });
|
||||||
@ -1693,7 +1695,8 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
|||||||
if (req.session.domainid != domain.id) { req.session = null; res.redirect(domain.url + getQueryPortion(req)); return; } // Check is the session is for the correct domain
|
if (req.session.domainid != domain.id) { req.session = null; res.redirect(domain.url + getQueryPortion(req)); return; } // Check is the session is for the correct domain
|
||||||
var user = obj.users[req.session.userid];
|
var user = obj.users[req.session.userid];
|
||||||
var logoutcontrol = 'Welcome ' + user.name + '.';
|
var logoutcontrol = 'Welcome ' + user.name + '.';
|
||||||
if ((domain.ldap == null) && (domain.sspi == null) && (obj.args.user == null) && (obj.args.nousers != true)) { logoutcontrol += ' <a href=' + domain.url + 'logout?' + Math.random() + ' style=color:white>Logout</a>'; } // If a default user is in use or no user mode, don't display the logout button
|
var extras = (req.query.key != null) ? ('&key=' + req.query.key) : '';
|
||||||
|
if ((domain.ldap == null) && (domain.sspi == null) && (obj.args.user == null) && (obj.args.nousers != true)) { logoutcontrol += ' <a href=' + domain.url + 'logout?' + Math.random() + extras + ' style=color:white>Logout</a>'; } // If a default user is in use or no user mode, don't display the logout button
|
||||||
render(req, res, getRenderPage('terms', req), { title: domain.title, title2: domain.title2, domainurl: domain.url, logoutControl: logoutcontrol });
|
render(req, res, getRenderPage('terms', req), { title: domain.title, title2: domain.title2, domainurl: domain.url, logoutControl: logoutcontrol });
|
||||||
} else {
|
} else {
|
||||||
render(req, res, getRenderPage('terms', req), { title: domain.title, title2: domain.title2, domainurl: domain.url });
|
render(req, res, getRenderPage('terms', req), { title: domain.title, title2: domain.title2, domainurl: domain.url });
|
||||||
@ -1726,6 +1729,9 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
|||||||
|
|
||||||
// Returns the mesh server root certificate
|
// Returns the mesh server root certificate
|
||||||
function handleRootCertRequest(req, res) {
|
function handleRootCertRequest(req, res) {
|
||||||
|
const domain = getDomain(req);
|
||||||
|
if (domain == null) { parent.debug('web', 'handleRootCertRequest: no domain'); res.sendStatus(404); return; }
|
||||||
|
if ((domain.loginkey != null) && (domain.loginkey != req.query.key)) { res.sendStatus(404); return; } // Check 3FA URL key
|
||||||
if ((obj.userAllowedIp != null) && (checkIpAddressEx(req, res, obj.userAllowedIp, false) === false)) { parent.debug('web', 'handleRootCertRequest: invalid ip'); return; } // Check server-wide IP filter only.
|
if ((obj.userAllowedIp != null) && (checkIpAddressEx(req, res, obj.userAllowedIp, false) === false)) { parent.debug('web', 'handleRootCertRequest: invalid ip'); return; } // Check server-wide IP filter only.
|
||||||
parent.debug('web', 'handleRootCertRequest()');
|
parent.debug('web', 'handleRootCertRequest()');
|
||||||
try {
|
try {
|
||||||
@ -1775,8 +1781,14 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
|||||||
scriptFile.mescript = Buffer.from(scriptEngine.script_compile(runscript), 'binary').toString('base64');
|
scriptFile.mescript = Buffer.from(scriptEngine.script_compile(runscript), 'binary').toString('base64');
|
||||||
scriptFile.scriptText = runscript;
|
scriptFile.scriptText = runscript;
|
||||||
|
|
||||||
|
// Randomize the environement detection
|
||||||
|
var randomDnsName;
|
||||||
|
do { randomDnsName = getRandomLowerCase(14); } while (randomDnsName == 'aabbccddeeffgg');
|
||||||
|
var text = JSON.stringify(scriptFile, null, ' ');
|
||||||
|
for (var i = 0; i < 5; i++) { text = text.replace('aabbccddeeffgg', randomDnsName); }
|
||||||
|
|
||||||
// Send the script
|
// Send the script
|
||||||
func(Buffer.from(JSON.stringify(scriptFile, null, ' ')));
|
func(Buffer.from(text));
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// Server name is a hostname
|
// Server name is a hostname
|
||||||
@ -1800,14 +1812,24 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
|||||||
scriptFile.mescript = Buffer.from(scriptEngine.script_compile(runscript), 'binary').toString('base64');
|
scriptFile.mescript = Buffer.from(scriptEngine.script_compile(runscript), 'binary').toString('base64');
|
||||||
scriptFile.scriptText = runscript;
|
scriptFile.scriptText = runscript;
|
||||||
|
|
||||||
|
// Randomize the environement detection
|
||||||
|
var randomDnsName;
|
||||||
|
do { randomDnsName = getRandomLowerCase(14); } while (randomDnsName == 'aabbccddeeffgg');
|
||||||
|
var text = JSON.stringify(scriptFile, null, ' ');
|
||||||
|
for (var i = 0; i < 5; i++) { text = text.replace('aabbccddeeffgg', randomDnsName); }
|
||||||
|
|
||||||
// Send the script
|
// Send the script
|
||||||
func(Buffer.from(JSON.stringify(scriptFile, null, ' ')));
|
func(Buffer.from(text));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns an mescript for Intel AMT configuration
|
// Returns an mescript for Intel AMT configuration
|
||||||
function handleMeScriptRequest(req, res) {
|
function handleMeScriptRequest(req, res) {
|
||||||
|
const domain = getDomain(req);
|
||||||
|
if (domain == null) { parent.debug('web', 'handleMeScriptRequest: no domain'); res.sendStatus(404); return; }
|
||||||
|
if ((domain.loginkey != null) && (domain.loginkey != req.query.key)) { res.sendStatus(404); return; } // Check 3FA URL key
|
||||||
|
|
||||||
if ((obj.userAllowedIp != null) && (checkIpAddressEx(req, res, obj.userAllowedIp, false) === false)) { return; } // Check server-wide IP filter only.
|
if ((obj.userAllowedIp != null) && (checkIpAddressEx(req, res, obj.userAllowedIp, false) === false)) { return; } // Check server-wide IP filter only.
|
||||||
if (req.query.type == 1) {
|
if (req.query.type == 1) {
|
||||||
obj.getCiraConfigurationScript(req.query.meshid, function (script) {
|
obj.getCiraConfigurationScript(req.query.meshid, function (script) {
|
||||||
@ -1835,6 +1857,8 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
|||||||
function handleDownloadUserFiles(req, res) {
|
function handleDownloadUserFiles(req, res) {
|
||||||
const domain = checkUserIpAddress(req, res);
|
const domain = checkUserIpAddress(req, res);
|
||||||
if (domain == null) { res.sendStatus(404); return; }
|
if (domain == null) { res.sendStatus(404); return; }
|
||||||
|
if ((domain.loginkey != null) && (domain.loginkey != req.query.key)) { res.sendStatus(404); return; } // Check 3FA URL key
|
||||||
|
|
||||||
if (obj.common.validateString(req.path, 1, 4096) == false) { res.sendStatus(404); return; }
|
if (obj.common.validateString(req.path, 1, 4096) == false) { res.sendStatus(404); return; }
|
||||||
var domainname = 'domain', spliturl = decodeURIComponent(req.path).split('/'), filename = '';
|
var domainname = 'domain', spliturl = decodeURIComponent(req.path).split('/'), filename = '';
|
||||||
if ((spliturl.length < 3) || (obj.common.IsFilenameValid(spliturl[2]) == false) || (domain.userQuota == -1)) { res.sendStatus(404); return; }
|
if ((spliturl.length < 3) || (obj.common.IsFilenameValid(spliturl[2]) == false) || (domain.userQuota == -1)) { res.sendStatus(404); return; }
|
||||||
@ -2788,6 +2812,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
|||||||
function handleBackupRequest(req, res) {
|
function handleBackupRequest(req, res) {
|
||||||
const domain = checkUserIpAddress(req, res);
|
const domain = checkUserIpAddress(req, res);
|
||||||
if (domain == null) { res.sendStatus(404); return; }
|
if (domain == null) { res.sendStatus(404); return; }
|
||||||
|
if ((domain.loginkey != null) && (domain.loginkey != req.query.key)) { res.sendStatus(404); return; } // Check 3FA URL key
|
||||||
if ((!req.session) || (req.session == null) || (!req.session.userid) || (obj.parent.args.noserverbackup == 1)) { res.sendStatus(401); return; }
|
if ((!req.session) || (req.session == null) || (!req.session.userid) || (obj.parent.args.noserverbackup == 1)) { res.sendStatus(401); return; }
|
||||||
var user = obj.users[req.session.userid];
|
var user = obj.users[req.session.userid];
|
||||||
if ((user == null) || ((user.siteadmin & 1) == 0)) { res.sendStatus(401); return; } // Check if we have server backup rights
|
if ((user == null) || ((user.siteadmin & 1) == 0)) { res.sendStatus(401); return; } // Check if we have server backup rights
|
||||||
@ -2820,6 +2845,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
|||||||
function handleRestoreRequest(req, res) {
|
function handleRestoreRequest(req, res) {
|
||||||
const domain = checkUserIpAddress(req, res);
|
const domain = checkUserIpAddress(req, res);
|
||||||
if (domain == null) { res.sendStatus(404); return; }
|
if (domain == null) { res.sendStatus(404); return; }
|
||||||
|
if ((domain.loginkey != null) && (domain.loginkey != req.query.key)) { res.sendStatus(404); return; } // Check 3FA URL key
|
||||||
if (obj.parent.args.noserverbackup == 1) { res.sendStatus(401); return; }
|
if (obj.parent.args.noserverbackup == 1) { res.sendStatus(401); return; }
|
||||||
var authUserid = null;
|
var authUserid = null;
|
||||||
if ((req.session != null) && (typeof req.session.userid == 'string')) { authUserid = req.session.userid; }
|
if ((req.session != null) && (typeof req.session.userid == 'string')) { authUserid = req.session.userid; }
|
||||||
@ -3429,7 +3455,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
obj.app.get(url + 'stop', function (req, res) { res.send('Stopping Server, <a href="' + url + '">click here to login</a>.'); setTimeout(function () { parent.Stop(); }, 500); });
|
//obj.app.get(url + 'stop', function (req, res) { res.send('Stopping Server, <a href="' + url + '">click here to login</a>.'); setTimeout(function () { parent.Stop(); }, 500); });
|
||||||
|
|
||||||
// Indicates to ExpressJS that the override public folder should be used to serve static files.
|
// Indicates to ExpressJS that the override public folder should be used to serve static files.
|
||||||
if (obj.parent.webPublicOverridePath != null) { obj.app.use(url, obj.express.static(obj.parent.webPublicOverridePath, { maxAge: '1h' })); }
|
if (obj.parent.webPublicOverridePath != null) { obj.app.use(url, obj.express.static(obj.parent.webPublicOverridePath, { maxAge: '1h' })); }
|
||||||
@ -3456,6 +3482,8 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
|||||||
|
|
||||||
// Authenticates a session and forwards
|
// Authenticates a session and forwards
|
||||||
function PerformWSSessionAuth(ws, req, noAuthOk, func) {
|
function PerformWSSessionAuth(ws, req, noAuthOk, func) {
|
||||||
|
// Check if this is a banned ip address
|
||||||
|
if (obj.checkAllowLogin(req) == false) { try { ws.send(JSON.stringify({ action: 'close', cause: 'banned', msg: 'banned-1' })); ws.close(); } catch (e) { } return; }
|
||||||
try {
|
try {
|
||||||
// Hold this websocket until we are ready.
|
// Hold this websocket until we are ready.
|
||||||
ws._socket.pause();
|
ws._socket.pause();
|
||||||
@ -3473,7 +3501,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
|||||||
if ((err == null) && (user)) {
|
if ((err == null) && (user)) {
|
||||||
// Check if a 2nd factor is needed
|
// Check if a 2nd factor is needed
|
||||||
if (checkUserOneTimePasswordRequired(domain, user) == true) {
|
if (checkUserOneTimePasswordRequired(domain, user) == true) {
|
||||||
if (req.query.token) {
|
if (typeof req.query.token != 'string') {
|
||||||
try { ws.send(JSON.stringify({ action: 'close', cause: 'noauth', msg: 'tokenrequired' })); ws.close(); } catch (e) { }
|
try { ws.send(JSON.stringify({ action: 'close', cause: 'noauth', msg: 'tokenrequired' })); ws.close(); } catch (e) { }
|
||||||
} else {
|
} else {
|
||||||
checkUserOneTimePassword(req, domain, user, req.query.token, null, function (result) {
|
checkUserOneTimePassword(req, domain, user, req.query.token, null, function (result) {
|
||||||
@ -3497,6 +3525,8 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
|||||||
} else {
|
} else {
|
||||||
// If not authenticated, close the websocket connection
|
// If not authenticated, close the websocket connection
|
||||||
parent.debug('web', 'ERR: Websocket bad user/pass auth');
|
parent.debug('web', 'ERR: Websocket bad user/pass auth');
|
||||||
|
//obj.parent.DispatchEvent(['*', 'server-users', 'user/' + domain.id + '/' + obj.args.user.toLowerCase()], obj, { action: 'authfail', userid: 'user/' + domain.id + '/' + obj.args.user.toLowerCase(), username: obj.args.user, domain: domain.id, msg: 'Invalid user login attempt from ' + cleanRemoteAddr(req.ip) });
|
||||||
|
//obj.setbadLogin(req);
|
||||||
try { ws.send(JSON.stringify({ action: 'close', cause: 'noauth', msg: 'noauth-2' })); ws.close(); } catch (e) { }
|
try { ws.send(JSON.stringify({ action: 'close', cause: 'noauth', msg: 'noauth-2' })); ws.close(); } catch (e) { }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -4005,6 +4035,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
|||||||
function checkAmtPassword(p) { return (p.length > 7) && (/\d/.test(p)) && (/[a-z]/.test(p)) && (/[A-Z]/.test(p)) && (/\W/.test(p)); }
|
function checkAmtPassword(p) { return (p.length > 7) && (/\d/.test(p)) && (/[a-z]/.test(p)) && (/[A-Z]/.test(p)) && (/\W/.test(p)); }
|
||||||
function getRandomAmtPassword() { var p; do { p = Buffer.from(obj.crypto.randomBytes(9), 'binary').toString('base64').split('/').join('@'); } while (checkAmtPassword(p) == false); return p; }
|
function getRandomAmtPassword() { var p; do { p = Buffer.from(obj.crypto.randomBytes(9), 'binary').toString('base64').split('/').join('@'); } while (checkAmtPassword(p) == false); return p; }
|
||||||
function getRandomPassword() { return Buffer.from(obj.crypto.randomBytes(9), 'binary').toString('base64').split('/').join('@'); }
|
function getRandomPassword() { return Buffer.from(obj.crypto.randomBytes(9), 'binary').toString('base64').split('/').join('@'); }
|
||||||
|
function getRandomLowerCase(len) { var r = '', random = obj.crypto.randomBytes(len); for (var i = 0; i < len; i++) { r += String.fromCharCode(97 + (random[i] % 26)); } return r; }
|
||||||
|
|
||||||
// Clean a IPv6 address that encodes a IPv4 address
|
// Clean a IPv6 address that encodes a IPv4 address
|
||||||
function cleanRemoteAddr(addr) { if (typeof addr != 'string') { return null; } if (addr.indexOf('::ffff:') == 0) { return addr.substring(7); } else { return addr; } }
|
function cleanRemoteAddr(addr) { if (typeof addr != 'string') { return null; } if (addr.indexOf('::ffff:') == 0) { return addr.substring(7); } else { return addr; } }
|
||||||
@ -4034,5 +4065,46 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
|||||||
} catch (ex) { console.log(ex); func(fd, tag); }
|
} catch (ex) { console.log(ex); func(fd, tag); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This is the invalid login throttling code
|
||||||
|
obj.badLoginTable = {};
|
||||||
|
obj.badLoginTableLastClean = 0;
|
||||||
|
if (parent.config.settings == null) { parent.config.settings = {}; }
|
||||||
|
if (parent.config.settings.maxinvalidlogin == null) { parent.config.settings.maxinvalidlogin = { time: 10, count: 10 }; }
|
||||||
|
if (typeof parent.config.settings.maxinvalidlogin.time != 'number') { parent.config.settings.maxinvalidlogin.time = 10; }
|
||||||
|
if (typeof parent.config.settings.maxinvalidlogin.count != 'number') { parent.config.settings.maxinvalidlogin.count = 10; }
|
||||||
|
if ((typeof parent.config.settings.maxinvalidlogin.coolofftime != 'number') || (parent.config.settings.maxinvalidlogin.coolofftime < 1)) { parent.config.settings.maxinvalidlogin.coolofftime = null; }
|
||||||
|
obj.setbadLogin = function (ip) { // Set an IP address that just did a bad login request
|
||||||
|
if (typeof ip == 'object') { ip = cleanRemoteAddr(ip.ip); }
|
||||||
|
if (++obj.badLoginTableLastClean > 100) { obj.cleanBadLoginTable(); }
|
||||||
|
if (typeof obj.badLoginTable[ip] == 'number') { if (obj.badLoginTable[ip] < Date.now()) { delete obj.badLoginTable[ip]; } else { return; } } // Check cooloff period
|
||||||
|
if (obj.badLoginTable[ip] == null) { obj.badLoginTable[ip] = [Date.now()]; } else { obj.badLoginTable[ip].push(Date.now()); }
|
||||||
|
if ((obj.badLoginTable[ip].length >= parent.config.settings.maxinvalidlogin.count) && (parent.config.settings.maxinvalidlogin.coolofftime != null)) {
|
||||||
|
obj.badLoginTable[ip] = Date.now() + (parent.config.settings.maxinvalidlogin.coolofftime * 60000); // Move to cooloff period
|
||||||
|
}
|
||||||
|
}
|
||||||
|
obj.checkAllowLogin = function (ip) { // Check if an IP address is allowed to login
|
||||||
|
if (typeof ip == 'object') { ip = cleanRemoteAddr(ip.ip); }
|
||||||
|
var cutoffTime = Date.now() - (parent.config.settings.maxinvalidlogin.time * 60000); // Time in minutes
|
||||||
|
var ipTable = obj.badLoginTable[ip];
|
||||||
|
if (ipTable == null) return true;
|
||||||
|
if (typeof ipTable == 'number') { if (obj.badLoginTable[ip] < Date.now()) { delete obj.badLoginTable[ip]; } else { return false; } } // Check cooloff period
|
||||||
|
while ((ipTable.length > 0) && (ipTable[0] < cutoffTime)) { ipTable.shift(); }
|
||||||
|
if (ipTable.length == 0) { delete obj.badLoginTable[ip]; return true; }
|
||||||
|
return (ipTable.length < parent.config.settings.maxinvalidlogin.count); // No more than x bad logins in x minutes
|
||||||
|
}
|
||||||
|
obj.cleanBadLoginTable = function () { // Clean up the IP address login blockage table, we do this occasionaly.
|
||||||
|
var cutoffTime = Date.now() - (parent.config.settings.maxinvalidlogin.time * 60000); // Time in minutes
|
||||||
|
for (var ip in obj.badLoginTable) {
|
||||||
|
var ipTable = obj.badLoginTable[ip];
|
||||||
|
if (typeof ipTable == 'number') {
|
||||||
|
if (obj.badLoginTable[ip] < Date.now()) { delete obj.badLoginTable[ip]; } // Check cooloff period
|
||||||
|
} else {
|
||||||
|
while ((ipTable.length > 0) && (ipTable[0] < cutoffTime)) { ipTable.shift(); }
|
||||||
|
if (ipTable.length == 0) { delete obj.badLoginTable[ip]; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
obj.badLoginTableLastClean = 0;
|
||||||
|
}
|
||||||
|
|
||||||
return obj;
|
return obj;
|
||||||
};
|
};
|
Loading…
Reference in New Issue
Block a user