Improved dependency management, main web port now uses TLS 1.2 only.

Ylian Saint-Hilaire committed Jan 31, 2018 at 16:10 UTC 49927f0abc5b9e4be6505a5f0de72389800830b4
4 files changed +66 -49
db.js
+1 -1
@@ -25,7 +25,7 @@ module.exports.CreateDB = function (args, datapath) {
25 if (args.mongodb) {
26 // Use MongoDB
27 obj.databaseType = 2;
28 - var Datastore = require("mongojs");
28 + var Datastore = require('mongojs');
29 var db = Datastore(args.mongodb);
30 var dbcollection = 'meshcentral';
31 if (args.mongodbcol) { dbcollection = args.mongodbcol; }
meshcentral.js
+58 -24
@@ -9,7 +9,7 @@
9 // If app metrics is available
10 if (process.argv[2] == '--launch') { try { require('appmetrics-dash').monitor({ url: '/', title: 'MeshCentral', port: 88, host: '127.0.0.1' }); } catch (e) { } }
11
12 -function CreateMeshCentralServer() {
12 +function CreateMeshCentralServer(config) {
13 var obj = {};
14 obj.db;
15 obj.webserver;
@@ -33,7 +33,7 @@ function CreateMeshCentralServer() {
33 obj.connectivityByNode = {}; // This object keeps a list of all connected CIRA and agents, by nodeid->value (value: 1 = Agent, 2 = CIRA, 4 = AmtDirect)
34 obj.peerConnectivityByNode = {}; // This object keeps a list of all connected CIRA and agents of peers, by serverid->nodeid->value (value: 1 = Agent, 2 = CIRA, 4 = AmtDirect)
35 obj.debugLevel = 0;
36 - obj.config = {}; // Configuration file
36 + obj.config = config; // Configuration file
37 obj.dbconfig = {}; // Persistance values, loaded from database
38 obj.certificateOperations = null;
39 obj.defaultMeshCmd = null;
@@ -82,6 +82,7 @@ function CreateMeshCentralServer() {
82 var validArguments = ['_', 'notls', 'user', 'port', 'mpsport', 'redirport', 'cert', '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', 'mpsdebug', 'mpspass', 'ciralocalfqdn', 'dbexport', 'dbimport', 'selfupdate', 'tlsoffload', 'userallowedip', 'fastcert', 'swarmport', 'swarmdebug', 'logintoken', 'logintokenkey', 'logintokengen', 'logintokengen', 'mailtokengen'];
83 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; } }
84 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; }
85 + for (var 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.
86
87 if ((obj.args.help == true) || (obj.args['?'] == true)) {
88 console.log('MeshCentral2 Beta 2, a web-based remote computer management web portal.\r\n');
@@ -198,22 +199,6 @@ function CreateMeshCentralServer() {
199 // Look to see if data and/or file path is specified
200 if (obj.args.datapath) { obj.datapath = obj.args.datapath; }
201 if (obj.args.filespath) { obj.filespath = obj.args.filespath; }
201 -
202 - // Read configuration file if present and change arguments.
203 - var configFilePath = obj.path.join(obj.datapath, 'config.json');
204 - if (obj.fs.existsSync(configFilePath)) {
205 - // Load and validate the configuration file
206 - try { obj.config = require(configFilePath); } catch (e) { console.log('ERROR: Unable to parse ' + configFilePath + '.'); return; }
207 - if (obj.config.domains == null) { obj.config.domains = {}; }
208 - for (var i in obj.config.domains) { if ((i.split('/').length > 1) || (i.split(' ').length > 1)) { console.log("ERROR: Error in config.json, domain names can't have spaces or /."); return; } }
209 - // Set the command line arguments to the config file if they are not present
210 - if (obj.config.settings) { for (var i in obj.config.settings) { if (obj.args[i] == null) obj.args[i] = obj.config.settings[i]; } }
211 - } else {
212 - // Copy the "sample-config.json" to give users a starting point
213 - var sampleConfigPath = obj.path.join(__dirname, 'sample-config.json');
214 - if (obj.fs.existsSync(sampleConfigPath)) { obj.fs.createReadStream(sampleConfigPath).pipe(obj.fs.createWriteStream(configFilePath)); }
215 - }
216 - obj.common.objKeysToLower(obj.config); // Lower case all keys in the config file
202
203 // Read environment variables. For a subset of arguments, we allow them to be read from environment variables.
204 var xenv = ['user', 'port', 'mpsport', 'redirport', 'exactport', 'debug'];
@@ -1033,10 +1018,49 @@ function CreateMeshCentralServer() {
1018 return obj;
1019 }
1020
1021 +// Return the server configuration
1022 +function getConfig() {
1023 + // Figure out the datapath location
1024 + var fs = require('fs');
1025 + var path = require('path');
1026 + var datapath = null;
1027 + var args = require('minimist')(process.argv.slice(2));
1028 + if ((__dirname.endsWith('/node_modules/meshcentral')) || (__dirname.endsWith('\\node_modules\\meshcentral')) || (__dirname.endsWith('/node_modules/meshcentral/')) || (__dirname.endsWith('\\node_modules\\meshcentral\\'))) {
1029 + datapath = path.join(__dirname, '../../meshcentral-data');
1030 + } else {
1031 + datapath = path.join(__dirname, '../meshcentral-data');
1032 + }
1033 + if (args.datapath) { datapath = args.datapath; }
1034 + try { fs.mkdirSync(datapath); } catch (e) { }
1035 +
1036 + // Read configuration file if present and change arguments.
1037 + var config = {}, configFilePath = path.join(datapath, 'config.json');
1038 + if (fs.existsSync(configFilePath)) {
1039 + // Load and validate the configuration file
1040 + try { config = require(configFilePath); } catch (e) { console.log('ERROR: Unable to parse ' + configFilePath + '.'); return null; }
1041 + if (config.domains == null) { config.domains = {}; }
1042 + for (var i in config.domains) { if ((i.split('/').length > 1) || (i.split(' ').length > 1)) { console.log("ERROR: Error in config.json, domain names can't have spaces or /."); return null; } }
1043 + } else {
1044 + // Copy the "sample-config.json" to give users a starting point
1045 + var sampleConfigPath = path.join(__dirname, 'sample-config.json');
1046 + if (fs.existsSync(sampleConfigPath)) { fs.createReadStream(sampleConfigPath).pipe(fs.createWriteStream(configFilePath)); }
1047 + }
1048 +
1049 + // Set the command line arguments to the config file if they are not present
1050 + if (!config.settings) { config.settings = {}; }
1051 + for (var i in args) { config.settings[i] = args[i]; }
1052 +
1053 + // Lower case all keys in the config file
1054 + require('./common.js').objKeysToLower(config);
1055 + return config;
1056 +}
1057 +
1058 +// Check if a list of modules are present and install any missing ones
1059 function InstallModules(modules, func) {
1060 if (modules.length > 0) { InstallModule(modules.shift(), InstallModules, modules, func); } else { func(); }
1061 }
1062
1063 +// Check if a module is present and install it if missing
1064 function InstallModule(modulename, func, tag1, tag2) {
1065 try {
1066 var module = require(modulename);
@@ -1057,10 +1081,20 @@ function InstallModule(modulename, func, tag1, tag2) {
1081 // Detect CTRL-C on Linux and stop nicely
1082 process.on('SIGINT', function () { if (meshserver != null) { meshserver.Stop(); meshserver = null; } console.log('Server Ctrl-C exit...'); process.exit(); });
1083
1060 -// Build the list of required modules
1061 -var modules = ['nedb', 'https', 'unzip', 'xmldom', 'express', 'mongojs', 'archiver', 'minimist', 'nodemailer', 'multiparty', 'node-forge', 'express-ws', 'compression', 'body-parser', 'connect-redis', 'express-session', 'express-handlebars'];
1062 -if (require('os').platform() == 'win32') { modules.push("node-sspi"); modules.push("node-windows"); }
1063 -
1064 -// Run as a command line, if we are not using service arguments, don't need to install the service package.
1084 +// Load the really basic modules
1085 var meshserver = null;
1066 -InstallModules(modules, function () { meshserver = CreateMeshCentralServer(); meshserver.Start(); });
\ No newline at end of file
1086 +InstallModules(['minimist'], function () {
1087 + // Get the server configuration
1088 + var config = getConfig();
1089 + if (config == null) { process.exit(); }
1090 +
1091 + // Build the list of required modules
1092 + var modules = ['ws', 'nedb', 'https', 'unzip', 'xmldom', 'express', 'mongojs', 'archiver', 'multiparty', 'node-forge', 'express-ws', 'compression', 'body-parser', 'connect-redis', 'express-session', 'express-handlebars'];
1093 + if (require('os').platform() == 'win32') { modules.push('node-sspi'); modules.push('node-windows'); } // Add Windows modules
1094 + 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
1095 + if (config.settings.mongodb != null) { modules.push('mongojs'); } // Add MongoDB
1096 + if (config.smtp != null) { modules.push('nodemailer'); } // Add SMTP support
1097 +
1098 + // Install any missing modules and launch the server
1099 + InstallModules(modules, function () { meshserver = CreateMeshCentralServer(config); meshserver.Start(); });
1100 +});
package.json
+3 -15
@@ -1,6 +1,6 @@
1 {
2 "name": "meshcentral",
3 - "version": "0.1.3-r",
3 + "version": "0.1.3-v",
4 "keywords": [
5 "Remote Management",
6 "Intel AMT",
@@ -29,32 +29,20 @@
29 "archiver": "^1.3.0",
30 "body-parser": "^1.18.2",
31 "compression": "^1.7.1",
32 - "connect-redis": "^3.3.2",
32 + "connect-redis": "^3.3.3",
33 "express": "^4.16.2",
34 "express-handlebars": "^3.0.0",
35 "express-session": "^1.15.6",
36 "express-ws": "^2.0.0",
37 "meshcentral": "*",
38 "minimist": "^1.2.0",
39 - "mongojs": "^2.4.1",
39 "multiparty": "^4.1.3",
40 "nedb": "^1.8.0",
41 "node-forge": "^0.6.49",
43 - "node-windows": "^0.1.14",
44 - "nodemailer": "^4.4.1",
42 "unzip": "^0.1.11",
46 - "ws": "^3.2.0",
43 + "ws": "^3.3.3",
44 "xmldom": "^0.1.27"
45 },
49 - "optionalDependencies": {
50 - "node-sspi": "^0.2.2",
51 - "node-windows": "^0.1.14",
52 - "mongojs": "^2.4.0",
53 - "greenlock": "^2.1.18",
54 - "le-store-certbot": "^2.0.5",
55 - "le-challenge-fs": "^2.0.8",
56 - "le-acme-core": "^2.1.1"
57 - },
46 "devDependencies": {},
47 "readme": "readme.txt"
48 }
webserver.js
+4 -9
@@ -72,7 +72,6 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
72 obj.tlsSniCredentials;
73 obj.dnsDomains = {};
74
75 -
75 // Mesh Rights
76 const MESHRIGHT_EDITMESH = 1;
77 const MESHRIGHT_MANAGEUSERS = 2;
@@ -140,14 +139,10 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
139 // Setup the HTTP server without TLS
140 obj.expressWs = require('express-ws')(obj.app);
141 } else {
143 - // Setup the HTTP server with TLS
144 - if (obj.tlsSniCredentials != null) {
145 - // We have multiple web server certificate used depending on the domain name
146 - obj.tlsServer = require('https').createServer({ SNICallback: TlsSniCallback, cert: obj.certificates.web.cert, key: obj.certificates.web.key, ca: obj.certificates.web.ca, rejectUnauthorized: true }, obj.app);
147 - } else {
148 - // We have a single web server certificate
149 - obj.tlsServer = require('https').createServer({ cert: obj.certificates.web.cert, key: obj.certificates.web.key, ca: obj.certificates.web.ca, rejectUnauthorized: true }, obj.app);
150 - }
142 + // Setup the HTTP server with TLS, use only TLS 1.2 and higher.
143 + var tlsOptions = { cert: obj.certificates.web.cert, key: obj.certificates.web.key, ca: obj.certificates.web.ca, rejectUnauthorized: true, secureOptions: obj.constants.SSL_OP_NO_SSLv2 | obj.constants.SSL_OP_NO_SSLv3 | obj.constants.SSL_OP_NO_COMPRESSION | obj.constants.SSL_OP_CIPHER_SERVER_PREFERENCE | obj.constants.SSL_OP_NO_TLSv1 | obj.constants.SSL_OP_NO_TLSv11 };
144 + if (obj.tlsSniCredentials != null) { tlsOptions.SNICallback = TlsSniCallback; } // We have multiple web server certificate used depending on the domain name
145 + obj.tlsServer = require('https').createServer(tlsOptions, obj.app);
146 obj.expressWs = require('express-ws')(obj.app, obj.tlsServer);
147 }
148