mirror of
https://github.com/Ylianst/MeshCentral.git
synced 2024-12-23 21:55:52 -05:00
Completed first pass with JsHint, updated windows MeshAgent.
This commit is contained in:
parent
d48f24911a
commit
562310bed1
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
185
agents/modules_meshcmd/promise.js
Normal file
185
agents/modules_meshcmd/promise.js
Normal file
@ -0,0 +1,185 @@
|
||||
/*
|
||||
Copyright 2018 Intel Corporation
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
var refTable = {};
|
||||
|
||||
function Promise(promiseFunc)
|
||||
{
|
||||
this._ObjectID = 'promise';
|
||||
this._internal = { promise: this, func: promiseFunc, completed: false, errors: false, completedArgs: [] };
|
||||
require('events').EventEmitter.call(this._internal);
|
||||
this._internal.on('_eventHook', function (eventName, eventCallback)
|
||||
{
|
||||
//console.log('hook', eventName, 'errors/' + this.errors + ' completed/' + this.completed);
|
||||
var r = null;
|
||||
|
||||
if (eventName == 'resolved' && !this.errors && this.completed)
|
||||
{
|
||||
r = eventCallback.apply(this, this.completedArgs);
|
||||
if(r!=null)
|
||||
{
|
||||
this.emit_returnValue('resolved', r);
|
||||
}
|
||||
}
|
||||
if (eventName == 'rejected' && this.errors && this.completed)
|
||||
{
|
||||
eventCallback.apply(this, this.completedArgs);
|
||||
}
|
||||
if (eventName == 'settled' && this.completed)
|
||||
{
|
||||
eventCallback.apply(this, []);
|
||||
}
|
||||
});
|
||||
this._internal.resolver = function _resolver()
|
||||
{
|
||||
_resolver._self.errors = false;
|
||||
_resolver._self.completed = true;
|
||||
_resolver._self.completedArgs = [];
|
||||
var args = ['resolved'];
|
||||
if (this.emit_returnValue && this.emit_returnValue('resolved') != null)
|
||||
{
|
||||
_resolver._self.completedArgs.push(this.emit_returnValue('resolved'));
|
||||
args.push(this.emit_returnValue('resolved'));
|
||||
}
|
||||
else
|
||||
{
|
||||
for (var a in arguments)
|
||||
{
|
||||
_resolver._self.completedArgs.push(arguments[a]);
|
||||
args.push(arguments[a]);
|
||||
}
|
||||
}
|
||||
_resolver._self.emit.apply(_resolver._self, args);
|
||||
_resolver._self.emit('settled');
|
||||
};
|
||||
this._internal.rejector = function _rejector()
|
||||
{
|
||||
_rejector._self.errors = true;
|
||||
_rejector._self.completed = true;
|
||||
_rejector._self.completedArgs = [];
|
||||
var args = ['rejected'];
|
||||
for (var a in arguments)
|
||||
{
|
||||
_rejector._self.completedArgs.push(arguments[a]);
|
||||
args.push(arguments[a]);
|
||||
}
|
||||
|
||||
_rejector._self.emit.apply(_rejector._self, args);
|
||||
_rejector._self.emit('settled');
|
||||
};
|
||||
this.catch = function(func)
|
||||
{
|
||||
this._internal.once('settled', func);
|
||||
}
|
||||
this.finally = function (func)
|
||||
{
|
||||
this._internal.once('settled', func);
|
||||
};
|
||||
this.then = function (resolved, rejected)
|
||||
{
|
||||
if (resolved) { this._internal.once('resolved', resolved); }
|
||||
if (rejected) { this._internal.once('rejected', rejected); }
|
||||
|
||||
var retVal = new Promise(function (r, j) { });
|
||||
|
||||
this._internal.once('resolved', retVal._internal.resolver);
|
||||
this._internal.once('rejected', retVal._internal.rejector);
|
||||
return (retVal);
|
||||
};
|
||||
|
||||
this._internal.resolver._self = this._internal;
|
||||
this._internal.rejector._self = this._internal;;
|
||||
|
||||
try
|
||||
{
|
||||
promiseFunc.call(this, this._internal.resolver, this._internal.rejector);
|
||||
}
|
||||
catch(e)
|
||||
{
|
||||
this._internal.errors = true;
|
||||
this._internal.completed = true;
|
||||
this._internal.completedArgs = [e];
|
||||
this._internal.emit('rejected', e);
|
||||
this._internal.emit('settled');
|
||||
}
|
||||
|
||||
if(!this._internal.completed)
|
||||
{
|
||||
// Save reference of this object
|
||||
refTable[this._internal._hashCode()] = this._internal;
|
||||
this._internal.once('settled', function () { refTable[this._hashCode()] = null; });
|
||||
}
|
||||
}
|
||||
|
||||
Promise.resolve = function resolve()
|
||||
{
|
||||
var retVal = new Promise(function (r, j) { });
|
||||
var args = [];
|
||||
for (var i in arguments)
|
||||
{
|
||||
args.push(arguments[i]);
|
||||
}
|
||||
retVal._internal.resolver.apply(retVal._internal, args);
|
||||
return (retVal);
|
||||
};
|
||||
Promise.reject = function reject() {
|
||||
var retVal = new Promise(function (r, j) { });
|
||||
var args = [];
|
||||
for (var i in arguments) {
|
||||
args.push(arguments[i]);
|
||||
}
|
||||
retVal._internal.rejector.apply(retVal._internal, args);
|
||||
return (retVal);
|
||||
};
|
||||
Promise.all = function all(promiseList)
|
||||
{
|
||||
var ret = new Promise(function (res, rej)
|
||||
{
|
||||
this.__rejector = rej;
|
||||
this.__resolver = res;
|
||||
this.__promiseList = promiseList;
|
||||
this.__done = false;
|
||||
this.__count = 0;
|
||||
});
|
||||
|
||||
for (var i in promiseList)
|
||||
{
|
||||
promiseList[i].then(function ()
|
||||
{
|
||||
// Success
|
||||
if(++ret.__count == ret.__promiseList.length)
|
||||
{
|
||||
ret.__done = true;
|
||||
ret.__resolver(ret.__promiseList);
|
||||
}
|
||||
}, function (arg)
|
||||
{
|
||||
// Failure
|
||||
if(!ret.__done)
|
||||
{
|
||||
ret.__done = true;
|
||||
ret.__rejector(arg);
|
||||
}
|
||||
});
|
||||
}
|
||||
if (promiseList.length == 0)
|
||||
{
|
||||
ret.__resolver(promiseList);
|
||||
}
|
||||
return (ret);
|
||||
};
|
||||
|
||||
module.exports = Promise;
|
@ -109,29 +109,16 @@ function serviceManager()
|
||||
}
|
||||
return admin;
|
||||
};
|
||||
this.getProgramFolder = function getProgramFolder() {
|
||||
if (require('os').arch() == 'x64') { // 64 bit Windows
|
||||
if (this.GM.PointerSize == 4) { return process.env['ProgramFiles(x86)']; } // 32 Bit App
|
||||
return process.env['ProgramFiles']; // 64 bit App
|
||||
}
|
||||
return process.env['ProgramFiles']; // 32 bit Windows
|
||||
};
|
||||
this.getServiceFolder = function getServiceFolder()
|
||||
{
|
||||
var destinationFolder = null;
|
||||
if (require('os').arch() == 'x64')
|
||||
{
|
||||
// 64 bit Windows
|
||||
if (this.GM.PointerSize == 4)
|
||||
{
|
||||
// 32 Bit App
|
||||
destinationFolder = process.env['ProgramFiles(x86)'];
|
||||
}
|
||||
else
|
||||
{
|
||||
// 64 bit App
|
||||
destinationFolder = process.env['ProgramFiles'];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 32 bit Windows
|
||||
destinationFolder = process.env['ProgramFiles'];
|
||||
}
|
||||
return (destinationFolder + '\\mesh');
|
||||
return this.getProgramFolder() + '\\mesh';
|
||||
};
|
||||
|
||||
this.enumerateService = function () {
|
||||
|
182
meshcentral.js
182
meshcentral.js
@ -6,23 +6,29 @@
|
||||
* @version v0.0.1
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
/*xjslint node: true */
|
||||
/*xjslint plusplus: true */
|
||||
/*xjslint maxlen: 256 */
|
||||
/*jshint node: true */
|
||||
/*jshint strict: false */
|
||||
/*jshint esversion: 6 */
|
||||
"use strict";
|
||||
|
||||
// If app metrics is available
|
||||
if (process.argv[2] == '--launch') { try { require('appmetrics-dash').monitor({ url: '/', title: 'MeshCentral', port: 88, host: '127.0.0.1' }); } catch (e) { } }
|
||||
|
||||
function CreateMeshCentralServer(config, args) {
|
||||
var obj = {};
|
||||
obj.db;
|
||||
obj.webserver;
|
||||
obj.redirserver;
|
||||
obj.mpsserver;
|
||||
obj.swarmserver;
|
||||
obj.mailserver;
|
||||
obj.amtEventHandler;
|
||||
obj.amtScanner;
|
||||
obj.meshScanner;
|
||||
obj.letsencrypt;
|
||||
obj.db = null;
|
||||
obj.webserver = null;
|
||||
obj.redirserver = null;
|
||||
obj.mpsserver = null;
|
||||
obj.swarmserver = null;
|
||||
obj.mailserver = null;
|
||||
obj.amtEventHandler = null;
|
||||
obj.amtScanner = null;
|
||||
obj.meshScanner = null;
|
||||
obj.letsencrypt = null;
|
||||
obj.eventsDispatch = {};
|
||||
obj.fs = require('fs');
|
||||
obj.path = require('path');
|
||||
@ -78,13 +84,14 @@ function CreateMeshCentralServer(config, args) {
|
||||
|
||||
// Start the Meshcentral server
|
||||
obj.Start = function () {
|
||||
var i;
|
||||
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.
|
||||
|
||||
// Check for invalid arguments
|
||||
var validArguments = ['_', 'notls', 'user', 'port', 'aliasport', 'mpsport', 'mpsaliasport', 'redirport', 'cert', 'mpscert', 'deletedomain', 'deletedefaultdomain', 'showall', 'showusers', 'shownodes', 'showmeshes', 'showevents', 'showpower', 'clearpower', 'showiplocations', 'help', 'exactports', 'install', 'uninstall', 'start', 'stop', 'restart', 'debug', 'filespath', 'datapath', 'noagentupdate', 'launch', 'noserverbackup', 'mongodb', 'mongodbcol', 'wanonly', 'lanonly', 'nousers', 'mpsdebug', 'mpspass', 'ciralocalfqdn', 'dbexport', 'dbimport', 'selfupdate', 'tlsoffload', 'userallowedip', 'fastcert', 'swarmport', 'swarmdebug', 'logintoken', 'logintokenkey', 'logintokengen', 'logintokengen', 'mailtokengen', 'admin', 'unadmin', 'sessionkey', 'sessiontime', 'minify'];
|
||||
for (var arg in obj.args) { obj.args[arg.toLocaleLowerCase()] = obj.args[arg]; if (validArguments.indexOf(arg.toLocaleLowerCase()) == -1) { console.log('Invalid argument "' + arg + '", use --help.'); return; } }
|
||||
if (obj.args.mongodb == true) { console.log('Must specify: --mongodb [connectionstring] \r\nSee https://docs.mongodb.com/manual/reference/connection-string/ for MongoDB connection string.'); return; }
|
||||
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.
|
||||
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.
|
||||
|
||||
if ((obj.args.help == true) || (obj.args['?'] == true)) {
|
||||
console.log('MeshCentral2 Beta 2, a web-based remote computer management web portal.\r\n');
|
||||
@ -106,19 +113,19 @@ function CreateMeshCentralServer(config, args) {
|
||||
console.log(' country and organization can optionaly be set.');
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Check if we need to install, start, stop, remove ourself as a background service
|
||||
if ((obj.service != null) && ((obj.args.install == true) || (obj.args.uninstall == true) || (obj.args.start == true) || (obj.args.stop == true) || (obj.args.restart == true))) {
|
||||
var env = [], xenv = ['user', 'port', 'aliasport', 'mpsport', 'mpsaliasport', 'redirport', 'exactport', 'debug'];
|
||||
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.
|
||||
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 });
|
||||
for (i in xenv) { if (obj.args[xenv[i]] != null) { env.push({ name: 'mesh' + xenv[i], value: obj.args[xenv[i]] }); } } // Set some args as service environement variables.
|
||||
var svc = new obj.service({ name: 'MeshCentral', description: 'MeshCentral Remote Management Server', script: obj.path.join(__dirname, 'winservice.js'), env: env, wait: 2, grow: 0.5 });
|
||||
svc.on('install', function () { console.log('MeshCentral service installed.'); svc.start(); });
|
||||
svc.on('uninstall', function () { console.log('MeshCentral service uninstalled.'); process.exit(); });
|
||||
svc.on('start', function () { console.log('MeshCentral service started.'); process.exit(); });
|
||||
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); } });
|
||||
svc.on('alreadyinstalled', function () { console.log('MeshCentral service already installed.'); process.exit(); });
|
||||
svc.on('invalidinstallation', function () { console.log('Invalid MeshCentral service installation.'); process.exit(); });
|
||||
|
||||
|
||||
if (obj.args.install == true) { try { svc.install(); } catch (e) { logException(e); } }
|
||||
if (obj.args.stop == true || obj.args.restart == true) { try { svc.stop(); } catch (e) { logException(e); } }
|
||||
if (obj.args.start == true || obj.args.restart == true) { try { svc.start(); } catch (e) { logException(e); } }
|
||||
@ -132,7 +139,7 @@ function CreateMeshCentralServer(config, args) {
|
||||
} else {
|
||||
// if "--launch" is not specified, launch the server as a child process.
|
||||
var startLine = '';
|
||||
for (var i in process.argv) {
|
||||
for (i in process.argv) {
|
||||
var arg = process.argv[i];
|
||||
if (arg.length > 0) {
|
||||
if (startLine.length > 0) startLine += ' ';
|
||||
@ -141,7 +148,7 @@ function CreateMeshCentralServer(config, args) {
|
||||
}
|
||||
obj.launchChildServer(startLine);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Launch MeshCentral as a child server and monitor it.
|
||||
obj.launchChildServer = function (startLine) {
|
||||
@ -166,7 +173,7 @@ function CreateMeshCentralServer(config, args) {
|
||||
console.log(error);
|
||||
console.log('ERROR: MeshCentral failed with critical error, check MeshErrors.txt. Restarting in 5 seconds...');
|
||||
setTimeout(function () { obj.launchChildServer(startLine); }, 5000);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
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) {
|
||||
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');
|
||||
});
|
||||
xprocess.on('close', function (code) { if ((code != 0) && (code != 123)) { /* console.log("Exited with code " + code); */ } });
|
||||
}
|
||||
};
|
||||
|
||||
// Get current and latest MeshCentral server versions using NPM
|
||||
obj.getLatestServerVersion = function (callback) {
|
||||
@ -190,44 +197,45 @@ function CreateMeshCentralServer(config, args) {
|
||||
if (code == 0) { try { latestVer = xprocess.data.split(' ').join('').split('\r').join('').split('\n').join(''); } catch (e) { } }
|
||||
callback(obj.currentVer, latestVer);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// Initiate server self-update
|
||||
obj.performServerUpdate = function () { console.log('Starting self upgrade...'); process.exit(200); }
|
||||
obj.performServerUpdate = function () { console.log('Starting self upgrade...'); process.exit(200); };
|
||||
|
||||
// Initiate server self-update
|
||||
obj.performServerCertUpdate = function () { console.log('Updating server certificates...'); process.exit(200); }
|
||||
obj.performServerCertUpdate = function () { console.log('Updating server certificates...'); process.exit(200); };
|
||||
|
||||
obj.StartEx = function () {
|
||||
var i;
|
||||
//var wincmd = require('node-windows');
|
||||
//wincmd.list(function (svc) { console.log(svc); }, true);
|
||||
|
||||
|
||||
// Write the server state
|
||||
obj.updateServerState('state', 'starting');
|
||||
|
||||
// Look to see if data and/or file path is specified
|
||||
if (obj.args.datapath) { obj.datapath = obj.args.datapath; }
|
||||
if (obj.args.filespath) { obj.filespath = obj.args.filespath; }
|
||||
|
||||
|
||||
// Read environment variables. For a subset of arguments, we allow them to be read from environment variables.
|
||||
var xenv = ['user', 'port', 'mpsport', 'mpsaliasport', 'redirport', 'exactport', 'debug'];
|
||||
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]]); } }
|
||||
|
||||
for (i in xenv) { if ((obj.args[xenv[i]] == null) && (process.env['mesh' + xenv[i]])) { obj.args[xenv[i]] = obj.common.toNumber(process.env['mesh' + xenv[i]]); } }
|
||||
|
||||
// Validate the domains, this is used for multi-hosting
|
||||
if (obj.config.domains == null) { obj.config.domains = {}; }
|
||||
if (obj.config.domains[''] == null) { obj.config.domains[''] = {}; }
|
||||
if (obj.config.domains[''].dns != null) { console.log("ERROR: Default domain can't have a DNS name."); return; }
|
||||
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;
|
||||
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;
|
||||
var bannedDomains = ['public', 'private', 'images', 'scripts', 'styles', 'views']; // List of banned domains
|
||||
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; } } }
|
||||
for (var i in obj.config.domains) {
|
||||
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; } } }
|
||||
for (i in obj.config.domains) {
|
||||
if (obj.config.domains[i].dns == null) { obj.config.domains[i].url = (i == '') ? '/' : ('/' + i + '/'); } else { obj.config.domains[i].url = '/'; }
|
||||
obj.config.domains[i].id = i;
|
||||
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(','); } }
|
||||
}
|
||||
|
||||
// Log passed arguments into Windows Service Log
|
||||
//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); }
|
||||
//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); }
|
||||
|
||||
// Look at passed in arguments
|
||||
if ((obj.args.user != null) && (typeof obj.args.user != 'string')) { delete obj.args.user; }
|
||||
@ -269,12 +277,12 @@ function CreateMeshCentralServer(config, args) {
|
||||
if (obj.args.dbimport == true) { obj.args.dbimport = obj.getConfigFilePath('meshcentral.db.json'); }
|
||||
var json = null, json2 = "", badCharCount = 0;
|
||||
try { json = obj.fs.readFileSync(obj.args.dbimport, { encoding: 'utf8' }); } catch (e) { console.log('Invalid JSON file: ' + obj.args.dbimport + '.'); process.exit(); }
|
||||
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
|
||||
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
|
||||
if (badCharCount > 0) { console.log(badCharCount + ' invalid character(s) where removed.'); }
|
||||
try { json = JSON.parse(json2); } catch (e) { console.log('Invalid JSON format: ' + obj.args.dbimport + ': ' + e); process.exit(); }
|
||||
if ((json == null) || (typeof json.length != 'number') || (json.length < 1)) { console.log('Invalid JSON format: ' + obj.args.dbimport + '.'); }
|
||||
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
|
||||
//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
|
||||
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
|
||||
//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
|
||||
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(); }); });
|
||||
return;
|
||||
}
|
||||
@ -333,7 +341,7 @@ function CreateMeshCentralServer(config, args) {
|
||||
obj.db.Get('dbconfig', function (err, dbconfig) {
|
||||
if (dbconfig.length == 1) { obj.dbconfig = dbconfig[0]; } else { obj.dbconfig = { _id: 'dbconfig', version: 1 }; }
|
||||
if (obj.dbconfig.amtWsEventSecret == null) { require('crypto').randomBytes(32, function (err, buf) { obj.dbconfig.amtWsEventSecret = buf.toString('hex'); obj.db.Set(obj.dbconfig); }); }
|
||||
|
||||
|
||||
// This is used by the user to create a username/password for a Intel AMT WSMAN event subscription
|
||||
if (obj.args.getwspass) {
|
||||
if (obj.args.getwspass.length == 64) {
|
||||
@ -367,12 +375,12 @@ function CreateMeshCentralServer(config, args) {
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// Done starting the redirection server, go on to load the server certificates
|
||||
obj.StartEx2 = function () {
|
||||
// Load server certificates
|
||||
obj.certificateOperations = require('./certoperations.js').CertificateOperations()
|
||||
obj.certificateOperations = require('./certoperations.js').CertificateOperations();
|
||||
obj.certificateOperations.GetMeshServerCertificate(obj, obj.args, obj.config, function (certs) {
|
||||
if (obj.config.letsencrypt == null) {
|
||||
obj.StartEx3(certs); // Just use the configured certificates
|
||||
@ -387,10 +395,11 @@ function CreateMeshCentralServer(config, args) {
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// Start the server with the given certificates
|
||||
obj.StartEx3 = function (certs) {
|
||||
var i;
|
||||
obj.certificates = certs;
|
||||
obj.certificateOperations.acceleratorStart(certs); // Set the state of the accelerators
|
||||
|
||||
@ -398,14 +407,14 @@ function CreateMeshCentralServer(config, args) {
|
||||
if (obj.certificates.CommonName == 'un-configured') { console.log('Server name not configured, running in LAN-only mode.'); obj.args.lanonly = true; }
|
||||
|
||||
// Check that no sub-domains have the same DNS as the parent
|
||||
for (var i in obj.config.domains) {
|
||||
for (i in obj.config.domains) {
|
||||
if ((obj.config.domains[i].dns != null) && (obj.certificates.CommonName.toLowerCase() === obj.config.domains[i].dns.toLowerCase())) {
|
||||
console.log("ERROR: Server sub-domain can't have same DNS name as the parent."); process.exit(0); return;
|
||||
}
|
||||
}
|
||||
|
||||
// Load the list of mesh agents and install scripts
|
||||
if (obj.args.noagentupdate == 1) { for (var i in obj.meshAgentsArchitectureNumbers) { obj.meshAgentsArchitectureNumbers[i].update = false; } }
|
||||
if (obj.args.noagentupdate == 1) { for (i in obj.meshAgentsArchitectureNumbers) { obj.meshAgentsArchitectureNumbers[i].update = false; } }
|
||||
obj.updateMeshAgentsTable(function () {
|
||||
obj.updateMeshAgentInstallScripts();
|
||||
|
||||
@ -460,7 +469,7 @@ function CreateMeshCentralServer(config, args) {
|
||||
obj.maintenanceTimer = setInterval(obj.maintenanceActions, 1000 * 60 * 60); // Run this every hour
|
||||
|
||||
// Dispatch an event that the server is now running
|
||||
obj.DispatchEvent(['*'], obj, { etype: 'server', action: 'started', msg: 'Server started' })
|
||||
obj.DispatchEvent(['*'], obj, { etype: 'server', action: 'started', msg: 'Server started' });
|
||||
|
||||
// Load the login cookie encryption key from the database if allowed
|
||||
if ((obj.config) && (obj.config.settings) && (obj.config.settings.allowlogintoken == true)) {
|
||||
@ -473,12 +482,12 @@ function CreateMeshCentralServer(config, args) {
|
||||
});
|
||||
}
|
||||
|
||||
obj.debug(1, 'Server started');
|
||||
//obj.debug(1, 'Server started');
|
||||
if (obj.args.nousers == true) { obj.updateServerState('nousers', '1'); }
|
||||
obj.updateServerState('state', 'running');
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// Perform maintenance operations (called every hour)
|
||||
obj.maintenanceActions = function () {
|
||||
@ -499,7 +508,7 @@ function CreateMeshCentralServer(config, args) {
|
||||
|
||||
// Perform other database cleanup
|
||||
obj.db.cleanup();
|
||||
}
|
||||
};
|
||||
|
||||
// Stop the Meshcentral server
|
||||
obj.Stop = function (restoreFile) {
|
||||
@ -507,7 +516,7 @@ function CreateMeshCentralServer(config, args) {
|
||||
if (!obj.db) return;
|
||||
|
||||
// Dispatch an event saying the server is now stopping
|
||||
obj.DispatchEvent(['*'], obj, { etype: 'server', action: 'stopped', msg: 'Server stopped' })
|
||||
obj.DispatchEvent(['*'], obj, { etype: 'server', action: 'stopped', msg: 'Server stopped' });
|
||||
|
||||
// Set all nodes to power state of unknown (0)
|
||||
var record = { type: 'power', time: Date.now(), node: '*', power: 0, s: 2 };
|
||||
@ -543,7 +552,7 @@ function CreateMeshCentralServer(config, args) {
|
||||
});
|
||||
}
|
||||
});
|
||||
zipfile.on("end", function () { setTimeout(function () { fs.unlinkSync(restoreFile); process.exit(123); }); });
|
||||
zipfile.on("end", function () { setTimeout(function () { obj.fs.unlinkSync(restoreFile); process.exit(123); }); });
|
||||
});
|
||||
} else {
|
||||
obj.debug(1, 'Server stopped');
|
||||
@ -553,25 +562,25 @@ function CreateMeshCentralServer(config, args) {
|
||||
|
||||
// Update the server state
|
||||
obj.updateServerState('state', 'stopped');
|
||||
}
|
||||
};
|
||||
|
||||
// Event Dispatch
|
||||
obj.AddEventDispatch = function (ids, target) {
|
||||
obj.debug(3, 'AddEventDispatch', ids);
|
||||
for (var i in ids) { var id = ids[i]; if (!obj.eventsDispatch[id]) { obj.eventsDispatch[id] = [target]; } else { obj.eventsDispatch[id].push(target); } }
|
||||
}
|
||||
};
|
||||
obj.RemoveEventDispatch = function (ids, target) {
|
||||
obj.debug(3, 'RemoveEventDispatch', id);
|
||||
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); } } }
|
||||
}
|
||||
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); } } }
|
||||
};
|
||||
obj.RemoveEventDispatchId = function (id) {
|
||||
obj.debug(3, 'RemoveEventDispatchId', id);
|
||||
if (obj.eventsDispatch[id] != null) { delete obj.eventsDispatch[id]; }
|
||||
}
|
||||
};
|
||||
obj.RemoveAllEventDispatch = function (target) {
|
||||
obj.debug(3, 'RemoveAllEventDispatch');
|
||||
for (var i in obj.eventsDispatch) { var j = obj.eventsDispatch[i].indexOf(target); if (j >= 0) { obj.eventsDispatch[i].splice(j, 1); } }
|
||||
}
|
||||
};
|
||||
obj.DispatchEvent = function (ids, source, event, fromPeerServer) {
|
||||
// If the database is not setup, exit now.
|
||||
if (!obj.db) return;
|
||||
@ -596,21 +605,21 @@ function CreateMeshCentralServer(config, args) {
|
||||
}
|
||||
}
|
||||
if ((fromPeerServer == null) && (obj.multiServer != null) && ((typeof event != 'object') || (event.nopeers != 1))) { obj.multiServer.DispatchEvent(ids, source, event); }
|
||||
}
|
||||
};
|
||||
|
||||
// Get the connection state of a node
|
||||
obj.GetConnectivityState = function (nodeid) { return obj.connectivityByNode[nodeid]; }
|
||||
obj.GetConnectivityState = function (nodeid) { return obj.connectivityByNode[nodeid]; };
|
||||
|
||||
// Get the routing server id for a given node and connection type, can never be self.
|
||||
obj.GetRoutingServerId = function (nodeid, connectType) {
|
||||
if (obj.multiServer == null) return null;
|
||||
for (serverid in obj.peerConnectivityByNode) {
|
||||
for (var serverid in obj.peerConnectivityByNode) {
|
||||
if (serverid == obj.serverId) continue;
|
||||
var state = obj.peerConnectivityByNode[serverid][nodeid];
|
||||
if ((state != null) && ((state.connectivity & connectType) != 0)) { return { serverid: serverid, meshid: state.meshid }; }
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
// Update the connection state of a node when in multi-server mode
|
||||
// Update obj.connectivityByNode using obj.peerConnectivityByNode for the list of nodes in argument
|
||||
@ -618,8 +627,8 @@ function CreateMeshCentralServer(config, args) {
|
||||
for (var nodeid in nodeids) {
|
||||
var meshid = null, state = null, oldConnectivity = 0, oldPowerState = 0, newConnectivity = 0, newPowerState = 0;
|
||||
var oldState = obj.connectivityByNode[nodeid];
|
||||
if (oldState != null) { meshid = oldState.meshid; oldConnectivity = oldState.connectivity; oldPowerState = oldState.powerState; }
|
||||
for (serverid in obj.peerConnectivityByNode) {
|
||||
if (oldState != null) { meshid = oldState.meshid; oldConnectivity = oldState.connectivity; oldPowerState = oldState.powerState; }
|
||||
for (var serverid in obj.peerConnectivityByNode) {
|
||||
var peerState = obj.peerConnectivityByNode[serverid][nodeid];
|
||||
if (peerState != null) {
|
||||
if (state == null) {
|
||||
@ -652,7 +661,7 @@ function CreateMeshCentralServer(config, args) {
|
||||
obj.DispatchEvent(['*', meshid], obj, { action: 'nodeconnect', meshid: meshid, nodeid: nodeid, conn: newConnectivity, pwr: newPowerState, nolog: 1, nopeers: 1 });
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Set the connectivity state of a node and setup the server so that messages can be routed correctly.
|
||||
// meshId: mesh identifier of format mesh/domain/meshidhex
|
||||
@ -660,8 +669,8 @@ function CreateMeshCentralServer(config, args) {
|
||||
// connectTime: time of connection, milliseconds elapsed since the UNIX epoch.
|
||||
// connectType: Bitmask, 1 = MeshAgent, 2 = Intel AMT CIRA, 4 = Intel AMT local.
|
||||
// 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
|
||||
var connectTypeStrings = ['', 'MeshAgent', 'Intel AMT CIRA', '', 'Intel AMT local'];
|
||||
var powerStateStrings = ['Unknown', 'Powered', 'Sleep', 'Sleep', 'Deep Sleep', 'Hibernating', 'Soft-Off', 'Present'];
|
||||
//var connectTypeStrings = ['', 'MeshAgent', 'Intel AMT CIRA', '', 'Intel AMT local'];
|
||||
//var powerStateStrings = ['Unknown', 'Powered', 'Sleep', 'Sleep', 'Deep Sleep', 'Hibernating', 'Soft-Off', 'Present'];
|
||||
obj.SetConnectivityState = function (meshid, nodeid, connectTime, connectType, powerState, serverid) {
|
||||
//console.log('SetConnectivity for ' + nodeid.substring(0, 16) + ', Type: ' + connectTypeStrings[connectType] + ', Power: ' + powerStateStrings[powerState] + (serverid == null ? ('') : (', ServerId: ' + serverid)));
|
||||
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) {
|
||||
|
||||
// Set node power state
|
||||
if (connectType == 1) { state.agentPower = powerState; } else if (connectType == 2) { state.ciraPower = powerState; } else if (connectType == 4) { state.amtPower = powerState; }
|
||||
var powerState = 0;
|
||||
var powerState = 0, oldPowerState = state.powerState;
|
||||
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; }
|
||||
if ((state.powerState == null) || (state.powerState != powerState)) {
|
||||
state.powerState = powerState;
|
||||
@ -731,7 +740,7 @@ function CreateMeshCentralServer(config, args) {
|
||||
var x = {}; x[nodeid] = 1;
|
||||
obj.UpdateConnectivityState(x);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Clear the connectivity state of a node and setup the server so that messages can be routed correctly.
|
||||
// meshId: mesh identifier of format mesh/domain/meshidhex
|
||||
@ -798,7 +807,7 @@ function CreateMeshCentralServer(config, args) {
|
||||
var x = {}; x[nodeid] = 1;
|
||||
obj.UpdateConnectivityState(x);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Update the default mesh core
|
||||
obj.updateMeshCoreTimer = 'notset';
|
||||
@ -845,9 +854,9 @@ function CreateMeshCentralServer(config, args) {
|
||||
obj.fs.watch(obj.path.join(meshcorePath, 'meshcore.js'), function (eventType, filename) {
|
||||
if (obj.updateMeshCoreTimer != null) { clearTimeout(obj.updateMeshCoreTimer); obj.updateMeshCoreTimer = null; }
|
||||
obj.updateMeshCoreTimer = setTimeout(function () { obj.updateMeshCore(); console.log('Updated meshcore.js.'); }, 5000);
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Update the default meshcmd
|
||||
obj.updateMeshCmdTimer = 'notset';
|
||||
@ -860,7 +869,7 @@ function CreateMeshCentralServer(config, args) {
|
||||
obj.defaultMeshCmd = null; if (func != null) { func(false); } // meshcmd.js not found
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Read meshcore.js and all .js files in the modules folder.
|
||||
var moduleAdditions = 'var addedModules = [];', modulesDir = null;
|
||||
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) {
|
||||
obj.fs.watch(obj.path.join(meshcmdPath, 'meshcmd.js'), function (eventType, filename) {
|
||||
if (obj.updateMeshCmdTimer != null) { clearTimeout(obj.updateMeshCmdTimer); obj.updateMeshCmdTimer = null; }
|
||||
obj.updateMeshCmdTimer = setTimeout(function () { obj.updateMeshCmd(); console.log('Updated meshcmd.js.'); }, 5000);
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// List of possible mesh agent install scripts
|
||||
var meshAgentsInstallScriptList = {
|
||||
@ -903,7 +912,7 @@ function CreateMeshCentralServer(config, args) {
|
||||
var stream = null;
|
||||
try {
|
||||
stream = obj.fs.createReadStream(scriptpath);
|
||||
stream.on('data', function (data) { this.hash.update(data, 'binary') });
|
||||
stream.on('data', function (data) { this.hash.update(data, 'binary'); });
|
||||
stream.on('error', function (data) {
|
||||
// If there is an error reading this file, make sure this agent is not in the agent table
|
||||
if (obj.meshAgentInstallScripts[this.info.id] != null) { delete obj.meshAgentInstallScripts[this.info.id]; }
|
||||
@ -915,7 +924,7 @@ function CreateMeshCentralServer(config, args) {
|
||||
obj.meshAgentInstallScripts[this.info.id].path = this.agentpath;
|
||||
obj.meshAgentInstallScripts[this.info.id].url = ((obj.args.notls == true) ? 'http://' : 'https://') + obj.certificates.CommonName + ':' + obj.args.port + '/meshagents?script=' + this.info.id;
|
||||
var stats = null;
|
||||
try { stats = obj.fs.statSync(this.agentpath) } catch (e) { }
|
||||
try { stats = obj.fs.statSync(this.agentpath); } catch (e) { }
|
||||
if (stats != null) { obj.meshAgentInstallScripts[this.info.id].size = stats.size; }
|
||||
});
|
||||
stream.info = meshAgentsInstallScriptList[scriptid];
|
||||
@ -923,7 +932,7 @@ function CreateMeshCentralServer(config, args) {
|
||||
stream.hash = obj.crypto.createHash('sha384', stream);
|
||||
} catch (e) { }
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// List of possible mesh agents
|
||||
obj.meshAgentsArchitectureNumbers = {
|
||||
@ -962,10 +971,10 @@ function CreateMeshCentralServer(config, args) {
|
||||
var archcount = 0;
|
||||
for (var archid in obj.meshAgentsArchitectureNumbers) {
|
||||
var agentpath = obj.path.join(__dirname, 'agents', obj.meshAgentsArchitectureNumbers[archid].localname);
|
||||
|
||||
|
||||
// Fetch all the agent binary information
|
||||
var stats = null;
|
||||
try { stats = obj.fs.statSync(agentpath) } catch (e) { }
|
||||
try { stats = obj.fs.statSync(agentpath); } catch (e) { }
|
||||
if ((stats != null)) {
|
||||
// If file exists
|
||||
archcount++;
|
||||
@ -991,7 +1000,7 @@ function CreateMeshCentralServer(config, args) {
|
||||
}
|
||||
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.
|
||||
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.
|
||||
}
|
||||
};
|
||||
|
||||
// Generate a time limited user login token
|
||||
obj.getLoginToken = function (userid, func) {
|
||||
@ -1016,7 +1025,7 @@ function CreateMeshCentralServer(config, args) {
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// Show the yser login token generation key
|
||||
obj.showLoginTokenKey = function (func) {
|
||||
@ -1031,13 +1040,13 @@ function CreateMeshCentralServer(config, args) {
|
||||
obj.db.Set({ _id: 'LoginCookieEncryptionKey', key: obj.loginCookieEncryptionKey.toString('hex'), time: Date.now() }, function () { func(obj.loginCookieEncryptionKey.toString('hex')); });
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// Generate a cryptographic key used to encode and decode cookies
|
||||
obj.generateCookieKey = function () {
|
||||
return new Buffer(obj.crypto.randomBytes(32), 'binary');
|
||||
//return Buffer.alloc(32, 0); // Sets the key to zeros, debug only.
|
||||
}
|
||||
};
|
||||
|
||||
// Encode an object as a cookie using a key. (key must be 32 bytes long)
|
||||
obj.encodeCookie = function (o, key) {
|
||||
@ -1048,7 +1057,7 @@ function CreateMeshCentralServer(config, args) {
|
||||
var crypted = Buffer.concat([cipher.update(JSON.stringify(o), 'utf8'), cipher.final()]);
|
||||
return Buffer.concat([iv, cipher.getAuthTag(), crypted]).toString('base64').replace(/\+/g, '@').replace(/\//g, '$');
|
||||
} catch (e) { return null; }
|
||||
}
|
||||
};
|
||||
|
||||
// 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)
|
||||
obj.decodeCookie = function (cookie, key, timeout) {
|
||||
@ -1065,7 +1074,7 @@ function CreateMeshCentralServer(config, args) {
|
||||
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)
|
||||
return o;
|
||||
} catch (e) { return null; }
|
||||
}
|
||||
};
|
||||
|
||||
// Debug
|
||||
obj.debug = function (lvl) {
|
||||
@ -1074,11 +1083,11 @@ function CreateMeshCentralServer(config, args) {
|
||||
else if (arguments.length == 3) { console.log(arguments[1], arguments[2]); }
|
||||
else if (arguments.length == 4) { console.log(arguments[1], arguments[2], arguments[3]); }
|
||||
else if (arguments.length == 5) { console.log(arguments[1], arguments[2], arguments[3], arguments[4]); }
|
||||
}
|
||||
};
|
||||
|
||||
// Update server state. Writes a server state file.
|
||||
var meshServerState = {};
|
||||
obj.updateServerState = function(name, val) {
|
||||
obj.updateServerState = function (name, val) {
|
||||
if ((name != null) && (val != null)) {
|
||||
var changed = false;
|
||||
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) {
|
||||
var r = 'time=' + Date.now() + '\r\n';
|
||||
for (var i in meshServerState) { r += (i + '=' + meshServerState[i] + '\r\n'); }
|
||||
obj.fs.writeFileSync(obj.getConfigFilePath('serverstate.txt'), r);
|
||||
}
|
||||
};
|
||||
|
||||
// Logging funtions
|
||||
function logException(e) { e += ''; logErrorEvent(e); }
|
||||
@ -1124,7 +1133,7 @@ function CreateMeshCentralServer(config, args) {
|
||||
}
|
||||
//console.log('getConfigFilePath(\"' + filename + '\") = ' + obj.path.join(obj.datapath, filename));
|
||||
return obj.path.join(obj.datapath, filename);
|
||||
}
|
||||
};
|
||||
|
||||
return obj;
|
||||
}
|
||||
@ -1132,6 +1141,7 @@ function CreateMeshCentralServer(config, args) {
|
||||
// Return the server configuration
|
||||
function getConfig() {
|
||||
// Figure out the datapath location
|
||||
var i;
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
var datapath = null;
|
||||
@ -1150,7 +1160,7 @@ function getConfig() {
|
||||
// Load and validate the configuration file
|
||||
try { config = require(configFilePath); } catch (e) { console.log('ERROR: Unable to parse ' + configFilePath + '.'); return null; }
|
||||
if (config.domains == null) { config.domains = {}; }
|
||||
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; } }
|
||||
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; } }
|
||||
} else {
|
||||
// Copy the "sample-config.json" to give users a starting point
|
||||
var sampleConfigPath = path.join(__dirname, 'sample-config.json');
|
||||
@ -1159,7 +1169,7 @@ function getConfig() {
|
||||
|
||||
// Set the command line arguments to the config file if they are not present
|
||||
if (!config.settings) { config.settings = {}; }
|
||||
for (var i in args) { config.settings[i] = args[i]; }
|
||||
for (i in args) { config.settings[i] = args[i]; }
|
||||
|
||||
// Lower case all keys in the config file
|
||||
require('./common.js').objKeysToLower(config);
|
||||
|
22
meshrelay.js
22
meshrelay.js
@ -6,7 +6,12 @@
|
||||
* @version v0.0.1
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
/*jslint node: true */
|
||||
/*jshint node: true */
|
||||
/*jshint strict:false */
|
||||
/*jshint -W097 */
|
||||
/*jshint esversion: 6 */
|
||||
"use strict";
|
||||
|
||||
module.exports.CreateMeshRelay = function (parent, ws, req, domain) {
|
||||
var obj = {};
|
||||
@ -23,9 +28,10 @@ module.exports.CreateMeshRelay = function (parent, ws, req, domain) {
|
||||
obj.close = function (arg) {
|
||||
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
|
||||
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
|
||||
}
|
||||
};
|
||||
|
||||
obj.sendAgentMessage = function (command, userid, domainid) {
|
||||
var rights;
|
||||
if (command.nodeid == null) return false;
|
||||
var user = obj.parent.users[userid];
|
||||
if (user == null) return false;
|
||||
@ -37,7 +43,7 @@ module.exports.CreateMeshRelay = function (parent, ws, req, domain) {
|
||||
var agent = obj.parent.wsagents[command.nodeid];
|
||||
if (agent != null) {
|
||||
// Check if we have permission to send a message to that node
|
||||
var rights = user.links[agent.dbMeshKey];
|
||||
rights = user.links[agent.dbMeshKey];
|
||||
if (rights != null || ((rights & 16) != 0)) { // TODO: 16 is console permission, may need more gradular permission checking
|
||||
command.sessionid = ws.sessionId; // Set the session id, required for responses.
|
||||
command.rights = rights.rights; // Add user rights flags to the message
|
||||
@ -50,7 +56,7 @@ module.exports.CreateMeshRelay = function (parent, ws, req, domain) {
|
||||
var routing = obj.parent.parent.GetRoutingServerId(command.nodeid, 1); // 1 = MeshAgent routing type
|
||||
if (routing != null) {
|
||||
// Check if we have permission to send a message to that node
|
||||
var rights = user.links[routing.meshid];
|
||||
rights = user.links[routing.meshid];
|
||||
if (rights != null || ((rights & 16) != 0)) { // TODO: 16 is console permission, may need more gradular permission checking
|
||||
command.fromSessionid = ws.sessionId; // Set the session id, required for responses.
|
||||
command.rights = rights.rights; // Add user rights flags to the message
|
||||
@ -61,7 +67,7 @@ module.exports.CreateMeshRelay = function (parent, ws, req, domain) {
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
if (req.query.auth == null) {
|
||||
// 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) {
|
||||
// Wait for other relay connection
|
||||
ws.pause(); // Hold traffic until the other connection
|
||||
parent.wsrelays[obj.id] = { peer1: obj, state: 1 };
|
||||
obj.parent.parent.debug(1, 'Relay holding: ' + obj.id + ' (' + obj.remoteaddr + ') ' + (obj.authenticated?'Authenticated':'') );
|
||||
obj.parent.parent.debug(1, 'Relay holding: ' + obj.id + ' (' + obj.remoteaddr + ') ' + (obj.authenticated ? 'Authenticated' : ''));
|
||||
|
||||
// Check if a peer server has this connection
|
||||
if (parent.parent.multiServer != null) {
|
||||
@ -213,6 +219,6 @@ module.exports.CreateMeshRelay = function (parent, ws, req, domain) {
|
||||
obj.id = null;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
return obj;
|
||||
}
|
||||
};
|
||||
|
@ -6,7 +6,12 @@
|
||||
* @version v0.0.1
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
/*jslint node: true */
|
||||
/*jshint node: true */
|
||||
/*jshint strict:false */
|
||||
/*jshint -W097 */
|
||||
/*jshint esversion: 6 */
|
||||
"use strict";
|
||||
|
||||
// Construct a Mesh Scanner object
|
||||
// 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) {
|
||||
|
||||
// Get a list of IPv4 and IPv6 interface addresses
|
||||
function getInterfaceList() {
|
||||
var i;
|
||||
var ipv4 = ['*'], ipv6 = ['*']; // Bind to IN_ADDR_ANY always
|
||||
var interfaces = require('os').networkInterfaces();
|
||||
for (var i in interfaces) {
|
||||
for (i in interfaces) {
|
||||
var xinterface = interfaces[i];
|
||||
for (var j in xinterface) {
|
||||
var interface2 = xinterface[j];
|
||||
@ -43,11 +49,11 @@ module.exports.CreateMeshScanner = function (parent) {
|
||||
|
||||
// Setup all IPv4 and IPv6 servers
|
||||
function setupServers() {
|
||||
var addresses = getInterfaceList();
|
||||
for (var i in obj.servers4) { obj.servers4[i].xxclear = true; }
|
||||
for (var i in obj.servers6) { obj.servers6[i].xxclear = true; }
|
||||
for (var i in addresses.ipv4) {
|
||||
var localAddress = addresses.ipv4[i];
|
||||
var addresses = getInterfaceList(), i, localAddress, bindOptions;
|
||||
for (i in obj.servers4) { obj.servers4[i].xxclear = true; }
|
||||
for (i in obj.servers6) { obj.servers6[i].xxclear = true; }
|
||||
for (i in addresses.ipv4) {
|
||||
localAddress = addresses.ipv4[i];
|
||||
if (obj.servers4[localAddress] != null) {
|
||||
// Server already exists
|
||||
obj.servers4[localAddress].xxclear = false;
|
||||
@ -59,7 +65,7 @@ module.exports.CreateMeshScanner = function (parent) {
|
||||
server4.xxtype = 4;
|
||||
server4.xxlocal = localAddress;
|
||||
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]; });
|
||||
var bindOptions = { port: 16989, exclusive: true };
|
||||
bindOptions = { port: 16989, exclusive: true };
|
||||
if (server4.xxlocal != '*') { bindOptions.address = server4.xxlocal; }
|
||||
server4.bind(bindOptions, function () {
|
||||
try {
|
||||
@ -77,8 +83,8 @@ module.exports.CreateMeshScanner = function (parent) {
|
||||
}
|
||||
}
|
||||
|
||||
for (var i in addresses.ipv6) {
|
||||
var localAddress = addresses.ipv6[i];
|
||||
for (i in addresses.ipv6) {
|
||||
localAddress = addresses.ipv6[i];
|
||||
if (obj.servers6[localAddress] != null) {
|
||||
// Server already exists
|
||||
obj.servers6[localAddress].xxclear = false;
|
||||
@ -90,7 +96,7 @@ module.exports.CreateMeshScanner = function (parent) {
|
||||
server6.xxtype = 6;
|
||||
server6.xxlocal = localAddress;
|
||||
server6.on('error', function (err) { this.close(); delete obj.servers6[this.xxlocal]; });
|
||||
var bindOptions = { port: 16989, exclusive: true };
|
||||
bindOptions = { port: 16989, exclusive: true };
|
||||
if (server6.xxlocal != '*') { bindOptions.address = server6.xxlocal; }
|
||||
server6.bind(bindOptions, function () {
|
||||
try {
|
||||
@ -108,14 +114,15 @@ module.exports.CreateMeshScanner = function (parent) {
|
||||
}
|
||||
}
|
||||
|
||||
for (var i in obj.servers4) { if (obj.servers4[i].xxclear == true) { obj.servers4[i].close(); delete obj.servers4[i]; }; }
|
||||
for (var i in obj.servers6) { if (obj.servers6[i].xxclear == true) { obj.servers6[i].close(); delete obj.servers6[i]; }; }
|
||||
for (i in obj.servers4) { if (obj.servers4[i].xxclear == true) { obj.servers4[i].close(); delete obj.servers4[i]; } }
|
||||
for (i in obj.servers6) { if (obj.servers6[i].xxclear == true) { obj.servers6[i].close(); delete obj.servers6[i]; } }
|
||||
}
|
||||
|
||||
// Clear all IPv4 and IPv6 servers
|
||||
function clearServers() {
|
||||
for (var i in obj.servers4) { obj.servers4[i].close(); delete obj.servers4[i]; }
|
||||
for (var i in obj.servers6) { obj.servers6[i].close(); delete obj.servers6[i]; }
|
||||
var i;
|
||||
for (i in obj.servers4) { obj.servers4[i].close(); delete obj.servers4[i]; }
|
||||
for (i in obj.servers6) { obj.servers6[i].close(); delete obj.servers6[i]; }
|
||||
}
|
||||
|
||||
// Start scanning for local network Mesh Agents
|
||||
@ -128,27 +135,28 @@ module.exports.CreateMeshScanner = function (parent) {
|
||||
setupServers();
|
||||
obj.mainTimer = setInterval(obj.performScan, periodicScanTime);
|
||||
return obj;
|
||||
}
|
||||
};
|
||||
|
||||
// Stop scanning for local network Mesh Agents
|
||||
obj.stop = function () {
|
||||
if (obj.mainTimer != null) { clearInterval(obj.mainTimer); obj.mainTimer = null; }
|
||||
clearServers();
|
||||
}
|
||||
};
|
||||
|
||||
// Look for all Mesh Agents that may be locally reachable, indicating the presense of this server.
|
||||
obj.performScan = function (server) {
|
||||
var i;
|
||||
if (server != null) {
|
||||
if (server.xxtype == 4) { try { server.send(obj.multicastPacket4, 0, obj.multicastPacket4.length, 16990, membershipIPv4); } catch (e) { } }
|
||||
if (server.xxtype == 6) { try { server.send(obj.multicastPacket6, 0, obj.multicastPacket6.length, 16990, membershipIPv6); } catch (e) { } }
|
||||
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) { } }
|
||||
if ((server.xxtype == 6) && (server.xxlocal == '*')) { try { server.send(obj.multicastPacket6, 0, obj.multicastPacket6.length, 16990, '::1'); } catch (e) { } }
|
||||
} else {
|
||||
for (var i in obj.servers4) { try { obj.servers4[i].send(obj.multicastPacket4, 0, obj.multicastPacket4.length, 16990, membershipIPv4); } catch (e) { } }
|
||||
for (var i in obj.servers6) { try { obj.servers6[i].send(obj.multicastPacket6, 0, obj.multicastPacket6.length, 16990, membershipIPv6); } catch (e) { } }
|
||||
for (i in obj.servers4) { try { obj.servers4[i].send(obj.multicastPacket4, 0, obj.multicastPacket4.length, 16990, membershipIPv4); } catch (e) { } }
|
||||
for (i in obj.servers6) { try { obj.servers6[i].send(obj.multicastPacket6, 0, obj.multicastPacket6.length, 16990, membershipIPv6); } catch (e) { } }
|
||||
setupServers(); // Check if any network interfaces where added or removed
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Called when a UDP packet is received from an agent.
|
||||
function onUdpPacket(msg, info, server) {
|
||||
@ -161,26 +169,27 @@ module.exports.CreateMeshScanner = function (parent) {
|
||||
|
||||
// As a side job, we also send server wake-on-lan packets
|
||||
obj.wakeOnLan = function (macs) {
|
||||
for (var i in macs) {
|
||||
var i, j;
|
||||
for (i in macs) {
|
||||
var mac = macs[i];
|
||||
var hexpacket = 'FFFFFFFFFFFF';
|
||||
for (var i = 0; i < 16; i++) { hexpacket += mac; }
|
||||
for (j = 0; j < 16; j++) { hexpacket += mac; }
|
||||
var wakepacket = Buffer.from(hexpacket, 'hex');
|
||||
//console.log(wakepacket.toString('hex'));
|
||||
|
||||
// Send the wake packet 3 times with small time intervals
|
||||
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); }
|
||||
for (var i in obj.servers6) { obj.servers6[i].send(wakepacket, 0, wakepacket.length, 16990, membershipIPv6); }
|
||||
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); }
|
||||
for (j in obj.servers6) { obj.servers6[j].send(wakepacket, 0, wakepacket.length, 16990, membershipIPv6); }
|
||||
setTimeout(function () {
|
||||
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); }
|
||||
for (var i in obj.servers6) { obj.servers6[i].send(wakepacket, 0, wakepacket.length, 16990, membershipIPv6); }
|
||||
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); }
|
||||
for (j in obj.servers6) { obj.servers6[j].send(wakepacket, 0, wakepacket.length, 16990, membershipIPv6); }
|
||||
}, 200);
|
||||
setTimeout(function () {
|
||||
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); }
|
||||
for (var i in obj.servers6) { obj.servers6[i].send(wakepacket, 0, wakepacket.length, 16990, membershipIPv6); }
|
||||
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); }
|
||||
for (j in obj.servers6) { obj.servers6[j].send(wakepacket, 0, wakepacket.length, 16990, membershipIPv6); }
|
||||
}, 500);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
return obj;
|
||||
}
|
||||
};
|
178
meshuser.js
178
meshuser.js
@ -6,7 +6,12 @@
|
||||
* @version v0.0.1
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
/*jslint node: true */
|
||||
/*jshint node: true */
|
||||
/*jshint strict:false */
|
||||
/*jshint -W097 */
|
||||
/*jshint esversion: 6 */
|
||||
"use strict";
|
||||
|
||||
// Construct a MeshAgent object, called upon connection
|
||||
module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
|
||||
@ -27,7 +32,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
|
||||
obj.close = function (arg) {
|
||||
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
|
||||
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
|
||||
}
|
||||
};
|
||||
|
||||
// Convert a mesh path array into a real path on the server side
|
||||
function meshPathToRealPath(meshpath, user) {
|
||||
@ -52,22 +57,22 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
|
||||
|
||||
//
|
||||
function copyFile(src, dest, func, tag) {
|
||||
//var ss = obj.fs.createReadStream(src, { flags: 'rb' });
|
||||
//var ss = obj.fs.createReadStream(src, { flags: 'rb' });
|
||||
//var ds = obj.fs.createWriteStream(dest, { flags: 'wb' });
|
||||
var ss = obj.fs.createReadStream(src);
|
||||
var ds = obj.fs.createWriteStream(dest);
|
||||
ss.fs = obj.fs;
|
||||
ss.pipe(ds);
|
||||
ss.pipe(ds);
|
||||
ds.ss = ss;
|
||||
/*
|
||||
if (!this._copyStreams) { this._copyStreams = {}; this._copyStreamID = 0; }
|
||||
ss.id = this._copyStreamID++;
|
||||
this._copyStreams[ss.id] = ss;
|
||||
*/
|
||||
if (arguments.length == 3 && typeof arguments[2] === 'function') { ds.on('close', arguments[2]); }
|
||||
else if (arguments.length == 4 && typeof arguments[3] === 'function') { ds.on('close', arguments[3]); }
|
||||
ds.on('close', function() { /*delete this.ss.fs._copyStreams[this.ss.id];*/ func(tag); });
|
||||
};
|
||||
if (arguments.length == 3 && typeof arguments[2] === 'function') { ds.on('close', arguments[2]); }
|
||||
else if (arguments.length == 4 && typeof arguments[3] === 'function') { ds.on('close', arguments[3]); }
|
||||
ds.on('close', function () { /*delete this.ss.fs._copyStreams[this.ss.id];*/ func(tag); });
|
||||
}
|
||||
|
||||
try {
|
||||
// Check if the user is logged in
|
||||
@ -83,7 +88,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
|
||||
obj.parent.wssessions2[ws.sessionId] = obj.ws;
|
||||
if (!obj.parent.wssessions[user._id]) { obj.parent.wssessions[user._id] = [ws]; } else { obj.parent.wssessions[user._id].push(obj.ws); }
|
||||
if (obj.parent.parent.multiServer == null) {
|
||||
obj.parent.parent.DispatchEvent(['*'], obj, { action: 'wssessioncount', username: user.name, count: obj.parent.wssessions[user._id].length, nolog: 1, domain: obj.domain.id })
|
||||
obj.parent.parent.DispatchEvent(['*'], obj, { action: 'wssessioncount', username: user.name, count: obj.parent.wssessions[user._id].length, nolog: 1, domain: obj.domain.id });
|
||||
} else {
|
||||
obj.parent.recountSessions(obj.ws.sessionId); // Recount sessions
|
||||
}
|
||||
@ -101,14 +106,14 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
|
||||
else { ws.send(JSON.stringify({ action: 'event', event: event })); }
|
||||
} catch (e) { }
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
user.subscriptions = obj.parent.subscribe(user._id, ws); // Subscribe to events
|
||||
obj.ws._socket.setKeepAlive(true, 240000); // Set TCP keep alive
|
||||
|
||||
// When data is received from the web socket
|
||||
ws.on('message', function (msg) {
|
||||
var command, user = obj.parent.users[req.session.userid];
|
||||
var command, user = obj.parent.users[req.session.userid], i = 0, mesh = null, meshid = null, nodeid = null, meshlinks = null, change = 0;
|
||||
try { command = JSON.parse(msg.toString('utf8')); } catch (e) { return; }
|
||||
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
|
||||
|
||||
@ -118,7 +123,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
|
||||
{
|
||||
// Request a list of all meshes this user as rights to
|
||||
var docs = [];
|
||||
for (var i in user.links) { if (obj.parent.meshes[i]) { docs.push(obj.parent.meshes[i]); } }
|
||||
for (i in user.links) { if (obj.parent.meshes[i]) { docs.push(obj.parent.meshes[i]); } }
|
||||
ws.send(JSON.stringify({ action: 'meshes', meshes: docs, tag: command.tag }));
|
||||
break;
|
||||
}
|
||||
@ -127,10 +132,10 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
|
||||
var links = [];
|
||||
if (command.meshid == null) {
|
||||
// Request a list of all meshes this user as rights to
|
||||
for (var i in user.links) { links.push(i); }
|
||||
for (i in user.links) { links.push(i); }
|
||||
} else {
|
||||
// Request list of all nodes for one specific meshid
|
||||
var meshid = command.meshid;
|
||||
meshid = command.meshid;
|
||||
if (obj.common.validateString(meshid, 0, 128) == false) return;
|
||||
if (meshid.split('/').length == 0) { meshid = 'mesh/' + domain.id + '/' + command.meshid; }
|
||||
if (user.links[meshid] != null) { links.push(meshid); }
|
||||
@ -139,7 +144,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
|
||||
// Request a list of all nodes
|
||||
obj.db.GetAllTypeNoTypeFieldMeshFiltered(links, domain.id, 'node', function (err, docs) {
|
||||
var r = {};
|
||||
for (var i in docs) {
|
||||
for (i in docs) {
|
||||
// Add the connection state
|
||||
var state = obj.parent.parent.GetConnectivityState(docs[i]._id);
|
||||
if (state) {
|
||||
@ -150,7 +155,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
|
||||
}
|
||||
|
||||
// Compress the meshid's
|
||||
var meshid = docs[i].meshid;
|
||||
meshid = docs[i].meshid;
|
||||
if (!r[meshid]) { r[meshid] = []; }
|
||||
delete docs[i].meshid;
|
||||
|
||||
@ -171,7 +176,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
|
||||
obj.db.getPowerTimeline(command.nodeid, function (err, docs) {
|
||||
if (err == null && docs.length > 0) {
|
||||
var timeline = [], time = null, previousPower;
|
||||
for (var i in docs) {
|
||||
for (i in docs) {
|
||||
var doc = docs[i];
|
||||
if (time == null) {
|
||||
// First element
|
||||
@ -228,14 +233,14 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
|
||||
if (path == null) break;
|
||||
|
||||
if ((command.fileop == 'createfolder') && (obj.common.IsFilenameValid(command.newfolder) == true)) { try { obj.fs.mkdirSync(path + "/" + command.newfolder); } catch (e) { } } // Create a new folder
|
||||
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
|
||||
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
|
||||
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
|
||||
else if ((command.fileop == 'copy') || (command.fileop == 'move')) {
|
||||
if (obj.common.validateArray(command.names, 1) == false) return;
|
||||
var scpath = meshPathToRealPath(command.scpath, user); // This will also check access rights
|
||||
if (scpath == null) break;
|
||||
// TODO: Check quota if this is a copy!!!!!!!!!!!!!!!!
|
||||
for (var i in command.names) {
|
||||
for (i in command.names) {
|
||||
var s = obj.path.join(scpath, command.names[i]), d = obj.path.join(path, command.names[i]);
|
||||
sendUpdate = false;
|
||||
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) {
|
||||
// Delete all events
|
||||
if (user.siteadmin != 0xFFFFFFFF) break;
|
||||
obj.db.RemoveAllEvents(domain.id);
|
||||
obj.parent.parent.DispatchEvent(['*', 'server-global'], obj, { action: 'clearevents', nolog: 1, domain: domain.id })
|
||||
obj.parent.parent.DispatchEvent(['*', 'server-global'], obj, { action: 'clearevents', nolog: 1, domain: domain.id });
|
||||
break;
|
||||
}
|
||||
case 'users':
|
||||
@ -327,7 +332,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
|
||||
// Request a list of all users
|
||||
if ((user.siteadmin & 2) == 0) break;
|
||||
var docs = [];
|
||||
for (var i in obj.parent.users) {
|
||||
for (i in obj.parent.users) {
|
||||
if ((obj.parent.users[i].domain == domain.id) && (obj.parent.users[i].name != '~')) {
|
||||
var userinfo = obj.common.Clone(obj.parent.users[i]);
|
||||
delete userinfo.hash;
|
||||
@ -403,10 +408,10 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
|
||||
if ((user.siteadmin & 2) == 0) break;
|
||||
if (obj.parent.parent.multiServer == null) {
|
||||
// No peering, use simple session counting
|
||||
for (var i in obj.parent.wssessions) { if (obj.parent.wssessions[i][0].domainid == domain.id) { wssessions[i] = obj.parent.wssessions[i].length; } }
|
||||
for (i in obj.parent.wssessions) { if (obj.parent.wssessions[i][0].domainid == domain.id) { wssessions[i] = obj.parent.wssessions[i].length; } }
|
||||
} else {
|
||||
// We have peer servers, use more complex session counting
|
||||
for (var userid in obj.parent.sessionsCount) { if (userid.split('/')[1] == domain.id) { wssessions[userid] = obj.parent.sessionsCount[userid]; } }
|
||||
for (i in obj.parent.sessionsCount) { if (i.split('/')[1] == domain.id) { wssessions[i] = obj.parent.sessionsCount[i]; } }
|
||||
}
|
||||
ws.send(JSON.stringify({ action: 'wssessioncount', wssessions: wssessions, tag: command.tag })); // wssessions is: userid --> count
|
||||
break;
|
||||
@ -422,15 +427,15 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
|
||||
|
||||
// Remove all the mesh links to this user
|
||||
if (deluser.links != null) {
|
||||
for (var meshid in deluser.links) {
|
||||
for (meshid in deluser.links) {
|
||||
// Get the mesh
|
||||
var mesh = obj.parent.meshes[meshid];
|
||||
mesh = obj.parent.meshes[meshid];
|
||||
if (mesh) {
|
||||
// Remove user from the mesh
|
||||
if (mesh.links[deluser._id] != null) { delete mesh.links[deluser._id]; obj.parent.db.Set(mesh); }
|
||||
// Notify mesh change
|
||||
var change = 'Removed user ' + deluser.name + ' from mesh ' + mesh.name;
|
||||
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 })
|
||||
change = 'Removed user ' + deluser.name + ' from mesh ' + mesh.name;
|
||||
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 });
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -446,7 +451,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
|
||||
|
||||
obj.db.Remove(deluserid);
|
||||
delete obj.parent.users[deluserid];
|
||||
obj.parent.parent.DispatchEvent(['*', 'server-users'], obj, { etype: 'user', userid: deluserid, username: deluser.name, action: 'accountremove', msg: 'Account removed', domain: domain.id })
|
||||
obj.parent.parent.DispatchEvent(['*', 'server-users'], obj, { etype: 'user', userid: deluserid, username: deluser.name, action: 'accountremove', msg: 'Account removed', domain: domain.id });
|
||||
obj.parent.parent.DispatchEvent([deluserid], obj, 'close');
|
||||
|
||||
break;
|
||||
@ -474,7 +479,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
|
||||
if (newuser2.subscriptions) { delete newuser2.subscriptions; }
|
||||
if (newuser2.salt) { delete newuser2.salt; }
|
||||
if (newuser2.hash) { delete newuser2.hash; }
|
||||
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 })
|
||||
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 });
|
||||
});
|
||||
}
|
||||
break;
|
||||
@ -483,12 +488,13 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
|
||||
{
|
||||
// Edit a user account, may involve changing email or administrator permissions
|
||||
if (((user.siteadmin & 2) != 0) || (user.name == command.name)) {
|
||||
var chguserid = 'user/' + domain.id + '/' + command.name.toLowerCase(), chguser = obj.parent.users[chguserid], change = 0;
|
||||
var chguserid = 'user/' + domain.id + '/' + command.name.toLowerCase(), chguser = obj.parent.users[chguserid];
|
||||
change = 0;
|
||||
if (chguser) {
|
||||
if (obj.common.validateString(command.email, 1, 256) && (chguser.email != command.email)) { chguser.email = command.email; change = 1; }
|
||||
if ((command.emailVerified === true || command.emailVerified === false) && (chguser.emailVerified != command.emailVerified)) { chguser.emailVerified = command.emailVerified; change = 1; }
|
||||
if (obj.common.validateInt(command.quota, 0) && (command.quota != chguser.quota)) { chguser.quota = command.quota; if (chguser.quota == null) { delete chguser.quota; } change = 1; }
|
||||
if ((user.siteadmin == 0xFFFFFFFF) && obj.common.validateInt(command.siteadmin) && (chguser.siteadmin != command.siteadmin)) { chguser.siteadmin = command.siteadmin; change = 1 }
|
||||
if ((user.siteadmin == 0xFFFFFFFF) && obj.common.validateInt(command.siteadmin) && (chguser.siteadmin != command.siteadmin)) { chguser.siteadmin = command.siteadmin; change = 1; }
|
||||
if (change == 1) {
|
||||
obj.db.SetUser(chguser);
|
||||
obj.parent.parent.DispatchEvent([chguser._id], obj, 'resubscribe');
|
||||
@ -500,7 +506,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
|
||||
delete userinfo.domain;
|
||||
delete userinfo.subscriptions;
|
||||
delete userinfo.passtype;
|
||||
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 })
|
||||
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 });
|
||||
}
|
||||
if ((chguser.siteadmin) && (chguser.siteadmin != 0xFFFFFFFF) && (chguser.siteadmin & 32)) {
|
||||
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) {
|
||||
|
||||
// Get the list of sessions for this user
|
||||
var sessions = obj.parent.wssessions[command.userid];
|
||||
if (sessions != null) { for (var i in sessions) { sessions[i].send(JSON.stringify(notification)); } }
|
||||
if (sessions != null) { for (i in sessions) { sessions[i].send(JSON.stringify(notification)); } }
|
||||
|
||||
if (obj.parent.parent.multiServer != null) {
|
||||
// TODO: Add multi-server support
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'serverversion':
|
||||
{
|
||||
@ -564,10 +571,10 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
|
||||
if ((command.meshtype == 1) || (command.meshtype == 2)) {
|
||||
// Create a type 1 agent-less Intel AMT mesh.
|
||||
obj.parent.crypto.randomBytes(48, function (err, buf) {
|
||||
var meshid = 'mesh/' + domain.id + '/' + buf.toString('base64').replace(/\+/g, '@').replace(/\//g, '$');
|
||||
var links = {}
|
||||
meshid = 'mesh/' + domain.id + '/' + buf.toString('base64').replace(/\+/g, '@').replace(/\//g, '$');
|
||||
var links = {};
|
||||
links[user._id] = { name: user.name, rights: 0xFFFFFFFF };
|
||||
var mesh = { type: 'mesh', _id: meshid, name: command.meshname, mtype: command.meshtype, desc: command.desc, domain: domain.id, links: links };
|
||||
mesh = { type: 'mesh', _id: meshid, name: command.meshname, mtype: command.meshtype, desc: command.desc, domain: domain.id, links: links };
|
||||
obj.db.Set(obj.common.escapeLinksFieldName(mesh));
|
||||
obj.parent.meshes[meshid] = mesh;
|
||||
obj.parent.parent.AddEventDispatch([meshid], ws);
|
||||
@ -575,7 +582,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
|
||||
user.links[meshid] = { rights: 0xFFFFFFFF };
|
||||
user.subscriptions = obj.parent.subscribe(user._id, ws);
|
||||
obj.db.SetUser(user);
|
||||
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 })
|
||||
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 });
|
||||
});
|
||||
}
|
||||
break;
|
||||
@ -586,17 +593,17 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
|
||||
if (obj.common.validateString(command.meshid, 1, 1024) == false) break; // Check the meshid
|
||||
obj.db.Get(command.meshid, function (err, meshes) {
|
||||
if (meshes.length != 1) return;
|
||||
var mesh = obj.common.unEscapeLinksFieldName(meshes[0]);
|
||||
mesh = obj.common.unEscapeLinksFieldName(meshes[0]);
|
||||
|
||||
// Check if this user has rights to do this
|
||||
if (mesh.links[user._id] == null || mesh.links[user._id].rights != 0xFFFFFFFF) return;
|
||||
if ((command.meshid.split('/').length != 3) || (command.meshid.split('/')[1] != domain.id)) return; // Invalid domain, operation only valid for current domain
|
||||
|
||||
// Fire the removal event first, because after this, the event will not route
|
||||
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 })
|
||||
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 });
|
||||
|
||||
// Remove all user links to this mesh
|
||||
for (var i in meshes) {
|
||||
for (i in meshes) {
|
||||
var links = meshes[i].links;
|
||||
for (var j in links) {
|
||||
var xuser = obj.parent.users[j];
|
||||
@ -608,8 +615,8 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
|
||||
|
||||
// Delete all files on the server for this mesh
|
||||
try {
|
||||
var meshpath = getServerRootFilePath(mesh);
|
||||
if (meshpath != null) { deleteFolderRec(meshpath); }
|
||||
var meshpath = obj.parent.getServerRootFilePath(mesh);
|
||||
if (meshpath != null) { obj.parent.deleteFolderRec(meshpath); }
|
||||
} catch (e) { }
|
||||
|
||||
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) {
|
||||
{
|
||||
// Change the name or description of a mesh
|
||||
if (obj.common.validateString(command.meshid, 1, 1024) == false) break; // Check the meshid
|
||||
var mesh = obj.parent.meshes[command.meshid], change = '';
|
||||
mesh = obj.parent.meshes[command.meshid];
|
||||
change = '';
|
||||
if (mesh) {
|
||||
// Check if this user has rights to do this
|
||||
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) {
|
||||
|
||||
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; }
|
||||
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; }
|
||||
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 }) }
|
||||
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 }); }
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -648,7 +656,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
|
||||
}
|
||||
|
||||
// Get the mesh
|
||||
var mesh = obj.parent.meshes[command.meshid], change = '';
|
||||
mesh = obj.parent.meshes[command.meshid];
|
||||
if (mesh) {
|
||||
// Check if this user has rights to do this
|
||||
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) {
|
||||
obj.db.Set(obj.common.escapeLinksFieldName(mesh));
|
||||
|
||||
// Notify mesh change
|
||||
var change = 'Added user ' + newuser.name + ' to mesh ' + mesh.name;
|
||||
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 })
|
||||
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 });
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -677,7 +684,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
|
||||
if ((command.userid.split('/').length != 3) || (command.userid.split('/')[1] != domain.id)) return; // Invalid domain, operation only valid for current domain
|
||||
|
||||
// Get the mesh
|
||||
var mesh = obj.parent.meshes[command.meshid];
|
||||
mesh = obj.parent.meshes[command.meshid];
|
||||
if (mesh) {
|
||||
// Check if this user has rights to do this
|
||||
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) {
|
||||
obj.db.Set(obj.common.escapeLinksFieldName(mesh));
|
||||
|
||||
// Notify mesh change
|
||||
var change = 'Removed user ' + deluser.name + ' from mesh ' + mesh.name;
|
||||
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 })
|
||||
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 });
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -723,7 +729,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
|
||||
if ((obj.parent.parent.args.wanonly == true) && (command.hostname)) { delete command.hostname; }
|
||||
|
||||
// Get the mesh
|
||||
var mesh = obj.parent.meshes[command.meshid];
|
||||
mesh = obj.parent.meshes[command.meshid];
|
||||
if (mesh) {
|
||||
if (mesh.mtype != 1) return; // This operation is only allowed for mesh type 1, Intel AMT agentless mesh.
|
||||
|
||||
@ -733,15 +739,14 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
|
||||
// Create a new nodeid
|
||||
obj.parent.crypto.randomBytes(48, function (err, buf) {
|
||||
// create the new node
|
||||
var nodeid = 'node/' + domain.id + '/' + buf.toString('base64').replace(/\+/g, '@').replace(/\//g, '$');;
|
||||
nodeid = 'node/' + domain.id + '/' + buf.toString('base64').replace(/\+/g, '@').replace(/\//g, '$');
|
||||
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 } };
|
||||
obj.db.Set(device);
|
||||
|
||||
// Event the new node
|
||||
var device2 = obj.common.Clone(device);
|
||||
delete device2.intelamt.pass; // Remove the Intel AMT password before eventing this.
|
||||
var change = 'Added device ' + command.devicename + ' to mesh ' + mesh.name;
|
||||
obj.parent.parent.DispatchEvent(['*', command.meshid], obj, { etype: 'node', username: user.name, action: 'addnode', node: device2, msg: change, domain: domain.id })
|
||||
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 });
|
||||
});
|
||||
}
|
||||
break;
|
||||
@ -763,8 +768,8 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
|
||||
{
|
||||
if (obj.common.validateArray(command.nodeids, 1) == false) break; // Check nodeid's
|
||||
|
||||
for (var i in command.nodeids) {
|
||||
var nodeid = command.nodeids[i];
|
||||
for (i in command.nodeids) {
|
||||
nodeid = command.nodeids[i];
|
||||
if (obj.common.validateString(nodeid, 1, 1024) == false) break; // Check nodeid
|
||||
if ((nodeid.split('/').length != 3) || (nodeid.split('/')[1] != domain.id)) return; // Invalid domain, operation only valid for current domain
|
||||
|
||||
@ -774,7 +779,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
|
||||
var node = nodes[0];
|
||||
|
||||
// Get the mesh for this device
|
||||
var mesh = obj.parent.meshes[node.meshid];
|
||||
mesh = obj.parent.meshes[node.meshid];
|
||||
if (mesh) {
|
||||
// Check if this user has rights to do this
|
||||
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) {
|
||||
obj.db.RemoveNode(node._id); // Remove all entries with node:id
|
||||
|
||||
// Event node deletion
|
||||
var change = 'Removed device ' + node.name + ' from mesh ' + mesh.name;
|
||||
obj.parent.parent.DispatchEvent(['*', node.meshid], obj, { etype: 'node', username: user.name, action: 'removenode', nodeid: node._id, msg: change, domain: domain.id })
|
||||
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 });
|
||||
|
||||
// Disconnect all connections if needed
|
||||
var state = obj.parent.parent.GetConnectivityState(nodeid);
|
||||
@ -807,8 +811,9 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
|
||||
// TODO: We can optimize this a lot.
|
||||
// - We should get a full list of all MAC's to wake first.
|
||||
// - We should try to only have one agent per subnet (using Gateway MAC) send a wake-on-lan.
|
||||
for (var i in command.nodeids) {
|
||||
var nodeid = command.nodeids[i], wakeActions = 0;
|
||||
for (i in command.nodeids) {
|
||||
nodeid = command.nodeids[i];
|
||||
var wakeActions = 0;
|
||||
if (obj.common.validateString(nodeid, 1, 1024) == false) break; // Check nodeid
|
||||
if ((nodeid.split('/').length == 3) && (nodeid.split('/')[1] == domain.id)) { // Validate the domain, operation only valid for current domain
|
||||
// Get the device
|
||||
@ -817,7 +822,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
|
||||
var node = nodes[0];
|
||||
|
||||
// Get the mesh for this device
|
||||
var mesh = obj.parent.meshes[node.meshid];
|
||||
mesh = obj.parent.meshes[node.meshid];
|
||||
if (mesh) {
|
||||
|
||||
// Check if this user has rights to do this
|
||||
@ -835,10 +840,10 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
|
||||
|
||||
// Get the list of mesh this user as access to
|
||||
var targetMeshes = [];
|
||||
for (var i in user.links) { targetMeshes.push(i); }
|
||||
for (i in user.links) { targetMeshes.push(i); }
|
||||
|
||||
// Go thru all the connected agents and send wake-on-lan on all the ones in the target mesh list
|
||||
for (var i in obj.parent.wsagents) {
|
||||
for (i in obj.parent.wsagents) {
|
||||
var agent = obj.parent.wsagents[i];
|
||||
if ((targetMeshes.indexOf(agent.dbMeshKey) >= 0) && (agent.authenticated == 2)) {
|
||||
//console.log('Asking agent ' + agent.dbNodeKey + ' to wake ' + macs.join(','));
|
||||
@ -862,8 +867,9 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
|
||||
case 'poweraction':
|
||||
{
|
||||
if (obj.common.validateArray(command.nodeids, 1) == false) break; // Check nodeid's
|
||||
for (var i in command.nodeids) {
|
||||
var nodeid = command.nodeids[i], powerActions = 0;
|
||||
for (i in command.nodeids) {
|
||||
nodeid = command.nodeids[i];
|
||||
var powerActions = 0;
|
||||
if (obj.common.validateString(nodeid, 1, 1024) == false) break; // Check nodeid
|
||||
if ((nodeid.split('/').length == 3) && (nodeid.split('/')[1] == domain.id)) { // Validate the domain, operation only valid for current domain
|
||||
// Get the device
|
||||
@ -872,7 +878,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
|
||||
var node = nodes[0];
|
||||
|
||||
// Get the mesh for this device
|
||||
var mesh = obj.parent.meshes[node.meshid];
|
||||
mesh = obj.parent.meshes[node.meshid];
|
||||
if (mesh) {
|
||||
|
||||
// Check if this user has rights to do this
|
||||
@ -899,8 +905,9 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
|
||||
if (obj.common.validateArray(command.nodeids, 1) == false) break; // Check nodeid's
|
||||
if (obj.common.validateString(command.title, 1, 512) == false) break; // Check title
|
||||
if (obj.common.validateString(command.msg, 1, 4096) == false) break; // Check message
|
||||
for (var i in command.nodeids) {
|
||||
var nodeid = command.nodeids[i], powerActions = 0;
|
||||
for (i in command.nodeids) {
|
||||
nodeid = command.nodeids[i];
|
||||
var powerActions = 0;
|
||||
if (obj.common.validateString(nodeid, 1, 1024) == false) break; // Check nodeid
|
||||
if ((nodeid.split('/').length == 3) && (nodeid.split('/')[1] == domain.id)) { // Validate the domain, operation only valid for current domain
|
||||
// Get the device
|
||||
@ -909,7 +916,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
|
||||
var node = nodes[0];
|
||||
|
||||
// Get the mesh for this device
|
||||
var mesh = obj.parent.meshes[node.meshid];
|
||||
mesh = obj.parent.meshes[node.meshid];
|
||||
if (mesh) {
|
||||
|
||||
// Check if this user has rights to do this
|
||||
@ -940,7 +947,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
|
||||
var node = nodes[0];
|
||||
|
||||
// Get the mesh for this device
|
||||
var mesh = obj.parent.meshes[node.meshid];
|
||||
mesh = obj.parent.meshes[node.meshid];
|
||||
if (mesh) {
|
||||
// Check if this user has rights to do this
|
||||
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) {
|
||||
var node = nodes[0];
|
||||
|
||||
// Get the mesh for this device
|
||||
var mesh = obj.parent.meshes[node.meshid];
|
||||
mesh = obj.parent.meshes[node.meshid];
|
||||
if (mesh) {
|
||||
// Check if this user has rights to do this
|
||||
if (mesh.links[user._id] == null || ((mesh.links[user._id].rights & 4) == 0)) return;
|
||||
|
||||
// Ready the node change event
|
||||
var changes = [], change = 0, event = { etype: 'node', username: user.name, action: 'changenode', nodeid: node._id, domain: domain.id };
|
||||
var changes = [], event = { etype: 'node', username: user.name, action: 'changenode', nodeid: node._id, domain: domain.id };
|
||||
change = 0;
|
||||
event.msg = ": ";
|
||||
|
||||
// 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) {
|
||||
data = obj.common.IntToStr(0) + data; // Add the 4 bytes encoding type & flags (Set to 0 for raw)
|
||||
obj.parent.sendMeshAgentCore(user, domain, command.nodeid, data);
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@ -1071,7 +1079,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
|
||||
if (obj.common.validateString(command.nodeid, 1, 1024) == false) break; // Check nodeid
|
||||
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 (???)
|
||||
if (nodes.length == 1) {
|
||||
var meshlinks = user.links[nodes[0].meshid];
|
||||
meshlinks = user.links[nodes[0].meshid];
|
||||
if ((meshlinks) && (meshlinks.rights) && (meshlinks.rights & obj.parent.MESHRIGHT_REMOTECONTROL != 0)) {
|
||||
// Add a user authentication cookie to a url
|
||||
var cookieContent = { userid: user._id, domainid: user.domain };
|
||||
@ -1093,7 +1101,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
|
||||
if ((command.meshid.split('/').length != 3) || (command.meshid.split('/')[1] != domain.id)) return; // Invalid domain, operation only valid for current domain
|
||||
|
||||
// Get the mesh
|
||||
var mesh = obj.parent.meshes[command.meshid];
|
||||
mesh = obj.parent.meshes[command.meshid];
|
||||
if (mesh) {
|
||||
if (mesh.mtype != 2) return; // This operation is only allowed for mesh type 2, agent mesh
|
||||
|
||||
@ -1118,7 +1126,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
|
||||
// Check if this user has rights on this id to set notes
|
||||
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 (???)
|
||||
if (nodes.length == 1) {
|
||||
var meshlinks = user.links[nodes[0].meshid];
|
||||
meshlinks = user.links[nodes[0].meshid];
|
||||
if ((meshlinks) && (meshlinks.rights) && (meshlinks.rights & obj.parent.MESHRIGHT_SETNOTES != 0)) {
|
||||
// Set the id's notes
|
||||
if (obj.common.validateString(command.notes, 1) == false) {
|
||||
@ -1131,7 +1139,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
|
||||
});
|
||||
} else if (idtype == 'mesh') {
|
||||
// Get the mesh for this device
|
||||
var mesh = obj.parent.meshes[command.id];
|
||||
mesh = obj.parent.meshes[command.id];
|
||||
if (mesh) {
|
||||
// Check if this user has rights to do this
|
||||
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) {
|
||||
var node = nodes[0];
|
||||
|
||||
// Get the mesh for this device
|
||||
var mesh = obj.parent.meshes[node.meshid];
|
||||
mesh = obj.parent.meshes[node.meshid];
|
||||
if (mesh) {
|
||||
// Check if this user has rights to do this
|
||||
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) {
|
||||
});
|
||||
} else if (idtype == 'mesh') {
|
||||
// Get the mesh for this device
|
||||
var mesh = obj.parent.meshes[command.id];
|
||||
mesh = obj.parent.meshes[command.id];
|
||||
if (mesh) {
|
||||
// Check if this user has rights to do this
|
||||
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) {
|
||||
var user = obj.parent.users[ws.userid];
|
||||
if (user) {
|
||||
if (obj.parent.parent.multiServer == null) {
|
||||
obj.parent.parent.DispatchEvent(['*'], obj, { action: 'wssessioncount', username: user.name, count: obj.parent.wssessions[ws.userid].length, nolog: 1, domain: obj.domain.id })
|
||||
obj.parent.parent.DispatchEvent(['*'], obj, { action: 'wssessioncount', username: user.name, count: obj.parent.wssessions[ws.userid].length, nolog: 1, domain: obj.domain.id });
|
||||
} else {
|
||||
obj.parent.recountSessions(ws.sessionId); // Recount sessions
|
||||
}
|
||||
@ -1241,7 +1249,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
|
||||
var httpport = ((obj.args.aliasport != null) ? obj.args.aliasport : obj.args.port);
|
||||
|
||||
// Build server information object
|
||||
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 }
|
||||
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 };
|
||||
if (obj.args.notls == true) { serverinfo.https = false; } else { serverinfo.https = true; serverinfo.redirport = obj.args.redirport; }
|
||||
|
||||
// Send server information
|
||||
@ -1259,7 +1267,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
|
||||
var r = {}, dir = obj.fs.readdirSync(path);
|
||||
for (var i in dir) {
|
||||
var f = { t: 3, d: 111 };
|
||||
var stat = obj.fs.statSync(path + '/' + dir[i])
|
||||
var stat = obj.fs.statSync(path + '/' + dir[i]);
|
||||
if ((stat.mode & 0x004000) == 0) { f.s = stat.size; f.d = stat.mtime.getTime(); } else { f.t = 2; f.f = readFilesRec(path + '/' + dir[i]); }
|
||||
r[dir[i]] = f;
|
||||
}
|
||||
@ -1316,7 +1324,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
|
||||
}
|
||||
|
||||
function EscapeHtml(x) { if (typeof x == "string") return x.replace(/&/g, '&').replace(/>/g, '>').replace(/</g, '<').replace(/"/g, '"').replace(/'/g, '''); if (typeof x == "boolean") return x; if (typeof x == "number") return x; }
|
||||
function EscapeHtmlBreaks(x) { if (typeof x == "string") return x.replace(/&/g, '&').replace(/>/g, '>').replace(/</g, '<').replace(/"/g, '"').replace(/'/g, ''').replace(/\r/g, '<br />').replace(/\n/g, '').replace(/\t/g, ' '); if (typeof x == "boolean") return x; if (typeof x == "number") return x; }
|
||||
//function EscapeHtmlBreaks(x) { if (typeof x == "string") return x.replace(/&/g, '&').replace(/>/g, '>').replace(/</g, '<').replace(/"/g, '"').replace(/'/g, ''').replace(/\r/g, '<br />').replace(/\n/g, '').replace(/\t/g, ' '); if (typeof x == "boolean") return x; if (typeof x == "number") return x; }
|
||||
|
||||
return obj;
|
||||
}
|
||||
};
|
@ -6,7 +6,12 @@
|
||||
* @version v0.0.1
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
/*jslint node: true */
|
||||
/*jshint node: true */
|
||||
/*jshint strict:false */
|
||||
/*jshint -W097 */
|
||||
/*jshint esversion: 6 */
|
||||
"use strict";
|
||||
|
||||
// Construct a Mesh Multi-Server object. This is used for MeshCentral-to-MeshCentral communication.
|
||||
module.exports.CreateMultiServer = function (parent, args) {
|
||||
@ -46,7 +51,7 @@ module.exports.CreateMultiServer = function (parent, args) {
|
||||
obj.stop = function () {
|
||||
obj.connectionState = 0;
|
||||
disconnect();
|
||||
}
|
||||
};
|
||||
|
||||
// Make one attempt at connecting to the server
|
||||
function connect() {
|
||||
@ -169,13 +174,13 @@ module.exports.CreateMultiServer = function (parent, args) {
|
||||
if (typeof msg == 'object') { obj.ws.send(JSON.stringify(msg)); return; }
|
||||
if (typeof msg == 'string') { obj.ws.send(msg); return; }
|
||||
} catch (e) { }
|
||||
}
|
||||
};
|
||||
|
||||
// Process incoming peer server JSON data
|
||||
function processServerData(msg) {
|
||||
var str = msg.toString('utf8');
|
||||
var str = msg.toString('utf8'), command = null;
|
||||
if (str[0] == '{') {
|
||||
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.
|
||||
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.
|
||||
if (command.action == 'info') {
|
||||
if (obj.authenticated != 3) {
|
||||
// We get the peer's serverid and database identifier.
|
||||
@ -198,7 +203,7 @@ module.exports.CreateMultiServer = function (parent, args) {
|
||||
|
||||
connect();
|
||||
return obj;
|
||||
}
|
||||
};
|
||||
|
||||
// Create a mesh server module that received a connection to another server
|
||||
obj.CreatePeerInServer = function (parent, ws, req) {
|
||||
@ -227,14 +232,14 @@ module.exports.CreateMultiServer = function (parent, args) {
|
||||
if (typeof data == 'object') { obj.ws.send(JSON.stringify(data)); return; }
|
||||
obj.ws.send(data);
|
||||
} catch (e) { }
|
||||
}
|
||||
};
|
||||
|
||||
// Disconnect this server
|
||||
obj.close = function (arg) {
|
||||
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
|
||||
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
|
||||
if (obj.authenticated == 3) { obj.parent.ClearPeerServer(obj, obj.peerServerId); obj.authenticated = 0; }
|
||||
}
|
||||
};
|
||||
|
||||
// When data is received from the peer server web socket
|
||||
ws.on('message', function (msg) {
|
||||
@ -244,7 +249,7 @@ module.exports.CreateMultiServer = function (parent, args) {
|
||||
if (obj.authenticated >= 2) { // We are authenticated
|
||||
if (msg.charCodeAt(0) == 123) { processServerData(msg); }
|
||||
if (msg.length < 2) return;
|
||||
var cmdid = obj.common.ReadShort(msg, 0);
|
||||
//var cmdid = obj.common.ReadShort(msg, 0);
|
||||
// Process binary commands (if any). None right now.
|
||||
}
|
||||
else if (obj.authenticated < 2) { // We are not authenticated
|
||||
@ -259,14 +264,14 @@ module.exports.CreateMultiServer = function (parent, args) {
|
||||
obj.peernonce = msg.substring(50);
|
||||
|
||||
// Perform the hash signature using the server agent certificate
|
||||
obj.parent.parent.certificateOperations.acceleratorPerformSignature(0, msg.substring(2) + obj.nonce, obj, function (signature) {
|
||||
obj.parent.parent.certificateOperations.acceleratorPerformSignature(0, msg.substring(2) + obj.nonce, obj, function (obj2, signature) {
|
||||
// Send back our certificate + signature
|
||||
obj2.send(obj2.common.ShortToStr(2) + obj.common.ShortToStr(obj2.agentCertificateAsn1.length) + obj2.agentCertificateAsn1 + signature); // Command 2, certificate + signature
|
||||
obj2.send(obj2.common.ShortToStr(2) + obj2.common.ShortToStr(obj2.agentCertificateAsn1.length) + obj2.agentCertificateAsn1 + signature); // Command 2, certificate + signature
|
||||
});
|
||||
|
||||
// Check the peer server signature if we can
|
||||
if (obj.unauthsign != null) {
|
||||
if (processPeerSignature(obj.unauthsign) == false) { disconnect(); return; } else { completePeerServerConnection(); }
|
||||
if (processPeerSignature(obj.unauthsign) == false) { obj.close(); return; } else { completePeerServerConnection(); }
|
||||
}
|
||||
}
|
||||
else if (cmd == 2) {
|
||||
@ -337,9 +342,9 @@ module.exports.CreateMultiServer = function (parent, args) {
|
||||
|
||||
// Process incoming peer server JSON data
|
||||
function processServerData(msg) {
|
||||
var str = msg.toString('utf8');
|
||||
var str = msg.toString('utf8'), command = null;
|
||||
if (str[0] == '{') {
|
||||
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.
|
||||
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.
|
||||
if (command.action == 'info') {
|
||||
if (obj.authenticated != 3) {
|
||||
// We get the peer's serverid and database identifier.
|
||||
@ -362,7 +367,7 @@ module.exports.CreateMultiServer = function (parent, args) {
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
};
|
||||
|
||||
// If we have no peering configuration, don't setup this object
|
||||
if (obj.peerConfig == null) { return null; }
|
||||
@ -375,34 +380,34 @@ module.exports.CreateMultiServer = function (parent, args) {
|
||||
var server = obj.peerServers[serverid];
|
||||
if (server && server.peerServerKey) return server.peerServerKey;
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
// Dispatch an event to all other MeshCentral2 peer servers
|
||||
obj.DispatchEvent = function (ids, source, event) {
|
||||
var busmsg = JSON.stringify({ action: 'bus', ids: ids, event: event });
|
||||
for (var serverid in obj.peerServers) { obj.peerServers[serverid].send(busmsg); }
|
||||
}
|
||||
};
|
||||
|
||||
// Dispatch a message to other MeshCentral2 peer servers
|
||||
obj.DispatchMessage = function (msg) {
|
||||
for (var serverid in obj.peerServers) { obj.peerServers[serverid].send(msg); }
|
||||
}
|
||||
};
|
||||
|
||||
// Dispatch a message to other MeshCentral2 peer servers
|
||||
obj.DispatchMessageSingleServer = function (msg, serverid) {
|
||||
var server = obj.peerServers[serverid];
|
||||
if (server != null) { server.send(msg); }
|
||||
}
|
||||
};
|
||||
|
||||
// Attempt to connect to all peers
|
||||
obj.ConnectToPeers = function () {
|
||||
for (serverId in obj.peerConfig.servers) {
|
||||
for (var serverId in obj.peerConfig.servers) {
|
||||
// We will only connect to names that are larger then ours. This way, eveyone has one connection to everyone else (no cross-connections).
|
||||
if ((serverId > obj.serverid) && (obj.peerConfig.servers[serverId].url != null) && (obj.outPeerServers[serverId] == null)) {
|
||||
obj.outPeerServers[serverId] = obj.CreatePeerOutServer(obj, serverId, obj.peerConfig.servers[serverId].url);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// We connected to a peer server, setup everything
|
||||
obj.SetupPeerServer = function (server, peerServerId) {
|
||||
@ -414,7 +419,7 @@ module.exports.CreateMultiServer = function (parent, args) {
|
||||
|
||||
// Send a list of user sessions to the peer
|
||||
server.send(JSON.stringify({ action: 'sessionsTable', sessionsTable: Object.keys(obj.parent.webserver.wssessions2) }));
|
||||
}
|
||||
};
|
||||
|
||||
// We disconnected to a peer server, clean up everything
|
||||
obj.ClearPeerServer = function (server, peerServerId) {
|
||||
@ -431,10 +436,11 @@ module.exports.CreateMultiServer = function (parent, args) {
|
||||
delete obj.parent.webserver.wsPeerSessions[peerServerId];
|
||||
delete obj.parent.webserver.wsPeerSessions3[peerServerId];
|
||||
obj.parent.webserver.recountSessions(); // Recount all sessions
|
||||
}
|
||||
};
|
||||
|
||||
// Process a message coming from a peer server
|
||||
obj.ProcessPeerServerMessage = function (server, peerServerId, msg) {
|
||||
var userid, i;
|
||||
//console.log('ProcessPeerServerMessage', peerServerId, msg);
|
||||
switch (msg.action) {
|
||||
case 'bus': {
|
||||
@ -449,10 +455,10 @@ module.exports.CreateMultiServer = function (parent, args) {
|
||||
case 'sessionsTable': {
|
||||
obj.parent.webserver.wsPeerSessions[peerServerId] = msg.sessionsTable;
|
||||
var userToSession = {};
|
||||
for (var i in msg.sessionsTable) {
|
||||
for (i in msg.sessionsTable) {
|
||||
var sessionid = msg.sessionsTable[i];
|
||||
obj.parent.webserver.wsPeerSessions2[sessionid] = peerServerId;
|
||||
var userid = sessionid.split('/').slice(0, 3).join('/'); // Take the sessionid and keep only the userid partion
|
||||
userid = sessionid.split('/').slice(0, 3).join('/'); // Take the sessionid and keep only the userid partion
|
||||
if (userToSession[userid] == null) { userToSession[userid] = [sessionid]; } else { userToSession[userid].push(sessionid); } // UserId -> [ SessionId ]
|
||||
}
|
||||
obj.parent.webserver.wsPeerSessions3[peerServerId] = userToSession; // ServerId --> UserId --> SessionId
|
||||
@ -462,17 +468,17 @@ module.exports.CreateMultiServer = function (parent, args) {
|
||||
case 'sessionStart': {
|
||||
obj.parent.webserver.wsPeerSessions[peerServerId].push(msg.sessionid);
|
||||
obj.parent.webserver.wsPeerSessions2[msg.sessionid] = peerServerId;
|
||||
var userid = msg.sessionid.split('/').slice(0, 3).join('/');
|
||||
userid = msg.sessionid.split('/').slice(0, 3).join('/');
|
||||
if (obj.parent.webserver.wsPeerSessions3[peerServerId] == null) { obj.parent.webserver.wsPeerSessions3[peerServerId] = {}; }
|
||||
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); }
|
||||
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); }
|
||||
obj.parent.webserver.recountSessions(msg.sessionid); // Recount a specific user
|
||||
break;
|
||||
}
|
||||
case 'sessionEnd': {
|
||||
var i = obj.parent.webserver.wsPeerSessions[peerServerId].indexOf(msg.sessionid);
|
||||
i = obj.parent.webserver.wsPeerSessions[peerServerId].indexOf(msg.sessionid);
|
||||
if (i >= 0) { obj.parent.webserver.wsPeerSessions[peerServerId].splice(i, 1); }
|
||||
delete obj.parent.webserver.wsPeerSessions2[msg.sessionid];
|
||||
var userid = msg.sessionid.split('/').slice(0, 3).join('/');
|
||||
userid = msg.sessionid.split('/').slice(0, 3).join('/');
|
||||
if (obj.parent.webserver.wsPeerSessions3[peerServerId][userid] != null) {
|
||||
i = obj.parent.webserver.wsPeerSessions3[peerServerId][userid].indexOf(msg.sessionid);
|
||||
if (i >= 0) {
|
||||
@ -498,7 +504,7 @@ module.exports.CreateMultiServer = function (parent, args) {
|
||||
// Yes, there is a waiting session, see if we must initiate.
|
||||
if (peerServerId > obj.parent.serverId) {
|
||||
// We must initiate the connection to the peer
|
||||
var userid = null;
|
||||
userid = null;
|
||||
if (rsession.peer1.req.session != null) { userid = rsession.peer1.req.session.userid; }
|
||||
obj.createPeerRelay(rsession.peer1.ws, rsession.peer1.req, peerServerId, userid);
|
||||
delete obj.parent.webserver.wsrelays[msg.id];
|
||||
@ -509,33 +515,33 @@ module.exports.CreateMultiServer = function (parent, args) {
|
||||
|
||||
// Clear all relay sessions that are more than 1 minute
|
||||
var oneMinuteAgo = Date.now() - 60000;
|
||||
for (var id in obj.parent.webserver.wsPeerRelays) { if (obj.parent.webserver.wsPeerRelays[id].time < oneMinuteAgo) { delete obj.parent.webserver.wsPeerRelays[id]; } }
|
||||
for (i in obj.parent.webserver.wsPeerRelays) { if (obj.parent.webserver.wsPeerRelays[i].time < oneMinuteAgo) { delete obj.parent.webserver.wsPeerRelays[i]; } }
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'msg': {
|
||||
if (msg.sessionid != null) {
|
||||
// Route this message to a connected user session
|
||||
if (command.fromNodeid != null) { command.nodeid = command.fromNodeid; delete command.fromNodeid; }
|
||||
var ws = obj.parent.webserver.wssessions2[command.sessionid];
|
||||
if (ws != null) { ws.send(JSON.stringify(command)); }
|
||||
if (msg.fromNodeid != null) { msg.nodeid = msg.fromNodeid; delete msg.fromNodeid; }
|
||||
var ws = obj.parent.webserver.wssessions2[msg.sessionid];
|
||||
if (ws != null) { ws.send(JSON.stringify(msg)); }
|
||||
} else if (msg.nodeid != null) {
|
||||
// Route this message to a connected agent
|
||||
if (command.fromSessionid != null) { command.sessionid = command.fromSessionid; delete command.fromSessionid; }
|
||||
if (msg.fromSessionid != null) { msg.sessionid = msg.fromSessionid; delete msg.fromSessionid; }
|
||||
var agent = obj.parent.webserver.wsagents[msg.nodeid];
|
||||
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
|
||||
} else if (msg.meshid != null) {
|
||||
// Route this message to all users of this mesh
|
||||
if (command.fromNodeid != null) { command.nodeid = command.fromNodeid; delete command.fromNodeid; }
|
||||
var cmdstr = JSON.stringify(command);
|
||||
for (var userid in obj.parent.webserver.wssessions) { // Find all connected users for this mesh and send the message
|
||||
if (msg.fromNodeid != null) { msg.nodeid = msg.fromNodeid; delete msg.fromNodeid; }
|
||||
var cmdstr = JSON.stringify(msg);
|
||||
for (userid in obj.parent.webserver.wssessions) { // Find all connected users for this mesh and send the message
|
||||
var user = obj.parent.webserver.users[userid];
|
||||
if (user) {
|
||||
var rights = user.links[msg.meshid];
|
||||
if (rights != null) { // TODO: Look at what rights are needed for message routing
|
||||
var sessions = obj.parent.webserver.wssessions[userid];
|
||||
// Send the message to all users on this server
|
||||
for (var i in sessions) { sessions[i].send(cmdstr); }
|
||||
for (i in sessions) { sessions[i].send(cmdstr); }
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -543,7 +549,7 @@ module.exports.CreateMultiServer = function (parent, args) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Create a tunnel connection to a peer server
|
||||
obj.createPeerRelay = function (ws, req, serverid, user) {
|
||||
@ -558,7 +564,7 @@ module.exports.CreateMultiServer = function (parent, args) {
|
||||
var path = req.path;
|
||||
if (path[0] == '/') path = path.substring(1);
|
||||
if (path.substring(path.length - 11) == '/.websocket') { path = path.substring(0, path.length - 11); }
|
||||
var queryStr = ''
|
||||
var queryStr = '';
|
||||
for (var i in req.query) { queryStr += ((queryStr == '') ? '?' : '&') + i + '=' + req.query[i]; }
|
||||
if (user != null) { queryStr += ((queryStr == '') ? '?' : '&') + 'auth=' + obj.parent.encodeCookie({ userid: user._id, domainid: user.domain }, cookieKey); }
|
||||
var url = obj.peerConfig.servers[serverid].url + path + queryStr;
|
||||
@ -566,7 +572,7 @@ module.exports.CreateMultiServer = function (parent, args) {
|
||||
// Setup an connect the web socket
|
||||
var tunnel = obj.createPeerRelayEx(ws, url, serverid);
|
||||
tunnel.connect();
|
||||
}
|
||||
};
|
||||
|
||||
// Create a tunnel connection to a peer server
|
||||
// We assume that "ws" is paused already.
|
||||
@ -610,7 +616,7 @@ module.exports.CreateMultiServer = function (parent, args) {
|
||||
|
||||
// If the web socket is closed, close the associated TCP connection.
|
||||
peerTunnel.ws1.on('close', function (req) { peerTunnel.parent.parent.debug(1, 'FTunnel disconnect ' + peerTunnel.serverid); peerTunnel.close(); });
|
||||
}
|
||||
};
|
||||
|
||||
// Disconnect both sides of the tunnel
|
||||
peerTunnel.close = function (arg) {
|
||||
@ -623,11 +629,11 @@ module.exports.CreateMultiServer = function (parent, args) {
|
||||
if (peerTunnel.ws1 != null) { try { peerTunnel.ws1.close(); peerTunnel.parent.parent.debug(1, 'FTunnel1: Soft disconnect '); } catch (e) { console.log(e); } }
|
||||
if (peerTunnel.ws2 != null) { try { peerTunnel.ws2.close(); peerTunnel.parent.parent.debug(1, 'FTunnel2: Soft disconnect '); } catch (e) { console.log(e); } }
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return peerTunnel;
|
||||
}
|
||||
};
|
||||
|
||||
setTimeout(function () { obj.ConnectToPeers(); }, 1000); // Delay this a little to make sure we are ready on our side.
|
||||
return obj;
|
||||
}
|
||||
};
|
7
pass.js
7
pass.js
@ -1,6 +1,11 @@
|
||||
// check out https://github.com/tj/node-pwd
|
||||
|
||||
'use strict';
|
||||
/*jslint node: true */
|
||||
/*jshint node: true */
|
||||
/*jshint strict:false */
|
||||
/*jshint -W097 */
|
||||
/*jshint esversion: 6 */
|
||||
"use strict";
|
||||
|
||||
// Module dependencies.
|
||||
const crypto = require('crypto');
|
||||
|
@ -6,7 +6,12 @@
|
||||
* @version v0.0.1
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
/*jslint node: true */
|
||||
/*jshint node: true */
|
||||
/*jshint strict:false */
|
||||
/*jshint -W097 */
|
||||
/*jshint esversion: 6 */
|
||||
"use strict";
|
||||
|
||||
// Construct a legacy Swarm Server server object
|
||||
module.exports.CreateSwarmServer = function (parent, db, args, certificates) {
|
||||
@ -18,7 +23,7 @@ module.exports.CreateSwarmServer = function (parent, db, args, certificates) {
|
||||
obj.legacyAgentConnections = {};
|
||||
obj.migrationAgents = {};
|
||||
const common = require('./common.js');
|
||||
const net = require('net');
|
||||
//const net = require('net');
|
||||
const tls = require('tls');
|
||||
const forge = require('node-forge');
|
||||
|
||||
@ -115,7 +120,7 @@ module.exports.CreateSwarmServer = function (parent, db, args, certificates) {
|
||||
USERAUTH2: 1031, // Authenticate a user to the swarm server (Uses SHA1 SALT)
|
||||
GUESTREMOTEDESKTOP: 2001, // Guest usage: Remote Desktop
|
||||
GUESTWEBRTCMESH: 2002 // Guest usage: WebRTC Mesh
|
||||
}
|
||||
};
|
||||
|
||||
obj.server = tls.createServer({ key: certificates.swarmserver.key, cert: certificates.swarmserver.cert, requestCert: true }, onConnection);
|
||||
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) {
|
||||
socket.setEncoding('binary');
|
||||
socket.pingTimer = setInterval(function () { obj.SendCommand(socket, LegacyMeshProtocol.PING); }, 20000);
|
||||
Debug(1, 'SWARM:New legacy agent connection');
|
||||
|
||||
|
||||
socket.addListener("data", function (data) {
|
||||
if (args.swarmdebug) { var buf = new Buffer(data, "binary"); console.log('SWARM <-- (' + buf.length + '):' + buf.toString('hex')); } // Print out received bytes
|
||||
socket.tag.accumulator += data;
|
||||
|
||||
|
||||
// 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.
|
||||
if (socket.tag.first == true) {
|
||||
if (socket.tag.accumulator.length < 3) return;
|
||||
@ -214,7 +219,7 @@ module.exports.CreateSwarmServer = function (parent, db, args, certificates) {
|
||||
Debug(3, 'Swarm:GETSTATE');
|
||||
if (len < 12) break;
|
||||
var statecmd = common.ReadInt(data, 0);
|
||||
var statesync = common.ReadInt(data, 4);
|
||||
//var statesync = common.ReadInt(data, 4);
|
||||
switch (statecmd) {
|
||||
case 6: { // Ask for agent block
|
||||
if (socket.tag.update != null) {
|
||||
@ -247,14 +252,14 @@ module.exports.CreateSwarmServer = function (parent, db, args, certificates) {
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
socket.addListener("close", function () {
|
||||
Debug(1, 'Swarm:Connection closed');
|
||||
try { delete obj.ciraConnections[socket.tag.nodeid]; } catch (e) { }
|
||||
obj.parent.ClearConnectivityState(socket.tag.meshid, socket.tag.nodeid, 2);
|
||||
if (socket.pingTimer != null) { clearInterval(socket.pingTimer); delete socket.pingTimer; }
|
||||
});
|
||||
|
||||
|
||||
socket.addListener("error", function () {
|
||||
//console.log("Swarm Error: " + socket.remoteAddress);
|
||||
});
|
||||
@ -311,19 +316,19 @@ module.exports.CreateSwarmServer = function (parent, db, args, certificates) {
|
||||
console.log(e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
// Disconnect legacy agent connection
|
||||
obj.close = function (socket) {
|
||||
try { socket.close(); } catch (e) { }
|
||||
try { delete obj.ciraConnections[socket.tag.nodeid]; } catch (e) { }
|
||||
obj.parent.ClearConnectivityState(socket.tag.meshid, socket.tag.nodeid, 2);
|
||||
}
|
||||
};
|
||||
|
||||
obj.SendCommand = function(socket, cmdid, data) {
|
||||
obj.SendCommand = function (socket, cmdid, data) {
|
||||
if (data == null) { data = ''; }
|
||||
Write(socket, common.ShortToStr(cmdid) + common.ShortToStr(data.length + 4) + data);
|
||||
}
|
||||
};
|
||||
|
||||
function Write(socket, data) {
|
||||
if (args.swarmdebug) {
|
||||
@ -335,7 +340,7 @@ module.exports.CreateSwarmServer = function (parent, db, args, certificates) {
|
||||
socket.write(new Buffer(data, "binary"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Debug
|
||||
function Debug(lvl) {
|
||||
if (lvl > obj.parent.debugLevel) return;
|
||||
@ -348,4 +353,4 @@ module.exports.CreateSwarmServer = function (parent, db, args, certificates) {
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
};
|
||||
|
@ -2251,9 +2251,8 @@
|
||||
var boundingBox = null;
|
||||
for (var i in nodes) {
|
||||
try {
|
||||
var loc = map_parseNodeLoc(nodes[i]);
|
||||
var feature = xxmap.markersSource.getFeatureById(nodes[i]._id);
|
||||
if ((typeof loc == 'object') && ((nodes[i].meshid == selectedMesh) || (selectedMesh == null))) { // Draw markers for devices with locations
|
||||
var loc = map_parseNodeLoc(nodes[i]), feature = xxmap.markersSource.getFeatureById(nodes[i]._id);
|
||||
if ((loc != null) && ((nodes[i].meshid == selectedMesh) || (selectedMesh == null))) { // Draw markers for devices with locations
|
||||
var lat = loc[0], lon = loc[1], type = loc[2];
|
||||
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; } }
|
||||
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 @@
|
||||
if (node.wifiloc) { loc = node.wifiloc; t = 2; }
|
||||
if (node.gpsloc) { loc = node.gpsloc; t = 3; }
|
||||
if (node.userloc) { loc = node.userloc; t = 4; }
|
||||
if ((loc == null) || (typeof loc != 'string')) return;
|
||||
if ((loc == null) || (typeof loc != 'string')) return null;
|
||||
loc = loc.split(',');
|
||||
if (t == 1) {
|
||||
// If this is IP location, randomize the position a little.
|
||||
@ -2450,12 +2449,14 @@
|
||||
}
|
||||
|
||||
// Since this is IP address location, add some fixed randomness to the location. Avoid pin pile-up.
|
||||
var loc = map_parseNodeLoc(node); lat = loc[0]; lon = loc[1];
|
||||
|
||||
if ((lat != feature.get('lat')) || (lon != feature.get('lon'))) { // Update lat and lon if changed
|
||||
feature.set('lat', lat); feature.set('lon', lon);
|
||||
var modifiedCoordinates = ol.proj.transform([parseFloat(lon), parseFloat(lat)], 'EPSG:4326','EPSG:3857');
|
||||
feature.getGeometry().setCoordinates(modifiedCoordinates);
|
||||
var loc = map_parseNodeLoc(node);
|
||||
if (loc != null) {
|
||||
var lat = loc[0], lon = loc[1];
|
||||
if ((lat != feature.get('lat')) || (lon != feature.get('lon'))) { // Update lat and lon if changed
|
||||
feature.set('lat', lat); feature.set('lon', lon);
|
||||
var modifiedCoordinates = ol.proj.transform([parseFloat(lon), parseFloat(lat)], 'EPSG:4326', 'EPSG:3857');
|
||||
feature.getGeometry().setCoordinates(modifiedCoordinates);
|
||||
}
|
||||
}
|
||||
|
||||
if (node.name != feature.get('name') ) { feature.set('name', node.name); } // Update name
|
||||
|
266
webserver.js
266
webserver.js
@ -6,7 +6,12 @@
|
||||
* @version v0.0.1
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
/*jslint node: true */
|
||||
/*jshint node: true */
|
||||
/*jshint strict:false */
|
||||
/*jshint -W097 */
|
||||
/*jshint esversion: 6 */
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
class SerialTunnel extends require('stream').Duplex {
|
||||
@ -22,9 +27,9 @@ class SerialTunnel extends require('stream').Duplex {
|
||||
function SerialTunnel(options) {
|
||||
var obj = new require('stream').Duplex(options);
|
||||
obj.forwardwrite = null;
|
||||
obj.updateBuffer = function (chunk) { this.push(chunk); }
|
||||
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
|
||||
obj._read = function(size) { } // Push nothing, anything to read should be pushed from updateBuffer()
|
||||
obj.updateBuffer = function (chunk) { this.push(chunk); };
|
||||
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
|
||||
obj._read = function (size) { }; // Push nothing, anything to read should be pushed from updateBuffer()
|
||||
return obj;
|
||||
}
|
||||
|
||||
@ -37,7 +42,7 @@ if (!String.prototype.endsWith) { String.prototype.endsWith = function (searchSt
|
||||
|
||||
// Construct a HTTP web server object
|
||||
module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
||||
var obj = {};
|
||||
var obj = {}, i = 0;
|
||||
|
||||
// Modules
|
||||
obj.fs = require('fs');
|
||||
@ -52,8 +57,8 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
||||
obj.common = require('./common.js');
|
||||
obj.express = require('express');
|
||||
obj.meshAgentHandler = require('./meshagent.js');
|
||||
obj.meshRelayHandler = require('./meshrelay.js')
|
||||
obj.meshUserHandler = require('./meshuser.js')
|
||||
obj.meshRelayHandler = require('./meshrelay.js');
|
||||
obj.meshUserHandler = require('./meshuser.js');
|
||||
obj.interceptor = require('./interceptor');
|
||||
|
||||
// Variables
|
||||
@ -63,13 +68,13 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
||||
obj.app = obj.express();
|
||||
obj.app.use(require('compression')());
|
||||
obj.tlsServer = null;
|
||||
obj.tcpServer;
|
||||
obj.tcpServer = null;
|
||||
obj.certificates = certificates;
|
||||
obj.args = args;
|
||||
obj.users = {};
|
||||
obj.meshes = {};
|
||||
obj.userAllowedIp = args.userallowedip; // List of allowed IP addresses for users
|
||||
obj.tlsSniCredentials;
|
||||
obj.tlsSniCredentials = null;
|
||||
obj.dnsDomains = {};
|
||||
//obj.agentConnCount = 0;
|
||||
|
||||
@ -93,13 +98,13 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
||||
|
||||
// Setup SSPI authentication if needed
|
||||
if ((obj.parent.platform == 'win32') && (obj.args.nousers != true) && (obj.parent.config != null) && (obj.parent.config.domains != null)) {
|
||||
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 }); } }
|
||||
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 }); } }
|
||||
}
|
||||
|
||||
// Perform hash on web certificate and agent certificate
|
||||
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' });
|
||||
obj.webCertificateHashs = { '': obj.webCertificateHash };
|
||||
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' }); } }
|
||||
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' }); } }
|
||||
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, '$');
|
||||
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' });
|
||||
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) {
|
||||
{
|
||||
var dnscount = 0;
|
||||
obj.tlsSniCredentials = {};
|
||||
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++; } }
|
||||
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++; } }
|
||||
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; }
|
||||
}
|
||||
function TlsSniCallback(name, cb) { var c = obj.tlsSniCredentials[name]; if (c != null) { cb(null, c); } else { cb(null, obj.tlsSniCredentials['']); } }
|
||||
|
||||
function EscapeHtml(x) { if (typeof x == "string") return x.replace(/&/g, '&').replace(/>/g, '>').replace(/</g, '<').replace(/"/g, '"').replace(/'/g, '''); if (typeof x == "boolean") return x; if (typeof x == "number") return x; }
|
||||
function EscapeHtmlBreaks(x) { if (typeof x == "string") return x.replace(/&/g, '&').replace(/>/g, '>').replace(/</g, '<').replace(/"/g, '"').replace(/'/g, ''').replace(/\r/g, '<br />').replace(/\n/g, '').replace(/\t/g, ' '); if (typeof x == "boolean") return x; if (typeof x == "number") return x; }
|
||||
//function EscapeHtmlBreaks(x) { if (typeof x == "string") return x.replace(/&/g, '&').replace(/>/g, '>').replace(/</g, '<').replace(/"/g, '"').replace(/'/g, ''').replace(/\r/g, '<br />').replace(/\n/g, '').replace(/\t/g, ' '); if (typeof x == "boolean") return x; if (typeof x == "number") return x; }
|
||||
|
||||
if (obj.args.notls || obj.args.tlsoffload) {
|
||||
// Setup the HTTP server without TLS
|
||||
@ -172,27 +177,28 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
||||
|
||||
// Session-persisted message middleware
|
||||
obj.app.use(function (req, res, next) {
|
||||
var err = null, msg = null, passhint = null;
|
||||
if (req.session != null) {
|
||||
var err = req.session.error;
|
||||
var msg = req.session.success;
|
||||
var passhint = req.session.passhint;
|
||||
err = req.session.error;
|
||||
msg = req.session.success;
|
||||
passhint = req.session.passhint;
|
||||
delete req.session.error;
|
||||
delete req.session.success;
|
||||
delete req.session.passhint;
|
||||
}
|
||||
res.locals.message = '';
|
||||
if (err) res.locals.message = '<p class="msg error">' + err + '</p>';
|
||||
if (msg) res.locals.message = '<p class="msg success">' + msg + '</p>';
|
||||
if (passhint) res.locals.passhint = EscapeHtml(passhint);
|
||||
if (err != null) res.locals.message = '<p class="msg error">' + err + '</p>';
|
||||
if (msg != null) res.locals.message = '<p class="msg success">' + msg + '</p>';
|
||||
if (passhint != null) res.locals.passhint = EscapeHtml(passhint);
|
||||
next();
|
||||
});
|
||||
|
||||
// Fetch all users from the database, keep this in memory
|
||||
obj.db.GetAllType('user', function (err, docs) {
|
||||
var domainUserCount = {};
|
||||
for (var i in parent.config.domains) { domainUserCount[i] = 0; }
|
||||
for (var i in docs) { var u = obj.users[docs[i]._id] = docs[i]; domainUserCount[u.domain]++; }
|
||||
for (var i in parent.config.domains) {
|
||||
var domainUserCount = {}, i = 0;
|
||||
for (i in parent.config.domains) { domainUserCount[i] = 0; }
|
||||
for (i in docs) { var u = obj.users[docs[i]._id] = docs[i]; domainUserCount[u.domain]++; }
|
||||
for (i in parent.config.domains) {
|
||||
if (domainUserCount[i] == 0) {
|
||||
if (parent.config.domains[i].newaccounts == 0) { parent.config.domains[i].newaccounts = 2; }
|
||||
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) {
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
obj.restrict = function (req, res, next) {
|
||||
@ -249,7 +255,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
||||
req.session.error = 'Access denied!';
|
||||
res.redirect(domain.url + 'login');
|
||||
}
|
||||
}
|
||||
};
|
||||
*/
|
||||
|
||||
// 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) {
|
||||
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.
|
||||
var x = req.url.split('/');
|
||||
if (x.length < 2) return parent.config.domains[''];
|
||||
var d = parent.config.domains[x[1].toLowerCase()];
|
||||
if ((d != null) && (d.dns == null)) return parent.config.domains[x[1].toLowerCase()];
|
||||
var y = parent.config.domains[x[1].toLowerCase()];
|
||||
if ((y != null) && (y.dns == null)) return parent.config.domains[x[1].toLowerCase()];
|
||||
return parent.config.domains[''];
|
||||
}
|
||||
|
||||
@ -298,8 +304,8 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
||||
res.set({ 'Cache-Control': 'no-cache, no-store, must-revalidate', 'Pragma': 'no-cache', 'Expires': '0' });
|
||||
// Destroy the user's session to log them out will be re-created next request
|
||||
if (req.session.userid) {
|
||||
var user = obj.users[req.session.userid]
|
||||
obj.parent.DispatchEvent(['*'], obj, { etype: 'user', username: user.name, action: 'logout', msg: 'Account logout', domain: domain.id })
|
||||
var user = obj.users[req.session.userid];
|
||||
obj.parent.DispatchEvent(['*'], obj, { etype: 'user', username: user.name, action: 'logout', msg: 'Account logout', domain: domain.id });
|
||||
}
|
||||
req.session = null;
|
||||
res.redirect(domain.url);
|
||||
@ -319,35 +325,35 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
||||
|
||||
// Regenerate session when signing in to prevent fixation
|
||||
//req.session.regenerate(function () {
|
||||
// Store the user's primary key in the session store to be retrieved, or in this case the entire user object
|
||||
// req.session.success = 'Authenticated as ' + user.name + 'click to <a href="/logout">logout</a>. You may now access <a href="/restricted">/restricted</a>.';
|
||||
delete req.session.loginmode;
|
||||
req.session.userid = userid;
|
||||
req.session.domainid = domain.id;
|
||||
req.session.currentNode = '';
|
||||
if (req.session.passhint) { delete req.session.passhint; }
|
||||
if (req.body.viewmode) { req.session.viewmode = req.body.viewmode; }
|
||||
if (req.body.host) {
|
||||
// TODO: This is a terrible search!!! FIX THIS.
|
||||
/*
|
||||
obj.db.GetAllType('node', function (err, docs) {
|
||||
for (var i = 0; i < docs.length; i++) {
|
||||
if (docs[i].name == req.body.host) {
|
||||
req.session.currentNode = docs[i]._id;
|
||||
break;
|
||||
}
|
||||
// Store the user's primary key in the session store to be retrieved, or in this case the entire user object
|
||||
// req.session.success = 'Authenticated as ' + user.name + 'click to <a href="/logout">logout</a>. You may now access <a href="/restricted">/restricted</a>.';
|
||||
delete req.session.loginmode;
|
||||
req.session.userid = userid;
|
||||
req.session.domainid = domain.id;
|
||||
req.session.currentNode = '';
|
||||
if (req.session.passhint) { delete req.session.passhint; }
|
||||
if (req.body.viewmode) { req.session.viewmode = req.body.viewmode; }
|
||||
if (req.body.host) {
|
||||
// TODO: This is a terrible search!!! FIX THIS.
|
||||
/*
|
||||
obj.db.GetAllType('node', function (err, docs) {
|
||||
for (var i = 0; i < docs.length; i++) {
|
||||
if (docs[i].name == req.body.host) {
|
||||
req.session.currentNode = docs[i]._id;
|
||||
break;
|
||||
}
|
||||
console.log("CurrentNode: " + req.session.currentNode);
|
||||
// This redirect happens after finding node is completed
|
||||
res.redirect(domain.url);
|
||||
});
|
||||
*/
|
||||
} else {
|
||||
}
|
||||
console.log("CurrentNode: " + req.session.currentNode);
|
||||
// This redirect happens after finding node is completed
|
||||
res.redirect(domain.url);
|
||||
}
|
||||
});
|
||||
*/
|
||||
} else {
|
||||
res.redirect(domain.url);
|
||||
}
|
||||
//});
|
||||
|
||||
obj.parent.DispatchEvent(['*'], obj, { etype: 'user', username: user.name, action: 'login', msg: 'Account login', domain: domain.id })
|
||||
obj.parent.DispatchEvent(['*'], obj, { etype: 'user', username: user.name, action: 'login', msg: 'Account login', domain: domain.id });
|
||||
} else {
|
||||
delete req.session.loginmode;
|
||||
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) {
|
||||
if (domain.newaccounts == 0) { res.sendStatus(401); return; }
|
||||
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 == '~') {
|
||||
req.session.loginmode = 2;
|
||||
req.session.error = '<b style=color:#8C001A>Unable to create account.</b>';;
|
||||
req.session.error = '<b style=color:#8C001A>Unable to create account.</b>';
|
||||
res.redirect(domain.url);
|
||||
} else {
|
||||
// Check if this email was already verified
|
||||
obj.db.GetUserWithVerifiedEmail(domain.id, req.body.email, function (err, docs) {
|
||||
if (docs.length > 0) {
|
||||
req.session.loginmode = 2;
|
||||
req.session.error = '<b style=color:#8C001A>Existing account with this email address.</b>';;
|
||||
req.session.error = '<b style=color:#8C001A>Existing account with this email address.</b>';
|
||||
res.redirect(domain.url);
|
||||
} else {
|
||||
// Check if there is domain.newAccountToken, check if supplied token is valid
|
||||
@ -406,7 +412,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
||||
obj.db.SetUser(user);
|
||||
if (obj.parent.mailserver != null) { obj.parent.mailserver.sendAccountCheckMail(domain, user.name, user.email); }
|
||||
});
|
||||
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 })
|
||||
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 });
|
||||
}
|
||||
res.redirect(domain.url);
|
||||
}
|
||||
@ -459,7 +465,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
||||
} else {
|
||||
obj.db.Get('user/' + cookie.u, function (err, docs) {
|
||||
if (docs.length == 0) {
|
||||
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>.' });
|
||||
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>.' });
|
||||
} else {
|
||||
var user = docs[0];
|
||||
if (user.email != cookie.e) {
|
||||
@ -488,13 +494,13 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
||||
delete userinfo.domain;
|
||||
delete userinfo.subscriptions;
|
||||
delete userinfo.passtype;
|
||||
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 })
|
||||
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 });
|
||||
|
||||
// Send the confirmation page
|
||||
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>.' });
|
||||
|
||||
// Send a notification
|
||||
obj.parent.DispatchEvent([user._id], obj, { action: 'notify', value: 'Email verified:<br /><b>' + EscapeHtml(userinfo.email) + '</b>.', nolog: 1 })
|
||||
obj.parent.DispatchEvent([user._id], obj, { action: 'notify', value: 'Email verified:<br /><b>' + EscapeHtml(userinfo.email) + '</b>.', nolog: 1 });
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -507,10 +513,11 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
||||
obj.crypto.randomBytes(16, function (err, buf) {
|
||||
var newpass = buf.toString('base64').split('=').join('').split('/').join('');
|
||||
require('./pass').hash(newpass, function (err, salt, hash) {
|
||||
var userinfo = null;
|
||||
if (err) throw err;
|
||||
|
||||
// Change the password
|
||||
var userinfo = obj.users[user._id];
|
||||
userinfo = obj.users[user._id];
|
||||
userinfo.salt = salt;
|
||||
userinfo.hash = hash;
|
||||
userinfo.passchange = Date.now();
|
||||
@ -518,7 +525,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
||||
obj.db.SetUser(userinfo);
|
||||
|
||||
// Event the change
|
||||
var userinfo = obj.common.Clone(userinfo);
|
||||
userinfo = obj.common.Clone(userinfo);
|
||||
delete userinfo.hash;
|
||||
delete userinfo.passhint;
|
||||
delete userinfo.salt;
|
||||
@ -526,7 +533,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
||||
delete userinfo.domain;
|
||||
delete userinfo.subscriptions;
|
||||
delete userinfo.passtype;
|
||||
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 })
|
||||
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 });
|
||||
|
||||
// Send the new password
|
||||
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) {
|
||||
if (mesh.links[escUserId] != null) { delete mesh.links[escUserId]; obj.db.Set(mesh); }
|
||||
// Notify mesh change
|
||||
var change = 'Removed user ' + user.name + ' from mesh ' + mesh.name;
|
||||
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 })
|
||||
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 });
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -582,7 +589,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
||||
delete obj.users[user._id];
|
||||
req.session = null;
|
||||
res.redirect(domain.url);
|
||||
obj.parent.DispatchEvent(['*', 'server-users'], obj, { etype: 'user', username: user.name, action: 'accountremove', msg: 'Account removed', domain: domain.id })
|
||||
obj.parent.DispatchEvent(['*', 'server-users'], obj, { etype: 'user', username: user.name, action: 'accountremove', msg: 'Account removed', domain: domain.id });
|
||||
} else {
|
||||
res.redirect(domain.url);
|
||||
}
|
||||
@ -609,7 +616,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
||||
obj.db.SetUser(user);
|
||||
req.session.viewmode = 2;
|
||||
res.redirect(domain.url);
|
||||
obj.parent.DispatchEvent(['*', 'server-users'], obj, { etype: 'user', username: user.name, action: 'passchange', msg: 'Account password changed: ' + user.name, domain: domain.id })
|
||||
obj.parent.DispatchEvent(['*', 'server-users'], obj, { etype: 'user', username: user.name, action: 'passchange', msg: 'Account password changed: ' + user.name, domain: domain.id });
|
||||
});
|
||||
}
|
||||
|
||||
@ -618,11 +625,10 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
||||
var domain = checkUserIpAddress(req, res);
|
||||
if (domain == null) return;
|
||||
if (!obj.args) { res.sendStatus(500); return; }
|
||||
var domain = getDomain(req);
|
||||
|
||||
if ((domain.sspi != null) && ((req.query.login == null) || (obj.parent.loginCookieEncryptionKey == null))) {
|
||||
// Login using SSPI
|
||||
domain.sspi.authenticate(req, res, function (err) { if ((err != null) || (req.connection.user == null)) { res.end('Authentication Required...'); } else { handleRootRequestEx(req, res, domain); } })
|
||||
domain.sspi.authenticate(req, res, function (err) { if ((err != null) || (req.connection.user == null)) { res.end('Authentication Required...'); } else { handleRootRequestEx(req, res, domain); } });
|
||||
} else {
|
||||
// Login using a different system
|
||||
handleRootRequestEx(req, res, domain);
|
||||
@ -630,7 +636,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
||||
}
|
||||
|
||||
function handleRootRequestEx(req, res, domain) {
|
||||
var nologout = false;
|
||||
var nologout = false, user = null, features = 0;
|
||||
res.set({ 'Cache-Control': 'no-cache, no-store, must-revalidate', 'Pragma': 'no-cache', 'Expires': '0' });
|
||||
|
||||
// Check if we have an incomplete domain name in the path
|
||||
@ -676,15 +682,15 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
||||
req.session.currentNode = '';
|
||||
|
||||
// Check if this user exists, create it if not.
|
||||
var user = obj.users[req.session.userid];
|
||||
user = obj.users[req.session.userid];
|
||||
if ((user == null) || (user.sid != req.session.usersid)) {
|
||||
// Create the domain user
|
||||
var usercount = 0, user = { type: 'user', _id: req.session.userid, name: req.connection.user, domain: domain.id, sid: req.session.usersid };
|
||||
var usercount = 0, user2 = { type: 'user', _id: req.session.userid, name: req.connection.user, domain: domain.id, sid: req.session.usersid };
|
||||
for (var i in obj.users) { if (obj.users[i].domain == domain.id) { usercount++; } }
|
||||
if (usercount == 0) { user.siteadmin = 0xFFFFFFFF; } // If this is the first user, give the account site admin.
|
||||
obj.users[req.session.userid] = user;
|
||||
obj.db.SetUser(user);
|
||||
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 })
|
||||
if (usercount == 0) { user2.siteadmin = 0xFFFFFFFF; } // If this is the first user, give the account site admin.
|
||||
obj.users[req.session.userid] = user2;
|
||||
obj.db.SetUser(user2);
|
||||
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 });
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -706,15 +712,11 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
||||
} else if (req.query.node) {
|
||||
currentNode = 'node/' + domain.id + '/' + req.query.node;
|
||||
}
|
||||
var user;
|
||||
var logoutcontrol;
|
||||
if (obj.args.nousers != true) {
|
||||
user = obj.users[req.session.userid]
|
||||
logoutcontrol = 'Welcome ' + user.name + '.';
|
||||
}
|
||||
var logoutcontrol = '';
|
||||
if (obj.args.nousers != true) { logoutcontrol = 'Welcome ' + obj.users[req.session.userid].name + '.'; }
|
||||
|
||||
// Give the web page a list of supported server features
|
||||
var features = 0;
|
||||
features = 0;
|
||||
if (obj.args.wanonly == true) { features += 1; } // WAN-only mode
|
||||
if (obj.args.lanonly == true) { features += 2; } // LAN-only mode
|
||||
if (obj.args.nousers == true) { features += 4; } // Single user mode
|
||||
@ -745,7 +747,8 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
||||
}
|
||||
} else {
|
||||
// Send back the login application
|
||||
var loginmode = req.session.loginmode, features = 0;
|
||||
var loginmode = req.session.loginmode;
|
||||
features = 0;
|
||||
delete req.session.loginmode; // Clear this state, if the user hits refresh, we want to go back to the login page.
|
||||
if ((parent.config != null) && (parent.config.settings != null) && (parent.config.settings.allowframing == true)) { features += 32; } // Allow site within iframe
|
||||
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) {
|
||||
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; } }
|
||||
|
||||
var stat = null;
|
||||
try { stat = obj.fs.statSync(path) } catch (e) { }
|
||||
try { stat = obj.fs.statSync(path); } catch (e) { }
|
||||
if ((stat != null) && ((stat.mode & 0x004000) == 0)) {
|
||||
if (req.query.download == 1) {
|
||||
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) {
|
||||
if (splitpath[1] != '') { serverpath += '-' + splitpath[1]; } // Add the domain if needed
|
||||
serverpath += ('/' + splitpath[0] + '-' + splitpath[2]);
|
||||
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
|
||||
var fullpath = obj.path.resolve(obj.filespath, serverpath), quota = 0;
|
||||
return { fullpath: fullpath, path: serverpath, name: filename, quota: obj.getQuota(objid, domain) };
|
||||
}
|
||||
return { fullpath: obj.path.resolve(obj.filespath, serverpath), path: serverpath, name: filename, quota: obj.getQuota(objid, domain) };
|
||||
};
|
||||
|
||||
// Return the maximum number of bytes allowed in the user account "My Files".
|
||||
obj.getQuota = function (objid, domain) {
|
||||
@ -944,7 +946,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
||||
return 1048576; // By default, the server will have a 1 meg limit on mesh accounts
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
// Download a file from the server
|
||||
function handleDownloadFile(req, res) {
|
||||
@ -1014,7 +1016,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
||||
obj.fs.mkdir(xfile.fullpath, function () {
|
||||
// Write the file
|
||||
obj.fs.writeFile(obj.path.join(xfile.fullpath, filename), filedata, function () {
|
||||
obj.parent.DispatchEvent([user._id], obj, 'updatefiles') // Fire an event causing this user to update this files
|
||||
obj.parent.DispatchEvent([user._id], obj, 'updatefiles'); // Fire an event causing this user to update this files
|
||||
});
|
||||
});
|
||||
})(xfile.fullpath, names[i], filedata);
|
||||
@ -1027,7 +1029,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
||||
var file = files.files[i], fpath = obj.path.join(xfile.fullpath, file.originalFilename);
|
||||
if (obj.common.IsFilenameValid(file.originalFilename) && ((totalsize + file.size) < xfile.quota)) { // Check if quota would not be broken if we add this file
|
||||
obj.fs.rename(file.path, fpath, function () {
|
||||
obj.parent.DispatchEvent([user._id], obj, 'updatefiles') // Fire an event causing this user to update this files
|
||||
obj.parent.DispatchEvent([user._id], obj, 'updatefiles'); // Fire an event causing this user to update this files
|
||||
});
|
||||
} else {
|
||||
try { obj.fs.unlink(file.path); } catch (e) { }
|
||||
@ -1051,7 +1053,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
||||
obj.parent.RemoveAllEventDispatch(target);
|
||||
obj.parent.AddEventDispatch(subscriptions, target);
|
||||
return subscriptions;
|
||||
}
|
||||
};
|
||||
|
||||
// Handle a web socket relay request
|
||||
function handleRelayWebSocket(ws, req) {
|
||||
@ -1143,13 +1145,13 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
||||
// CIRA ---> TLS
|
||||
Debug(3, 'Relay TLS CIRA data', data.length);
|
||||
if (data.length > 0) { try { ser.updateBuffer(Buffer.from(data, 'binary')); } catch (e) { } }
|
||||
}
|
||||
};
|
||||
|
||||
// Handke CIRA tunnel state change
|
||||
chnl.onStateChange = function (ciraconn, state) {
|
||||
Debug(2, 'Relay TLS CIRA state change', state);
|
||||
if (state == 0) { try { ws.close(); } catch (e) { } }
|
||||
}
|
||||
};
|
||||
|
||||
// TLSSocket to encapsulate TLS communication, which then tunneled via SerialTunnel an then wrapped through CIRA APF
|
||||
var TLSSocket = require('tls').TLSSocket;
|
||||
@ -1199,18 +1201,18 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
||||
ws.forwardclient.onStateChange = function (ciraconn, state) {
|
||||
Debug(2, 'Relay CIRA state change', state);
|
||||
if (state == 0) { try { ws.close(); } catch (e) { } }
|
||||
}
|
||||
};
|
||||
|
||||
ws.forwardclient.onData = function (ciraconn, data) {
|
||||
Debug(4, 'Relay CIRA data', data.length);
|
||||
if (ws.interceptor) { data = ws.interceptor.processAmtData(data); } // Run data thru interceptor
|
||||
if (data.length > 0) { try { ws.send(data); } catch (e) { } } // TODO: Add TLS support
|
||||
}
|
||||
};
|
||||
|
||||
ws.forwardclient.onSendOk = function (ciraconn) {
|
||||
// TODO: Flow control? (Dont' really need it with AMT, but would be nice)
|
||||
//console.log('onSendOk');
|
||||
}
|
||||
};
|
||||
|
||||
// Fetch Intel AMT credentials & Setup interceptor
|
||||
if (req.query.p == 1) {
|
||||
@ -1345,7 +1347,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
||||
var r = 0, dir;
|
||||
try { dir = obj.fs.readdirSync(path); } catch (e) { return 0; }
|
||||
for (var i in dir) {
|
||||
var stat = obj.fs.statSync(path + '/' + dir[i])
|
||||
var stat = obj.fs.statSync(path + '/' + dir[i]);
|
||||
if ((stat.mode & 0x004000) == 0) { r += stat.size; } else { r += readTotalFileSize(path + '/' + dir[i]); }
|
||||
}
|
||||
return r;
|
||||
@ -1359,15 +1361,15 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
||||
if (obj.fs.lstatSync(pathx).isDirectory()) { deleteFolderRec(pathx); } else { obj.fs.unlinkSync(pathx); }
|
||||
});
|
||||
obj.fs.rmdirSync(path);
|
||||
};
|
||||
}
|
||||
|
||||
// Handle Intel AMT events
|
||||
// To subscribe, add "http://server:port/amtevents.ashx" to Intel AMT subscriptions.
|
||||
obj.handleAmtEventRequest = function (req, res) {
|
||||
var domain = getDomain(req);
|
||||
try {
|
||||
if (req.headers['authorization']) {
|
||||
var authstr = req.headers['authorization'];
|
||||
if (req.headers.authorization) {
|
||||
var authstr = req.headers.authorization;
|
||||
if (authstr.substring(0, 7) == "Digest ") {
|
||||
var auth = obj.common.parseNameValueList(obj.common.quoteSplit(authstr.substring(7)));
|
||||
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) {
|
||||
res.set({ 'WWW-Authenticate': 'Digest realm="' + obj.httpAuthRealm + '", qop="auth,auth-int", nonce="' + nonce + '", opaque="' + opaque + '"' });
|
||||
res.sendStatus(401);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// Handle a server backup request
|
||||
function handleBackupRequest(req, res) {
|
||||
@ -1541,11 +1543,11 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
||||
// If the agentid is 3 or 4, check if we have a signed MeshCmd.exe
|
||||
if ((agentid == 3)) { // Signed Windows MeshCmd.exe x86
|
||||
var stats = null, meshCmdPath = obj.path.join(__dirname, 'agents', 'MeshCmd-signed.exe');
|
||||
try { stats = obj.fs.statSync(meshCmdPath) } catch (e) { }
|
||||
try { stats = obj.fs.statSync(meshCmdPath); } catch (e) { }
|
||||
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; }
|
||||
} else if ((agentid == 4)) { // Signed Windows MeshCmd64.exe x64
|
||||
var stats = null, meshCmd64Path = obj.path.join(__dirname, 'agents', 'MeshCmd64-signed.exe');
|
||||
try { stats = obj.fs.statSync(meshCmd64Path) } catch (e) { }
|
||||
try { stats = obj.fs.statSync(meshCmd64Path); } catch (e) { }
|
||||
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; }
|
||||
}
|
||||
// No signed agents, we are going to merge a new MeshCmd.
|
||||
@ -1581,7 +1583,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
||||
serverId: obj.agentCertificateHashHex.toUpperCase(), // SHA384 of server HTTPS public key
|
||||
serverHttpsHash: new Buffer(obj.webCertificateHash, 'binary').toString('hex').toUpperCase(), // SHA384 of server HTTPS certificate
|
||||
debugLevel: 0
|
||||
}
|
||||
};
|
||||
if (user != null) { meshaction.username = user.name; }
|
||||
var httpsPort = ((obj.args.aliasport == null) ? obj.args.port : obj.args.aliasport); // Use HTTPS alias port is specified
|
||||
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) {
|
||||
serverId: obj.agentCertificateHashHex.toUpperCase(), // SHA384 of server HTTPS public key
|
||||
serverHttpsHash: new Buffer(obj.webCertificateHash, 'binary').toString('hex').toUpperCase(), // SHA384 of server HTTPS certificate
|
||||
debugLevel: 0
|
||||
}
|
||||
};
|
||||
if (user != null) { meshaction.username = user.name; }
|
||||
var httpsPort = ((obj.args.aliasport == null) ? obj.args.port : obj.args.aliasport); // Use HTTPS alias port is specified
|
||||
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) {
|
||||
response += '</table></body></html>';
|
||||
res.send(response);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Get the web server hostname. This may change if using a domain with a DNS name.
|
||||
function getWebServerName(domain) {
|
||||
@ -1660,7 +1662,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
||||
|
||||
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' });
|
||||
res.send(meshsettings);
|
||||
}
|
||||
};
|
||||
|
||||
// Add HTTP security headers to all responses
|
||||
obj.app.use(function (req, res, next) {
|
||||
@ -1785,7 +1787,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
||||
// Check we have agent rights
|
||||
var rights = user.links[agent.dbMeshKey].rights;
|
||||
if ((rights != null) && ((rights & MESHRIGHT_AGENTCONSOLE) != 0) && (user.siteadmin == 0xFFFFFFFF)) { agent.close(disconnectMode); }
|
||||
}
|
||||
};
|
||||
|
||||
// Send the core module to the mesh agent
|
||||
obj.sendMeshAgentCore = function (user, domain, nodeid, core) {
|
||||
@ -1815,7 +1817,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
||||
agent.send(obj.common.ShortToStr(10) + obj.common.ShortToStr(0) + hash + core);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Get the server path of a user or mesh object
|
||||
function getServerRootFilePath(obj) {
|
||||
@ -1878,36 +1880,37 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
||||
|
||||
// Count sessions and event any changes
|
||||
obj.recountSessions = function (changedSessionId) {
|
||||
var userid, oldcount, newcount, x, serverid;
|
||||
if (changedSessionId == null) {
|
||||
// Recount all sessions
|
||||
|
||||
// Calculate the session count for all userid's
|
||||
var newSessionsCount = {};
|
||||
for (var userid in obj.wssessions) { newSessionsCount[userid] = obj.wssessions[userid].length; }
|
||||
for (var serverid in obj.wsPeerSessions3) {
|
||||
for (var userid in obj.wsPeerSessions3[serverid]) {
|
||||
var c = obj.wsPeerSessions3[serverid][userid].length;
|
||||
if (newSessionsCount[userid] == null) { newSessionsCount[userid] = c; } else { newSessionsCount[userid] += c; }
|
||||
for (userid in obj.wssessions) { newSessionsCount[userid] = obj.wssessions[userid].length; }
|
||||
for (serverid in obj.wsPeerSessions3) {
|
||||
for (userid in obj.wsPeerSessions3[serverid]) {
|
||||
x = obj.wsPeerSessions3[serverid][userid].length;
|
||||
if (newSessionsCount[userid] == null) { newSessionsCount[userid] = x; } else { newSessionsCount[userid] += x; }
|
||||
}
|
||||
}
|
||||
|
||||
// See what session counts have changed, event any changes
|
||||
for (var userid in newSessionsCount) {
|
||||
var newcount = newSessionsCount[userid];
|
||||
var oldcount = obj.sessionsCount[userid];
|
||||
for (userid in newSessionsCount) {
|
||||
newcount = newSessionsCount[userid];
|
||||
oldcount = obj.sessionsCount[userid];
|
||||
if (oldcount == null) { oldcount = 0; } else { delete obj.sessionsCount[userid]; }
|
||||
if (newcount != oldcount) {
|
||||
var x = userid.split('/');
|
||||
obj.parent.DispatchEvent(['*'], obj, { action: 'wssessioncount', username: x[2], count: newcount, domain: x[1], nolog: 1, nopeers: 1 })
|
||||
x = userid.split('/');
|
||||
obj.parent.DispatchEvent(['*'], obj, { action: 'wssessioncount', username: x[2], count: newcount, domain: x[1], nolog: 1, nopeers: 1 });
|
||||
}
|
||||
}
|
||||
|
||||
// If there are any counts left in the old counts, event to zero
|
||||
for (var userid in obj.sessionsCount) {
|
||||
var oldcount = obj.sessionsCount[userid];
|
||||
for (userid in obj.sessionsCount) {
|
||||
oldcount = obj.sessionsCount[userid];
|
||||
if ((oldcount != null) && (oldcount != 0)) {
|
||||
var x = userid.split('/');
|
||||
obj.parent.DispatchEvent(['*'], obj, { action: 'wssessioncount', username: x[2], count: 0, domain: x[1], nolog: 1, nopeers: 1 })
|
||||
x = userid.split('/');
|
||||
obj.parent.DispatchEvent(['*'], obj, { action: 'wssessioncount', username: x[2], count: 0, domain: x[1], nolog: 1, nopeers: 1 });
|
||||
}
|
||||
}
|
||||
|
||||
@ -1915,23 +1918,23 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
||||
obj.sessionsCount = newSessionsCount;
|
||||
} else {
|
||||
// Figure out the userid
|
||||
var userid = changedSessionId.split('/').slice(0, 3).join('/');
|
||||
userid = changedSessionId.split('/').slice(0, 3).join('/');
|
||||
|
||||
// Recount only changedSessionId
|
||||
var newcount = 0;
|
||||
newcount = 0;
|
||||
if (obj.wssessions[userid] != null) { newcount = obj.wssessions[userid].length; }
|
||||
for (var serverid in obj.wsPeerSessions3) { if (obj.wsPeerSessions3[serverid][userid] != null) { newcount += obj.wsPeerSessions3[serverid][userid].length; } }
|
||||
var oldcount = obj.sessionsCount[userid];
|
||||
for (serverid in obj.wsPeerSessions3) { if (obj.wsPeerSessions3[serverid][userid] != null) { newcount += obj.wsPeerSessions3[serverid][userid].length; } }
|
||||
oldcount = obj.sessionsCount[userid];
|
||||
if (oldcount == null) { oldcount = 0; }
|
||||
|
||||
// If the count changed, update and event
|
||||
if (newcount != oldcount) {
|
||||
var x = userid.split('/');
|
||||
obj.parent.DispatchEvent(['*'], obj, { action: 'wssessioncount', username: x[2], count: newcount, domain: x[1], nolog: 1, nopeers: 1 })
|
||||
x = userid.split('/');
|
||||
obj.parent.DispatchEvent(['*'], obj, { action: 'wssessioncount', username: x[2], count: newcount, domain: x[1], nolog: 1, nopeers: 1 });
|
||||
obj.sessionsCount[userid] = newcount;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Return true if a mobile browser is detected.
|
||||
// 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) {
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
};
|
@ -6,7 +6,12 @@
|
||||
* @version v0.0.1
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
/*jslint node: true */
|
||||
/*jshint node: true */
|
||||
/*jshint strict:false */
|
||||
/*jshint -W097 */
|
||||
/*jshint esversion: 6 */
|
||||
"use strict";
|
||||
|
||||
// This module is only called when MeshCentral is running as a Windows service.
|
||||
// In this case, we don't want to start a child process, so we launch directly without arguments.
|
||||
|
Loading…
Reference in New Issue
Block a user