Completed first pass with JsHint, updated windows MeshAgent.

Ylian Saint-Hilaire committed Aug 30, 2018 at 12:05 UTC 562310bed1bb8e843db3b65efeec225d25a5f955
18 files changed +664 -435
agents/MeshCmd-signed.exe
Binary files a/agents/MeshCmd-signed.exe and b/agents/MeshCmd-signed.exe differ
agents/MeshCmd64-signed.exe
Binary files a/agents/MeshCmd64-signed.exe and b/agents/MeshCmd64-signed.exe differ
agents/MeshService-signed.exe
Binary files a/agents/MeshService-signed.exe and b/agents/MeshService-signed.exe differ
agents/MeshService.exe
Binary files a/agents/MeshService.exe and b/agents/MeshService.exe differ
agents/MeshService64-signed.exe
Binary files a/agents/MeshService64-signed.exe and b/agents/MeshService64-signed.exe differ
agents/MeshService64.exe
Binary files a/agents/MeshService64.exe and b/agents/MeshService64.exe differ
agents/modules_meshcmd/promise.js new
+185
@@ -0,0 +1,185 @@
1 +/*
2 +Copyright 2018 Intel Corporation
3 +
4 +Licensed under the Apache License, Version 2.0 (the "License");
5 +you may not use this file except in compliance with the License.
6 +You may obtain a copy of the License at
7 +
8 + http://www.apache.org/licenses/LICENSE-2.0
9 +
10 +Unless required by applicable law or agreed to in writing, software
11 +distributed under the License is distributed on an "AS IS" BASIS,
12 +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 +See the License for the specific language governing permissions and
14 +limitations under the License.
15 +*/
16 +
17 +var refTable = {};
18 +
19 +function Promise(promiseFunc)
20 +{
21 + this._ObjectID = 'promise';
22 + this._internal = { promise: this, func: promiseFunc, completed: false, errors: false, completedArgs: [] };
23 + require('events').EventEmitter.call(this._internal);
24 + this._internal.on('_eventHook', function (eventName, eventCallback)
25 + {
26 + //console.log('hook', eventName, 'errors/' + this.errors + ' completed/' + this.completed);
27 + var r = null;
28 +
29 + if (eventName == 'resolved' && !this.errors && this.completed)
30 + {
31 + r = eventCallback.apply(this, this.completedArgs);
32 + if(r!=null)
33 + {
34 + this.emit_returnValue('resolved', r);
35 + }
36 + }
37 + if (eventName == 'rejected' && this.errors && this.completed)
38 + {
39 + eventCallback.apply(this, this.completedArgs);
40 + }
41 + if (eventName == 'settled' && this.completed)
42 + {
43 + eventCallback.apply(this, []);
44 + }
45 + });
46 + this._internal.resolver = function _resolver()
47 + {
48 + _resolver._self.errors = false;
49 + _resolver._self.completed = true;
50 + _resolver._self.completedArgs = [];
51 + var args = ['resolved'];
52 + if (this.emit_returnValue && this.emit_returnValue('resolved') != null)
53 + {
54 + _resolver._self.completedArgs.push(this.emit_returnValue('resolved'));
55 + args.push(this.emit_returnValue('resolved'));
56 + }
57 + else
58 + {
59 + for (var a in arguments)
60 + {
61 + _resolver._self.completedArgs.push(arguments[a]);
62 + args.push(arguments[a]);
63 + }
64 + }
65 + _resolver._self.emit.apply(_resolver._self, args);
66 + _resolver._self.emit('settled');
67 + };
68 + this._internal.rejector = function _rejector()
69 + {
70 + _rejector._self.errors = true;
71 + _rejector._self.completed = true;
72 + _rejector._self.completedArgs = [];
73 + var args = ['rejected'];
74 + for (var a in arguments)
75 + {
76 + _rejector._self.completedArgs.push(arguments[a]);
77 + args.push(arguments[a]);
78 + }
79 +
80 + _rejector._self.emit.apply(_rejector._self, args);
81 + _rejector._self.emit('settled');
82 + };
83 + this.catch = function(func)
84 + {
85 + this._internal.once('settled', func);
86 + }
87 + this.finally = function (func)
88 + {
89 + this._internal.once('settled', func);
90 + };
91 + this.then = function (resolved, rejected)
92 + {
93 + if (resolved) { this._internal.once('resolved', resolved); }
94 + if (rejected) { this._internal.once('rejected', rejected); }
95 +
96 + var retVal = new Promise(function (r, j) { });
97 +
98 + this._internal.once('resolved', retVal._internal.resolver);
99 + this._internal.once('rejected', retVal._internal.rejector);
100 + return (retVal);
101 + };
102 +
103 + this._internal.resolver._self = this._internal;
104 + this._internal.rejector._self = this._internal;;
105 +
106 + try
107 + {
108 + promiseFunc.call(this, this._internal.resolver, this._internal.rejector);
109 + }
110 + catch(e)
111 + {
112 + this._internal.errors = true;
113 + this._internal.completed = true;
114 + this._internal.completedArgs = [e];
115 + this._internal.emit('rejected', e);
116 + this._internal.emit('settled');
117 + }
118 +
119 + if(!this._internal.completed)
120 + {
121 + // Save reference of this object
122 + refTable[this._internal._hashCode()] = this._internal;
123 + this._internal.once('settled', function () { refTable[this._hashCode()] = null; });
124 + }
125 +}
126 +
127 +Promise.resolve = function resolve()
128 +{
129 + var retVal = new Promise(function (r, j) { });
130 + var args = [];
131 + for (var i in arguments)
132 + {
133 + args.push(arguments[i]);
134 + }
135 + retVal._internal.resolver.apply(retVal._internal, args);
136 + return (retVal);
137 +};
138 +Promise.reject = function reject() {
139 + var retVal = new Promise(function (r, j) { });
140 + var args = [];
141 + for (var i in arguments) {
142 + args.push(arguments[i]);
143 + }
144 + retVal._internal.rejector.apply(retVal._internal, args);
145 + return (retVal);
146 +};
147 +Promise.all = function all(promiseList)
148 +{
149 + var ret = new Promise(function (res, rej)
150 + {
151 + this.__rejector = rej;
152 + this.__resolver = res;
153 + this.__promiseList = promiseList;
154 + this.__done = false;
155 + this.__count = 0;
156 + });
157 +
158 + for (var i in promiseList)
159 + {
160 + promiseList[i].then(function ()
161 + {
162 + // Success
163 + if(++ret.__count == ret.__promiseList.length)
164 + {
165 + ret.__done = true;
166 + ret.__resolver(ret.__promiseList);
167 + }
168 + }, function (arg)
169 + {
170 + // Failure
171 + if(!ret.__done)
172 + {
173 + ret.__done = true;
174 + ret.__rejector(arg);
175 + }
176 + });
177 + }
178 + if (promiseList.length == 0)
179 + {
180 + ret.__resolver(promiseList);
181 + }
182 + return (ret);
183 +};
184 +
185 +module.exports = Promise;
\ No newline at end of file
agents/modules_meshcmd/service-manager.js
+8 -21
@@ -109,29 +109,16 @@ function serviceManager()
109 }
110 return admin;
111 };
112 + this.getProgramFolder = function getProgramFolder() {
113 + if (require('os').arch() == 'x64') { // 64 bit Windows
114 + if (this.GM.PointerSize == 4) { return process.env['ProgramFiles(x86)']; } // 32 Bit App
115 + return process.env['ProgramFiles']; // 64 bit App
116 + }
117 + return process.env['ProgramFiles']; // 32 bit Windows
118 + };
119 this.getServiceFolder = function getServiceFolder()
120 {
114 - var destinationFolder = null;
115 - if (require('os').arch() == 'x64')
116 - {
117 - // 64 bit Windows
118 - if (this.GM.PointerSize == 4)
119 - {
120 - // 32 Bit App
121 - destinationFolder = process.env['ProgramFiles(x86)'];
122 - }
123 - else
124 - {
125 - // 64 bit App
126 - destinationFolder = process.env['ProgramFiles'];
127 - }
128 - }
129 - else
130 - {
131 - // 32 bit Windows
132 - destinationFolder = process.env['ProgramFiles'];
133 - }
134 - return (destinationFolder + '\\mesh');
121 + return this.getProgramFolder() + '\\mesh';
122 };
123
124 this.enumerateService = function () {
meshcentral.js
+96 -86
@@ -6,23 +6,29 @@
6 * @version v0.0.1
7 */
8
9 -'use strict';
9 +/*xjslint node: true */
10 +/*xjslint plusplus: true */
11 +/*xjslint maxlen: 256 */
12 +/*jshint node: true */
13 +/*jshint strict: false */
14 +/*jshint esversion: 6 */
15 +"use strict";
16
17 // If app metrics is available
18 if (process.argv[2] == '--launch') { try { require('appmetrics-dash').monitor({ url: '/', title: 'MeshCentral', port: 88, host: '127.0.0.1' }); } catch (e) { } }
19
20 function CreateMeshCentralServer(config, args) {
21 var obj = {};
16 - obj.db;
17 - obj.webserver;
18 - obj.redirserver;
19 - obj.mpsserver;
20 - obj.swarmserver;
21 - obj.mailserver;
22 - obj.amtEventHandler;
23 - obj.amtScanner;
24 - obj.meshScanner;
25 - obj.letsencrypt;
22 + obj.db = null;
23 + obj.webserver = null;
24 + obj.redirserver = null;
25 + obj.mpsserver = null;
26 + obj.swarmserver = null;
27 + obj.mailserver = null;
28 + obj.amtEventHandler = null;
29 + obj.amtScanner = null;
30 + obj.meshScanner = null;
31 + obj.letsencrypt = null;
32 obj.eventsDispatch = {};
33 obj.fs = require('fs');
34 obj.path = require('path');
@@ -78,13 +84,14 @@ function CreateMeshCentralServer(config, args) {
84
85 // Start the Meshcentral server
86 obj.Start = function () {
87 + var i;
88 try { require('./pass').hash('test', function () { }); } catch (e) { console.log('Old version of node, must upgrade.'); return; } // TODO: Not sure if this test works or not.
89
90 // Check for invalid arguments
91 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', 'mpsdebug', 'mpspass', 'ciralocalfqdn', 'dbexport', 'dbimport', 'selfupdate', 'tlsoffload', 'userallowedip', 'fastcert', 'swarmport', 'swarmdebug', 'logintoken', 'logintokenkey', 'logintokengen', 'logintokengen', 'mailtokengen', 'admin', 'unadmin', 'sessionkey', 'sessiontime', 'minify'];
92 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; } }
93 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; }
87 - 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.
94 + 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.
95
96 if ((obj.args.help == true) || (obj.args['?'] == true)) {
97 console.log('MeshCentral2 Beta 2, a web-based remote computer management web portal.\r\n');
@@ -106,19 +113,19 @@ function CreateMeshCentralServer(config, args) {
113 console.log(' country and organization can optionaly be set.');
114 return;
115 }
109 -
116 +
117 // Check if we need to install, start, stop, remove ourself as a background service
118 if ((obj.service != null) && ((obj.args.install == true) || (obj.args.uninstall == true) || (obj.args.start == true) || (obj.args.stop == true) || (obj.args.restart == true))) {
119 var env = [], xenv = ['user', 'port', 'aliasport', 'mpsport', 'mpsaliasport', 'redirport', 'exactport', 'debug'];
113 - for (var 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.
114 - var svc = new obj.service({ name: 'MeshCentral', description: 'MeshCentral Remote Management Server', script: obj.path.join(__dirname, 'winservice.js'), env: env, wait: 2, grow: .5 });
120 + 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.
121 + 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 });
122 svc.on('install', function () { console.log('MeshCentral service installed.'); svc.start(); });
123 svc.on('uninstall', function () { console.log('MeshCentral service uninstalled.'); process.exit(); });
124 svc.on('start', function () { console.log('MeshCentral service started.'); process.exit(); });
125 svc.on('stop', function () { console.log('MeshCentral service stopped.'); if (obj.args.stop) { process.exit(); } if (obj.args.restart) { console.log('Holding 5 seconds...'); setTimeout(function () { svc.start(); }, 5000); } });
126 svc.on('alreadyinstalled', function () { console.log('MeshCentral service already installed.'); process.exit(); });
127 svc.on('invalidinstallation', function () { console.log('Invalid MeshCentral service installation.'); process.exit(); });
121 -
128 +
129 if (obj.args.install == true) { try { svc.install(); } catch (e) { logException(e); } }
130 if (obj.args.stop == true || obj.args.restart == true) { try { svc.stop(); } catch (e) { logException(e); } }
131 if (obj.args.start == true || obj.args.restart == true) { try { svc.start(); } catch (e) { logException(e); } }
@@ -132,7 +139,7 @@ function CreateMeshCentralServer(config, args) {
139 } else {
140 // if "--launch" is not specified, launch the server as a child process.
141 var startLine = '';
135 - for (var i in process.argv) {
142 + for (i in process.argv) {
143 var arg = process.argv[i];
144 if (arg.length > 0) {
145 if (startLine.length > 0) startLine += ' ';
@@ -141,7 +148,7 @@ function CreateMeshCentralServer(config, args) {
148 }
149 obj.launchChildServer(startLine);
150 }
144 - }
151 + };
152
153 // Launch MeshCentral as a child server and monitor it.
154 obj.launchChildServer = function (startLine) {
@@ -166,7 +173,7 @@ function CreateMeshCentralServer(config, args) {
173 console.log(error);
174 console.log('ERROR: MeshCentral failed with critical error, check MeshErrors.txt. Restarting in 5 seconds...');
175 setTimeout(function () { obj.launchChildServer(startLine); }, 5000);
169 - }
176 + }
177 }
178 });
179 xprocess.stdout.on('data', function (data) { if (data[data.length - 1] == '\n') { data = data.substring(0, data.length - 1); } if (data.indexOf('Updating settings folder...') >= 0) { xprocess.xrestart = 1; } else if (data.indexOf('Updating server certificates...') >= 0) { xprocess.xrestart = 1; } else if (data.indexOf('Server Ctrl-C exit...') >= 0) { xprocess.xrestart = 2; } else if (data.indexOf('Starting self upgrade...') >= 0) { xprocess.xrestart = 3; } console.log(data); });
@@ -175,7 +182,7 @@ function CreateMeshCentralServer(config, args) {
182 if (data[data.length - 1] == '\n') { data = data.substring(0, data.length - 1); } obj.fs.appendFileSync(obj.getConfigFilePath('mesherrors.txt'), '-------- ' + new Date().toLocaleString() + ' --------\r\n\r\n' + data + '\r\n\r\n\r\n');
183 });
184 xprocess.on('close', function (code) { if ((code != 0) && (code != 123)) { /* console.log("Exited with code " + code); */ } });
178 - }
185 + };
186
187 // Get current and latest MeshCentral server versions using NPM
188 obj.getLatestServerVersion = function (callback) {
@@ -190,44 +197,45 @@ function CreateMeshCentralServer(config, args) {
197 if (code == 0) { try { latestVer = xprocess.data.split(' ').join('').split('\r').join('').split('\n').join(''); } catch (e) { } }
198 callback(obj.currentVer, latestVer);
199 });
193 - }
200 + };
201
202 // Initiate server self-update
196 - obj.performServerUpdate = function () { console.log('Starting self upgrade...'); process.exit(200); }
203 + obj.performServerUpdate = function () { console.log('Starting self upgrade...'); process.exit(200); };
204
205 // Initiate server self-update
199 - obj.performServerCertUpdate = function () { console.log('Updating server certificates...'); process.exit(200); }
206 + obj.performServerCertUpdate = function () { console.log('Updating server certificates...'); process.exit(200); };
207
208 obj.StartEx = function () {
209 + var i;
210 //var wincmd = require('node-windows');
211 //wincmd.list(function (svc) { console.log(svc); }, true);
204 -
212 +
213 // Write the server state
214 obj.updateServerState('state', 'starting');
215
216 // Look to see if data and/or file path is specified
217 if (obj.args.datapath) { obj.datapath = obj.args.datapath; }
218 if (obj.args.filespath) { obj.filespath = obj.args.filespath; }
211 -
219 +
220 // Read environment variables. For a subset of arguments, we allow them to be read from environment variables.
221 var xenv = ['user', 'port', 'mpsport', 'mpsaliasport', 'redirport', 'exactport', 'debug'];
214 - for (var 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]]); } }
215 -
222 + 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]]); } }
223 +
224 // Validate the domains, this is used for multi-hosting
225 if (obj.config.domains == null) { obj.config.domains = {}; }
226 if (obj.config.domains[''] == null) { obj.config.domains[''] = {}; }
227 if (obj.config.domains[''].dns != null) { console.log("ERROR: Default domain can't have a DNS name."); return; }
220 - var xdomains = {}; for (var i in obj.config.domains) { if (!obj.config.domains[i].title) { obj.config.domains[i].title = 'MeshCentral'; } if (!obj.config.domains[i].title2) { obj.config.domains[i].title2 = '2.0 Beta 2'; } xdomains[i.toLowerCase()] = obj.config.domains[i]; } obj.config.domains = xdomains;
228 + var xdomains = {}; for (i in obj.config.domains) { if (!obj.config.domains[i].title) { obj.config.domains[i].title = 'MeshCentral'; } if (!obj.config.domains[i].title2) { obj.config.domains[i].title2 = '2.0 Beta 2'; } xdomains[i.toLowerCase()] = obj.config.domains[i]; } obj.config.domains = xdomains;
229 var bannedDomains = ['public', 'private', 'images', 'scripts', 'styles', 'views']; // List of banned domains
222 - for (var i in obj.config.domains) { for (var j in bannedDomains) { if (i == bannedDomains[j]) { console.log("ERROR: Domain '" + i + "' is not allowed domain name in ./data/config.json."); return; } } }
223 - for (var i in obj.config.domains) {
230 + for (i in obj.config.domains) { for (var j in bannedDomains) { if (i == bannedDomains[j]) { console.log("ERROR: Domain '" + i + "' is not allowed domain name in ./data/config.json."); return; } } }
231 + for (i in obj.config.domains) {
232 if (obj.config.domains[i].dns == null) { obj.config.domains[i].url = (i == '') ? '/' : ('/' + i + '/'); } else { obj.config.domains[i].url = '/'; }
233 obj.config.domains[i].id = i;
234 if (typeof obj.config.domains[i].userallowedip == 'string') { obj.config.domains[i].userallowedip = null; if (obj.config.domains[i].userallowedip != "") { obj.config.domains[i].userallowedip = obj.config.domains[i].userallowedip.split(','); } }
235 }
236
237 // Log passed arguments into Windows Service Log
230 - //if (obj.servicelog != null) { var s = ''; for (var i in obj.args) { if (i != '_') { if (s.length > 0) { s += ', '; } s += i + "=" + obj.args[i]; } } logInfoEvent('MeshServer started with arguments: ' + s); }
238 + //if (obj.servicelog != null) { var s = ''; for (i in obj.args) { if (i != '_') { if (s.length > 0) { s += ', '; } s += i + "=" + obj.args[i]; } } logInfoEvent('MeshServer started with arguments: ' + s); }
239
240 // Look at passed in arguments
241 if ((obj.args.user != null) && (typeof obj.args.user != 'string')) { delete obj.args.user; }
@@ -269,12 +277,12 @@ function CreateMeshCentralServer(config, args) {
277 if (obj.args.dbimport == true) { obj.args.dbimport = obj.getConfigFilePath('meshcentral.db.json'); }
278 var json = null, json2 = "", badCharCount = 0;
279 try { json = obj.fs.readFileSync(obj.args.dbimport, { encoding: 'utf8' }); } catch (e) { console.log('Invalid JSON file: ' + obj.args.dbimport + '.'); process.exit(); }
272 - for (var i = 0; i < json.length; i++) { if (json.charCodeAt(i) >= 32) { json2 += json[i]; } else { var tt = json.charCodeAt(i); if (tt != 10 && tt != 13) { badCharCount++; } } } // Remove all bad chars
280 + for (i = 0; i < json.length; i++) { if (json.charCodeAt(i) >= 32) { json2 += json[i]; } else { var tt = json.charCodeAt(i); if (tt != 10 && tt != 13) { badCharCount++; } } } // Remove all bad chars
281 if (badCharCount > 0) { console.log(badCharCount + ' invalid character(s) where removed.'); }
282 try { json = JSON.parse(json2); } catch (e) { console.log('Invalid JSON format: ' + obj.args.dbimport + ': ' + e); process.exit(); }
283 if ((json == null) || (typeof json.length != 'number') || (json.length < 1)) { console.log('Invalid JSON format: ' + obj.args.dbimport + '.'); }
276 - for (var i in json) { if ((json[i].type == "mesh") && (json[i].links != null)) { for (var j in json[i].links) { var esc = obj.common.escapeFieldName(j); if (esc !== j) { json[i].links[esc] = json[i].links[j]; delete json[i].links[j]; } } } } // Escape MongoDB invalid field chars
277 - //for (var i in json) { if ((json[i].type == "node") && (json[i].host != null)) { json[i].rname = json[i].host; delete json[i].host; } } // DEBUG: Change host to rname
284 + for (i in json) { if ((json[i].type == "mesh") && (json[i].links != null)) { for (var j in json[i].links) { var esc = obj.common.escapeFieldName(j); if (esc !== j) { json[i].links[esc] = json[i].links[j]; delete json[i].links[j]; } } } } // Escape MongoDB invalid field chars
285 + //for (i in json) { if ((json[i].type == "node") && (json[i].host != null)) { json[i].rname = json[i].host; delete json[i].host; } } // DEBUG: Change host to rname
286 obj.db.RemoveAll(function () { obj.db.InsertMany(json, function (err) { if (err != null) { console.log(err); } else { console.log('Imported ' + json.length + ' objects(s) from ' + obj.args.dbimport + '.'); } process.exit(); }); });
287 return;
288 }
@@ -333,7 +341,7 @@ function CreateMeshCentralServer(config, args) {
341 obj.db.Get('dbconfig', function (err, dbconfig) {
342 if (dbconfig.length == 1) { obj.dbconfig = dbconfig[0]; } else { obj.dbconfig = { _id: 'dbconfig', version: 1 }; }
343 if (obj.dbconfig.amtWsEventSecret == null) { require('crypto').randomBytes(32, function (err, buf) { obj.dbconfig.amtWsEventSecret = buf.toString('hex'); obj.db.Set(obj.dbconfig); }); }
336 -
344 +
345 // This is used by the user to create a username/password for a Intel AMT WSMAN event subscription
346 if (obj.args.getwspass) {
347 if (obj.args.getwspass.length == 64) {
@@ -367,12 +375,12 @@ function CreateMeshCentralServer(config, args) {
375 }
376 });
377 });
370 - }
378 + };
379
380 // Done starting the redirection server, go on to load the server certificates
381 obj.StartEx2 = function () {
382 // Load server certificates
375 - obj.certificateOperations = require('./certoperations.js').CertificateOperations()
383 + obj.certificateOperations = require('./certoperations.js').CertificateOperations();
384 obj.certificateOperations.GetMeshServerCertificate(obj, obj.args, obj.config, function (certs) {
385 if (obj.config.letsencrypt == null) {
386 obj.StartEx3(certs); // Just use the configured certificates
@@ -387,10 +395,11 @@ function CreateMeshCentralServer(config, args) {
395 }
396 }
397 });
390 - }
398 + };
399
400 // Start the server with the given certificates
401 obj.StartEx3 = function (certs) {
402 + var i;
403 obj.certificates = certs;
404 obj.certificateOperations.acceleratorStart(certs); // Set the state of the accelerators
405
@@ -398,14 +407,14 @@ function CreateMeshCentralServer(config, args) {
407 if (obj.certificates.CommonName == 'un-configured') { console.log('Server name not configured, running in LAN-only mode.'); obj.args.lanonly = true; }
408
409 // Check that no sub-domains have the same DNS as the parent
401 - for (var i in obj.config.domains) {
410 + for (i in obj.config.domains) {
411 if ((obj.config.domains[i].dns != null) && (obj.certificates.CommonName.toLowerCase() === obj.config.domains[i].dns.toLowerCase())) {
412 console.log("ERROR: Server sub-domain can't have same DNS name as the parent."); process.exit(0); return;
413 }
414 }
415
416 // Load the list of mesh agents and install scripts
408 - if (obj.args.noagentupdate == 1) { for (var i in obj.meshAgentsArchitectureNumbers) { obj.meshAgentsArchitectureNumbers[i].update = false; } }
417 + if (obj.args.noagentupdate == 1) { for (i in obj.meshAgentsArchitectureNumbers) { obj.meshAgentsArchitectureNumbers[i].update = false; } }
418 obj.updateMeshAgentsTable(function () {
419 obj.updateMeshAgentInstallScripts();
420
@@ -460,7 +469,7 @@ function CreateMeshCentralServer(config, args) {
469 obj.maintenanceTimer = setInterval(obj.maintenanceActions, 1000 * 60 * 60); // Run this every hour
470
471 // Dispatch an event that the server is now running
463 - obj.DispatchEvent(['*'], obj, { etype: 'server', action: 'started', msg: 'Server started' })
472 + obj.DispatchEvent(['*'], obj, { etype: 'server', action: 'started', msg: 'Server started' });
473
474 // Load the login cookie encryption key from the database if allowed
475 if ((obj.config) && (obj.config.settings) && (obj.config.settings.allowlogintoken == true)) {
@@ -473,12 +482,12 @@ function CreateMeshCentralServer(config, args) {
482 });
483 }
484
476 - obj.debug(1, 'Server started');
485 + //obj.debug(1, 'Server started');
486 if (obj.args.nousers == true) { obj.updateServerState('nousers', '1'); }
487 obj.updateServerState('state', 'running');
488 });
489 });
481 - }
490 + };
491
492 // Perform maintenance operations (called every hour)
493 obj.maintenanceActions = function () {
@@ -499,7 +508,7 @@ function CreateMeshCentralServer(config, args) {
508
509 // Perform other database cleanup
510 obj.db.cleanup();
502 - }
511 + };
512
513 // Stop the Meshcentral server
514 obj.Stop = function (restoreFile) {
@@ -507,7 +516,7 @@ function CreateMeshCentralServer(config, args) {
516 if (!obj.db) return;
517
518 // Dispatch an event saying the server is now stopping
510 - obj.DispatchEvent(['*'], obj, { etype: 'server', action: 'stopped', msg: 'Server stopped' })
519 + obj.DispatchEvent(['*'], obj, { etype: 'server', action: 'stopped', msg: 'Server stopped' });
520
521 // Set all nodes to power state of unknown (0)
522 var record = { type: 'power', time: Date.now(), node: '*', power: 0, s: 2 };
@@ -543,7 +552,7 @@ function CreateMeshCentralServer(config, args) {
552 });
553 }
554 });
546 - zipfile.on("end", function () { setTimeout(function () { fs.unlinkSync(restoreFile); process.exit(123); }); });
555 + zipfile.on("end", function () { setTimeout(function () { obj.fs.unlinkSync(restoreFile); process.exit(123); }); });
556 });
557 } else {
558 obj.debug(1, 'Server stopped');
@@ -553,25 +562,25 @@ function CreateMeshCentralServer(config, args) {
562
563 // Update the server state
564 obj.updateServerState('state', 'stopped');
556 - }
565 + };
566
567 // Event Dispatch
568 obj.AddEventDispatch = function (ids, target) {
569 obj.debug(3, 'AddEventDispatch', ids);
570 for (var i in ids) { var id = ids[i]; if (!obj.eventsDispatch[id]) { obj.eventsDispatch[id] = [target]; } else { obj.eventsDispatch[id].push(target); } }
562 - }
571 + };
572 obj.RemoveEventDispatch = function (ids, target) {
573 obj.debug(3, 'RemoveEventDispatch', id);
565 - for (var i in ids) { var id = ids[i]; if (obj.eventsDispatch[id]) { var j = obj.eventsDispatch[id].indexOf(target); if (j >= 0) { array.splice(j, 1); } } }
566 - }
574 + for (var i in ids) { var id = ids[i]; if (obj.eventsDispatch[id]) { var j = obj.eventsDispatch[id].indexOf(target); if (j >= 0) { obj.eventsDispatch[id].splice(j, 1); } } }
575 + };
576 obj.RemoveEventDispatchId = function (id) {
577 obj.debug(3, 'RemoveEventDispatchId', id);
578 if (obj.eventsDispatch[id] != null) { delete obj.eventsDispatch[id]; }
570 - }
579 + };
580 obj.RemoveAllEventDispatch = function (target) {
581 obj.debug(3, 'RemoveAllEventDispatch');
582 for (var i in obj.eventsDispatch) { var j = obj.eventsDispatch[i].indexOf(target); if (j >= 0) { obj.eventsDispatch[i].splice(j, 1); } }
574 - }
583 + };
584 obj.DispatchEvent = function (ids, source, event, fromPeerServer) {
585 // If the database is not setup, exit now.
586 if (!obj.db) return;
@@ -596,21 +605,21 @@ function CreateMeshCentralServer(config, args) {
605 }
606 }
607 if ((fromPeerServer == null) && (obj.multiServer != null) && ((typeof event != 'object') || (event.nopeers != 1))) { obj.multiServer.DispatchEvent(ids, source, event); }
599 - }
608 + };
609
610 // Get the connection state of a node
602 - obj.GetConnectivityState = function (nodeid) { return obj.connectivityByNode[nodeid]; }
611 + obj.GetConnectivityState = function (nodeid) { return obj.connectivityByNode[nodeid]; };
612
613 // Get the routing server id for a given node and connection type, can never be self.
614 obj.GetRoutingServerId = function (nodeid, connectType) {
615 if (obj.multiServer == null) return null;
607 - for (serverid in obj.peerConnectivityByNode) {
616 + for (var serverid in obj.peerConnectivityByNode) {
617 if (serverid == obj.serverId) continue;
618 var state = obj.peerConnectivityByNode[serverid][nodeid];
619 if ((state != null) && ((state.connectivity & connectType) != 0)) { return { serverid: serverid, meshid: state.meshid }; }
620 }
621 return null;
613 - }
622 + };
623
624 // Update the connection state of a node when in multi-server mode
625 // Update obj.connectivityByNode using obj.peerConnectivityByNode for the list of nodes in argument
@@ -618,8 +627,8 @@ function CreateMeshCentralServer(config, args) {
627 for (var nodeid in nodeids) {
628 var meshid = null, state = null, oldConnectivity = 0, oldPowerState = 0, newConnectivity = 0, newPowerState = 0;
629 var oldState = obj.connectivityByNode[nodeid];
621 - if (oldState != null) { meshid = oldState.meshid; oldConnectivity = oldState.connectivity; oldPowerState = oldState.powerState; }
622 - for (serverid in obj.peerConnectivityByNode) {
630 + if (oldState != null) { meshid = oldState.meshid; oldConnectivity = oldState.connectivity; oldPowerState = oldState.powerState; }
631 + for (var serverid in obj.peerConnectivityByNode) {
632 var peerState = obj.peerConnectivityByNode[serverid][nodeid];
633 if (peerState != null) {
634 if (state == null) {
@@ -652,7 +661,7 @@ function CreateMeshCentralServer(config, args) {
661 obj.DispatchEvent(['*', meshid], obj, { action: 'nodeconnect', meshid: meshid, nodeid: nodeid, conn: newConnectivity, pwr: newPowerState, nolog: 1, nopeers: 1 });
662 }
663 }
655 - }
664 + };
665
666 // Set the connectivity state of a node and setup the server so that messages can be routed correctly.
667 // meshId: mesh identifier of format mesh/domain/meshidhex
@@ -660,8 +669,8 @@ function CreateMeshCentralServer(config, args) {
669 // connectTime: time of connection, milliseconds elapsed since the UNIX epoch.
670 // connectType: Bitmask, 1 = MeshAgent, 2 = Intel AMT CIRA, 4 = Intel AMT local.
671 // powerState: Value, 0 = Unknown, 1 = S0 power on, 2 = S1 Sleep, 3 = S2 Sleep, 4 = S3 Sleep, 5 = S4 Hibernate, 6 = S5 Soft-Off, 7 = Present
663 - var connectTypeStrings = ['', 'MeshAgent', 'Intel AMT CIRA', '', 'Intel AMT local'];
664 - var powerStateStrings = ['Unknown', 'Powered', 'Sleep', 'Sleep', 'Deep Sleep', 'Hibernating', 'Soft-Off', 'Present'];
672 + //var connectTypeStrings = ['', 'MeshAgent', 'Intel AMT CIRA', '', 'Intel AMT local'];
673 + //var powerStateStrings = ['Unknown', 'Powered', 'Sleep', 'Sleep', 'Deep Sleep', 'Hibernating', 'Soft-Off', 'Present'];
674 obj.SetConnectivityState = function (meshid, nodeid, connectTime, connectType, powerState, serverid) {
675 //console.log('SetConnectivity for ' + nodeid.substring(0, 16) + ', Type: ' + connectTypeStrings[connectType] + ', Power: ' + powerStateStrings[powerState] + (serverid == null ? ('') : (', ServerId: ' + serverid)));
676 if ((serverid == null) && (obj.multiServer != null)) { obj.multiServer.DispatchMessage({ action: 'SetConnectivityState', meshid: meshid, nodeid: nodeid, connectTime: connectTime, connectType: connectType, powerState: powerState }); }
@@ -716,7 +725,7 @@ function CreateMeshCentralServer(config, args) {
725
726 // Set node power state
727 if (connectType == 1) { state.agentPower = powerState; } else if (connectType == 2) { state.ciraPower = powerState; } else if (connectType == 4) { state.amtPower = powerState; }
719 - var powerState = 0;
728 + var powerState = 0, oldPowerState = state.powerState;
729 if ((state.connectivity & 1) != 0) { powerState = state.agentPower; } else if ((state.connectivity & 2) != 0) { powerState = state.ciraPower; } else if ((state.connectivity & 4) != 0) { powerState = state.amtPower; }
730 if ((state.powerState == null) || (state.powerState != powerState)) {
731 state.powerState = powerState;
@@ -731,7 +740,7 @@ function CreateMeshCentralServer(config, args) {
740 var x = {}; x[nodeid] = 1;
741 obj.UpdateConnectivityState(x);
742 }
734 - }
743 + };
744
745 // Clear the connectivity state of a node and setup the server so that messages can be routed correctly.
746 // meshId: mesh identifier of format mesh/domain/meshidhex
@@ -798,7 +807,7 @@ function CreateMeshCentralServer(config, args) {
807 var x = {}; x[nodeid] = 1;
808 obj.UpdateConnectivityState(x);
809 }
801 - }
810 + };
811
812 // Update the default mesh core
813 obj.updateMeshCoreTimer = 'notset';
@@ -845,9 +854,9 @@ function CreateMeshCentralServer(config, args) {
854 obj.fs.watch(obj.path.join(meshcorePath, 'meshcore.js'), function (eventType, filename) {
855 if (obj.updateMeshCoreTimer != null) { clearTimeout(obj.updateMeshCoreTimer); obj.updateMeshCoreTimer = null; }
856 obj.updateMeshCoreTimer = setTimeout(function () { obj.updateMeshCore(); console.log('Updated meshcore.js.'); }, 5000);
848 - })
857 + });
858 }
850 - }
859 + };
860
861 // Update the default meshcmd
862 obj.updateMeshCmdTimer = 'notset';
@@ -860,7 +869,7 @@ function CreateMeshCentralServer(config, args) {
869 obj.defaultMeshCmd = null; if (func != null) { func(false); } // meshcmd.js not found
870 }
871 }
863 -
872 +
873 // Read meshcore.js and all .js files in the modules folder.
874 var moduleAdditions = 'var addedModules = [];', modulesDir = null;
875 var meshCmd = obj.fs.readFileSync(obj.path.join(meshcmdPath, 'meshcmd.js')).toString().replace("'***Mesh*Cmd*Version***'", '\'' + obj.currentVer + '\'');
@@ -886,9 +895,9 @@ function CreateMeshCentralServer(config, args) {
895 obj.fs.watch(obj.path.join(meshcmdPath, 'meshcmd.js'), function (eventType, filename) {
896 if (obj.updateMeshCmdTimer != null) { clearTimeout(obj.updateMeshCmdTimer); obj.updateMeshCmdTimer = null; }
897 obj.updateMeshCmdTimer = setTimeout(function () { obj.updateMeshCmd(); console.log('Updated meshcmd.js.'); }, 5000);
889 - })
898 + });
899 }
891 - }
900 + };
901
902 // List of possible mesh agent install scripts
903 var meshAgentsInstallScriptList = {
@@ -903,7 +912,7 @@ function CreateMeshCentralServer(config, args) {
912 var stream = null;
913 try {
914 stream = obj.fs.createReadStream(scriptpath);
906 - stream.on('data', function (data) { this.hash.update(data, 'binary') });
915 + stream.on('data', function (data) { this.hash.update(data, 'binary'); });
916 stream.on('error', function (data) {
917 // If there is an error reading this file, make sure this agent is not in the agent table
918 if (obj.meshAgentInstallScripts[this.info.id] != null) { delete obj.meshAgentInstallScripts[this.info.id]; }
@@ -915,7 +924,7 @@ function CreateMeshCentralServer(config, args) {
924 obj.meshAgentInstallScripts[this.info.id].path = this.agentpath;
925 obj.meshAgentInstallScripts[this.info.id].url = ((obj.args.notls == true) ? 'http://' : 'https://') + obj.certificates.CommonName + ':' + obj.args.port + '/meshagents?script=' + this.info.id;
926 var stats = null;
918 - try { stats = obj.fs.statSync(this.agentpath) } catch (e) { }
927 + try { stats = obj.fs.statSync(this.agentpath); } catch (e) { }
928 if (stats != null) { obj.meshAgentInstallScripts[this.info.id].size = stats.size; }
929 });
930 stream.info = meshAgentsInstallScriptList[scriptid];
@@ -923,7 +932,7 @@ function CreateMeshCentralServer(config, args) {
932 stream.hash = obj.crypto.createHash('sha384', stream);
933 } catch (e) { }
934 }
926 - }
935 + };
936
937 // List of possible mesh agents
938 obj.meshAgentsArchitectureNumbers = {
@@ -962,10 +971,10 @@ function CreateMeshCentralServer(config, args) {
971 var archcount = 0;
972 for (var archid in obj.meshAgentsArchitectureNumbers) {
973 var agentpath = obj.path.join(__dirname, 'agents', obj.meshAgentsArchitectureNumbers[archid].localname);
965 -
974 +
975 // Fetch all the agent binary information
976 var stats = null;
968 - try { stats = obj.fs.statSync(agentpath) } catch (e) { }
977 + try { stats = obj.fs.statSync(agentpath); } catch (e) { }
978 if ((stats != null)) {
979 // If file exists
980 archcount++;
@@ -991,7 +1000,7 @@ function CreateMeshCentralServer(config, args) {
1000 }
1001 if ((obj.meshAgentBinaries[3] == null) && (obj.meshAgentBinaries[10003] != null)) { obj.meshAgentBinaries[3] = obj.meshAgentBinaries[10003]; } // If only the unsigned windows binaries are present, use them.
1002 if ((obj.meshAgentBinaries[4] == null) && (obj.meshAgentBinaries[10004] != null)) { obj.meshAgentBinaries[4] = obj.meshAgentBinaries[10004]; } // If only the unsigned windows binaries are present, use them.
994 - }
1003 + };
1004
1005 // Generate a time limited user login token
1006 obj.getLoginToken = function (userid, func) {
@@ -1016,7 +1025,7 @@ function CreateMeshCentralServer(config, args) {
1025 });
1026 }
1027 });
1019 - }
1028 + };
1029
1030 // Show the yser login token generation key
1031 obj.showLoginTokenKey = function (func) {
@@ -1031,13 +1040,13 @@ function CreateMeshCentralServer(config, args) {
1040 obj.db.Set({ _id: 'LoginCookieEncryptionKey', key: obj.loginCookieEncryptionKey.toString('hex'), time: Date.now() }, function () { func(obj.loginCookieEncryptionKey.toString('hex')); });
1041 }
1042 });
1034 - }
1043 + };
1044
1045 // Generate a cryptographic key used to encode and decode cookies
1046 obj.generateCookieKey = function () {
1047 return new Buffer(obj.crypto.randomBytes(32), 'binary');
1048 //return Buffer.alloc(32, 0); // Sets the key to zeros, debug only.
1040 - }
1049 + };
1050
1051 // Encode an object as a cookie using a key. (key must be 32 bytes long)
1052 obj.encodeCookie = function (o, key) {
@@ -1048,7 +1057,7 @@ function CreateMeshCentralServer(config, args) {
1057 var crypted = Buffer.concat([cipher.update(JSON.stringify(o), 'utf8'), cipher.final()]);
1058 return Buffer.concat([iv, cipher.getAuthTag(), crypted]).toString('base64').replace(/\+/g, '@').replace(/\//g, '$');
1059 } catch (e) { return null; }
1051 - }
1060 + };
1061
1062 // Decode a cookie back into an object using a key. Return null if it's not a valid cookie. (key must be 32 bytes long)
1063 obj.decodeCookie = function (cookie, key, timeout) {
@@ -1065,7 +1074,7 @@ function CreateMeshCentralServer(config, args) {
1074 if ((o.dtime > (timeout * 60000)) || (o.dtime < -30000)) return null; // The cookie is only valid 120 seconds, or 30 seconds back in time (in case other server's clock is not quite right)
1075 return o;
1076 } catch (e) { return null; }
1068 - }
1077 + };
1078
1079 // Debug
1080 obj.debug = function (lvl) {
@@ -1074,11 +1083,11 @@ function CreateMeshCentralServer(config, args) {
1083 else if (arguments.length == 3) { console.log(arguments[1], arguments[2]); }
1084 else if (arguments.length == 4) { console.log(arguments[1], arguments[2], arguments[3]); }
1085 else if (arguments.length == 5) { console.log(arguments[1], arguments[2], arguments[3], arguments[4]); }
1077 - }
1086 + };
1087
1088 // Update server state. Writes a server state file.
1089 var meshServerState = {};
1081 - obj.updateServerState = function(name, val) {
1090 + obj.updateServerState = function (name, val) {
1091 if ((name != null) && (val != null)) {
1092 var changed = false;
1093 if ((name != null) && (meshServerState[name] != val)) { if ((val == null) && (meshServerState[name] != null)) { delete meshServerState[name]; changed = true; } else { if (meshServerState[name] != val) { meshServerState[name] = val; changed = true; } } }
@@ -1087,7 +1096,7 @@ function CreateMeshCentralServer(config, args) {
1096 var r = 'time=' + Date.now() + '\r\n';
1097 for (var i in meshServerState) { r += (i + '=' + meshServerState[i] + '\r\n'); }
1098 obj.fs.writeFileSync(obj.getConfigFilePath('serverstate.txt'), r);
1090 - }
1099 + };
1100
1101 // Logging funtions
1102 function logException(e) { e += ''; logErrorEvent(e); }
@@ -1124,7 +1133,7 @@ function CreateMeshCentralServer(config, args) {
1133 }
1134 //console.log('getConfigFilePath(\"' + filename + '\") = ' + obj.path.join(obj.datapath, filename));
1135 return obj.path.join(obj.datapath, filename);
1127 - }
1136 + };
1137
1138 return obj;
1139 }
@@ -1132,6 +1141,7 @@ function CreateMeshCentralServer(config, args) {
1141 // Return the server configuration
1142 function getConfig() {
1143 // Figure out the datapath location
1144 + var i;
1145 var fs = require('fs');
1146 var path = require('path');
1147 var datapath = null;
@@ -1150,7 +1160,7 @@ function getConfig() {
1160 // Load and validate the configuration file
1161 try { config = require(configFilePath); } catch (e) { console.log('ERROR: Unable to parse ' + configFilePath + '.'); return null; }
1162 if (config.domains == null) { config.domains = {}; }
1153 - 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; } }
1163 + for (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; } }
1164 } else {
1165 // Copy the "sample-config.json" to give users a starting point
1166 var sampleConfigPath = path.join(__dirname, 'sample-config.json');
@@ -1159,7 +1169,7 @@ function getConfig() {
1169
1170 // Set the command line arguments to the config file if they are not present
1171 if (!config.settings) { config.settings = {}; }
1162 - for (var i in args) { config.settings[i] = args[i]; }
1172 + for (i in args) { config.settings[i] = args[i]; }
1173
1174 // Lower case all keys in the config file
1175 require('./common.js').objKeysToLower(config);
meshrelay.js
+14 -8
@@ -6,7 +6,12 @@
6 * @version v0.0.1
7 */
8
9 -'use strict';
9 +/*jslint node: true */
10 +/*jshint node: true */
11 +/*jshint strict:false */
12 +/*jshint -W097 */
13 +/*jshint esversion: 6 */
14 +"use strict";
15
16 module.exports.CreateMeshRelay = function (parent, ws, req, domain) {
17 var obj = {};
@@ -23,9 +28,10 @@ module.exports.CreateMeshRelay = function (parent, ws, req, domain) {
28 obj.close = function (arg) {
29 if ((arg == 1) || (arg == null)) { try { obj.ws.close(); obj.parent.parent.debug(1, 'Relay: Soft disconnect (' + obj.remoteaddr + ')'); } catch (e) { console.log(e); } } // Soft close, close the websocket
30 if (arg == 2) { try { obj.ws._socket._parent.end(); obj.parent.parent.debug(1, 'Relay: Hard disconnect (' + obj.remoteaddr + ')'); } catch (e) { console.log(e); } } // Hard close, close the TCP socket
26 - }
31 + };
32
33 obj.sendAgentMessage = function (command, userid, domainid) {
34 + var rights;
35 if (command.nodeid == null) return false;
36 var user = obj.parent.users[userid];
37 if (user == null) return false;
@@ -37,7 +43,7 @@ module.exports.CreateMeshRelay = function (parent, ws, req, domain) {
43 var agent = obj.parent.wsagents[command.nodeid];
44 if (agent != null) {
45 // Check if we have permission to send a message to that node
40 - var rights = user.links[agent.dbMeshKey];
46 + rights = user.links[agent.dbMeshKey];
47 if (rights != null || ((rights & 16) != 0)) { // TODO: 16 is console permission, may need more gradular permission checking
48 command.sessionid = ws.sessionId; // Set the session id, required for responses.
49 command.rights = rights.rights; // Add user rights flags to the message
@@ -50,7 +56,7 @@ module.exports.CreateMeshRelay = function (parent, ws, req, domain) {
56 var routing = obj.parent.parent.GetRoutingServerId(command.nodeid, 1); // 1 = MeshAgent routing type
57 if (routing != null) {
58 // Check if we have permission to send a message to that node
53 - var rights = user.links[routing.meshid];
59 + rights = user.links[routing.meshid];
60 if (rights != null || ((rights & 16) != 0)) { // TODO: 16 is console permission, may need more gradular permission checking
61 command.fromSessionid = ws.sessionId; // Set the session id, required for responses.
62 command.rights = rights.rights; // Add user rights flags to the message
@@ -61,7 +67,7 @@ module.exports.CreateMeshRelay = function (parent, ws, req, domain) {
67 }
68 }
69 return false;
64 - }
70 + };
71
72 if (req.query.auth == null) {
73 // Use ExpressJS session, check if this session is a logged in user, at least one of the two connections will need to be authenticated.
@@ -160,7 +166,7 @@ module.exports.CreateMeshRelay = function (parent, ws, req, domain) {
166 // Wait for other relay connection
167 ws.pause(); // Hold traffic until the other connection
168 parent.wsrelays[obj.id] = { peer1: obj, state: 1 };
163 - obj.parent.parent.debug(1, 'Relay holding: ' + obj.id + ' (' + obj.remoteaddr + ') ' + (obj.authenticated?'Authenticated':'') );
169 + obj.parent.parent.debug(1, 'Relay holding: ' + obj.id + ' (' + obj.remoteaddr + ') ' + (obj.authenticated ? 'Authenticated' : ''));
170
171 // Check if a peer server has this connection
172 if (parent.parent.multiServer != null) {
@@ -213,6 +219,6 @@ module.exports.CreateMeshRelay = function (parent, ws, req, domain) {
219 obj.id = null;
220 }
221 });
216 -
222 +
223 return obj;
218 -}
224 +};
meshscanner.js
+40 -31
@@ -6,7 +6,12 @@
6 * @version v0.0.1
7 */
8
9 -'use strict';
9 +/*jslint node: true */
10 +/*jshint node: true */
11 +/*jshint strict:false */
12 +/*jshint -W097 */
13 +/*jshint esversion: 6 */
14 +"use strict";
15
16 // Construct a Mesh Scanner object
17 // TODO: We need once "server4" and "server6" per interface, or change the default multicast interface as we send.
@@ -26,9 +31,10 @@ module.exports.CreateMeshScanner = function (parent) {
31
32 // Get a list of IPv4 and IPv6 interface addresses
33 function getInterfaceList() {
34 + var i;
35 var ipv4 = ['*'], ipv6 = ['*']; // Bind to IN_ADDR_ANY always
36 var interfaces = require('os').networkInterfaces();
31 - for (var i in interfaces) {
37 + for (i in interfaces) {
38 var xinterface = interfaces[i];
39 for (var j in xinterface) {
40 var interface2 = xinterface[j];
@@ -43,11 +49,11 @@ module.exports.CreateMeshScanner = function (parent) {
49
50 // Setup all IPv4 and IPv6 servers
51 function setupServers() {
46 - var addresses = getInterfaceList();
47 - for (var i in obj.servers4) { obj.servers4[i].xxclear = true; }
48 - for (var i in obj.servers6) { obj.servers6[i].xxclear = true; }
49 - for (var i in addresses.ipv4) {
50 - var localAddress = addresses.ipv4[i];
52 + var addresses = getInterfaceList(), i, localAddress, bindOptions;
53 + for (i in obj.servers4) { obj.servers4[i].xxclear = true; }
54 + for (i in obj.servers6) { obj.servers6[i].xxclear = true; }
55 + for (i in addresses.ipv4) {
56 + localAddress = addresses.ipv4[i];
57 if (obj.servers4[localAddress] != null) {
58 // Server already exists
59 obj.servers4[localAddress].xxclear = false;
@@ -59,7 +65,7 @@ module.exports.CreateMeshScanner = function (parent) {
65 server4.xxtype = 4;
66 server4.xxlocal = localAddress;
67 server4.on('error', function (err) { if (this.xxlocal == '*') { console.log("ERROR: Server port 16989 not available, check if server is running twice."); } this.close(); delete obj.servers6[this.xxlocal]; });
62 - var bindOptions = { port: 16989, exclusive: true };
68 + bindOptions = { port: 16989, exclusive: true };
69 if (server4.xxlocal != '*') { bindOptions.address = server4.xxlocal; }
70 server4.bind(bindOptions, function () {
71 try {
@@ -77,8 +83,8 @@ module.exports.CreateMeshScanner = function (parent) {
83 }
84 }
85
80 - for (var i in addresses.ipv6) {
81 - var localAddress = addresses.ipv6[i];
86 + for (i in addresses.ipv6) {
87 + localAddress = addresses.ipv6[i];
88 if (obj.servers6[localAddress] != null) {
89 // Server already exists
90 obj.servers6[localAddress].xxclear = false;
@@ -90,7 +96,7 @@ module.exports.CreateMeshScanner = function (parent) {
96 server6.xxtype = 6;
97 server6.xxlocal = localAddress;
98 server6.on('error', function (err) { this.close(); delete obj.servers6[this.xxlocal]; });
93 - var bindOptions = { port: 16989, exclusive: true };
99 + bindOptions = { port: 16989, exclusive: true };
100 if (server6.xxlocal != '*') { bindOptions.address = server6.xxlocal; }
101 server6.bind(bindOptions, function () {
102 try {
@@ -108,14 +114,15 @@ module.exports.CreateMeshScanner = function (parent) {
114 }
115 }
116
111 - for (var i in obj.servers4) { if (obj.servers4[i].xxclear == true) { obj.servers4[i].close(); delete obj.servers4[i]; }; }
112 - for (var i in obj.servers6) { if (obj.servers6[i].xxclear == true) { obj.servers6[i].close(); delete obj.servers6[i]; }; }
117 + for (i in obj.servers4) { if (obj.servers4[i].xxclear == true) { obj.servers4[i].close(); delete obj.servers4[i]; } }
118 + for (i in obj.servers6) { if (obj.servers6[i].xxclear == true) { obj.servers6[i].close(); delete obj.servers6[i]; } }
119 }
120
121 // Clear all IPv4 and IPv6 servers
122 function clearServers() {
117 - for (var i in obj.servers4) { obj.servers4[i].close(); delete obj.servers4[i]; }
118 - for (var i in obj.servers6) { obj.servers6[i].close(); delete obj.servers6[i]; }
123 + var i;
124 + for (i in obj.servers4) { obj.servers4[i].close(); delete obj.servers4[i]; }
125 + for (i in obj.servers6) { obj.servers6[i].close(); delete obj.servers6[i]; }
126 }
127
128 // Start scanning for local network Mesh Agents
@@ -128,27 +135,28 @@ module.exports.CreateMeshScanner = function (parent) {
135 setupServers();
136 obj.mainTimer = setInterval(obj.performScan, periodicScanTime);
137 return obj;
131 - }
138 + };
139
140 // Stop scanning for local network Mesh Agents
141 obj.stop = function () {
142 if (obj.mainTimer != null) { clearInterval(obj.mainTimer); obj.mainTimer = null; }
143 clearServers();
137 - }
144 + };
145
146 // Look for all Mesh Agents that may be locally reachable, indicating the presense of this server.
147 obj.performScan = function (server) {
148 + var i;
149 if (server != null) {
150 if (server.xxtype == 4) { try { server.send(obj.multicastPacket4, 0, obj.multicastPacket4.length, 16990, membershipIPv4); } catch (e) { } }
151 if (server.xxtype == 6) { try { server.send(obj.multicastPacket6, 0, obj.multicastPacket6.length, 16990, membershipIPv6); } catch (e) { } }
152 if ((server.xxtype == 4) && (server.xxlocal == '*')) { try { server.send(obj.multicastPacket4, 0, obj.multicastPacket4.length, 16990, '127.0.0.1'); } catch (e) { } try { server.send(obj.multicastPacket4, 0, obj.multicastPacket4.length, 16990, '255.255.255.255'); } catch (e) { } }
153 if ((server.xxtype == 6) && (server.xxlocal == '*')) { try { server.send(obj.multicastPacket6, 0, obj.multicastPacket6.length, 16990, '::1'); } catch (e) { } }
154 } else {
147 - for (var i in obj.servers4) { try { obj.servers4[i].send(obj.multicastPacket4, 0, obj.multicastPacket4.length, 16990, membershipIPv4); } catch (e) { } }
148 - for (var i in obj.servers6) { try { obj.servers6[i].send(obj.multicastPacket6, 0, obj.multicastPacket6.length, 16990, membershipIPv6); } catch (e) { } }
155 + for (i in obj.servers4) { try { obj.servers4[i].send(obj.multicastPacket4, 0, obj.multicastPacket4.length, 16990, membershipIPv4); } catch (e) { } }
156 + for (i in obj.servers6) { try { obj.servers6[i].send(obj.multicastPacket6, 0, obj.multicastPacket6.length, 16990, membershipIPv6); } catch (e) { } }
157 setupServers(); // Check if any network interfaces where added or removed
158 }
151 - }
159 + };
160
161 // Called when a UDP packet is received from an agent.
162 function onUdpPacket(msg, info, server) {
@@ -161,26 +169,27 @@ module.exports.CreateMeshScanner = function (parent) {
169
170 // As a side job, we also send server wake-on-lan packets
171 obj.wakeOnLan = function (macs) {
164 - for (var i in macs) {
172 + var i, j;
173 + for (i in macs) {
174 var mac = macs[i];
175 var hexpacket = 'FFFFFFFFFFFF';
167 - for (var i = 0; i < 16; i++) { hexpacket += mac; }
176 + for (j = 0; j < 16; j++) { hexpacket += mac; }
177 var wakepacket = Buffer.from(hexpacket, 'hex');
178 //console.log(wakepacket.toString('hex'));
179
180 // Send the wake packet 3 times with small time intervals
172 - for (var i in obj.servers4) { obj.servers4[i].send(wakepacket, 0, wakepacket.length, 7, "255.255.255.255"); obj.servers4[i].send(wakepacket, 0, wakepacket.length, 16990, membershipIPv4); }
173 - for (var i in obj.servers6) { obj.servers6[i].send(wakepacket, 0, wakepacket.length, 16990, membershipIPv6); }
181 + for (j in obj.servers4) { obj.servers4[j].send(wakepacket, 0, wakepacket.length, 7, "255.255.255.255"); obj.servers4[j].send(wakepacket, 0, wakepacket.length, 16990, membershipIPv4); }
182 + for (j in obj.servers6) { obj.servers6[j].send(wakepacket, 0, wakepacket.length, 16990, membershipIPv6); }
183 setTimeout(function () {
175 - for (var i in obj.servers4) { obj.servers4[i].send(wakepacket, 0, wakepacket.length, 7, "255.255.255.255"); obj.servers4[i].send(wakepacket, 0, wakepacket.length, 16990, membershipIPv4); }
176 - for (var i in obj.servers6) { obj.servers6[i].send(wakepacket, 0, wakepacket.length, 16990, membershipIPv6); }
184 + for (j in obj.servers4) { obj.servers4[j].send(wakepacket, 0, wakepacket.length, 7, "255.255.255.255"); obj.servers4[j].send(wakepacket, 0, wakepacket.length, 16990, membershipIPv4); }
185 + for (j in obj.servers6) { obj.servers6[j].send(wakepacket, 0, wakepacket.length, 16990, membershipIPv6); }
186 }, 200);
187 setTimeout(function () {
179 - for (var i in obj.servers4) { obj.servers4[i].send(wakepacket, 0, wakepacket.length, 7, "255.255.255.255"); obj.servers4[i].send(wakepacket, 0, wakepacket.length, 16990, membershipIPv4); }
180 - for (var i in obj.servers6) { obj.servers6[i].send(wakepacket, 0, wakepacket.length, 16990, membershipIPv6); }
188 + for (j in obj.servers4) { obj.servers4[j].send(wakepacket, 0, wakepacket.length, 7, "255.255.255.255"); obj.servers4[j].send(wakepacket, 0, wakepacket.length, 16990, membershipIPv4); }
189 + for (j in obj.servers6) { obj.servers6[j].send(wakepacket, 0, wakepacket.length, 16990, membershipIPv6); }
190 }, 500);
191 }
183 - }
184 -
192 + };
193 +
194 return obj;
186 -}
\ No newline at end of file
195 +};
\ No newline at end of file
meshuser.js
+93 -85
@@ -6,7 +6,12 @@
6 * @version v0.0.1
7 */
8
9 -'use strict';
9 +/*jslint node: true */
10 +/*jshint node: true */
11 +/*jshint strict:false */
12 +/*jshint -W097 */
13 +/*jshint esversion: 6 */
14 +"use strict";
15
16 // Construct a MeshAgent object, called upon connection
17 module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
@@ -27,7 +32,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
32 obj.close = function (arg) {
33 if ((arg == 1) || (arg == null)) { try { obj.ws.close(); obj.parent.parent.debug(1, 'Soft disconnect'); } catch (e) { console.log(e); } } // Soft close, close the websocket
34 if (arg == 2) { try { obj.ws._socket._parent.end(); obj.parent.parent.debug(1, 'Hard disconnect'); } catch (e) { console.log(e); } } // Hard close, close the TCP socket
30 - }
35 + };
36
37 // Convert a mesh path array into a real path on the server side
38 function meshPathToRealPath(meshpath, user) {
@@ -52,22 +57,22 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
57
58 //
59 function copyFile(src, dest, func, tag) {
55 - //var ss = obj.fs.createReadStream(src, { flags: 'rb' });
60 + //var ss = obj.fs.createReadStream(src, { flags: 'rb' });
61 //var ds = obj.fs.createWriteStream(dest, { flags: 'wb' });
62 var ss = obj.fs.createReadStream(src);
63 var ds = obj.fs.createWriteStream(dest);
64 ss.fs = obj.fs;
60 - ss.pipe(ds);
65 + ss.pipe(ds);
66 ds.ss = ss;
67 /*
68 if (!this._copyStreams) { this._copyStreams = {}; this._copyStreamID = 0; }
69 ss.id = this._copyStreamID++;
70 this._copyStreams[ss.id] = ss;
71 */
67 - if (arguments.length == 3 && typeof arguments[2] === 'function') { ds.on('close', arguments[2]); }
68 - else if (arguments.length == 4 && typeof arguments[3] === 'function') { ds.on('close', arguments[3]); }
69 - ds.on('close', function() { /*delete this.ss.fs._copyStreams[this.ss.id];*/ func(tag); });
70 - };
72 + if (arguments.length == 3 && typeof arguments[2] === 'function') { ds.on('close', arguments[2]); }
73 + else if (arguments.length == 4 && typeof arguments[3] === 'function') { ds.on('close', arguments[3]); }
74 + ds.on('close', function () { /*delete this.ss.fs._copyStreams[this.ss.id];*/ func(tag); });
75 + }
76
77 try {
78 // Check if the user is logged in
@@ -83,7 +88,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
88 obj.parent.wssessions2[ws.sessionId] = obj.ws;
89 if (!obj.parent.wssessions[user._id]) { obj.parent.wssessions[user._id] = [ws]; } else { obj.parent.wssessions[user._id].push(obj.ws); }
90 if (obj.parent.parent.multiServer == null) {
86 - obj.parent.parent.DispatchEvent(['*'], obj, { action: 'wssessioncount', username: user.name, count: obj.parent.wssessions[user._id].length, nolog: 1, domain: obj.domain.id })
91 + obj.parent.parent.DispatchEvent(['*'], obj, { action: 'wssessioncount', username: user.name, count: obj.parent.wssessions[user._id].length, nolog: 1, domain: obj.domain.id });
92 } else {
93 obj.parent.recountSessions(obj.ws.sessionId); // Recount sessions
94 }
@@ -101,14 +106,14 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
106 else { ws.send(JSON.stringify({ action: 'event', event: event })); }
107 } catch (e) { }
108 }
104 - }
109 + };
110
111 user.subscriptions = obj.parent.subscribe(user._id, ws); // Subscribe to events
112 obj.ws._socket.setKeepAlive(true, 240000); // Set TCP keep alive
113
114 // When data is received from the web socket
115 ws.on('message', function (msg) {
111 - var command, user = obj.parent.users[req.session.userid];
116 + var command, user = obj.parent.users[req.session.userid], i = 0, mesh = null, meshid = null, nodeid = null, meshlinks = null, change = 0;
117 try { command = JSON.parse(msg.toString('utf8')); } catch (e) { return; }
118 if ((user == null) || (obj.common.validateString(command.action, 3, 32) == false)) return; // User must be set and action must be a string between 3 and 32 chars
119
@@ -118,7 +123,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
123 {
124 // Request a list of all meshes this user as rights to
125 var docs = [];
121 - for (var i in user.links) { if (obj.parent.meshes[i]) { docs.push(obj.parent.meshes[i]); } }
126 + for (i in user.links) { if (obj.parent.meshes[i]) { docs.push(obj.parent.meshes[i]); } }
127 ws.send(JSON.stringify({ action: 'meshes', meshes: docs, tag: command.tag }));
128 break;
129 }
@@ -127,10 +132,10 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
132 var links = [];
133 if (command.meshid == null) {
134 // Request a list of all meshes this user as rights to
130 - for (var i in user.links) { links.push(i); }
135 + for (i in user.links) { links.push(i); }
136 } else {
137 // Request list of all nodes for one specific meshid
133 - var meshid = command.meshid;
138 + meshid = command.meshid;
139 if (obj.common.validateString(meshid, 0, 128) == false) return;
140 if (meshid.split('/').length == 0) { meshid = 'mesh/' + domain.id + '/' + command.meshid; }
141 if (user.links[meshid] != null) { links.push(meshid); }
@@ -139,7 +144,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
144 // Request a list of all nodes
145 obj.db.GetAllTypeNoTypeFieldMeshFiltered(links, domain.id, 'node', function (err, docs) {
146 var r = {};
142 - for (var i in docs) {
147 + for (i in docs) {
148 // Add the connection state
149 var state = obj.parent.parent.GetConnectivityState(docs[i]._id);
150 if (state) {
@@ -150,7 +155,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
155 }
156
157 // Compress the meshid's
153 - var meshid = docs[i].meshid;
158 + meshid = docs[i].meshid;
159 if (!r[meshid]) { r[meshid] = []; }
160 delete docs[i].meshid;
161
@@ -171,7 +176,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
176 obj.db.getPowerTimeline(command.nodeid, function (err, docs) {
177 if (err == null && docs.length > 0) {
178 var timeline = [], time = null, previousPower;
174 - for (var i in docs) {
179 + for (i in docs) {
180 var doc = docs[i];
181 if (time == null) {
182 // First element
@@ -228,14 +233,14 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
233 if (path == null) break;
234
235 if ((command.fileop == 'createfolder') && (obj.common.IsFilenameValid(command.newfolder) == true)) { try { obj.fs.mkdirSync(path + "/" + command.newfolder); } catch (e) { } } // Create a new folder
231 - else if (command.fileop == 'delete') { if (obj.common.validateArray(command.delfiles, 1) == false) return; for (var i in command.delfiles) { if (obj.common.IsFilenameValid(command.delfiles[i]) == true) { var fullpath = path + "/" + command.delfiles[i]; try { obj.fs.rmdirSync(fullpath); } catch (e) { try { obj.fs.unlinkSync(fullpath); } catch (e) { } } } } } // Delete
236 + else if (command.fileop == 'delete') { if (obj.common.validateArray(command.delfiles, 1) == false) return; for (i in command.delfiles) { if (obj.common.IsFilenameValid(command.delfiles[i]) == true) { var fullpath = path + "/" + command.delfiles[i]; try { obj.fs.rmdirSync(fullpath); } catch (e) { try { obj.fs.unlinkSync(fullpath); } catch (e) { } } } } } // Delete
237 else if ((command.fileop == 'rename') && (obj.common.IsFilenameValid(command.oldname) == true) && (obj.common.IsFilenameValid(command.newname) == true)) { try { obj.fs.renameSync(path + "/" + command.oldname, path + "/" + command.newname); } catch (e) { } } // Rename
238 else if ((command.fileop == 'copy') || (command.fileop == 'move')) {
239 if (obj.common.validateArray(command.names, 1) == false) return;
240 var scpath = meshPathToRealPath(command.scpath, user); // This will also check access rights
241 if (scpath == null) break;
242 // TODO: Check quota if this is a copy!!!!!!!!!!!!!!!!
238 - for (var i in command.names) {
243 + for (i in command.names) {
244 var s = obj.path.join(scpath, command.names[i]), d = obj.path.join(path, command.names[i]);
245 sendUpdate = false;
246 copyFile(s, d, function (op) { if (op != null) { obj.fs.unlink(op, function () { obj.parent.parent.DispatchEvent([user._id], obj, 'updatefiles'); }); } else { obj.parent.parent.DispatchEvent([user._id], obj, 'updatefiles'); } }, ((command.fileop == 'move') ? s : null));
@@ -319,7 +324,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
324 // Delete all events
325 if (user.siteadmin != 0xFFFFFFFF) break;
326 obj.db.RemoveAllEvents(domain.id);
322 - obj.parent.parent.DispatchEvent(['*', 'server-global'], obj, { action: 'clearevents', nolog: 1, domain: domain.id })
327 + obj.parent.parent.DispatchEvent(['*', 'server-global'], obj, { action: 'clearevents', nolog: 1, domain: domain.id });
328 break;
329 }
330 case 'users':
@@ -327,7 +332,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
332 // Request a list of all users
333 if ((user.siteadmin & 2) == 0) break;
334 var docs = [];
330 - for (var i in obj.parent.users) {
335 + for (i in obj.parent.users) {
336 if ((obj.parent.users[i].domain == domain.id) && (obj.parent.users[i].name != '~')) {
337 var userinfo = obj.common.Clone(obj.parent.users[i]);
338 delete userinfo.hash;
@@ -403,10 +408,10 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
408 if ((user.siteadmin & 2) == 0) break;
409 if (obj.parent.parent.multiServer == null) {
410 // No peering, use simple session counting
406 - for (var i in obj.parent.wssessions) { if (obj.parent.wssessions[i][0].domainid == domain.id) { wssessions[i] = obj.parent.wssessions[i].length; } }
411 + for (i in obj.parent.wssessions) { if (obj.parent.wssessions[i][0].domainid == domain.id) { wssessions[i] = obj.parent.wssessions[i].length; } }
412 } else {
413 // We have peer servers, use more complex session counting
409 - for (var userid in obj.parent.sessionsCount) { if (userid.split('/')[1] == domain.id) { wssessions[userid] = obj.parent.sessionsCount[userid]; } }
414 + for (i in obj.parent.sessionsCount) { if (i.split('/')[1] == domain.id) { wssessions[i] = obj.parent.sessionsCount[i]; } }
415 }
416 ws.send(JSON.stringify({ action: 'wssessioncount', wssessions: wssessions, tag: command.tag })); // wssessions is: userid --> count
417 break;
@@ -422,15 +427,15 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
427
428 // Remove all the mesh links to this user
429 if (deluser.links != null) {
425 - for (var meshid in deluser.links) {
430 + for (meshid in deluser.links) {
431 // Get the mesh
427 - var mesh = obj.parent.meshes[meshid];
432 + mesh = obj.parent.meshes[meshid];
433 if (mesh) {
434 // Remove user from the mesh
435 if (mesh.links[deluser._id] != null) { delete mesh.links[deluser._id]; obj.parent.db.Set(mesh); }
436 // Notify mesh change
432 - var change = 'Removed user ' + deluser.name + ' from mesh ' + mesh.name;
433 - obj.parent.parent.DispatchEvent(['*', mesh._id, deluser._id, userid], obj, { etype: 'mesh', username: user.name, userid: userid, meshid: mesh._id, name: mesh.name, mtype: mesh.mtype, desc: mesh.desc, action: 'meshchange', links: mesh.links, msg: change, domain: domain.id })
437 + change = 'Removed user ' + deluser.name + ' from mesh ' + mesh.name;
438 + obj.parent.parent.DispatchEvent(['*', mesh._id, deluser._id, user._id], obj, { etype: 'mesh', username: user.name, userid: user._id, meshid: mesh._id, name: mesh.name, mtype: mesh.mtype, desc: mesh.desc, action: 'meshchange', links: mesh.links, msg: change, domain: domain.id });
439 }
440 }
441 }
@@ -446,7 +451,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
451
452 obj.db.Remove(deluserid);
453 delete obj.parent.users[deluserid];
449 - obj.parent.parent.DispatchEvent(['*', 'server-users'], obj, { etype: 'user', userid: deluserid, username: deluser.name, action: 'accountremove', msg: 'Account removed', domain: domain.id })
454 + obj.parent.parent.DispatchEvent(['*', 'server-users'], obj, { etype: 'user', userid: deluserid, username: deluser.name, action: 'accountremove', msg: 'Account removed', domain: domain.id });
455 obj.parent.parent.DispatchEvent([deluserid], obj, 'close');
456
457 break;
@@ -474,7 +479,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
479 if (newuser2.subscriptions) { delete newuser2.subscriptions; }
480 if (newuser2.salt) { delete newuser2.salt; }
481 if (newuser2.hash) { delete newuser2.hash; }
477 - obj.parent.parent.DispatchEvent(['*', 'server-users'], obj, { etype: 'user', username: newusername, account: newuser2, action: 'accountcreate', msg: 'Account created, email is ' + command.email, domain: domain.id })
482 + obj.parent.parent.DispatchEvent(['*', 'server-users'], obj, { etype: 'user', username: newusername, account: newuser2, action: 'accountcreate', msg: 'Account created, email is ' + command.email, domain: domain.id });
483 });
484 }
485 break;
@@ -483,12 +488,13 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
488 {
489 // Edit a user account, may involve changing email or administrator permissions
490 if (((user.siteadmin & 2) != 0) || (user.name == command.name)) {
486 - var chguserid = 'user/' + domain.id + '/' + command.name.toLowerCase(), chguser = obj.parent.users[chguserid], change = 0;
491 + var chguserid = 'user/' + domain.id + '/' + command.name.toLowerCase(), chguser = obj.parent.users[chguserid];
492 + change = 0;
493 if (chguser) {
494 if (obj.common.validateString(command.email, 1, 256) && (chguser.email != command.email)) { chguser.email = command.email; change = 1; }
495 if ((command.emailVerified === true || command.emailVerified === false) && (chguser.emailVerified != command.emailVerified)) { chguser.emailVerified = command.emailVerified; change = 1; }
496 if (obj.common.validateInt(command.quota, 0) && (command.quota != chguser.quota)) { chguser.quota = command.quota; if (chguser.quota == null) { delete chguser.quota; } change = 1; }
491 - if ((user.siteadmin == 0xFFFFFFFF) && obj.common.validateInt(command.siteadmin) && (chguser.siteadmin != command.siteadmin)) { chguser.siteadmin = command.siteadmin; change = 1 }
497 + if ((user.siteadmin == 0xFFFFFFFF) && obj.common.validateInt(command.siteadmin) && (chguser.siteadmin != command.siteadmin)) { chguser.siteadmin = command.siteadmin; change = 1; }
498 if (change == 1) {
499 obj.db.SetUser(chguser);
500 obj.parent.parent.DispatchEvent([chguser._id], obj, 'resubscribe');
@@ -500,7 +506,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
506 delete userinfo.domain;
507 delete userinfo.subscriptions;
508 delete userinfo.passtype;
503 - obj.parent.parent.DispatchEvent(['*', 'server-users', user._id, chguser._id], obj, { etype: 'user', username: user.name, account: userinfo, action: 'accountchange', msg: 'Account changed: ' + command.name, domain: domain.id })
509 + obj.parent.parent.DispatchEvent(['*', 'server-users', user._id, chguser._id], obj, { etype: 'user', username: user.name, account: userinfo, action: 'accountchange', msg: 'Account changed: ' + command.name, domain: domain.id });
510 }
511 if ((chguser.siteadmin) && (chguser.siteadmin != 0xFFFFFFFF) && (chguser.siteadmin & 32)) {
512 obj.parent.parent.DispatchEvent([chguser._id], obj, 'close'); // Disconnect all this user's sessions
@@ -534,11 +540,12 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
540
541 // Get the list of sessions for this user
542 var sessions = obj.parent.wssessions[command.userid];
537 - if (sessions != null) { for (var i in sessions) { sessions[i].send(JSON.stringify(notification)); } }
543 + if (sessions != null) { for (i in sessions) { sessions[i].send(JSON.stringify(notification)); } }
544
545 if (obj.parent.parent.multiServer != null) {
546 // TODO: Add multi-server support
547 }
548 + break;
549 }
550 case 'serverversion':
551 {
@@ -564,10 +571,10 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
571 if ((command.meshtype == 1) || (command.meshtype == 2)) {
572 // Create a type 1 agent-less Intel AMT mesh.
573 obj.parent.crypto.randomBytes(48, function (err, buf) {
567 - var meshid = 'mesh/' + domain.id + '/' + buf.toString('base64').replace(/\+/g, '@').replace(/\//g, '$');
568 - var links = {}
574 + meshid = 'mesh/' + domain.id + '/' + buf.toString('base64').replace(/\+/g, '@').replace(/\//g, '$');
575 + var links = {};
576 links[user._id] = { name: user.name, rights: 0xFFFFFFFF };
570 - var mesh = { type: 'mesh', _id: meshid, name: command.meshname, mtype: command.meshtype, desc: command.desc, domain: domain.id, links: links };
577 + mesh = { type: 'mesh', _id: meshid, name: command.meshname, mtype: command.meshtype, desc: command.desc, domain: domain.id, links: links };
578 obj.db.Set(obj.common.escapeLinksFieldName(mesh));
579 obj.parent.meshes[meshid] = mesh;
580 obj.parent.parent.AddEventDispatch([meshid], ws);
@@ -575,7 +582,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
582 user.links[meshid] = { rights: 0xFFFFFFFF };
583 user.subscriptions = obj.parent.subscribe(user._id, ws);
584 obj.db.SetUser(user);
578 - obj.parent.parent.DispatchEvent(['*', meshid, user._id], obj, { etype: 'mesh', username: user.name, meshid: meshid, name: command.meshname, mtype: command.meshtype, desc: command.desc, action: 'createmesh', links: links, msg: 'Mesh created: ' + command.meshname, domain: domain.id })
585 + obj.parent.parent.DispatchEvent(['*', meshid, user._id], obj, { etype: 'mesh', username: user.name, meshid: meshid, name: command.meshname, mtype: command.meshtype, desc: command.desc, action: 'createmesh', links: links, msg: 'Mesh created: ' + command.meshname, domain: domain.id });
586 });
587 }
588 break;
@@ -586,17 +593,17 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
593 if (obj.common.validateString(command.meshid, 1, 1024) == false) break; // Check the meshid
594 obj.db.Get(command.meshid, function (err, meshes) {
595 if (meshes.length != 1) return;
589 - var mesh = obj.common.unEscapeLinksFieldName(meshes[0]);
596 + mesh = obj.common.unEscapeLinksFieldName(meshes[0]);
597
598 // Check if this user has rights to do this
599 if (mesh.links[user._id] == null || mesh.links[user._id].rights != 0xFFFFFFFF) return;
600 if ((command.meshid.split('/').length != 3) || (command.meshid.split('/')[1] != domain.id)) return; // Invalid domain, operation only valid for current domain
601
602 // Fire the removal event first, because after this, the event will not route
596 - obj.parent.parent.DispatchEvent(['*', command.meshid], obj, { etype: 'mesh', username: user.name, meshid: command.meshid, name: command.meshname, action: 'deletemesh', msg: 'Mesh deleted: ' + command.meshname, domain: domain.id })
603 + obj.parent.parent.DispatchEvent(['*', command.meshid], obj, { etype: 'mesh', username: user.name, meshid: command.meshid, name: command.meshname, action: 'deletemesh', msg: 'Mesh deleted: ' + command.meshname, domain: domain.id });
604
605 // Remove all user links to this mesh
599 - for (var i in meshes) {
606 + for (i in meshes) {
607 var links = meshes[i].links;
608 for (var j in links) {
609 var xuser = obj.parent.users[j];
@@ -608,8 +615,8 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
615
616 // Delete all files on the server for this mesh
617 try {
611 - var meshpath = getServerRootFilePath(mesh);
612 - if (meshpath != null) { deleteFolderRec(meshpath); }
618 + var meshpath = obj.parent.getServerRootFilePath(mesh);
619 + if (meshpath != null) { obj.parent.deleteFolderRec(meshpath); }
620 } catch (e) { }
621
622 obj.parent.parent.RemoveEventDispatchId(command.meshid); // Remove all subscriptions to this mesh
@@ -622,7 +629,8 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
629 {
630 // Change the name or description of a mesh
631 if (obj.common.validateString(command.meshid, 1, 1024) == false) break; // Check the meshid
625 - var mesh = obj.parent.meshes[command.meshid], change = '';
632 + mesh = obj.parent.meshes[command.meshid];
633 + change = '';
634 if (mesh) {
635 // Check if this user has rights to do this
636 if (mesh.links[user._id] == null || ((mesh.links[user._id].rights & 1) == 0)) return;
@@ -630,7 +638,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
638
639 if ((obj.common.validateString(command.meshname, 1, 64) == true) && (command.meshname != mesh.name)) { change = 'Mesh name changed from "' + mesh.name + '" to "' + command.meshname + '"'; mesh.name = command.meshname; }
640 if ((obj.common.validateString(command.desc, 0, 1024) == true) && (command.desc != mesh.desc)) { if (change != '') change += ' and description changed'; else change += 'Mesh "' + mesh.name + '" description changed'; mesh.desc = command.desc; }
633 - if (change != '') { obj.db.Set(obj.common.escapeLinksFieldName(mesh)); obj.parent.parent.DispatchEvent(['*', mesh._id, user._id], obj, { etype: 'mesh', username: user.name, meshid: mesh._id, name: mesh.name, mtype: mesh.mtype, desc: mesh.desc, action: 'meshchange', links: mesh.links, msg: change, domain: domain.id }) }
641 + if (change != '') { obj.db.Set(obj.common.escapeLinksFieldName(mesh)); obj.parent.parent.DispatchEvent(['*', mesh._id, user._id], obj, { etype: 'mesh', username: user.name, meshid: mesh._id, name: mesh.name, mtype: mesh.mtype, desc: mesh.desc, action: 'meshchange', links: mesh.links, msg: change, domain: domain.id }); }
642 }
643 break;
644 }
@@ -648,7 +656,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
656 }
657
658 // Get the mesh
651 - var mesh = obj.parent.meshes[command.meshid], change = '';
659 + mesh = obj.parent.meshes[command.meshid];
660 if (mesh) {
661 // Check if this user has rights to do this
662 if (mesh.links[user._id] == null || ((mesh.links[user._id].rights & 2) == 0)) return;
@@ -665,8 +673,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
673 obj.db.Set(obj.common.escapeLinksFieldName(mesh));
674
675 // Notify mesh change
668 - var change = 'Added user ' + newuser.name + ' to mesh ' + mesh.name;
669 - obj.parent.parent.DispatchEvent(['*', mesh._id, user._id, newuserid], obj, { etype: 'mesh', username: newuser.name, userid: command.userid, meshid: mesh._id, name: mesh.name, mtype: mesh.mtype, desc: mesh.desc, action: 'meshchange', links: mesh.links, msg: change, domain: domain.id })
676 + obj.parent.parent.DispatchEvent(['*', mesh._id, user._id, newuserid], obj, { etype: 'mesh', username: newuser.name, userid: command.userid, meshid: mesh._id, name: mesh.name, mtype: mesh.mtype, desc: mesh.desc, action: 'meshchange', links: mesh.links, msg: 'Added user ' + newuser.name + ' to mesh ' + mesh.name, domain: domain.id });
677 }
678 break;
679 }
@@ -677,7 +684,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
684 if ((command.userid.split('/').length != 3) || (command.userid.split('/')[1] != domain.id)) return; // Invalid domain, operation only valid for current domain
685
686 // Get the mesh
680 - var mesh = obj.parent.meshes[command.meshid];
687 + mesh = obj.parent.meshes[command.meshid];
688 if (mesh) {
689 // Check if this user has rights to do this
690 if (mesh.links[user._id] == null || ((mesh.links[user._id].rights & 2) == 0)) return;
@@ -701,8 +708,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
708 obj.db.Set(obj.common.escapeLinksFieldName(mesh));
709
710 // Notify mesh change
704 - var change = 'Removed user ' + deluser.name + ' from mesh ' + mesh.name;
705 - obj.parent.parent.DispatchEvent(['*', mesh._id, user._id, command.userid], obj, { etype: 'mesh', username: user.name, userid: deluser.name, meshid: mesh._id, name: mesh.name, mtype: mesh.mtype, desc: mesh.desc, action: 'meshchange', links: mesh.links, msg: change, domain: domain.id })
711 + obj.parent.parent.DispatchEvent(['*', mesh._id, user._id, command.userid], obj, { etype: 'mesh', username: user.name, userid: deluser.name, meshid: mesh._id, name: mesh.name, mtype: mesh.mtype, desc: mesh.desc, action: 'meshchange', links: mesh.links, msg: 'Removed user ' + deluser.name + ' from mesh ' + mesh.name, domain: domain.id });
712 }
713 }
714 break;
@@ -723,7 +729,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
729 if ((obj.parent.parent.args.wanonly == true) && (command.hostname)) { delete command.hostname; }
730
731 // Get the mesh
726 - var mesh = obj.parent.meshes[command.meshid];
732 + mesh = obj.parent.meshes[command.meshid];
733 if (mesh) {
734 if (mesh.mtype != 1) return; // This operation is only allowed for mesh type 1, Intel AMT agentless mesh.
735
@@ -733,15 +739,14 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
739 // Create a new nodeid
740 obj.parent.crypto.randomBytes(48, function (err, buf) {
741 // create the new node
736 - var nodeid = 'node/' + domain.id + '/' + buf.toString('base64').replace(/\+/g, '@').replace(/\//g, '$');;
742 + nodeid = 'node/' + domain.id + '/' + buf.toString('base64').replace(/\+/g, '@').replace(/\//g, '$');
743 var device = { type: 'node', mtype: 1, _id: nodeid, meshid: command.meshid, name: command.devicename, host: command.hostname, domain: domain.id, intelamt: { user: command.amtusername, pass: command.amtpassword, tls: command.amttls } };
744 obj.db.Set(device);
745
746 // Event the new node
747 var device2 = obj.common.Clone(device);
748 delete device2.intelamt.pass; // Remove the Intel AMT password before eventing this.
743 - var change = 'Added device ' + command.devicename + ' to mesh ' + mesh.name;
744 - obj.parent.parent.DispatchEvent(['*', command.meshid], obj, { etype: 'node', username: user.name, action: 'addnode', node: device2, msg: change, domain: domain.id })
749 + obj.parent.parent.DispatchEvent(['*', command.meshid], obj, { etype: 'node', username: user.name, action: 'addnode', node: device2, msg: 'Added device ' + command.devicename + ' to mesh ' + mesh.name, domain: domain.id });
750 });
751 }
752 break;
@@ -763,8 +768,8 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
768 {
769 if (obj.common.validateArray(command.nodeids, 1) == false) break; // Check nodeid's
770
766 - for (var i in command.nodeids) {
767 - var nodeid = command.nodeids[i];
771 + for (i in command.nodeids) {
772 + nodeid = command.nodeids[i];
773 if (obj.common.validateString(nodeid, 1, 1024) == false) break; // Check nodeid
774 if ((nodeid.split('/').length != 3) || (nodeid.split('/')[1] != domain.id)) return; // Invalid domain, operation only valid for current domain
775
@@ -774,7 +779,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
779 var node = nodes[0];
780
781 // Get the mesh for this device
777 - var mesh = obj.parent.meshes[node.meshid];
782 + mesh = obj.parent.meshes[node.meshid];
783 if (mesh) {
784 // Check if this user has rights to do this
785 if (mesh.links[user._id] == null || ((mesh.links[user._id].rights & 4) == 0)) return;
@@ -786,8 +791,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
791 obj.db.RemoveNode(node._id); // Remove all entries with node:id
792
793 // Event node deletion
789 - var change = 'Removed device ' + node.name + ' from mesh ' + mesh.name;
790 - obj.parent.parent.DispatchEvent(['*', node.meshid], obj, { etype: 'node', username: user.name, action: 'removenode', nodeid: node._id, msg: change, domain: domain.id })
794 + obj.parent.parent.DispatchEvent(['*', node.meshid], obj, { etype: 'node', username: user.name, action: 'removenode', nodeid: node._id, msg: 'Removed device ' + node.name + ' from mesh ' + mesh.name, domain: domain.id });
795
796 // Disconnect all connections if needed
797 var state = obj.parent.parent.GetConnectivityState(nodeid);
@@ -807,8 +811,9 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
811 // TODO: We can optimize this a lot.
812 // - We should get a full list of all MAC's to wake first.
813 // - We should try to only have one agent per subnet (using Gateway MAC) send a wake-on-lan.
810 - for (var i in command.nodeids) {
811 - var nodeid = command.nodeids[i], wakeActions = 0;
814 + for (i in command.nodeids) {
815 + nodeid = command.nodeids[i];
816 + var wakeActions = 0;
817 if (obj.common.validateString(nodeid, 1, 1024) == false) break; // Check nodeid
818 if ((nodeid.split('/').length == 3) && (nodeid.split('/')[1] == domain.id)) { // Validate the domain, operation only valid for current domain
819 // Get the device
@@ -817,7 +822,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
822 var node = nodes[0];
823
824 // Get the mesh for this device
820 - var mesh = obj.parent.meshes[node.meshid];
825 + mesh = obj.parent.meshes[node.meshid];
826 if (mesh) {
827
828 // Check if this user has rights to do this
@@ -835,10 +840,10 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
840
841 // Get the list of mesh this user as access to
842 var targetMeshes = [];
838 - for (var i in user.links) { targetMeshes.push(i); }
843 + for (i in user.links) { targetMeshes.push(i); }
844
845 // Go thru all the connected agents and send wake-on-lan on all the ones in the target mesh list
841 - for (var i in obj.parent.wsagents) {
846 + for (i in obj.parent.wsagents) {
847 var agent = obj.parent.wsagents[i];
848 if ((targetMeshes.indexOf(agent.dbMeshKey) >= 0) && (agent.authenticated == 2)) {
849 //console.log('Asking agent ' + agent.dbNodeKey + ' to wake ' + macs.join(','));
@@ -862,8 +867,9 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
867 case 'poweraction':
868 {
869 if (obj.common.validateArray(command.nodeids, 1) == false) break; // Check nodeid's
865 - for (var i in command.nodeids) {
866 - var nodeid = command.nodeids[i], powerActions = 0;
870 + for (i in command.nodeids) {
871 + nodeid = command.nodeids[i];
872 + var powerActions = 0;
873 if (obj.common.validateString(nodeid, 1, 1024) == false) break; // Check nodeid
874 if ((nodeid.split('/').length == 3) && (nodeid.split('/')[1] == domain.id)) { // Validate the domain, operation only valid for current domain
875 // Get the device
@@ -872,7 +878,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
878 var node = nodes[0];
879
880 // Get the mesh for this device
875 - var mesh = obj.parent.meshes[node.meshid];
881 + mesh = obj.parent.meshes[node.meshid];
882 if (mesh) {
883
884 // Check if this user has rights to do this
@@ -899,8 +905,9 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
905 if (obj.common.validateArray(command.nodeids, 1) == false) break; // Check nodeid's
906 if (obj.common.validateString(command.title, 1, 512) == false) break; // Check title
907 if (obj.common.validateString(command.msg, 1, 4096) == false) break; // Check message
902 - for (var i in command.nodeids) {
903 - var nodeid = command.nodeids[i], powerActions = 0;
908 + for (i in command.nodeids) {
909 + nodeid = command.nodeids[i];
910 + var powerActions = 0;
911 if (obj.common.validateString(nodeid, 1, 1024) == false) break; // Check nodeid
912 if ((nodeid.split('/').length == 3) && (nodeid.split('/')[1] == domain.id)) { // Validate the domain, operation only valid for current domain
913 // Get the device
@@ -909,7 +916,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
916 var node = nodes[0];
917
918 // Get the mesh for this device
912 - var mesh = obj.parent.meshes[node.meshid];
919 + mesh = obj.parent.meshes[node.meshid];
920 if (mesh) {
921
922 // Check if this user has rights to do this
@@ -940,7 +947,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
947 var node = nodes[0];
948
949 // Get the mesh for this device
943 - var mesh = obj.parent.meshes[node.meshid];
950 + mesh = obj.parent.meshes[node.meshid];
951 if (mesh) {
952 // Check if this user has rights to do this
953 if (mesh.links[user._id] == null || (mesh.links[user._id].rights == 0)) { ws.send(JSON.stringify({ action: 'getnetworkinfo', nodeid: command.nodeid, netif: null })); return; }
@@ -968,13 +975,14 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
975 var node = nodes[0];
976
977 // Get the mesh for this device
971 - var mesh = obj.parent.meshes[node.meshid];
978 + mesh = obj.parent.meshes[node.meshid];
979 if (mesh) {
980 // Check if this user has rights to do this
981 if (mesh.links[user._id] == null || ((mesh.links[user._id].rights & 4) == 0)) return;
982
983 // Ready the node change event
977 - var changes = [], change = 0, event = { etype: 'node', username: user.name, action: 'changenode', nodeid: node._id, domain: domain.id };
984 + var changes = [], event = { etype: 'node', username: user.name, action: 'changenode', nodeid: node._id, domain: domain.id };
985 + change = 0;
986 event.msg = ": ";
987
988 // If we are in WAN-only mode, host is not used
@@ -1041,7 +1049,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
1049 data = obj.common.IntToStr(0) + data; // Add the 4 bytes encoding type & flags (Set to 0 for raw)
1050 obj.parent.sendMeshAgentCore(user, domain, command.nodeid, data);
1051 }
1044 - })
1052 + });
1053 }
1054 }
1055 } else {
@@ -1071,7 +1079,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
1079 if (obj.common.validateString(command.nodeid, 1, 1024) == false) break; // Check nodeid
1080 obj.db.Get(command.nodeid, function (err, nodes) { // TODO: Make a NodeRights(user) method that also does not do a db call if agent is connected (???)
1081 if (nodes.length == 1) {
1074 - var meshlinks = user.links[nodes[0].meshid];
1082 + meshlinks = user.links[nodes[0].meshid];
1083 if ((meshlinks) && (meshlinks.rights) && (meshlinks.rights & obj.parent.MESHRIGHT_REMOTECONTROL != 0)) {
1084 // Add a user authentication cookie to a url
1085 var cookieContent = { userid: user._id, domainid: user.domain };
@@ -1093,7 +1101,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
1101 if ((command.meshid.split('/').length != 3) || (command.meshid.split('/')[1] != domain.id)) return; // Invalid domain, operation only valid for current domain
1102
1103 // Get the mesh
1096 - var mesh = obj.parent.meshes[command.meshid];
1104 + mesh = obj.parent.meshes[command.meshid];
1105 if (mesh) {
1106 if (mesh.mtype != 2) return; // This operation is only allowed for mesh type 2, agent mesh
1107
@@ -1118,7 +1126,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
1126 // Check if this user has rights on this id to set notes
1127 obj.db.Get(command.id, function (err, nodes) { // TODO: Make a NodeRights(user) method that also does not do a db call if agent is connected (???)
1128 if (nodes.length == 1) {
1121 - var meshlinks = user.links[nodes[0].meshid];
1129 + meshlinks = user.links[nodes[0].meshid];
1130 if ((meshlinks) && (meshlinks.rights) && (meshlinks.rights & obj.parent.MESHRIGHT_SETNOTES != 0)) {
1131 // Set the id's notes
1132 if (obj.common.validateString(command.notes, 1) == false) {
@@ -1131,7 +1139,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
1139 });
1140 } else if (idtype == 'mesh') {
1141 // Get the mesh for this device
1134 - var mesh = obj.parent.meshes[command.id];
1142 + mesh = obj.parent.meshes[command.id];
1143 if (mesh) {
1144 // Check if this user has rights to do this
1145 if (mesh.links[user._id] == null || (mesh.links[user._id].rights == 0)) { return; }
@@ -1170,7 +1178,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
1178 var node = nodes[0];
1179
1180 // Get the mesh for this device
1173 - var mesh = obj.parent.meshes[node.meshid];
1181 + mesh = obj.parent.meshes[node.meshid];
1182 if (mesh) {
1183 // Check if this user has rights to do this
1184 if (mesh.links[user._id] == null || (mesh.links[user._id].rights == 0)) { return; }
@@ -1184,7 +1192,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
1192 });
1193 } else if (idtype == 'mesh') {
1194 // Get the mesh for this device
1187 - var mesh = obj.parent.meshes[command.id];
1195 + mesh = obj.parent.meshes[command.id];
1196 if (mesh) {
1197 // Check if this user has rights to do this
1198 if (mesh.links[user._id] == null || (mesh.links[user._id].rights == 0)) { return; }
@@ -1223,7 +1231,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
1231 var user = obj.parent.users[ws.userid];
1232 if (user) {
1233 if (obj.parent.parent.multiServer == null) {
1226 - obj.parent.parent.DispatchEvent(['*'], obj, { action: 'wssessioncount', username: user.name, count: obj.parent.wssessions[ws.userid].length, nolog: 1, domain: obj.domain.id })
1234 + obj.parent.parent.DispatchEvent(['*'], obj, { action: 'wssessioncount', username: user.name, count: obj.parent.wssessions[ws.userid].length, nolog: 1, domain: obj.domain.id });
1235 } else {
1236 obj.parent.recountSessions(ws.sessionId); // Recount sessions
1237 }
@@ -1241,7 +1249,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
1249 var httpport = ((obj.args.aliasport != null) ? obj.args.aliasport : obj.args.port);
1250
1251 // Build server information object
1244 - var serverinfo = { name: obj.parent.certificates.CommonName, mpsname: obj.parent.certificates.AmtMpsName, mpsport: mpsport, mpspass: obj.args.mpspass, port: httpport, emailcheck: obj.parent.parent.mailserver != null }
1252 + var serverinfo = { name: obj.parent.certificates.CommonName, mpsname: obj.parent.certificates.AmtMpsName, mpsport: mpsport, mpspass: obj.args.mpspass, port: httpport, emailcheck: obj.parent.parent.mailserver != null };
1253 if (obj.args.notls == true) { serverinfo.https = false; } else { serverinfo.https = true; serverinfo.redirport = obj.args.redirport; }
1254
1255 // Send server information
@@ -1259,7 +1267,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
1267 var r = {}, dir = obj.fs.readdirSync(path);
1268 for (var i in dir) {
1269 var f = { t: 3, d: 111 };
1262 - var stat = obj.fs.statSync(path + '/' + dir[i])
1270 + var stat = obj.fs.statSync(path + '/' + dir[i]);
1271 if ((stat.mode & 0x004000) == 0) { f.s = stat.size; f.d = stat.mtime.getTime(); } else { f.t = 2; f.f = readFilesRec(path + '/' + dir[i]); }
1272 r[dir[i]] = f;
1273 }
@@ -1316,7 +1324,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
1324 }
1325
1326 function EscapeHtml(x) { if (typeof x == "string") return x.replace(/&/g, '&amp;').replace(/>/g, '&gt;').replace(/</g, '&lt;').replace(/"/g, '&quot;').replace(/'/g, '&apos;'); if (typeof x == "boolean") return x; if (typeof x == "number") return x; }
1319 - function EscapeHtmlBreaks(x) { if (typeof x == "string") return x.replace(/&/g, '&amp;').replace(/>/g, '&gt;').replace(/</g, '&lt;').replace(/"/g, '&quot;').replace(/'/g, '&apos;').replace(/\r/g, '<br />').replace(/\n/g, '').replace(/\t/g, '&nbsp;&nbsp;'); if (typeof x == "boolean") return x; if (typeof x == "number") return x; }
1327 + //function EscapeHtmlBreaks(x) { if (typeof x == "string") return x.replace(/&/g, '&amp;').replace(/>/g, '&gt;').replace(/</g, '&lt;').replace(/"/g, '&quot;').replace(/'/g, '&apos;').replace(/\r/g, '<br />').replace(/\n/g, '').replace(/\t/g, '&nbsp;&nbsp;'); if (typeof x == "boolean") return x; if (typeof x == "number") return x; }
1328
1329 return obj;
1322 -}
1330 +};
\ No newline at end of file
multiserver.js
+52 -46
@@ -6,7 +6,12 @@
6 * @version v0.0.1
7 */
8
9 -'use strict';
9 +/*jslint node: true */
10 +/*jshint node: true */
11 +/*jshint strict:false */
12 +/*jshint -W097 */
13 +/*jshint esversion: 6 */
14 +"use strict";
15
16 // Construct a Mesh Multi-Server object. This is used for MeshCentral-to-MeshCentral communication.
17 module.exports.CreateMultiServer = function (parent, args) {
@@ -46,7 +51,7 @@ module.exports.CreateMultiServer = function (parent, args) {
51 obj.stop = function () {
52 obj.connectionState = 0;
53 disconnect();
49 - }
54 + };
55
56 // Make one attempt at connecting to the server
57 function connect() {
@@ -169,13 +174,13 @@ module.exports.CreateMultiServer = function (parent, args) {
174 if (typeof msg == 'object') { obj.ws.send(JSON.stringify(msg)); return; }
175 if (typeof msg == 'string') { obj.ws.send(msg); return; }
176 } catch (e) { }
172 - }
177 + };
178
179 // Process incoming peer server JSON data
180 function processServerData(msg) {
176 - var str = msg.toString('utf8');
181 + var str = msg.toString('utf8'), command = null;
182 if (str[0] == '{') {
178 - try { command = JSON.parse(str) } catch (e) { obj.parent.parent.debug(1, 'Unable to parse server JSON (' + obj.remoteaddr + ').'); return; } // If the command can't be parsed, ignore it.
183 + try { command = JSON.parse(str); } catch (e) { obj.parent.parent.debug(1, 'Unable to parse server JSON (' + obj.remoteaddr + ').'); return; } // If the command can't be parsed, ignore it.
184 if (command.action == 'info') {
185 if (obj.authenticated != 3) {
186 // We get the peer's serverid and database identifier.
@@ -198,7 +203,7 @@ module.exports.CreateMultiServer = function (parent, args) {
203
204 connect();
205 return obj;
201 - }
206 + };
207
208 // Create a mesh server module that received a connection to another server
209 obj.CreatePeerInServer = function (parent, ws, req) {
@@ -227,14 +232,14 @@ module.exports.CreateMultiServer = function (parent, args) {
232 if (typeof data == 'object') { obj.ws.send(JSON.stringify(data)); return; }
233 obj.ws.send(data);
234 } catch (e) { }
230 - }
235 + };
236
237 // Disconnect this server
238 obj.close = function (arg) {
239 if ((arg == 1) || (arg == null)) { try { obj.ws.close(); obj.parent.parent.debug(1, 'InPeer: Soft disconnect ' + obj.peerServerId + ' (' + obj.remoteaddr + ')'); } catch (e) { console.log(e); } } // Soft close, close the websocket
240 if (arg == 2) { try { obj.ws._socket._parent.end(); obj.parent.parent.debug(1, 'InPeer: Hard disconnect ' + obj.peerServerId + ' (' + obj.remoteaddr + ')'); } catch (e) { console.log(e); } } // Hard close, close the TCP socket
241 if (obj.authenticated == 3) { obj.parent.ClearPeerServer(obj, obj.peerServerId); obj.authenticated = 0; }
237 - }
242 + };
243
244 // When data is received from the peer server web socket
245 ws.on('message', function (msg) {
@@ -244,7 +249,7 @@ module.exports.CreateMultiServer = function (parent, args) {
249 if (obj.authenticated >= 2) { // We are authenticated
250 if (msg.charCodeAt(0) == 123) { processServerData(msg); }
251 if (msg.length < 2) return;
247 - var cmdid = obj.common.ReadShort(msg, 0);
252 + //var cmdid = obj.common.ReadShort(msg, 0);
253 // Process binary commands (if any). None right now.
254 }
255 else if (obj.authenticated < 2) { // We are not authenticated
@@ -259,14 +264,14 @@ module.exports.CreateMultiServer = function (parent, args) {
264 obj.peernonce = msg.substring(50);
265
266 // Perform the hash signature using the server agent certificate
262 - obj.parent.parent.certificateOperations.acceleratorPerformSignature(0, msg.substring(2) + obj.nonce, obj, function (signature) {
267 + obj.parent.parent.certificateOperations.acceleratorPerformSignature(0, msg.substring(2) + obj.nonce, obj, function (obj2, signature) {
268 // Send back our certificate + signature
264 - obj2.send(obj2.common.ShortToStr(2) + obj.common.ShortToStr(obj2.agentCertificateAsn1.length) + obj2.agentCertificateAsn1 + signature); // Command 2, certificate + signature
269 + obj2.send(obj2.common.ShortToStr(2) + obj2.common.ShortToStr(obj2.agentCertificateAsn1.length) + obj2.agentCertificateAsn1 + signature); // Command 2, certificate + signature
270 });
271
272 // Check the peer server signature if we can
273 if (obj.unauthsign != null) {
269 - if (processPeerSignature(obj.unauthsign) == false) { disconnect(); return; } else { completePeerServerConnection(); }
274 + if (processPeerSignature(obj.unauthsign) == false) { obj.close(); return; } else { completePeerServerConnection(); }
275 }
276 }
277 else if (cmd == 2) {
@@ -337,9 +342,9 @@ module.exports.CreateMultiServer = function (parent, args) {
342
343 // Process incoming peer server JSON data
344 function processServerData(msg) {
340 - var str = msg.toString('utf8');
345 + var str = msg.toString('utf8'), command = null;
346 if (str[0] == '{') {
342 - try { command = JSON.parse(str) } catch (e) { obj.parent.parent.debug(1, 'Unable to parse server JSON (' + obj.remoteaddr + ').'); return; } // If the command can't be parsed, ignore it.
347 + try { command = JSON.parse(str); } catch (e) { obj.parent.parent.debug(1, 'Unable to parse server JSON (' + obj.remoteaddr + ').'); return; } // If the command can't be parsed, ignore it.
348 if (command.action == 'info') {
349 if (obj.authenticated != 3) {
350 // We get the peer's serverid and database identifier.
@@ -362,7 +367,7 @@ module.exports.CreateMultiServer = function (parent, args) {
367 }
368
369 return obj;
365 - }
370 + };
371
372 // If we have no peering configuration, don't setup this object
373 if (obj.peerConfig == null) { return null; }
@@ -375,34 +380,34 @@ module.exports.CreateMultiServer = function (parent, args) {
380 var server = obj.peerServers[serverid];
381 if (server && server.peerServerKey) return server.peerServerKey;
382 return null;
378 - }
383 + };
384
385 // Dispatch an event to all other MeshCentral2 peer servers
386 obj.DispatchEvent = function (ids, source, event) {
387 var busmsg = JSON.stringify({ action: 'bus', ids: ids, event: event });
388 for (var serverid in obj.peerServers) { obj.peerServers[serverid].send(busmsg); }
384 - }
389 + };
390
391 // Dispatch a message to other MeshCentral2 peer servers
392 obj.DispatchMessage = function (msg) {
393 for (var serverid in obj.peerServers) { obj.peerServers[serverid].send(msg); }
389 - }
394 + };
395
396 // Dispatch a message to other MeshCentral2 peer servers
397 obj.DispatchMessageSingleServer = function (msg, serverid) {
398 var server = obj.peerServers[serverid];
399 if (server != null) { server.send(msg); }
395 - }
400 + };
401
402 // Attempt to connect to all peers
403 obj.ConnectToPeers = function () {
399 - for (serverId in obj.peerConfig.servers) {
404 + for (var serverId in obj.peerConfig.servers) {
405 // We will only connect to names that are larger then ours. This way, eveyone has one connection to everyone else (no cross-connections).
406 if ((serverId > obj.serverid) && (obj.peerConfig.servers[serverId].url != null) && (obj.outPeerServers[serverId] == null)) {
407 obj.outPeerServers[serverId] = obj.CreatePeerOutServer(obj, serverId, obj.peerConfig.servers[serverId].url);
408 }
409 }
405 - }
410 + };
411
412 // We connected to a peer server, setup everything
413 obj.SetupPeerServer = function (server, peerServerId) {
@@ -414,7 +419,7 @@ module.exports.CreateMultiServer = function (parent, args) {
419
420 // Send a list of user sessions to the peer
421 server.send(JSON.stringify({ action: 'sessionsTable', sessionsTable: Object.keys(obj.parent.webserver.wssessions2) }));
417 - }
422 + };
423
424 // We disconnected to a peer server, clean up everything
425 obj.ClearPeerServer = function (server, peerServerId) {
@@ -431,10 +436,11 @@ module.exports.CreateMultiServer = function (parent, args) {
436 delete obj.parent.webserver.wsPeerSessions[peerServerId];
437 delete obj.parent.webserver.wsPeerSessions3[peerServerId];
438 obj.parent.webserver.recountSessions(); // Recount all sessions
434 - }
439 + };
440
441 // Process a message coming from a peer server
442 obj.ProcessPeerServerMessage = function (server, peerServerId, msg) {
443 + var userid, i;
444 //console.log('ProcessPeerServerMessage', peerServerId, msg);
445 switch (msg.action) {
446 case 'bus': {
@@ -449,10 +455,10 @@ module.exports.CreateMultiServer = function (parent, args) {
455 case 'sessionsTable': {
456 obj.parent.webserver.wsPeerSessions[peerServerId] = msg.sessionsTable;
457 var userToSession = {};
452 - for (var i in msg.sessionsTable) {
458 + for (i in msg.sessionsTable) {
459 var sessionid = msg.sessionsTable[i];
460 obj.parent.webserver.wsPeerSessions2[sessionid] = peerServerId;
455 - var userid = sessionid.split('/').slice(0, 3).join('/'); // Take the sessionid and keep only the userid partion
461 + userid = sessionid.split('/').slice(0, 3).join('/'); // Take the sessionid and keep only the userid partion
462 if (userToSession[userid] == null) { userToSession[userid] = [sessionid]; } else { userToSession[userid].push(sessionid); } // UserId -> [ SessionId ]
463 }
464 obj.parent.webserver.wsPeerSessions3[peerServerId] = userToSession; // ServerId --> UserId --> SessionId
@@ -462,17 +468,17 @@ module.exports.CreateMultiServer = function (parent, args) {
468 case 'sessionStart': {
469 obj.parent.webserver.wsPeerSessions[peerServerId].push(msg.sessionid);
470 obj.parent.webserver.wsPeerSessions2[msg.sessionid] = peerServerId;
465 - var userid = msg.sessionid.split('/').slice(0, 3).join('/');
471 + userid = msg.sessionid.split('/').slice(0, 3).join('/');
472 if (obj.parent.webserver.wsPeerSessions3[peerServerId] == null) { obj.parent.webserver.wsPeerSessions3[peerServerId] = {}; }
467 - if (obj.parent.webserver.wsPeerSessions3[peerServerId][userid] == null) { obj.parent.webserver.wsPeerSessions3[peerServerId][userid] = [ msg.sessionid ]; } else { obj.parent.webserver.wsPeerSessions3[peerServerId][userid].push(msg.sessionid); }
473 + if (obj.parent.webserver.wsPeerSessions3[peerServerId][userid] == null) { obj.parent.webserver.wsPeerSessions3[peerServerId][userid] = [msg.sessionid]; } else { obj.parent.webserver.wsPeerSessions3[peerServerId][userid].push(msg.sessionid); }
474 obj.parent.webserver.recountSessions(msg.sessionid); // Recount a specific user
475 break;
476 }
477 case 'sessionEnd': {
472 - var i = obj.parent.webserver.wsPeerSessions[peerServerId].indexOf(msg.sessionid);
478 + i = obj.parent.webserver.wsPeerSessions[peerServerId].indexOf(msg.sessionid);
479 if (i >= 0) { obj.parent.webserver.wsPeerSessions[peerServerId].splice(i, 1); }
480 delete obj.parent.webserver.wsPeerSessions2[msg.sessionid];
475 - var userid = msg.sessionid.split('/').slice(0, 3).join('/');
481 + userid = msg.sessionid.split('/').slice(0, 3).join('/');
482 if (obj.parent.webserver.wsPeerSessions3[peerServerId][userid] != null) {
483 i = obj.parent.webserver.wsPeerSessions3[peerServerId][userid].indexOf(msg.sessionid);
484 if (i >= 0) {
@@ -498,7 +504,7 @@ module.exports.CreateMultiServer = function (parent, args) {
504 // Yes, there is a waiting session, see if we must initiate.
505 if (peerServerId > obj.parent.serverId) {
506 // We must initiate the connection to the peer
501 - var userid = null;
507 + userid = null;
508 if (rsession.peer1.req.session != null) { userid = rsession.peer1.req.session.userid; }
509 obj.createPeerRelay(rsession.peer1.ws, rsession.peer1.req, peerServerId, userid);
510 delete obj.parent.webserver.wsrelays[msg.id];
@@ -509,33 +515,33 @@ module.exports.CreateMultiServer = function (parent, args) {
515
516 // Clear all relay sessions that are more than 1 minute
517 var oneMinuteAgo = Date.now() - 60000;
512 - for (var id in obj.parent.webserver.wsPeerRelays) { if (obj.parent.webserver.wsPeerRelays[id].time < oneMinuteAgo) { delete obj.parent.webserver.wsPeerRelays[id]; } }
518 + for (i in obj.parent.webserver.wsPeerRelays) { if (obj.parent.webserver.wsPeerRelays[i].time < oneMinuteAgo) { delete obj.parent.webserver.wsPeerRelays[i]; } }
519 }
520 break;
521 }
522 case 'msg': {
523 if (msg.sessionid != null) {
524 // Route this message to a connected user session
519 - if (command.fromNodeid != null) { command.nodeid = command.fromNodeid; delete command.fromNodeid; }
520 - var ws = obj.parent.webserver.wssessions2[command.sessionid];
521 - if (ws != null) { ws.send(JSON.stringify(command)); }
525 + if (msg.fromNodeid != null) { msg.nodeid = msg.fromNodeid; delete msg.fromNodeid; }
526 + var ws = obj.parent.webserver.wssessions2[msg.sessionid];
527 + if (ws != null) { ws.send(JSON.stringify(msg)); }
528 } else if (msg.nodeid != null) {
529 // Route this message to a connected agent
524 - if (command.fromSessionid != null) { command.sessionid = command.fromSessionid; delete command.fromSessionid; }
530 + if (msg.fromSessionid != null) { msg.sessionid = msg.fromSessionid; delete msg.fromSessionid; }
531 var agent = obj.parent.webserver.wsagents[msg.nodeid];
532 if (agent != null) { delete msg.nodeid; agent.send(JSON.stringify(msg)); } // Remove the nodeid since it's implyed and send the message to the agent
533 } else if (msg.meshid != null) {
534 // Route this message to all users of this mesh
529 - if (command.fromNodeid != null) { command.nodeid = command.fromNodeid; delete command.fromNodeid; }
530 - var cmdstr = JSON.stringify(command);
531 - for (var userid in obj.parent.webserver.wssessions) { // Find all connected users for this mesh and send the message
535 + if (msg.fromNodeid != null) { msg.nodeid = msg.fromNodeid; delete msg.fromNodeid; }
536 + var cmdstr = JSON.stringify(msg);
537 + for (userid in obj.parent.webserver.wssessions) { // Find all connected users for this mesh and send the message
538 var user = obj.parent.webserver.users[userid];
539 if (user) {
540 var rights = user.links[msg.meshid];
541 if (rights != null) { // TODO: Look at what rights are needed for message routing
542 var sessions = obj.parent.webserver.wssessions[userid];
543 // Send the message to all users on this server
538 - for (var i in sessions) { sessions[i].send(cmdstr); }
544 + for (i in sessions) { sessions[i].send(cmdstr); }
545 }
546 }
547 }
@@ -543,7 +549,7 @@ module.exports.CreateMultiServer = function (parent, args) {
549 break;
550 }
551 }
546 - }
552 + };
553
554 // Create a tunnel connection to a peer server
555 obj.createPeerRelay = function (ws, req, serverid, user) {
@@ -558,7 +564,7 @@ module.exports.CreateMultiServer = function (parent, args) {
564 var path = req.path;
565 if (path[0] == '/') path = path.substring(1);
566 if (path.substring(path.length - 11) == '/.websocket') { path = path.substring(0, path.length - 11); }
561 - var queryStr = ''
567 + var queryStr = '';
568 for (var i in req.query) { queryStr += ((queryStr == '') ? '?' : '&') + i + '=' + req.query[i]; }
569 if (user != null) { queryStr += ((queryStr == '') ? '?' : '&') + 'auth=' + obj.parent.encodeCookie({ userid: user._id, domainid: user.domain }, cookieKey); }
570 var url = obj.peerConfig.servers[serverid].url + path + queryStr;
@@ -566,7 +572,7 @@ module.exports.CreateMultiServer = function (parent, args) {
572 // Setup an connect the web socket
573 var tunnel = obj.createPeerRelayEx(ws, url, serverid);
574 tunnel.connect();
569 - }
575 + };
576
577 // Create a tunnel connection to a peer server
578 // We assume that "ws" is paused already.
@@ -610,7 +616,7 @@ module.exports.CreateMultiServer = function (parent, args) {
616
617 // If the web socket is closed, close the associated TCP connection.
618 peerTunnel.ws1.on('close', function (req) { peerTunnel.parent.parent.debug(1, 'FTunnel disconnect ' + peerTunnel.serverid); peerTunnel.close(); });
613 - }
619 + };
620
621 // Disconnect both sides of the tunnel
622 peerTunnel.close = function (arg) {
@@ -623,11 +629,11 @@ module.exports.CreateMultiServer = function (parent, args) {
629 if (peerTunnel.ws1 != null) { try { peerTunnel.ws1.close(); peerTunnel.parent.parent.debug(1, 'FTunnel1: Soft disconnect '); } catch (e) { console.log(e); } }
630 if (peerTunnel.ws2 != null) { try { peerTunnel.ws2.close(); peerTunnel.parent.parent.debug(1, 'FTunnel2: Soft disconnect '); } catch (e) { console.log(e); } }
631 }
626 - }
632 + };
633
634 return peerTunnel;
629 - }
635 + };
636
637 setTimeout(function () { obj.ConnectToPeers(); }, 1000); // Delay this a little to make sure we are ready on our side.
638 return obj;
633 -}
639 +};
\ No newline at end of file
pass.js
+6 -1
@@ -1,6 +1,11 @@
1 // check out https://github.com/tj/node-pwd
2
3 -'use strict';
3 +/*jslint node: true */
4 +/*jshint node: true */
5 +/*jshint strict:false */
6 +/*jshint -W097 */
7 +/*jshint esversion: 6 */
8 +"use strict";
9
10 // Module dependencies.
11 const crypto = require('crypto');
swarmserver.js
+19 -14
@@ -6,7 +6,12 @@
6 * @version v0.0.1
7 */
8
9 -'use strict';
9 +/*jslint node: true */
10 +/*jshint node: true */
11 +/*jshint strict:false */
12 +/*jshint -W097 */
13 +/*jshint esversion: 6 */
14 +"use strict";
15
16 // Construct a legacy Swarm Server server object
17 module.exports.CreateSwarmServer = function (parent, db, args, certificates) {
@@ -18,7 +23,7 @@ module.exports.CreateSwarmServer = function (parent, db, args, certificates) {
23 obj.legacyAgentConnections = {};
24 obj.migrationAgents = {};
25 const common = require('./common.js');
21 - const net = require('net');
26 + //const net = require('net');
27 const tls = require('tls');
28 const forge = require('node-forge');
29
@@ -115,7 +120,7 @@ module.exports.CreateSwarmServer = function (parent, db, args, certificates) {
120 USERAUTH2: 1031, // Authenticate a user to the swarm server (Uses SHA1 SALT)
121 GUESTREMOTEDESKTOP: 2001, // Guest usage: Remote Desktop
122 GUESTWEBRTCMESH: 2002 // Guest usage: WebRTC Mesh
118 - }
123 + };
124
125 obj.server = tls.createServer({ key: certificates.swarmserver.key, cert: certificates.swarmserver.cert, requestCert: true }, onConnection);
126 obj.server.listen(args.swarmport, function () { console.log('MeshCentral Legacy Swarm Server running on ' + certificates.CommonName + ':' + args.swarmport + '.'); obj.parent.updateServerState('swarm-port', args.swarmport); }).on('error', function (err) { console.error('ERROR: MeshCentral Swarm Server server port ' + args.swarmport + ' is not available.'); if (args.exactports) { process.exit(); } });
@@ -146,11 +151,11 @@ module.exports.CreateSwarmServer = function (parent, db, args, certificates) {
151 socket.setEncoding('binary');
152 socket.pingTimer = setInterval(function () { obj.SendCommand(socket, LegacyMeshProtocol.PING); }, 20000);
153 Debug(1, 'SWARM:New legacy agent connection');
149 -
154 +
155 socket.addListener("data", function (data) {
156 if (args.swarmdebug) { var buf = new Buffer(data, "binary"); console.log('SWARM <-- (' + buf.length + '):' + buf.toString('hex')); } // Print out received bytes
157 socket.tag.accumulator += data;
153 -
158 +
159 // Detect if this is an HTTPS request, if it is, return a simple answer and disconnect. This is useful for debugging access to the MPS port.
160 if (socket.tag.first == true) {
161 if (socket.tag.accumulator.length < 3) return;
@@ -214,7 +219,7 @@ module.exports.CreateSwarmServer = function (parent, db, args, certificates) {
219 Debug(3, 'Swarm:GETSTATE');
220 if (len < 12) break;
221 var statecmd = common.ReadInt(data, 0);
217 - var statesync = common.ReadInt(data, 4);
222 + //var statesync = common.ReadInt(data, 4);
223 switch (statecmd) {
224 case 6: { // Ask for agent block
225 if (socket.tag.update != null) {
@@ -247,14 +252,14 @@ module.exports.CreateSwarmServer = function (parent, db, args, certificates) {
252 }
253 return len;
254 }
250 -
255 +
256 socket.addListener("close", function () {
257 Debug(1, 'Swarm:Connection closed');
258 try { delete obj.ciraConnections[socket.tag.nodeid]; } catch (e) { }
259 obj.parent.ClearConnectivityState(socket.tag.meshid, socket.tag.nodeid, 2);
260 if (socket.pingTimer != null) { clearInterval(socket.pingTimer); delete socket.pingTimer; }
261 });
257 -
262 +
263 socket.addListener("error", function () {
264 //console.log("Swarm Error: " + socket.remoteAddress);
265 });
@@ -311,19 +316,19 @@ module.exports.CreateSwarmServer = function (parent, db, args, certificates) {
316 console.log(e);
317 }
318 return null;
314 - }
319 + };
320
321 // Disconnect legacy agent connection
322 obj.close = function (socket) {
323 try { socket.close(); } catch (e) { }
324 try { delete obj.ciraConnections[socket.tag.nodeid]; } catch (e) { }
325 obj.parent.ClearConnectivityState(socket.tag.meshid, socket.tag.nodeid, 2);
321 - }
326 + };
327
323 - obj.SendCommand = function(socket, cmdid, data) {
328 + obj.SendCommand = function (socket, cmdid, data) {
329 if (data == null) { data = ''; }
330 Write(socket, common.ShortToStr(cmdid) + common.ShortToStr(data.length + 4) + data);
326 - }
331 + };
332
333 function Write(socket, data) {
334 if (args.swarmdebug) {
@@ -335,7 +340,7 @@ module.exports.CreateSwarmServer = function (parent, db, args, certificates) {
340 socket.write(new Buffer(data, "binary"));
341 }
342 }
338 -
343 +
344 // Debug
345 function Debug(lvl) {
346 if (lvl > obj.parent.debugLevel) return;
@@ -348,4 +353,4 @@ module.exports.CreateSwarmServer = function (parent, db, args, certificates) {
353 }
354
355 return obj;
351 -}
356 +};
views/default.handlebars
+11 -10
@@ -2251,9 +2251,8 @@
2251 var boundingBox = null;
2252 for (var i in nodes) {
2253 try {
2254 - var loc = map_parseNodeLoc(nodes[i]);
2255 - var feature = xxmap.markersSource.getFeatureById(nodes[i]._id);
2256 - if ((typeof loc == 'object') && ((nodes[i].meshid == selectedMesh) || (selectedMesh == null))) { // Draw markers for devices with locations
2254 + var loc = map_parseNodeLoc(nodes[i]), feature = xxmap.markersSource.getFeatureById(nodes[i]._id);
2255 + if ((loc != null) && ((nodes[i].meshid == selectedMesh) || (selectedMesh == null))) { // Draw markers for devices with locations
2256 var lat = loc[0], lon = loc[1], type = loc[2];
2257 if (boundingBox == null) { boundingBox = [ lat, lon, lat, lon, 0 ]; } else { if (lat < boundingBox[0]) { boundingBox[0] = lat; } if (lon < boundingBox[1]) { boundingBox[1] = lon; } if (lat > boundingBox[2]) { boundingBox[2] = lat; } if (lon > boundingBox[3]) { boundingBox[3] = lon; } }
2258 if (feature == null) { addFeature(nodes[i]); boundingBox[4] = 1; } else { updateFeature(nodes[i], feature); feature.setStyle(markerStyle(nodes[i], loc[2])); } // Update Feature
@@ -2311,7 +2310,7 @@
2310 if (node.wifiloc) { loc = node.wifiloc; t = 2; }
2311 if (node.gpsloc) { loc = node.gpsloc; t = 3; }
2312 if (node.userloc) { loc = node.userloc; t = 4; }
2314 - if ((loc == null) || (typeof loc != 'string')) return;
2313 + if ((loc == null) || (typeof loc != 'string')) return null;
2314 loc = loc.split(',');
2315 if (t == 1) {
2316 // If this is IP location, randomize the position a little.
@@ -2450,12 +2449,14 @@
2449 }
2450
2451 // Since this is IP address location, add some fixed randomness to the location. Avoid pin pile-up.
2453 - var loc = map_parseNodeLoc(node); lat = loc[0]; lon = loc[1];
2454 -
2455 - if ((lat != feature.get('lat')) || (lon != feature.get('lon'))) { // Update lat and lon if changed
2456 - feature.set('lat', lat); feature.set('lon', lon);
2457 - var modifiedCoordinates = ol.proj.transform([parseFloat(lon), parseFloat(lat)], 'EPSG:4326','EPSG:3857');
2458 - feature.getGeometry().setCoordinates(modifiedCoordinates);
2452 + var loc = map_parseNodeLoc(node);
2453 + if (loc != null) {
2454 + var lat = loc[0], lon = loc[1];
2455 + if ((lat != feature.get('lat')) || (lon != feature.get('lon'))) { // Update lat and lon if changed
2456 + feature.set('lat', lat); feature.set('lon', lon);
2457 + var modifiedCoordinates = ol.proj.transform([parseFloat(lon), parseFloat(lat)], 'EPSG:4326', 'EPSG:3857');
2458 + feature.getGeometry().setCoordinates(modifiedCoordinates);
2459 + }
2460 }
2461
2462 if (node.name != feature.get('name') ) { feature.set('name', node.name); } // Update name
webserver.js
+134 -132
@@ -6,7 +6,12 @@
6 * @version v0.0.1
7 */
8
9 -'use strict';
9 +/*jslint node: true */
10 +/*jshint node: true */
11 +/*jshint strict:false */
12 +/*jshint -W097 */
13 +/*jshint esversion: 6 */
14 +"use strict";
15
16 /*
17 class SerialTunnel extends require('stream').Duplex {
@@ -22,9 +27,9 @@ class SerialTunnel extends require('stream').Duplex {
27 function SerialTunnel(options) {
28 var obj = new require('stream').Duplex(options);
29 obj.forwardwrite = null;
25 - obj.updateBuffer = function (chunk) { this.push(chunk); }
26 - obj._write = function (chunk, encoding, callback) { if (obj.forwardwrite != null) { obj.forwardwrite(chunk); } else { console.err("Failed to fwd _write."); } if (callback) callback(); } // Pass data written to forward
27 - obj._read = function(size) { } // Push nothing, anything to read should be pushed from updateBuffer()
30 + obj.updateBuffer = function (chunk) { this.push(chunk); };
31 + obj._write = function (chunk, encoding, callback) { if (obj.forwardwrite != null) { obj.forwardwrite(chunk); } else { console.err("Failed to fwd _write."); } if (callback) callback(); }; // Pass data written to forward
32 + obj._read = function (size) { }; // Push nothing, anything to read should be pushed from updateBuffer()
33 return obj;
34 }
35
@@ -37,7 +42,7 @@ if (!String.prototype.endsWith) { String.prototype.endsWith = function (searchSt
42
43 // Construct a HTTP web server object
44 module.exports.CreateWebServer = function (parent, db, args, certificates) {
40 - var obj = {};
45 + var obj = {}, i = 0;
46
47 // Modules
48 obj.fs = require('fs');
@@ -52,8 +57,8 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
57 obj.common = require('./common.js');
58 obj.express = require('express');
59 obj.meshAgentHandler = require('./meshagent.js');
55 - obj.meshRelayHandler = require('./meshrelay.js')
56 - obj.meshUserHandler = require('./meshuser.js')
60 + obj.meshRelayHandler = require('./meshrelay.js');
61 + obj.meshUserHandler = require('./meshuser.js');
62 obj.interceptor = require('./interceptor');
63
64 // Variables
@@ -63,13 +68,13 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
68 obj.app = obj.express();
69 obj.app.use(require('compression')());
70 obj.tlsServer = null;
66 - obj.tcpServer;
71 + obj.tcpServer = null;
72 obj.certificates = certificates;
73 obj.args = args;
74 obj.users = {};
75 obj.meshes = {};
76 obj.userAllowedIp = args.userallowedip; // List of allowed IP addresses for users
72 - obj.tlsSniCredentials;
77 + obj.tlsSniCredentials = null;
78 obj.dnsDomains = {};
79 //obj.agentConnCount = 0;
80
@@ -93,13 +98,13 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
98
99 // Setup SSPI authentication if needed
100 if ((obj.parent.platform == 'win32') && (obj.args.nousers != true) && (obj.parent.config != null) && (obj.parent.config.domains != null)) {
96 - for (var i in obj.parent.config.domains) { if (obj.parent.config.domains[i].auth == 'sspi') { var nodeSSPI = require('node-sspi'); obj.parent.config.domains[i].sspi = new nodeSSPI({ retrieveGroups: true, offerBasic: false }); } }
101 + for (i in obj.parent.config.domains) { if (obj.parent.config.domains[i].auth == 'sspi') { var nodeSSPI = require('node-sspi'); obj.parent.config.domains[i].sspi = new nodeSSPI({ retrieveGroups: true, offerBasic: false }); } }
102 }
103
104 // Perform hash on web certificate and agent certificate
105 obj.webCertificateHash = parent.certificateOperations.forge.pki.getPublicKeyFingerprint(parent.certificateOperations.forge.pki.certificateFromPem(obj.certificates.web.cert).publicKey, { md: parent.certificateOperations.forge.md.sha384.create(), encoding: 'binary' });
106 obj.webCertificateHashs = { '': obj.webCertificateHash };
102 - for (var i in obj.parent.config.domains) { if (obj.parent.config.domains[i].dns != null) { obj.webCertificateHashs[i] = parent.certificateOperations.forge.pki.getPublicKeyFingerprint(parent.certificateOperations.forge.pki.certificateFromPem(obj.parent.config.domains[i].certs.cert).publicKey, { md: parent.certificateOperations.forge.md.sha384.create(), encoding: 'binary' }); } }
107 + for (i in obj.parent.config.domains) { if (obj.parent.config.domains[i].dns != null) { obj.webCertificateHashs[i] = parent.certificateOperations.forge.pki.getPublicKeyFingerprint(parent.certificateOperations.forge.pki.certificateFromPem(obj.parent.config.domains[i].certs.cert).publicKey, { md: parent.certificateOperations.forge.md.sha384.create(), encoding: 'binary' }); } }
108 obj.webCertificateHashBase64 = new Buffer(parent.certificateOperations.forge.pki.getPublicKeyFingerprint(parent.certificateOperations.forge.pki.certificateFromPem(obj.certificates.web.cert).publicKey, { md: parent.certificateOperations.forge.md.sha384.create(), encoding: 'binary' }), 'binary').toString('base64').replace(/\+/g, '@').replace(/\//g, '$');
109 obj.agentCertificateHashHex = parent.certificateOperations.forge.pki.getPublicKeyFingerprint(parent.certificateOperations.forge.pki.certificateFromPem(obj.certificates.agent.cert).publicKey, { md: parent.certificateOperations.forge.md.sha384.create(), encoding: 'hex' });
110 obj.agentCertificateHashBase64 = new Buffer(parent.certificateOperations.forge.pki.getPublicKeyFingerprint(parent.certificateOperations.forge.pki.certificateFromPem(obj.certificates.agent.cert).publicKey, { md: parent.certificateOperations.forge.md.sha384.create(), encoding: 'binary' }), 'binary').toString('base64').replace(/\+/g, '@').replace(/\//g, '$');
@@ -130,13 +135,13 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
135 {
136 var dnscount = 0;
137 obj.tlsSniCredentials = {};
133 - for (var i in obj.certificates.dns) { if (obj.parent.config.domains[i].dns != null) { obj.dnsDomains[obj.parent.config.domains[i].dns.toLowerCase()] = obj.parent.config.domains[i]; obj.tlsSniCredentials[obj.parent.config.domains[i].dns] = obj.tls.createSecureContext(obj.certificates.dns[i]).context; dnscount++; } }
138 + for (i in obj.certificates.dns) { if (obj.parent.config.domains[i].dns != null) { obj.dnsDomains[obj.parent.config.domains[i].dns.toLowerCase()] = obj.parent.config.domains[i]; obj.tlsSniCredentials[obj.parent.config.domains[i].dns] = obj.tls.createSecureContext(obj.certificates.dns[i]).context; dnscount++; } }
139 if (dnscount > 0) { obj.tlsSniCredentials[''] = obj.tls.createSecureContext({ cert: obj.certificates.web.cert, key: obj.certificates.web.key, ca: obj.certificates.web.ca }).context; } else { obj.tlsSniCredentials = null; }
140 }
141 function TlsSniCallback(name, cb) { var c = obj.tlsSniCredentials[name]; if (c != null) { cb(null, c); } else { cb(null, obj.tlsSniCredentials['']); } }
142
143 function EscapeHtml(x) { if (typeof x == "string") return x.replace(/&/g, '&amp;').replace(/>/g, '&gt;').replace(/</g, '&lt;').replace(/"/g, '&quot;').replace(/'/g, '&apos;'); if (typeof x == "boolean") return x; if (typeof x == "number") return x; }
139 - function EscapeHtmlBreaks(x) { if (typeof x == "string") return x.replace(/&/g, '&amp;').replace(/>/g, '&gt;').replace(/</g, '&lt;').replace(/"/g, '&quot;').replace(/'/g, '&apos;').replace(/\r/g, '<br />').replace(/\n/g, '').replace(/\t/g, '&nbsp;&nbsp;'); if (typeof x == "boolean") return x; if (typeof x == "number") return x; }
144 + //function EscapeHtmlBreaks(x) { if (typeof x == "string") return x.replace(/&/g, '&amp;').replace(/>/g, '&gt;').replace(/</g, '&lt;').replace(/"/g, '&quot;').replace(/'/g, '&apos;').replace(/\r/g, '<br />').replace(/\n/g, '').replace(/\t/g, '&nbsp;&nbsp;'); if (typeof x == "boolean") return x; if (typeof x == "number") return x; }
145
146 if (obj.args.notls || obj.args.tlsoffload) {
147 // Setup the HTTP server without TLS
@@ -172,27 +177,28 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
177
178 // Session-persisted message middleware
179 obj.app.use(function (req, res, next) {
180 + var err = null, msg = null, passhint = null;
181 if (req.session != null) {
176 - var err = req.session.error;
177 - var msg = req.session.success;
178 - var passhint = req.session.passhint;
182 + err = req.session.error;
183 + msg = req.session.success;
184 + passhint = req.session.passhint;
185 delete req.session.error;
186 delete req.session.success;
187 delete req.session.passhint;
188 }
189 res.locals.message = '';
184 - if (err) res.locals.message = '<p class="msg error">' + err + '</p>';
185 - if (msg) res.locals.message = '<p class="msg success">' + msg + '</p>';
186 - if (passhint) res.locals.passhint = EscapeHtml(passhint);
190 + if (err != null) res.locals.message = '<p class="msg error">' + err + '</p>';
191 + if (msg != null) res.locals.message = '<p class="msg success">' + msg + '</p>';
192 + if (passhint != null) res.locals.passhint = EscapeHtml(passhint);
193 next();
194 });
195
196 // Fetch all users from the database, keep this in memory
197 obj.db.GetAllType('user', function (err, docs) {
192 - var domainUserCount = {};
193 - for (var i in parent.config.domains) { domainUserCount[i] = 0; }
194 - for (var i in docs) { var u = obj.users[docs[i]._id] = docs[i]; domainUserCount[u.domain]++; }
195 - for (var i in parent.config.domains) {
198 + var domainUserCount = {}, i = 0;
199 + for (i in parent.config.domains) { domainUserCount[i] = 0; }
200 + for (i in docs) { var u = obj.users[docs[i]._id] = docs[i]; domainUserCount[u.domain]++; }
201 + for (i in parent.config.domains) {
202 if (domainUserCount[i] == 0) {
203 if (parent.config.domains[i].newaccounts == 0) { parent.config.domains[i].newaccounts = 2; }
204 console.log('Server ' + ((i == '') ? '' : (i + ' ')) + 'has no users, next new account will be site administrator.');
@@ -237,7 +243,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
243 });
244 }
245 }
240 - }
246 + };
247
248 /*
249 obj.restrict = function (req, res, next) {
@@ -249,7 +255,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
255 req.session.error = 'Access denied!';
256 res.redirect(domain.url + 'login');
257 }
252 - }
258 + };
259 */
260
261 // Check if the source IP address is allowed for a given allowed list, return false if not
@@ -287,8 +293,8 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
293 if (req.headers.host != null) { var d = obj.dnsDomains[req.headers.host.toLowerCase()]; if (d != null) return d; } // If this is a DNS name domain, return it here.
294 var x = req.url.split('/');
295 if (x.length < 2) return parent.config.domains[''];
290 - var d = parent.config.domains[x[1].toLowerCase()];
291 - if ((d != null) && (d.dns == null)) return parent.config.domains[x[1].toLowerCase()];
296 + var y = parent.config.domains[x[1].toLowerCase()];
297 + if ((y != null) && (y.dns == null)) return parent.config.domains[x[1].toLowerCase()];
298 return parent.config.domains[''];
299 }
300
@@ -298,8 +304,8 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
304 res.set({ 'Cache-Control': 'no-cache, no-store, must-revalidate', 'Pragma': 'no-cache', 'Expires': '0' });
305 // Destroy the user's session to log them out will be re-created next request
306 if (req.session.userid) {
301 - var user = obj.users[req.session.userid]
302 - obj.parent.DispatchEvent(['*'], obj, { etype: 'user', username: user.name, action: 'logout', msg: 'Account logout', domain: domain.id })
307 + var user = obj.users[req.session.userid];
308 + obj.parent.DispatchEvent(['*'], obj, { etype: 'user', username: user.name, action: 'logout', msg: 'Account logout', domain: domain.id });
309 }
310 req.session = null;
311 res.redirect(domain.url);
@@ -319,35 +325,35 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
325
326 // Regenerate session when signing in to prevent fixation
327 //req.session.regenerate(function () {
322 - // Store the user's primary key in the session store to be retrieved, or in this case the entire user object
323 - // req.session.success = 'Authenticated as ' + user.name + 'click to <a href="/logout">logout</a>. You may now access <a href="/restricted">/restricted</a>.';
324 - delete req.session.loginmode;
325 - req.session.userid = userid;
326 - req.session.domainid = domain.id;
327 - req.session.currentNode = '';
328 - if (req.session.passhint) { delete req.session.passhint; }
329 - if (req.body.viewmode) { req.session.viewmode = req.body.viewmode; }
330 - if (req.body.host) {
331 - // TODO: This is a terrible search!!! FIX THIS.
332 - /*
333 - obj.db.GetAllType('node', function (err, docs) {
334 - for (var i = 0; i < docs.length; i++) {
335 - if (docs[i].name == req.body.host) {
336 - req.session.currentNode = docs[i]._id;
337 - break;
338 - }
328 + // Store the user's primary key in the session store to be retrieved, or in this case the entire user object
329 + // req.session.success = 'Authenticated as ' + user.name + 'click to <a href="/logout">logout</a>. You may now access <a href="/restricted">/restricted</a>.';
330 + delete req.session.loginmode;
331 + req.session.userid = userid;
332 + req.session.domainid = domain.id;
333 + req.session.currentNode = '';
334 + if (req.session.passhint) { delete req.session.passhint; }
335 + if (req.body.viewmode) { req.session.viewmode = req.body.viewmode; }
336 + if (req.body.host) {
337 + // TODO: This is a terrible search!!! FIX THIS.
338 + /*
339 + obj.db.GetAllType('node', function (err, docs) {
340 + for (var i = 0; i < docs.length; i++) {
341 + if (docs[i].name == req.body.host) {
342 + req.session.currentNode = docs[i]._id;
343 + break;
344 }
340 - console.log("CurrentNode: " + req.session.currentNode);
341 - // This redirect happens after finding node is completed
342 - res.redirect(domain.url);
343 - });
344 - */
345 - } else {
345 + }
346 + console.log("CurrentNode: " + req.session.currentNode);
347 + // This redirect happens after finding node is completed
348 res.redirect(domain.url);
347 - }
349 + });
350 + */
351 + } else {
352 + res.redirect(domain.url);
353 + }
354 //});
355
350 - obj.parent.DispatchEvent(['*'], obj, { etype: 'user', username: user.name, action: 'login', msg: 'Account login', domain: domain.id })
356 + obj.parent.DispatchEvent(['*'], obj, { etype: 'user', username: user.name, action: 'login', msg: 'Account login', domain: domain.id });
357 } else {
358 delete req.session.loginmode;
359 if (err == 'locked') { req.session.error = '<b style=color:#8C001A>Account locked.</b>'; } else { req.session.error = '<b style=color:#8C001A>Login failed, check username and password.</b>'; }
@@ -367,14 +373,14 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
373 if (domain.newaccounts == 0) { res.sendStatus(401); return; }
374 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 == '~') {
375 req.session.loginmode = 2;
370 - req.session.error = '<b style=color:#8C001A>Unable to create account.</b>';;
376 + req.session.error = '<b style=color:#8C001A>Unable to create account.</b>';
377 res.redirect(domain.url);
378 } else {
379 // Check if this email was already verified
380 obj.db.GetUserWithVerifiedEmail(domain.id, req.body.email, function (err, docs) {
381 if (docs.length > 0) {
382 req.session.loginmode = 2;
377 - req.session.error = '<b style=color:#8C001A>Existing account with this email address.</b>';;
383 + req.session.error = '<b style=color:#8C001A>Existing account with this email address.</b>';
384 res.redirect(domain.url);
385 } else {
386 // Check if there is domain.newAccountToken, check if supplied token is valid
@@ -406,7 +412,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
412 obj.db.SetUser(user);
413 if (obj.parent.mailserver != null) { obj.parent.mailserver.sendAccountCheckMail(domain, user.name, user.email); }
414 });
409 - obj.parent.DispatchEvent(['*', 'server-users'], obj, { etype: 'user', username: user.name, account: user, action: 'accountcreate', msg: 'Account created, email is ' + req.body.email, domain: domain.id })
415 + obj.parent.DispatchEvent(['*', 'server-users'], obj, { etype: 'user', username: user.name, account: user, action: 'accountcreate', msg: 'Account created, email is ' + req.body.email, domain: domain.id });
416 }
417 res.redirect(domain.url);
418 }
@@ -459,7 +465,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
465 } else {
466 obj.db.Get('user/' + cookie.u, function (err, docs) {
467 if (docs.length == 0) {
462 - res.render(obj.path.join(__dirname, 'views/message'), { title: domain.title, title2: domain.title2, title3: 'Account Verification', message: 'ERROR: Invalid username \"' + EscapeHtml(user.name) + '\". <a href="' + domain.url + '">Go to login page</a>.' });
468 + res.render(obj.path.join(__dirname, 'views/message'), { title: domain.title, title2: domain.title2, title3: 'Account Verification', message: 'ERROR: Invalid username \"' + EscapeHtml(cookie.u) + '\". <a href="' + domain.url + '">Go to login page</a>.' });
469 } else {
470 var user = docs[0];
471 if (user.email != cookie.e) {
@@ -488,13 +494,13 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
494 delete userinfo.domain;
495 delete userinfo.subscriptions;
496 delete userinfo.passtype;
491 - obj.parent.DispatchEvent(['*', 'server-users', user._id], obj, { etype: 'user', username: userinfo.name, account: userinfo, action: 'accountchange', msg: 'Verified email of user ' + EscapeHtml(user.name) + ' (' + EscapeHtml(userinfo.email) + ')', domain: domain.id })
497 + obj.parent.DispatchEvent(['*', 'server-users', user._id], obj, { etype: 'user', username: userinfo.name, account: userinfo, action: 'accountchange', msg: 'Verified email of user ' + EscapeHtml(user.name) + ' (' + EscapeHtml(userinfo.email) + ')', domain: domain.id });
498
499 // Send the confirmation page
500 res.render(obj.path.join(__dirname, 'views/message'), { title: domain.title, title2: domain.title2, title3: 'Account Verification', message: 'Verified email <b>' + EscapeHtml(user.email) + '</b> for user account <b>' + EscapeHtml(user.name) + '</b>. <a href="' + domain.url + '">Go to login page</a>.' });
501
502 // Send a notification
497 - obj.parent.DispatchEvent([user._id], obj, { action: 'notify', value: 'Email verified:<br /><b>' + EscapeHtml(userinfo.email) + '</b>.', nolog: 1 })
503 + obj.parent.DispatchEvent([user._id], obj, { action: 'notify', value: 'Email verified:<br /><b>' + EscapeHtml(userinfo.email) + '</b>.', nolog: 1 });
504 }
505 });
506 }
@@ -507,10 +513,11 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
513 obj.crypto.randomBytes(16, function (err, buf) {
514 var newpass = buf.toString('base64').split('=').join('').split('/').join('');
515 require('./pass').hash(newpass, function (err, salt, hash) {
516 + var userinfo = null;
517 if (err) throw err;
518
519 // Change the password
513 - var userinfo = obj.users[user._id];
520 + userinfo = obj.users[user._id];
521 userinfo.salt = salt;
522 userinfo.hash = hash;
523 userinfo.passchange = Date.now();
@@ -518,7 +525,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
525 obj.db.SetUser(userinfo);
526
527 // Event the change
521 - var userinfo = obj.common.Clone(userinfo);
528 + userinfo = obj.common.Clone(userinfo);
529 delete userinfo.hash;
530 delete userinfo.passhint;
531 delete userinfo.salt;
@@ -526,7 +533,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
533 delete userinfo.domain;
534 delete userinfo.subscriptions;
535 delete userinfo.passtype;
529 - obj.parent.DispatchEvent(['*', 'server-users', user._id], obj, { etype: 'user', username: userinfo.name, account: userinfo, action: 'accountchange', msg: 'Password reset for user ' + EscapeHtml(user.name), domain: domain.id })
536 + obj.parent.DispatchEvent(['*', 'server-users', user._id], obj, { etype: 'user', username: userinfo.name, account: userinfo, action: 'accountchange', msg: 'Password reset for user ' + EscapeHtml(user.name), domain: domain.id });
537
538 // Send the new password
539 res.render(obj.path.join(__dirname, 'views/message'), { title: domain.title, title2: domain.title2, title3: 'Account Verification', message: '<div>Password for account <b>' + EscapeHtml(user.name) + '</b> has been reset to:</div><div style=padding:14px;font-size:18px><b>' + EscapeHtml(newpass) + '</b></div>Login and go to the \"My Account\" tab to update your password. <a href="' + domain.url + '">Go to login page</a>.' });
@@ -569,7 +576,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
576 if (mesh.links[escUserId] != null) { delete mesh.links[escUserId]; obj.db.Set(mesh); }
577 // Notify mesh change
578 var change = 'Removed user ' + user.name + ' from mesh ' + mesh.name;
572 - obj.parent.DispatchEvent(['*', mesh._id, user._id, userid], obj, { etype: 'mesh', username: user.name, userid: userid, meshid: mesh._id, name: mesh.name, mtype: mesh.mtype, desc: mesh.desc, action: 'meshchange', links: mesh.links, msg: change, domain: domain.id })
579 + obj.parent.DispatchEvent(['*', mesh._id, user._id, userid], obj, { etype: 'mesh', username: user.name, userid: userid, meshid: mesh._id, name: mesh.name, mtype: mesh.mtype, desc: mesh.desc, action: 'meshchange', links: mesh.links, msg: change, domain: domain.id });
580 }
581 }
582 }
@@ -582,7 +589,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
589 delete obj.users[user._id];
590 req.session = null;
591 res.redirect(domain.url);
585 - obj.parent.DispatchEvent(['*', 'server-users'], obj, { etype: 'user', username: user.name, action: 'accountremove', msg: 'Account removed', domain: domain.id })
592 + obj.parent.DispatchEvent(['*', 'server-users'], obj, { etype: 'user', username: user.name, action: 'accountremove', msg: 'Account removed', domain: domain.id });
593 } else {
594 res.redirect(domain.url);
595 }
@@ -609,7 +616,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
616 obj.db.SetUser(user);
617 req.session.viewmode = 2;
618 res.redirect(domain.url);
612 - obj.parent.DispatchEvent(['*', 'server-users'], obj, { etype: 'user', username: user.name, action: 'passchange', msg: 'Account password changed: ' + user.name, domain: domain.id })
619 + obj.parent.DispatchEvent(['*', 'server-users'], obj, { etype: 'user', username: user.name, action: 'passchange', msg: 'Account password changed: ' + user.name, domain: domain.id });
620 });
621 }
622
@@ -618,11 +625,10 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
625 var domain = checkUserIpAddress(req, res);
626 if (domain == null) return;
627 if (!obj.args) { res.sendStatus(500); return; }
621 - var domain = getDomain(req);
628
629 if ((domain.sspi != null) && ((req.query.login == null) || (obj.parent.loginCookieEncryptionKey == null))) {
630 // Login using SSPI
625 - domain.sspi.authenticate(req, res, function (err) { if ((err != null) || (req.connection.user == null)) { res.end('Authentication Required...'); } else { handleRootRequestEx(req, res, domain); } })
631 + domain.sspi.authenticate(req, res, function (err) { if ((err != null) || (req.connection.user == null)) { res.end('Authentication Required...'); } else { handleRootRequestEx(req, res, domain); } });
632 } else {
633 // Login using a different system
634 handleRootRequestEx(req, res, domain);
@@ -630,7 +636,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
636 }
637
638 function handleRootRequestEx(req, res, domain) {
633 - var nologout = false;
639 + var nologout = false, user = null, features = 0;
640 res.set({ 'Cache-Control': 'no-cache, no-store, must-revalidate', 'Pragma': 'no-cache', 'Expires': '0' });
641
642 // Check if we have an incomplete domain name in the path
@@ -676,15 +682,15 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
682 req.session.currentNode = '';
683
684 // Check if this user exists, create it if not.
679 - var user = obj.users[req.session.userid];
685 + user = obj.users[req.session.userid];
686 if ((user == null) || (user.sid != req.session.usersid)) {
687 // Create the domain user
682 - var usercount = 0, user = { type: 'user', _id: req.session.userid, name: req.connection.user, domain: domain.id, sid: req.session.usersid };
688 + var usercount = 0, user2 = { type: 'user', _id: req.session.userid, name: req.connection.user, domain: domain.id, sid: req.session.usersid };
689 for (var i in obj.users) { if (obj.users[i].domain == domain.id) { usercount++; } }
684 - if (usercount == 0) { user.siteadmin = 0xFFFFFFFF; } // If this is the first user, give the account site admin.
685 - obj.users[req.session.userid] = user;
686 - obj.db.SetUser(user);
687 - obj.parent.DispatchEvent(['*', 'server-users'], obj, { etype: 'user', username: req.connection.user, account: user, action: 'accountcreate', msg: 'Domain account created, user ' + req.connection.user, domain: domain.id })
690 + if (usercount == 0) { user2.siteadmin = 0xFFFFFFFF; } // If this is the first user, give the account site admin.
691 + obj.users[req.session.userid] = user2;
692 + obj.db.SetUser(user2);
693 + obj.parent.DispatchEvent(['*', 'server-users'], obj, { etype: 'user', username: req.connection.user, account: user2, action: 'accountcreate', msg: 'Domain account created, user ' + req.connection.user, domain: domain.id });
694 }
695 }
696 }
@@ -706,15 +712,11 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
712 } else if (req.query.node) {
713 currentNode = 'node/' + domain.id + '/' + req.query.node;
714 }
709 - var user;
710 - var logoutcontrol;
711 - if (obj.args.nousers != true) {
712 - user = obj.users[req.session.userid]
713 - logoutcontrol = 'Welcome ' + user.name + '.';
714 - }
715 + var logoutcontrol = '';
716 + if (obj.args.nousers != true) { logoutcontrol = 'Welcome ' + obj.users[req.session.userid].name + '.'; }
717
718 // Give the web page a list of supported server features
717 - var features = 0;
719 + features = 0;
720 if (obj.args.wanonly == true) { features += 1; } // WAN-only mode
721 if (obj.args.lanonly == true) { features += 2; } // LAN-only mode
722 if (obj.args.nousers == true) { features += 4; } // Single user mode
@@ -745,7 +747,8 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
747 }
748 } else {
749 // Send back the login application
748 - var loginmode = req.session.loginmode, features = 0;
750 + var loginmode = req.session.loginmode;
751 + features = 0;
752 delete req.session.loginmode; // Clear this state, if the user hits refresh, we want to go back to the login page.
753 if ((parent.config != null) && (parent.config.settings != null) && (parent.config.settings.allowframing == true)) { features += 32; } // Allow site within iframe
754 var httpsPort = ((obj.args.aliasport == null) ? obj.args.port : obj.args.aliasport); // Use HTTPS alias port is specified
@@ -900,7 +903,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
903 for (var i = 3; i < spliturl.length; i++) { if (obj.common.IsFilenameValid(spliturl[i]) == true) { path += '/' + spliturl[i]; filename = spliturl[i]; } else { res.sendStatus(404); return; } }
904
905 var stat = null;
903 - try { stat = obj.fs.statSync(path) } catch (e) { }
906 + try { stat = obj.fs.statSync(path); } catch (e) { }
907 if ((stat != null) && ((stat.mode & 0x004000) == 0)) {
908 if (req.query.download == 1) {
909 res.set({ 'Cache-Control': 'no-cache, no-store, must-revalidate', 'Pragma': 'no-cache', 'Expires': '0', 'Content-Type': 'application/octet-stream', 'Content-Disposition': 'attachment; filename=\"' + filename + '\"' });
@@ -923,9 +926,8 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
926 if (splitpath[1] != '') { serverpath += '-' + splitpath[1]; } // Add the domain if needed
927 serverpath += ('/' + splitpath[0] + '-' + splitpath[2]);
928 for (var i = 3; i < splitpath.length; i++) { if (obj.common.IsFilenameValid(splitpath[i]) == true) { serverpath += '/' + splitpath[i]; filename = splitpath[i]; } else { return null; } } // Check that each folder is correct
926 - var fullpath = obj.path.resolve(obj.filespath, serverpath), quota = 0;
927 - return { fullpath: fullpath, path: serverpath, name: filename, quota: obj.getQuota(objid, domain) };
928 - }
929 + return { fullpath: obj.path.resolve(obj.filespath, serverpath), path: serverpath, name: filename, quota: obj.getQuota(objid, domain) };
930 + };
931
932 // Return the maximum number of bytes allowed in the user account "My Files".
933 obj.getQuota = function (objid, domain) {
@@ -944,7 +946,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
946 return 1048576; // By default, the server will have a 1 meg limit on mesh accounts
947 }
948 return 0;
947 - }
949 + };
950
951 // Download a file from the server
952 function handleDownloadFile(req, res) {
@@ -1014,7 +1016,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1016 obj.fs.mkdir(xfile.fullpath, function () {
1017 // Write the file
1018 obj.fs.writeFile(obj.path.join(xfile.fullpath, filename), filedata, function () {
1017 - obj.parent.DispatchEvent([user._id], obj, 'updatefiles') // Fire an event causing this user to update this files
1019 + obj.parent.DispatchEvent([user._id], obj, 'updatefiles'); // Fire an event causing this user to update this files
1020 });
1021 });
1022 })(xfile.fullpath, names[i], filedata);
@@ -1027,7 +1029,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1029 var file = files.files[i], fpath = obj.path.join(xfile.fullpath, file.originalFilename);
1030 if (obj.common.IsFilenameValid(file.originalFilename) && ((totalsize + file.size) < xfile.quota)) { // Check if quota would not be broken if we add this file
1031 obj.fs.rename(file.path, fpath, function () {
1030 - obj.parent.DispatchEvent([user._id], obj, 'updatefiles') // Fire an event causing this user to update this files
1032 + obj.parent.DispatchEvent([user._id], obj, 'updatefiles'); // Fire an event causing this user to update this files
1033 });
1034 } else {
1035 try { obj.fs.unlink(file.path); } catch (e) { }
@@ -1051,7 +1053,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1053 obj.parent.RemoveAllEventDispatch(target);
1054 obj.parent.AddEventDispatch(subscriptions, target);
1055 return subscriptions;
1054 - }
1056 + };
1057
1058 // Handle a web socket relay request
1059 function handleRelayWebSocket(ws, req) {
@@ -1143,13 +1145,13 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1145 // CIRA ---> TLS
1146 Debug(3, 'Relay TLS CIRA data', data.length);
1147 if (data.length > 0) { try { ser.updateBuffer(Buffer.from(data, 'binary')); } catch (e) { } }
1146 - }
1148 + };
1149
1150 // Handke CIRA tunnel state change
1151 chnl.onStateChange = function (ciraconn, state) {
1152 Debug(2, 'Relay TLS CIRA state change', state);
1153 if (state == 0) { try { ws.close(); } catch (e) { } }
1152 - }
1154 + };
1155
1156 // TLSSocket to encapsulate TLS communication, which then tunneled via SerialTunnel an then wrapped through CIRA APF
1157 var TLSSocket = require('tls').TLSSocket;
@@ -1199,18 +1201,18 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1201 ws.forwardclient.onStateChange = function (ciraconn, state) {
1202 Debug(2, 'Relay CIRA state change', state);
1203 if (state == 0) { try { ws.close(); } catch (e) { } }
1202 - }
1204 + };
1205
1206 ws.forwardclient.onData = function (ciraconn, data) {
1207 Debug(4, 'Relay CIRA data', data.length);
1208 if (ws.interceptor) { data = ws.interceptor.processAmtData(data); } // Run data thru interceptor
1209 if (data.length > 0) { try { ws.send(data); } catch (e) { } } // TODO: Add TLS support
1208 - }
1210 + };
1211
1212 ws.forwardclient.onSendOk = function (ciraconn) {
1213 // TODO: Flow control? (Dont' really need it with AMT, but would be nice)
1214 //console.log('onSendOk');
1213 - }
1215 + };
1216
1217 // Fetch Intel AMT credentials & Setup interceptor
1218 if (req.query.p == 1) {
@@ -1345,7 +1347,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1347 var r = 0, dir;
1348 try { dir = obj.fs.readdirSync(path); } catch (e) { return 0; }
1349 for (var i in dir) {
1348 - var stat = obj.fs.statSync(path + '/' + dir[i])
1350 + var stat = obj.fs.statSync(path + '/' + dir[i]);
1351 if ((stat.mode & 0x004000) == 0) { r += stat.size; } else { r += readTotalFileSize(path + '/' + dir[i]); }
1352 }
1353 return r;
@@ -1359,15 +1361,15 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1361 if (obj.fs.lstatSync(pathx).isDirectory()) { deleteFolderRec(pathx); } else { obj.fs.unlinkSync(pathx); }
1362 });
1363 obj.fs.rmdirSync(path);
1362 - };
1364 + }
1365
1366 // Handle Intel AMT events
1367 // To subscribe, add "http://server:port/amtevents.ashx" to Intel AMT subscriptions.
1368 obj.handleAmtEventRequest = function (req, res) {
1369 var domain = getDomain(req);
1370 try {
1369 - if (req.headers['authorization']) {
1370 - var authstr = req.headers['authorization'];
1371 + if (req.headers.authorization) {
1372 + var authstr = req.headers.authorization;
1373 if (authstr.substring(0, 7) == "Digest ") {
1374 var auth = obj.common.parseNameValueList(obj.common.quoteSplit(authstr.substring(7)));
1375 if ((req.url === auth.uri) && (obj.httpAuthRealm === auth.realm) && (auth.opaque === obj.crypto.createHmac('SHA384', obj.httpAuthRandom).update(auth.nonce).digest('hex'))) {
@@ -1436,7 +1438,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1438 res.set({ 'WWW-Authenticate': 'Digest realm="' + obj.httpAuthRealm + '", qop="auth,auth-int", nonce="' + nonce + '", opaque="' + opaque + '"' });
1439 res.sendStatus(401);
1440 });
1439 - }
1441 + };
1442
1443 // Handle a server backup request
1444 function handleBackupRequest(req, res) {
@@ -1541,11 +1543,11 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1543 // If the agentid is 3 or 4, check if we have a signed MeshCmd.exe
1544 if ((agentid == 3)) { // Signed Windows MeshCmd.exe x86
1545 var stats = null, meshCmdPath = obj.path.join(__dirname, 'agents', 'MeshCmd-signed.exe');
1544 - try { stats = obj.fs.statSync(meshCmdPath) } catch (e) { }
1546 + try { stats = obj.fs.statSync(meshCmdPath); } catch (e) { }
1547 if ((stats != 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=meshcmd' + ((req.query.meshcmd <= 3) ? '.exe' : '') }); res.sendFile(meshCmdPath); return; }
1548 } else if ((agentid == 4)) { // Signed Windows MeshCmd64.exe x64
1549 var stats = null, meshCmd64Path = obj.path.join(__dirname, 'agents', 'MeshCmd64-signed.exe');
1548 - try { stats = obj.fs.statSync(meshCmd64Path) } catch (e) { }
1550 + try { stats = obj.fs.statSync(meshCmd64Path); } catch (e) { }
1551 if ((stats != 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=meshcmd' + ((req.query.meshcmd <= 4) ? '.exe' : '') }); res.sendFile(meshCmd64Path); return; }
1552 }
1553 // No signed agents, we are going to merge a new MeshCmd.
@@ -1581,7 +1583,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1583 serverId: obj.agentCertificateHashHex.toUpperCase(), // SHA384 of server HTTPS public key
1584 serverHttpsHash: new Buffer(obj.webCertificateHash, 'binary').toString('hex').toUpperCase(), // SHA384 of server HTTPS certificate
1585 debugLevel: 0
1584 - }
1586 + };
1587 if (user != null) { meshaction.username = user.name; }
1588 var httpsPort = ((obj.args.aliasport == null) ? obj.args.port : obj.args.aliasport); // Use HTTPS alias port is specified
1589 if (obj.args.lanonly != true) { meshaction.serverUrl = ((obj.args.notls == true) ? 'ws://' : 'wss://') + getWebServerName(domain) + ':' + httpsPort + '/' + ((domain.id == '') ? '' : ('/' + domain.id)) + 'meshrelay.ashx'; }
@@ -1596,7 +1598,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1598 serverId: obj.agentCertificateHashHex.toUpperCase(), // SHA384 of server HTTPS public key
1599 serverHttpsHash: new Buffer(obj.webCertificateHash, 'binary').toString('hex').toUpperCase(), // SHA384 of server HTTPS certificate
1600 debugLevel: 0
1599 - }
1601 + };
1602 if (user != null) { meshaction.username = user.name; }
1603 var httpsPort = ((obj.args.aliasport == null) ? obj.args.port : obj.args.aliasport); // Use HTTPS alias port is specified
1604 if (obj.args.lanonly != true) { meshaction.serverUrl = ((obj.args.notls == true) ? 'ws://' : 'wss://') + getWebServerName(domain) + ':' + httpsPort + '/' + ((domain.id == '') ? '' : ('/' + domain.id)) + 'meshrelay.ashx'; }
@@ -1619,7 +1621,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1621 response += '</table></body></html>';
1622 res.send(response);
1623 }
1622 - }
1624 + };
1625
1626 // Get the web server hostname. This may change if using a domain with a DNS name.
1627 function getWebServerName(domain) {
@@ -1660,7 +1662,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1662
1663 res.set({ 'Cache-Control': 'no-cache, no-store, must-revalidate', 'Pragma': 'no-cache', 'Expires': '0', 'Content-Type': 'application/octet-stream', 'Content-Disposition': 'attachment; filename=meshagent.msh' });
1664 res.send(meshsettings);
1663 - }
1665 + };
1666
1667 // Add HTTP security headers to all responses
1668 obj.app.use(function (req, res, next) {
@@ -1785,7 +1787,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1787 // Check we have agent rights
1788 var rights = user.links[agent.dbMeshKey].rights;
1789 if ((rights != null) && ((rights & MESHRIGHT_AGENTCONSOLE) != 0) && (user.siteadmin == 0xFFFFFFFF)) { agent.close(disconnectMode); }
1788 - }
1790 + };
1791
1792 // Send the core module to the mesh agent
1793 obj.sendMeshAgentCore = function (user, domain, nodeid, core) {
@@ -1815,7 +1817,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1817 agent.send(obj.common.ShortToStr(10) + obj.common.ShortToStr(0) + hash + core);
1818 }
1819 }
1818 - }
1820 + };
1821
1822 // Get the server path of a user or mesh object
1823 function getServerRootFilePath(obj) {
@@ -1878,36 +1880,37 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1880
1881 // Count sessions and event any changes
1882 obj.recountSessions = function (changedSessionId) {
1883 + var userid, oldcount, newcount, x, serverid;
1884 if (changedSessionId == null) {
1885 // Recount all sessions
1886
1887 // Calculate the session count for all userid's
1888 var newSessionsCount = {};
1886 - for (var userid in obj.wssessions) { newSessionsCount[userid] = obj.wssessions[userid].length; }
1887 - for (var serverid in obj.wsPeerSessions3) {
1888 - for (var userid in obj.wsPeerSessions3[serverid]) {
1889 - var c = obj.wsPeerSessions3[serverid][userid].length;
1890 - if (newSessionsCount[userid] == null) { newSessionsCount[userid] = c; } else { newSessionsCount[userid] += c; }
1889 + for (userid in obj.wssessions) { newSessionsCount[userid] = obj.wssessions[userid].length; }
1890 + for (serverid in obj.wsPeerSessions3) {
1891 + for (userid in obj.wsPeerSessions3[serverid]) {
1892 + x = obj.wsPeerSessions3[serverid][userid].length;
1893 + if (newSessionsCount[userid] == null) { newSessionsCount[userid] = x; } else { newSessionsCount[userid] += x; }
1894 }
1895 }
1896
1897 // See what session counts have changed, event any changes
1895 - for (var userid in newSessionsCount) {
1896 - var newcount = newSessionsCount[userid];
1897 - var oldcount = obj.sessionsCount[userid];
1898 + for (userid in newSessionsCount) {
1899 + newcount = newSessionsCount[userid];
1900 + oldcount = obj.sessionsCount[userid];
1901 if (oldcount == null) { oldcount = 0; } else { delete obj.sessionsCount[userid]; }
1902 if (newcount != oldcount) {
1900 - var x = userid.split('/');
1901 - obj.parent.DispatchEvent(['*'], obj, { action: 'wssessioncount', username: x[2], count: newcount, domain: x[1], nolog: 1, nopeers: 1 })
1903 + x = userid.split('/');
1904 + obj.parent.DispatchEvent(['*'], obj, { action: 'wssessioncount', username: x[2], count: newcount, domain: x[1], nolog: 1, nopeers: 1 });
1905 }
1906 }
1907
1908 // If there are any counts left in the old counts, event to zero
1906 - for (var userid in obj.sessionsCount) {
1907 - var oldcount = obj.sessionsCount[userid];
1909 + for (userid in obj.sessionsCount) {
1910 + oldcount = obj.sessionsCount[userid];
1911 if ((oldcount != null) && (oldcount != 0)) {
1909 - var x = userid.split('/');
1910 - obj.parent.DispatchEvent(['*'], obj, { action: 'wssessioncount', username: x[2], count: 0, domain: x[1], nolog: 1, nopeers: 1 })
1912 + x = userid.split('/');
1913 + obj.parent.DispatchEvent(['*'], obj, { action: 'wssessioncount', username: x[2], count: 0, domain: x[1], nolog: 1, nopeers: 1 });
1914 }
1915 }
1916
@@ -1915,23 +1918,23 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1918 obj.sessionsCount = newSessionsCount;
1919 } else {
1920 // Figure out the userid
1918 - var userid = changedSessionId.split('/').slice(0, 3).join('/');
1921 + userid = changedSessionId.split('/').slice(0, 3).join('/');
1922
1923 // Recount only changedSessionId
1921 - var newcount = 0;
1924 + newcount = 0;
1925 if (obj.wssessions[userid] != null) { newcount = obj.wssessions[userid].length; }
1923 - for (var serverid in obj.wsPeerSessions3) { if (obj.wsPeerSessions3[serverid][userid] != null) { newcount += obj.wsPeerSessions3[serverid][userid].length; } }
1924 - var oldcount = obj.sessionsCount[userid];
1926 + for (serverid in obj.wsPeerSessions3) { if (obj.wsPeerSessions3[serverid][userid] != null) { newcount += obj.wsPeerSessions3[serverid][userid].length; } }
1927 + oldcount = obj.sessionsCount[userid];
1928 if (oldcount == null) { oldcount = 0; }
1929
1930 // If the count changed, update and event
1931 if (newcount != oldcount) {
1929 - var x = userid.split('/');
1930 - obj.parent.DispatchEvent(['*'], obj, { action: 'wssessioncount', username: x[2], count: newcount, domain: x[1], nolog: 1, nopeers: 1 })
1932 + x = userid.split('/');
1933 + obj.parent.DispatchEvent(['*'], obj, { action: 'wssessioncount', username: x[2], count: newcount, domain: x[1], nolog: 1, nopeers: 1 });
1934 obj.sessionsCount[userid] = newcount;
1935 }
1936 }
1934 - }
1937 + };
1938
1939 // Return true if a mobile browser is detected.
1940 // This code comes from "http://detectmobilebrowsers.com/" and was modified, This is free and unencumbered software released into the public domain. For more information, please refer to the http://unlicense.org/
@@ -1943,5 +1946,4 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1946 }
1947
1948 return obj;
1946 -}
1947 -
1949 +};
\ No newline at end of file
winservice.js
+6 -1
@@ -6,7 +6,12 @@
6 * @version v0.0.1
7 */
8
9 -'use strict';
9 +/*jslint node: true */
10 +/*jshint node: true */
11 +/*jshint strict:false */
12 +/*jshint -W097 */
13 +/*jshint esversion: 6 */
14 +"use strict";
15
16 // This module is only called when MeshCentral is running as a Windows service.
17 // In this case, we don't want to start a child process, so we launch directly without arguments.