Improved support for reverse-proxy certificate loading.

Ylian Saint-Hilaire committed Oct 29, 2019 at 16:17 UTC 1f06f916102e8952c67ec8647175eba49ffd9806
6 files changed +127 -88
certoperations.js
+1 -2
@@ -196,7 +196,6 @@ module.exports.CertificateOperations = function (parent) {
196
197 // Return the certificate of the remote HTTPS server
198 obj.loadCertificate = function (url, hostname, tag, func) {
199 - console.log('loadCertificate', url, hostname);
199 const u = require('url').parse(url);
200 if (u.protocol == 'https:') {
201 // Read the certificate from HTTPS
@@ -218,7 +217,7 @@ module.exports.CertificateOperations = function (parent) {
217 func(url, data, hostname, tag);
218 }
219 });
221 - } else { func(url, null, tag); }
220 + } else { func(url, null, hostname, tag); }
221 };
222
223 // Check if a configuration file exists
common.js
+3
@@ -35,6 +35,9 @@ module.exports.makeFilename = function (v) { return v.split('\\').join('').split
35 // Move an element from one position in an array to a new position
36 module.exports.ArrayElementMove = function(arr, from, to) { arr.splice(to, 0, arr.splice(from, 1)[0]); };
37
38 +// Format a string with arguments, "replaces {0} and {1}..."
39 +module.exports.format = function (format) { var args = Array.prototype.slice.call(arguments, 1); return format.replace(/{(\d+)}/g, function (match, number) { return typeof args[number] != 'undefined' ? args[number] : match; }); };
40 +
41 // Print object for HTML
42 module.exports.ObjectToStringEx = function (x, c) {
43 var r = "", i;
meshagent.js
+8
@@ -53,6 +53,9 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
53 parent.parent.ClearConnectivityState(obj.dbMeshKey, obj.dbNodeKey, 1);
54 }
55
56 + // Remove this agent from the list of agents with bad web certificates
57 + if (obj.badWebCert) { delete parent.wsagentsWithBadWebCerts[obj.badWebCert]; }
58 +
59 // Get the current mesh
60 const mesh = parent.meshes[obj.dbMeshKey];
61
@@ -381,6 +384,11 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
384 } else {
385 // Check that the server hash matches our own web certificate hash (SHA384)
386 if ((getWebCertHash(domain) != msg.substring(2, 50)) && (getWebCertFullHash(domain) != msg.substring(2, 50))) {
387 + if (parent.parent.supportsProxyCertificatesRequest !== false) {
388 + obj.badWebCert = Buffer.from(parent.crypto.randomBytes(16), 'binary').toString('base64');
389 + parent.wsagentsWithBadWebCerts[obj.badWebCert] = obj; // Add this agent to the list of of agents with bad web certificates.
390 + parent.parent.updateProxyCertificates();
391 + }
392 parent.agentStats.agentBadWebCertHashCount++;
393 console.log('Agent bad web cert hash (Agent:' + (Buffer.from(msg.substring(2, 50), 'binary').toString('hex').substring(0, 10)) + ' != Server:' + (Buffer.from(getWebCertHash(domain), 'binary').toString('hex').substring(0, 10)) + ' or ' + (new Buffer(getWebCertFullHash(domain), 'binary').toString('hex').substring(0, 10)) + '), holding connection (' + obj.remoteaddrport + ').');
394 console.log('Agent reported web cert hash:' + (Buffer.from(msg.substring(2, 50), 'binary').toString('hex')) + '.');
meshcentral.js
+102 -74
@@ -396,34 +396,34 @@ function CreateMeshCentralServer(config, args) {
396
397 // Show a list of all configuration files in the database
398 if (obj.args.dblistconfigfiles) {
399 - obj.db.GetAllType('cfile', function (err, docs) { if (err == null) { if (docs.length == 0) { console.log('No files found.'); } else { for (var i in docs) { console.log(docs[i]._id.split('/')[1] + ', ' + Buffer.from(docs[i].data, 'base64').length + ' bytes.'); } } } else { console.log('Unable to read from database.'); } process.exit(); }); return;
399 + obj.db.GetAllType('cfile', function (err, docs) { if (err == null) { if (docs.length == 0) { console.log("No files found."); } else { for (var i in docs) { console.log(docs[i]._id.split('/')[1] + ', ' + Buffer.from(docs[i].data, 'base64').length + ' bytes.'); } } } else { console.log('Unable to read from database.'); } process.exit(); }); return;
400 }
401
402 // Display the content of a configuration file in the database
403 if (obj.args.dbshowconfigfile) {
404 - if (typeof obj.args.configkey != 'string') { console.log('Error, --configkey is required.'); process.exit(); return; }
404 + if (typeof obj.args.configkey != 'string') { console.log("Error, --configkey is required."); process.exit(); return; }
405 obj.db.getConfigFile(obj.args.dbshowconfigfile, function (err, docs) {
406 if (err == null) {
407 - if (docs.length == 0) { console.log('File not found.'); } else {
407 + if (docs.length == 0) { console.log("File not found."); } else {
408 var data = obj.db.decryptData(obj.args.configkey, docs[0].data);
409 - if (data == null) { console.log('Invalid config key.'); } else { console.log(data); }
409 + if (data == null) { console.log("Invalid config key."); } else { console.log(data); }
410 }
411 - } else { console.log('Unable to read from database.'); }
411 + } else { console.log("Unable to read from database."); }
412 process.exit();
413 }); return;
414 }
415
416 // Delete all configuration files from database
417 if (obj.args.dbdeleteconfigfiles) {
418 - console.log('Deleting all configuration files from the database...'); obj.db.RemoveAllOfType('cfile', function () { console.log('Done.'); process.exit(); });
418 + console.log("Deleting all configuration files from the database..."); obj.db.RemoveAllOfType('cfile', function () { console.log('Done.'); process.exit(); });
419 }
420
421 // Push all relevent files from meshcentral-data into the database
422 if (obj.args.dbpushconfigfiles) {
423 - if (typeof obj.args.configkey != 'string') { console.log('Error, --configkey is required.'); process.exit(); return; }
423 + if (typeof obj.args.configkey != 'string') { console.log("Error, --configkey is required."); process.exit(); return; }
424 if ((obj.args.dbpushconfigfiles !== true) && (typeof obj.args.dbpushconfigfiles != 'string')) {
425 - console.log('Usage: --dbpulldatafiles (path) This will import files from folder into the database');
426 - console.log(' --dbpulldatafiles This will import files from meshcentral-data into the db.');
425 + console.log("Usage: --dbpulldatafiles (path) This will import files from folder into the database");
426 + console.log(" --dbpulldatafiles This will import files from meshcentral-data into the db.");
427 process.exit();
428 } else {
429 if ((obj.args.dbpushconfigfiles == '*') || (obj.args.dbpushconfigfiles === true)) { obj.args.dbpushconfigfiles = obj.datapath; }
@@ -454,20 +454,20 @@ function CreateMeshCentralServer(config, args) {
454
455 // Pull all database files into meshcentral-data
456 if (obj.args.dbpullconfigfiles) {
457 - if (typeof obj.args.configkey != 'string') { console.log('Error, --configkey is required.'); process.exit(); return; }
457 + if (typeof obj.args.configkey != 'string') { console.log("Error, --configkey is required."); process.exit(); return; }
458 if (typeof obj.args.dbpullconfigfiles != 'string') {
459 - console.log('Usage: --dbpulldatafiles (path)');
459 + console.log("Usage: --dbpulldatafiles (path)");
460 process.exit();
461 } else {
462 obj.db.GetAllType('cfile', function (err, docs) {
463 if (err == null) {
464 if (docs.length == 0) {
465 - console.log('File not found.');
465 + console.log("File not found.");
466 } else {
467 for (var i in docs) {
468 const file = docs[i]._id.split('/')[1], binary = obj.db.decryptData(obj.args.configkey, docs[i].data);
469 if (binary == null) {
470 - console.log('Invalid config key.');
470 + console.log("Invalid config key.");
471 } else {
472 var fullFileName = obj.path.join(obj.args.dbpullconfigfiles, file);
473 try { obj.fs.writeFileSync(fullFileName, binary); } catch (ex) { console.log('Unable to write to ' + fullFileName); process.exit(); return; }
@@ -476,7 +476,7 @@ function CreateMeshCentralServer(config, args) {
476 }
477 }
478 } else {
479 - console.log('Unable to read from database.');
479 + console.log("Unable to read from database.");
480 }
481 process.exit();
482 });
@@ -603,10 +603,10 @@ function CreateMeshCentralServer(config, args) {
603 var key = null;
604 if (typeof obj.args.configkey == 'string') { key = obj.args.configkey; }
605 else if (typeof obj.args.loadconfigfromdb == 'string') { key = obj.args.loadconfigfromdb; }
606 - if (key == null) { console.log('Error, --configkey is required.'); process.exit(); return; }
606 + if (key == null) { console.log("Error, --configkey is required."); process.exit(); return; }
607 obj.db.getAllConfigFiles(key, function (configFiles) {
608 - if (configFiles == null) { console.log('Error, no configuration files found or invalid configkey.'); process.exit(); return; }
609 - if (!configFiles['config.json']) { console.log('Error, could not file config.json from database.'); process.exit(); return; }
608 + if (configFiles == null) { console.log("Error, no configuration files found or invalid configkey."); process.exit(); return; }
609 + if (!configFiles['config.json']) { console.log("Error, could not file config.json from database."); process.exit(); return; }
610 obj.configurationFiles = configFiles;
611
612 // Parse the new configuration file
@@ -744,9 +744,9 @@ function CreateMeshCentralServer(config, args) {
744 var adminname = obj.args.admin.split('/');
745 if (adminname.length == 1) { adminname = 'user//' + adminname[0]; }
746 else if (adminname.length == 2) { adminname = 'user/' + adminname[0] + '/' + adminname[1]; }
747 - else { console.log('Invalid administrator name.'); process.exit(); return; }
747 + else { console.log("Invalid administrator name."); process.exit(); return; }
748 obj.db.Get(adminname, function (err, user) {
749 - if (user.length != 1) { console.log('Invalid user name.'); process.exit(); return; }
749 + if (user.length != 1) { console.log("Invalid user name."); process.exit(); return; }
750 user[0].siteadmin = 4294967295; // 0xFFFFFFFF
751 obj.db.Set(user[0], function () {
752 if (user[0].domain == '') { console.log('User ' + user[0].name + ' set to site administrator.'); } else { console.log('User ' + user[0].name + ' of domain ' + user[0].domain + ' set to site administrator.'); }
@@ -762,9 +762,9 @@ function CreateMeshCentralServer(config, args) {
762 var adminname = obj.args.unadmin.split('/');
763 if (adminname.length == 1) { adminname = 'user//' + adminname[0]; }
764 else if (adminname.length == 2) { adminname = 'user/' + adminname[0] + '/' + adminname[1]; }
765 - else { console.log('Invalid administrator name.'); process.exit(); return; }
765 + else { console.log("Invalid administrator name."); process.exit(); return; }
766 obj.db.Get(adminname, function (err, user) {
767 - if (user.length != 1) { console.log('Invalid user name.'); process.exit(); return; }
767 + if (user.length != 1) { console.log("Invalid user name."); process.exit(); return; }
768 if (user[0].siteadmin) { delete user[0].siteadmin; }
769 obj.db.Set(user[0], function () {
770 if (user[0].domain == '') { console.log('User ' + user[0].name + ' is not a site administrator.'); } else { console.log('User ' + user[0].name + ' of domain ' + user[0].domain + ' is not a site administrator.'); }
@@ -793,15 +793,15 @@ function CreateMeshCentralServer(config, args) {
793 while (obj.dbconfig.amtWsEventSecret == null) { process.nextTick(); }
794 var username = buf.toString('hex');
795 var nodeid = obj.args.getwspass;
796 - var pass = obj.crypto.createHash('sha384').update(username.toLowerCase() + ":" + nodeid + ":" + obj.dbconfig.amtWsEventSecret).digest("base64").substring(0, 12).split("/").join("x").split("\\").join("x");
797 - console.log('--- Intel(r) AMT WSMAN eventing credentials ---');
798 - console.log('Username: ' + username);
799 - console.log('Password: ' + pass);
800 - console.log('Argument: ' + nodeid);
796 + var pass = obj.crypto.createHash('sha384').update(username.toLowerCase() + ':' + nodeid + ':' + obj.dbconfig.amtWsEventSecret).digest('base64').substring(0, 12).split('/').join('x').split('\\').join('x');
797 + console.log("--- Intel(r) AMT WSMAN eventing credentials ---");
798 + console.log("Username: " + username);
799 + console.log("Password: " + pass);
800 + console.log("Argument: " + nodeid);
801 process.exit();
802 });
803 } else {
804 - console.log('Invalid NodeID.');
804 + console.log("Invalid NodeID.");
805 process.exit();
806 }
807 return;
@@ -809,7 +809,7 @@ function CreateMeshCentralServer(config, args) {
809
810 // Start plugin manager if configuration allows this.
811 if ((obj.config) && (obj.config.settings) && (obj.config.settings.plugins != null)) {
812 - obj.pluginHandler = require("./pluginHandler.js").pluginHandler(obj);
812 + obj.pluginHandler = require('./pluginHandler.js').pluginHandler(obj);
813 }
814
815 // Load the default meshcore and meshcmd
@@ -838,7 +838,7 @@ function CreateMeshCentralServer(config, args) {
838 if (obj.letsencrypt != null) {
839 obj.letsencrypt.getCertificate(certs, obj.StartEx3); // Use Let's Encrypt certificate
840 } else {
841 - console.log('ERROR: Unable to setup GreenLock module.');
841 + console.log("ERROR: Unable to setup GreenLock module.");
842 obj.StartEx3(certs); // Let's Encrypt did not load, just use the configured certificates
843 }
844 }
@@ -847,50 +847,23 @@ function CreateMeshCentralServer(config, args) {
847
848 // Start the server with the given certificates, but check if we have web certificates to load
849 obj.StartEx3 = function (certs) {
850 - var i, webCertLoadCount = 0;
850 obj.certificates = certs;
851 obj.certificateOperations.acceleratorStart(certs); // Set the state of the accelerators
852
853 // Load any domain web certificates
855 - for (i in obj.config.domains) {
854 + for (var i in obj.config.domains) {
855 // Load any Intel AMT ACM activation certificates
856 obj.certificateOperations.loadIntelAmtAcmCerts(obj.config.domains[i].amtacmactivation);
857
859 - if (obj.config.domains[i].certurl != null) {
860 - // Fix the URL and add 'https://' if needed
858 + if (typeof obj.config.domains[i].certurl == 'string') {
859 + obj.supportsProxyCertificatesRequest = true; // If a certurl is set, enable proxy cert requests
860 + // Then, fix the URL and add 'https://' if needed
861 if (obj.config.domains[i].certurl.indexOf('://') < 0) { obj.config.domains[i].certurl = 'https://' + obj.config.domains[i].certurl; }
862 -
863 - // Load web certs
864 - webCertLoadCount++;
865 - var dnsname = obj.config.domains[i].dns;
866 - if ((dnsname == null) && (obj.config.settings.cert != null)) { dnsname = obj.config.settings.cert; }
867 - obj.certificateOperations.loadCertificate(obj.config.domains[i].certurl, dnsname, obj.config.domains[i], function (url, cert, xhostname, xdomain) {
868 - if (cert != null) {
869 - // Hash the entire cert
870 - var hash = obj.crypto.createHash('sha384').update(Buffer.from(cert, 'binary')).digest('hex');
871 - if (xdomain.certhash != hash) { xdomain.certkeyhash = hash; xdomain.certhash = hash; }
872 -
873 - try {
874 - // Decode a RSA certificate and hash the public key, if this is not RSA, skip this.
875 - var forgeCert = obj.certificateOperations.forge.pki.certificateFromAsn1(obj.certificateOperations.forge.asn1.fromDer(cert));
876 - xdomain.certkeyhash = obj.certificateOperations.forge.pki.getPublicKeyFingerprint(forgeCert.publicKey, { md: obj.certificateOperations.forge.md.sha384.create(), encoding: 'hex' });
877 - //console.log('V1: ' + xdomain.certkeyhash);
878 - } catch (ex) { }
879 -
880 - console.log('Loaded web certificate from \"' + url + '\", host: \"' + xhostname + '\"');
881 - console.log(' SHA384 cert hash: ' + xdomain.certhash);
882 - if (xdomain.certhash != xdomain.certkeyhash) { console.log(' SHA384 key hash: ' + xdomain.certkeyhash); }
883 - } else {
884 - console.log('Failed to load web certificate at: \"' + url + '\", host: \"' + xhostname + '\"');
885 - }
886 - webCertLoadCount--;
887 - if (webCertLoadCount == 0) { obj.StartEx4(); } // Done loading all certificates
888 - });
862 }
863 }
864
892 - // No certificate to load, start the server
893 - if (webCertLoadCount == 0) { obj.StartEx4(); }
865 + if (obj.supportsProxyCertificatesRequest == true) { obj.updateProxyCertificates(); }
866 + obj.StartEx4(); // Keep going
867 }
868
869 // Start the server with the given certificates
@@ -903,7 +876,7 @@ function CreateMeshCentralServer(config, args) {
876 // Write server version and run mode
877 var productionMode = (process.env.NODE_ENV && (process.env.NODE_ENV == 'production'));
878 var runmode = (obj.args.lanonly ? 2 : (obj.args.wanonly ? 1 : 0));
906 - console.log('MeshCentral v' + obj.currentVer + ', ' + (['Hybrid (LAN + WAN) mode', 'WAN mode', 'LAN mode'][runmode]) + (productionMode ? ', Production mode.' : '.'));
879 + console.log("MeshCentral v" + obj.currentVer + ', ' + (["Hybrid (LAN + WAN) mode", "WAN mode", "LAN mode"][runmode]) + (productionMode ? ", Production mode." : '.'));
880
881 // Check that no sub-domains have the same DNS as the parent
882 for (i in obj.config.domains) {
@@ -1029,9 +1002,9 @@ function CreateMeshCentralServer(config, args) {
1002 obj.DispatchEvent(['*'], obj, { action: 'servertimelinestats', data: data }); // Event the server stats
1003 }, 300000);
1004
1032 - obj.debug('main', 'Server started');
1005 + obj.debug('main', "Server started");
1006 if (obj.args.nousers == true) { obj.updateServerState('nousers', '1'); }
1034 - obj.updateServerState('state', 'running');
1007 + obj.updateServerState('state', "running");
1008
1009 // Setup auto-backup defaults
1010 if (obj.config.settings.autobackup == null) { obj.config.settings.autobackup = { backupintervalhours: 24, keeplastdaysbackup: 10 }; }
@@ -1045,6 +1018,61 @@ function CreateMeshCentralServer(config, args) {
1018 });
1019 };
1020
1021 + // Refresh any certificate hashs from the reverse proxy
1022 + obj.pendingProxyCertificatesRequests = 0;
1023 + obj.lastProxyCertificatesRequest = null;
1024 + obj.supportsProxyCertificatesRequest = false;
1025 + obj.updateProxyCertificates = function () {
1026 + var i;
1027 + if ((obj.pendingProxyCertificatesRequests > 0) || (obj.supportsProxyCertificatesRequest == false)) { return; }
1028 + if ((obj.lastProxyCertificatesRequest != null) && ((Date.now() - obj.lastProxyCertificatesRequest) < 120000)) { return; } // Don't allow this call more than every 2 minutes.
1029 + obj.lastProxyCertificatesRequest = Date.now();
1030 +
1031 + // Load any domain web certificates
1032 + for (i in obj.config.domains) {
1033 + if (obj.config.domains[i].certurl != null) {
1034 + // Load web certs
1035 + obj.pendingProxyCertificatesRequests++;
1036 + var dnsname = obj.config.domains[i].dns;
1037 + if ((dnsname == null) && (obj.config.settings.cert != null)) { dnsname = obj.config.settings.cert; }
1038 + obj.certificateOperations.loadCertificate(obj.config.domains[i].certurl, dnsname, obj.config.domains[i], function (url, cert, xhostname, xdomain) {
1039 + obj.pendingProxyCertificatesRequests--;
1040 + if (cert != null) {
1041 + // Hash the entire cert
1042 + var hash = obj.crypto.createHash('sha384').update(Buffer.from(cert, 'binary')).digest('hex');
1043 + if (xdomain.certhash != hash) { // The certificate has changed.
1044 + xdomain.certkeyhash = hash;
1045 + xdomain.certhash = hash;
1046 +
1047 + try {
1048 + // Decode a RSA certificate and hash the public key, if this is not RSA, skip this.
1049 + var forgeCert = obj.certificateOperations.forge.pki.certificateFromAsn1(obj.certificateOperations.forge.asn1.fromDer(cert));
1050 + xdomain.certkeyhash = obj.certificateOperations.forge.pki.getPublicKeyFingerprint(forgeCert.publicKey, { md: obj.certificateOperations.forge.md.sha384.create(), encoding: 'hex' });
1051 + //console.log('V1: ' + xdomain.certkeyhash);
1052 + } catch (ex) {
1053 + delete xdomain.certkeyhash;
1054 + }
1055 +
1056 + if (obj.webserver) {
1057 + obj.webserver.webCertificateHashs[xdomain.id] = obj.webserver.webCertificateFullHashs[xdomain.id] = Buffer.from(hash, 'hex').toString('binary');
1058 + if (xdomain.certkeyhash != null) { obj.webserver.webCertificateHashs[xdomain.id] = Buffer.from(xdomain.certkeyhash, 'hex').toString('binary'); }
1059 +
1060 + // Disconnect all agents with bad web certificates
1061 + for (var i in obj.webserver.wsagentsWithBadWebCerts) { obj.webserver.wsagentsWithBadWebCerts[i].close(1); }
1062 + }
1063 +
1064 + console.log(obj.common.format("Loaded web certificate from \"{0}\", host: \"{1}\"", url, xhostname));
1065 + console.log(obj.common.format(" SHA384 cert hash: {0}", xdomain.certhash));
1066 + if ((xdomain.certkeyhash != null) && (xdomain.certhash != xdomain.certkeyhash)) { console.log(obj.common.format(" SHA384 key hash: {0}", xdomain.certkeyhash)); }
1067 + }
1068 + } else {
1069 + console.log(obj.common.format("Failed to load web certificate at: \"{0}\", host: \"{1}\"", url, xhostname));
1070 + }
1071 + });
1072 + }
1073 + }
1074 + }
1075 +
1076 // Perform maintenance operations (called every hour)
1077 obj.maintenanceActions = function () {
1078 // Check for self-update that targets a specific version
@@ -1068,19 +1096,19 @@ function CreateMeshCentralServer(config, args) {
1096 if (!obj.db) return;
1097
1098 // Dispatch an event saying the server is now stopping
1071 - obj.DispatchEvent(['*'], obj, { etype: 'server', action: 'stopped', msg: 'Server stopped' });
1099 + obj.DispatchEvent(['*'], obj, { etype: 'server', action: 'stopped', msg: "Server stopped" });
1100
1101 // Set all nodes to power state of unknown (0)
1102 obj.db.storePowerEvent({ time: new Date(), nodeid: '*', power: 0, s: 2 }, obj.multiServer, function () { // s:2 indicates that the server is shutting down.
1103 if (restoreFile) {
1076 - obj.debug('main', 'Server stopped, updating settings: ' + restoreFile);
1077 - console.log('Updating settings folder...');
1104 + obj.debug('main', obj.common.format("Server stopped, updating settings: {0}", restoreFile));
1105 + console.log("Updating settings folder...");
1106
1079 - var yauzl = require("yauzl");
1107 + var yauzl = require('yauzl');
1108 yauzl.open(restoreFile, { lazyEntries: true }, function (err, zipfile) {
1109 if (err) throw err;
1110 zipfile.readEntry();
1083 - zipfile.on("entry", function (entry) {
1111 + zipfile.on('entry', function (entry) {
1112 if (/\/$/.test(entry.fileName)) {
1113 // Directory file names end with '/'.
1114 // Note that entires for directories themselves are optional.
@@ -1090,22 +1118,22 @@ function CreateMeshCentralServer(config, args) {
1118 // file entry
1119 zipfile.openReadStream(entry, function (err, readStream) {
1120 if (err) throw err;
1093 - readStream.on("end", function () { zipfile.readEntry(); });
1121 + readStream.on('end', function () { zipfile.readEntry(); });
1122 // console.log('Extracting:', obj.getConfigFilePath(entry.fileName));
1123 readStream.pipe(obj.fs.createWriteStream(obj.getConfigFilePath(entry.fileName)));
1124 });
1125 }
1126 });
1099 - zipfile.on("end", function () { setTimeout(function () { obj.fs.unlinkSync(restoreFile); process.exit(123); }); });
1127 + zipfile.on('end', function () { setTimeout(function () { obj.fs.unlinkSync(restoreFile); process.exit(123); }); });
1128 });
1129 } else {
1102 - obj.debug('main', 'Server stopped');
1130 + obj.debug('main', "Server stopped");
1131 process.exit(0);
1132 }
1133 });
1134
1135 // Update the server state
1108 - obj.updateServerState('state', 'stopped');
1136 + obj.updateServerState('state', "stopped");
1137 };
1138
1139 // Event Dispatch
package.json
+1 -1
@@ -1,6 +1,6 @@
1 {
2 "name": "meshcentral",
3 - "version": "0.4.3-o",
3 + "version": "0.4.3-p",
4 "keywords": [
5 "Remote Management",
6 "Intel AMT",
webserver.js
+12 -11
@@ -156,20 +156,21 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
156 }
157
158 // Main lists
159 - obj.wsagents = {}; // NodeId --> Agent
159 + obj.wsagents = {}; // NodeId --> Agent
160 + obj.wsagentsWithBadWebCerts = {}; // NodeId --> Agent
161 obj.wsagentsDisconnections = {};
162 obj.wsagentsDisconnectionsTimer = null;
163 obj.duplicateAgentsLog = {};
163 - obj.wssessions = {}; // UserId --> Array Of Sessions
164 - obj.wssessions2 = {}; // "UserId + SessionRnd" --> Session (Note that the SessionId is the UserId + / + SessionRnd)
165 - obj.wsPeerSessions = {}; // ServerId --> Array Of "UserId + SessionRnd"
166 - obj.wsPeerSessions2 = {}; // "UserId + SessionRnd" --> ServerId
167 - obj.wsPeerSessions3 = {}; // ServerId --> UserId --> [ SessionId ]
168 - obj.sessionsCount = {}; // Merged session counters, used when doing server peering. UserId --> SessionCount
169 - obj.wsrelays = {}; // Id -> Relay
170 - obj.wsPeerRelays = {}; // Id -> { ServerId, Time }
171 - var tlsSessionStore = {}; // Store TLS session information for quick resume.
172 - var tlsSessionStoreCount = 0; // Number of cached TLS session information in store.
164 + obj.wssessions = {}; // UserId --> Array Of Sessions
165 + obj.wssessions2 = {}; // "UserId + SessionRnd" --> Session (Note that the SessionId is the UserId + / + SessionRnd)
166 + obj.wsPeerSessions = {}; // ServerId --> Array Of "UserId + SessionRnd"
167 + obj.wsPeerSessions2 = {}; // "UserId + SessionRnd" --> ServerId
168 + obj.wsPeerSessions3 = {}; // ServerId --> UserId --> [ SessionId ]
169 + obj.sessionsCount = {}; // Merged session counters, used when doing server peering. UserId --> SessionCount
170 + obj.wsrelays = {}; // Id -> Relay
171 + obj.wsPeerRelays = {}; // Id -> { ServerId, Time }
172 + var tlsSessionStore = {}; // Store TLS session information for quick resume.
173 + var tlsSessionStoreCount = 0; // Number of cached TLS session information in store.
174
175 // Setup randoms
176 obj.crypto.randomBytes(48, function (err, buf) { obj.httpAuthRandom = buf; });