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