mirror of
				https://github.com/Ylianst/MeshCentral.git
				synced 2025-03-09 15:40:18 +00:00 
			
		
		
		
	Added new account creation and server peering flow control
This commit is contained in:
		
							parent
							
								
									fb5114399f
								
							
						
					
					
						commit
						040440db79
					
				
					 7 changed files with 530 additions and 193 deletions
				
			
		
							
								
								
									
										56
									
								
								meshagent.js
									
										
									
									
									
								
							
							
						
						
									
										56
									
								
								meshagent.js
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -83,7 +83,7 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
 | 
			
		|||
                }
 | 
			
		||||
            }
 | 
			
		||||
            else if (cmdid == 12) { // MeshCommand_AgentHash
 | 
			
		||||
                if ((msg.length == 36) && (obj.agentInfo != undefined) && (obj.agentInfo.update == true)) {
 | 
			
		||||
                if ((msg.length == 36) && (obj.agentInfo != null) && (obj.agentInfo.update == true)) {
 | 
			
		||||
                    var agenthash = obj.common.rstr2hex(msg.substring(4)).toLowerCase();
 | 
			
		||||
                    if (agenthash != obj.agentInfo.hash) {
 | 
			
		||||
                        // Mesh agent update required
 | 
			
		||||
| 
						 | 
				
			
			@ -168,7 +168,7 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
 | 
			
		|||
                obj.send(obj.common.ShortToStr(2) + obj.common.ShortToStr(parent.agentCertificatAsn1.length) + parent.agentCertificatAsn1 + privateKey.sign(md)); // Command 2, certificate + signature
 | 
			
		||||
 | 
			
		||||
                // Check the agent signature if we can
 | 
			
		||||
                if (obj.unauthsign != undefined) {
 | 
			
		||||
                if (obj.unauthsign != null) {
 | 
			
		||||
                    if (processAgentSignature(obj.unauthsign) == false) { disonnect(); return; } else { completeAgentConnection(); }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			@ -185,7 +185,7 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
 | 
			
		|||
                obj.unauth.nodeid = obj.forge.pki.getPublicKeyFingerprint(obj.unauth.nodeCert.publicKey, { encoding: 'hex', md: obj.forge.md.sha256.create() });
 | 
			
		||||
 | 
			
		||||
                // Check the agent signature if we can
 | 
			
		||||
                if (obj.agentnonce == undefined) { obj.unauthsign = msg.substring(4 + certlen); } else { if (processAgentSignature(msg.substring(4 + certlen)) == false) { disonnect(); return; } }
 | 
			
		||||
                if (obj.agentnonce == null) { obj.unauthsign = msg.substring(4 + certlen); } else { if (processAgentSignature(msg.substring(4 + certlen)) == false) { disonnect(); return; } }
 | 
			
		||||
                completeAgentConnection();
 | 
			
		||||
            }
 | 
			
		||||
            else if (cmd == 3) {
 | 
			
		||||
| 
						 | 
				
			
			@ -248,7 +248,7 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
 | 
			
		|||
                } else {
 | 
			
		||||
                    // Device already exists, look if changes has occured
 | 
			
		||||
                    device = nodes[0];
 | 
			
		||||
                    if (device.agent == undefined) {
 | 
			
		||||
                    if (device.agent == null) {
 | 
			
		||||
                        device.agent = { ver: obj.agentInfo.agentVersion, id: obj.agentInfo.agentId, caps: obj.agentInfo.capabilities }; change = 1;
 | 
			
		||||
                    } else {
 | 
			
		||||
                        var changes = [], change = 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -292,7 +292,7 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
 | 
			
		|||
 | 
			
		||||
                // Check if we need to make an native update check
 | 
			
		||||
                obj.agentInfo = obj.parent.parent.meshAgentBinaries[obj.agentInfo.agentId];
 | 
			
		||||
                if ((obj.agentInfo != undefined) && (obj.agentInfo.update == true)) { obj.send(obj.common.ShortToStr(12) + obj.common.ShortToStr(0)); } // Ask the agent for it's executable binary hash
 | 
			
		||||
                if ((obj.agentInfo != null) && (obj.agentInfo.update == true)) { obj.send(obj.common.ShortToStr(12) + obj.common.ShortToStr(0)); } // Ask the agent for it's executable binary hash
 | 
			
		||||
 | 
			
		||||
                // Check if we already have IP location information for this node
 | 
			
		||||
                obj.db.Get('iploc_' + obj.remoteaddr, function (err, iplocs) {
 | 
			
		||||
| 
						 | 
				
			
			@ -364,52 +364,64 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
 | 
			
		|||
                    {
 | 
			
		||||
                        // Route a message.
 | 
			
		||||
                        // If this command has a sessionid, that is the target.
 | 
			
		||||
                        if (command.sessionid != undefined) {
 | 
			
		||||
                        if (command.sessionid != null) {
 | 
			
		||||
                            var splitsessionid = command.sessionid.split('/');
 | 
			
		||||
                            // Check that we are in the same domain and the user has rights over this node.
 | 
			
		||||
                            if ((splitsessionid[0] == 'user') && (splitsessionid[1] == domain.id)) {
 | 
			
		||||
                                // Check if this user has rights to get this message
 | 
			
		||||
                                //if (mesh.links[user._id] == undefined || ((mesh.links[user._id].rights & 16) == 0)) return; // TODO!!!!!!!!!!!!!!!!!!!!!
 | 
			
		||||
                                //if (mesh.links[user._id] == null || ((mesh.links[user._id].rights & 16) == 0)) return; // TODO!!!!!!!!!!!!!!!!!!!!!
 | 
			
		||||
                                
 | 
			
		||||
                                // See if the session is connected
 | 
			
		||||
                                // See if the session is connected. If so, go ahead and send this message to the target node
 | 
			
		||||
                                var ws = obj.parent.wssessions2[command.sessionid];
 | 
			
		||||
                                
 | 
			
		||||
                                // Go ahead and send this message to the target node
 | 
			
		||||
                                if (ws != undefined) {
 | 
			
		||||
                                if (ws != null) {
 | 
			
		||||
                                    command.nodeid = obj.dbNodeKey; // Set the nodeid, required for responses.
 | 
			
		||||
                                    delete command.sessionid;       // Remove the sessionid, since we are sending to that sessionid, so it's implyed.
 | 
			
		||||
                                    ws.send(JSON.stringify(command));
 | 
			
		||||
                                } else if (obj.parent.parent.multiServer != null) {
 | 
			
		||||
                                    // We need to send this message to other servers
 | 
			
		||||
                                    command.fromNodeid = obj.dbNodeKey;
 | 
			
		||||
                                    obj.parent.parent.multiServer.DispatchMessage(command);
 | 
			
		||||
                                }
 | 
			
		||||
                            }
 | 
			
		||||
                        } else if (command.userid != undefined) { // If this command has a userid, that is the target.
 | 
			
		||||
                        } else if (command.userid != null) { // If this command has a userid, that is the target.
 | 
			
		||||
                            var splituserid = command.userid.split('/');
 | 
			
		||||
                            // Check that we are in the same domain and the user has rights over this node.
 | 
			
		||||
                            if ((splituserid[0] == 'user') && (splituserid[1] == domain.id)) {
 | 
			
		||||
                                // Check if this user has rights to get this message
 | 
			
		||||
                                //if (mesh.links[user._id] == undefined || ((mesh.links[user._id].rights & 16) == 0)) return; // TODO!!!!!!!!!!!!!!!!!!!!!
 | 
			
		||||
                                //if (mesh.links[user._id] == null || ((mesh.links[user._id].rights & 16) == 0)) return; // TODO!!!!!!!!!!!!!!!!!!!!!
 | 
			
		||||
 | 
			
		||||
                                // See if the session is connected
 | 
			
		||||
                                var sessions = obj.parent.wssessions[command.userid];
 | 
			
		||||
 | 
			
		||||
                                // Go ahead and send this message to the target node
 | 
			
		||||
                                if (sessions != undefined) {
 | 
			
		||||
                                if (sessions != null) {
 | 
			
		||||
                                    command.nodeid = obj.dbNodeKey; // Set the nodeid, required for responses.
 | 
			
		||||
                                    delete command.userid;          // Remove the userid, since we are sending to that userid, so it's implyed.
 | 
			
		||||
                                    for (var i in sessions) { sessions[i].send(JSON.stringify(command)); }
 | 
			
		||||
                                }
 | 
			
		||||
                            }
 | 
			
		||||
                        } else { // Route this command to the mesh
 | 
			
		||||
                            command.nodeid = obj.dbNodeKey;
 | 
			
		||||
                            var cmdstr = JSON.stringify(command);
 | 
			
		||||
                            for (var userid in obj.parent.wssessions) { // Find all connected users for this mesh and send the message
 | 
			
		||||
                                var user = obj.parent.users[userid];
 | 
			
		||||
                                if (user) {
 | 
			
		||||
                                    var rights = user.links[obj.dbMeshKey];
 | 
			
		||||
                                    if (rights != undefined) { // TODO: Look at what rights are needed for message routing
 | 
			
		||||
                                        command.nodeid = obj.dbNodeKey;
 | 
			
		||||
                                    if (rights != null) { // TODO: Look at what rights are needed for message routing
 | 
			
		||||
                                        var sessions = obj.parent.wssessions[userid];
 | 
			
		||||
                                        for (var i in sessions) { sessions[i].send(JSON.stringify(command)); }
 | 
			
		||||
                                        // Send the message to all users on this server
 | 
			
		||||
                                        for (var i in sessions) { sessions[i].send(cmdstr); }
 | 
			
		||||
                                    }
 | 
			
		||||
                                }
 | 
			
		||||
                            }
 | 
			
		||||
 | 
			
		||||
                            // Send the message to all users of other servers
 | 
			
		||||
                            if (obj.parent.parent.multiServer != null) {
 | 
			
		||||
                                delete command.nodeid;
 | 
			
		||||
                                command.fromNodeid = obj.dbNodeKey;
 | 
			
		||||
                                command.meshid = obj.dbMeshKey;
 | 
			
		||||
                                obj.parent.parent.multiServer.DispatchMessage(command);
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                        break;
 | 
			
		||||
                    }
 | 
			
		||||
| 
						 | 
				
			
			@ -455,10 +467,10 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
 | 
			
		|||
 | 
			
		||||
    // Change the current core information string and event it
 | 
			
		||||
    function ChangeAgentCoreInfo(command) {
 | 
			
		||||
        if ((command == undefined) || (command == null)) return; // Safety, should never happen.
 | 
			
		||||
        if ((command == null) || (command == null)) return; // Safety, should never happen.
 | 
			
		||||
 | 
			
		||||
        // Check capabilities value
 | 
			
		||||
        if (command.caps == undefined || command.caps == null) { command.caps = 0; } else { if (typeof command.caps != 'number') command.caps = 0; }
 | 
			
		||||
        if (command.caps == null || command.caps == null) { command.caps = 0; } else { if (typeof command.caps != 'number') command.caps = 0; }
 | 
			
		||||
 | 
			
		||||
        // Check that the mesh exists
 | 
			
		||||
        obj.db.Get(obj.dbMeshKey, function (err, meshes) {
 | 
			
		||||
| 
						 | 
				
			
			@ -472,7 +484,7 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
 | 
			
		|||
                    var changes = [], change = 0;
 | 
			
		||||
 | 
			
		||||
                    // Check if anything changes
 | 
			
		||||
                    if (device.agent.core != command.value) { if ((command.value == null) && (device.agent.core != undefined)) { delete device.agent.core; } else { device.agent.core = command.value; } change = 1; changes.push('agent core'); }
 | 
			
		||||
                    if (device.agent.core != command.value) { if ((command.value == null) && (device.agent.core != null)) { delete device.agent.core; } else { device.agent.core = command.value; } change = 1; changes.push('agent core'); }
 | 
			
		||||
                    if ((device.agent.caps & 0xFFFFFFE7) != (command.caps & 0xFFFFFFE7)) { device.agent.caps = ((device.agent.caps & 24) + (command.caps & 0xFFFFFFE7)); change = 1; changes.push('agent capabilities'); } // Allow Javascript on the agent to change all capabilities except console and javascript support
 | 
			
		||||
                    if (command.intelamt) {
 | 
			
		||||
                        if (!device.intelamt) { device.intelamt = {}; }
 | 
			
		||||
| 
						 | 
				
			
			@ -504,7 +516,7 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
 | 
			
		|||
 | 
			
		||||
    // Change the current core information string and event it
 | 
			
		||||
    function ChangeAgentLocationInfo(command) {
 | 
			
		||||
        if ((command == undefined) || (command == null)) return; // Safety, should never happen.
 | 
			
		||||
        if ((command == null) || (command == null)) return; // Safety, should never happen.
 | 
			
		||||
 | 
			
		||||
        // Check that the mesh exists
 | 
			
		||||
        obj.db.Get(obj.dbMeshKey, function (err, meshes) {
 | 
			
		||||
| 
						 | 
				
			
			@ -539,7 +551,7 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
 | 
			
		|||
 | 
			
		||||
    // Update the mesh agent tab in the database
 | 
			
		||||
    function ChangeAgentTag(tag) {
 | 
			
		||||
        if (tag.length == 0) { tag = undefined; }
 | 
			
		||||
        if (tag.length == 0) { tag = null; }
 | 
			
		||||
        // Get the node and change it if needed
 | 
			
		||||
        obj.db.Get(obj.dbNodeKey, function (err, nodes) {
 | 
			
		||||
            if (nodes.length != 1) return;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -37,7 +37,7 @@ function CreateMeshCentralServer() {
 | 
			
		|||
    obj.currentVer = null;
 | 
			
		||||
    obj.maintenanceTimer = null;
 | 
			
		||||
    obj.serverId = null;
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    // Create data and files folders if needed
 | 
			
		||||
    try { obj.fs.mkdirSync(obj.datapath); } catch (e) { }
 | 
			
		||||
    try { obj.fs.mkdirSync(obj.filespath); } catch (e) { }
 | 
			
		||||
| 
						 | 
				
			
			@ -84,7 +84,7 @@ function CreateMeshCentralServer() {
 | 
			
		|||
        // 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', 'mpsport', 'redirport', 'exactport', 'debug'];
 | 
			
		||||
            for (var i in xenv) { if (obj.args[xenv[i]] != undefined) { env.push({ name: 'mesh' + xenv[i], value: obj.args[xenv[i]] }); } } // Set some args as service environement variables.
 | 
			
		||||
            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: process.argv[1] + '.js', env: env, wait: 2, grow: .5 });
 | 
			
		||||
            svc.on('install', function () { console.log('MeshCentral service installed.'); svc.start(); });
 | 
			
		||||
            svc.on('uninstall', function () { console.log('MeshCentral service uninstalled.'); process.exit(); });
 | 
			
		||||
| 
						 | 
				
			
			@ -150,7 +150,7 @@ function CreateMeshCentralServer() {
 | 
			
		|||
 | 
			
		||||
    // Get current and latest MeshCentral server versions using NPM
 | 
			
		||||
    obj.getLatestServerVersion = function (callback) {
 | 
			
		||||
        if (callback == undefined) return;
 | 
			
		||||
        if (callback == null) return;
 | 
			
		||||
        var child_process = require('child_process');
 | 
			
		||||
        var xprocess = child_process.exec('npm view meshcentral dist-tags.latest', function (error, stdout, stderr) { });
 | 
			
		||||
        xprocess.data = '';
 | 
			
		||||
| 
						 | 
				
			
			@ -177,20 +177,20 @@ function CreateMeshCentralServer() {
 | 
			
		|||
        if (require('fs').existsSync(obj.path.join(obj.datapath, 'config.json'))) {
 | 
			
		||||
            // Load and validate the configuration file
 | 
			
		||||
            try { obj.config = require(obj.path.join(obj.datapath, 'config.json')); } catch (e) { console.log('ERROR: Unable to parse ./data/config.json.'); return; }
 | 
			
		||||
            if (obj.config.domains == undefined) { obj.config.domains = {}; }
 | 
			
		||||
            if (obj.config.domains == null) { obj.config.domains = {}; }
 | 
			
		||||
            for (var i in obj.config.domains) { if ((i.split('/').length > 1) || (i.split(' ').length > 1)) { console.log("ERROR: Error in config.json, domain names can't have spaces or /."); return; } }
 | 
			
		||||
            
 | 
			
		||||
            // Set the command line arguments to the config file if they are not present
 | 
			
		||||
            if (obj.config.settings) { for (var i in obj.config.settings) { if (obj.args[i] == undefined) obj.args[i] = obj.config.settings[i]; } }
 | 
			
		||||
            if (obj.config.settings) { for (var i in obj.config.settings) { if (obj.args[i] == null) obj.args[i] = obj.config.settings[i]; } }
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        // Read environment variables. For a subset of arguments, we allow them to be read from environment variables.
 | 
			
		||||
        var xenv = ['user', 'port', 'mpsport', 'redirport', 'exactport', 'debug'];
 | 
			
		||||
        for (var i in xenv) { if ((obj.args[xenv[i]] == undefined) && (process.env['mesh' + xenv[i]])) { obj.args[xenv[i]] = obj.common.toNumber(process.env['mesh' + xenv[i]]); } }
 | 
			
		||||
        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]]); } }
 | 
			
		||||
        
 | 
			
		||||
        // Validate the domains, this is used for multi-hosting
 | 
			
		||||
        if (obj.config.domains == undefined) { obj.config.domains = {}; }
 | 
			
		||||
        if (obj.config.domains[''] == undefined) { obj.config.domains[''] = { }; }
 | 
			
		||||
        if (obj.config.domains == null) { obj.config.domains = {}; }
 | 
			
		||||
        if (obj.config.domains[''] == null) { obj.config.domains[''] = { }; }
 | 
			
		||||
        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 1'; } 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; } } }
 | 
			
		||||
| 
						 | 
				
			
			@ -200,11 +200,11 @@ function CreateMeshCentralServer() {
 | 
			
		|||
        //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); }
 | 
			
		||||
 | 
			
		||||
        // Look at passed in arguments
 | 
			
		||||
        if ((obj.args.ciralocalfqdn != undefined) && ((obj.args.lanonly == true) || (obj.args.wanonly == true))) { console.log("WARNING: CIRA local FQDN's ignored when server in LAN-only or WAN-only mode."); }
 | 
			
		||||
        if ((obj.args.ciralocalfqdn != undefined) && (obj.args.ciralocalfqdn.split(',').length > 4)) { console.log("WARNING: Can't have more than 4 CIRA local FQDN's. Ignoring value."); obj.args.ciralocalfqdn = undefined; }
 | 
			
		||||
        if (obj.args.port == undefined || typeof obj.args.port != 'number') { if (obj.args.notls == undefined) { obj.args.port = 443; } else { obj.args.port = 80; } }
 | 
			
		||||
        if (obj.args.mpsport == undefined || typeof obj.args.mpsport != 'number') obj.args.mpsport = 4433;
 | 
			
		||||
        if (obj.args.notls == undefined && obj.args.redirport == undefined) obj.args.redirport = 80;
 | 
			
		||||
        if ((obj.args.ciralocalfqdn != null) && ((obj.args.lanonly == true) || (obj.args.wanonly == true))) { console.log("WARNING: CIRA local FQDN's ignored when server in LAN-only or WAN-only mode."); }
 | 
			
		||||
        if ((obj.args.ciralocalfqdn != null) && (obj.args.ciralocalfqdn.split(',').length > 4)) { console.log("WARNING: Can't have more than 4 CIRA local FQDN's. Ignoring value."); obj.args.ciralocalfqdn = null; }
 | 
			
		||||
        if (obj.args.port == null || typeof obj.args.port != 'number') { if (obj.args.notls == null) { obj.args.port = 443; } else { obj.args.port = 80; } }
 | 
			
		||||
        if (obj.args.mpsport == null || typeof obj.args.mpsport != 'number') obj.args.mpsport = 4433;
 | 
			
		||||
        if (obj.args.notls == null && obj.args.redirport == null) obj.args.redirport = 80;
 | 
			
		||||
        if (typeof obj.args.debug == 'number') obj.debugLevel = obj.args.debug;
 | 
			
		||||
        if (obj.args.debug == true) obj.debugLevel = 1;
 | 
			
		||||
        obj.db = require('./db.js').CreateDB(obj.args, obj.datapath);
 | 
			
		||||
| 
						 | 
				
			
			@ -249,13 +249,13 @@ function CreateMeshCentralServer() {
 | 
			
		|||
            // Read or setup database configuration values
 | 
			
		||||
            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 == undefined) { require('crypto').randomBytes(32, function (err, buf) { obj.dbconfig.amtWsEventSecret = buf.toString('hex'); obj.db.Set(obj.dbconfig); }); }
 | 
			
		||||
                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) {
 | 
			
		||||
                        require('crypto').randomBytes(6, function (err, buf) {
 | 
			
		||||
                            while (obj.dbconfig.amtWsEventSecret == undefined) { process.nextTick(); }
 | 
			
		||||
                            while (obj.dbconfig.amtWsEventSecret == null) { process.nextTick(); }
 | 
			
		||||
                            var username = buf.toString('hex');
 | 
			
		||||
                            var nodeid = obj.args.getwspass;
 | 
			
		||||
                            var pass = require('crypto').createHash('sha256').update(username.toLowerCase() + ":" + nodeid.toUpperCase() + ":" + obj.dbconfig.amtWsEventSecret).digest("base64").substring(0, 12).split("/").join("x").split("\\").join("x");
 | 
			
		||||
| 
						 | 
				
			
			@ -292,7 +292,7 @@ function CreateMeshCentralServer() {
 | 
			
		|||
                        // Setup Mesh Multi-Server if needed
 | 
			
		||||
                        obj.multiServer = require('./multiserver.js').CreateMultiServer(obj, obj.args);
 | 
			
		||||
                        if (obj.multiServer != null) {
 | 
			
		||||
                            obj.serverId = obj.config.peers.serverId;
 | 
			
		||||
                            obj.serverId = obj.multiServer.serverid;
 | 
			
		||||
                            for (var serverid in obj.config.peers.servers) { obj.peerConnectivityByNode[serverid] = {}; }
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -305,7 +305,7 @@ function CreateMeshCentralServer() {
 | 
			
		|||
                        }
 | 
			
		||||
 | 
			
		||||
                        // Setup and start the redirection server if needed
 | 
			
		||||
                        if ((obj.args.redirport != undefined) && (typeof obj.args.redirport == 'number') && (obj.args.redirport != 0)) {
 | 
			
		||||
                        if ((obj.args.redirport != null) && (typeof obj.args.redirport == 'number') && (obj.args.redirport != 0)) {
 | 
			
		||||
                            obj.redirserver = require('./redirserver.js').CreateRedirServer(obj, obj.db, obj.args, obj.certificates);
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -393,7 +393,7 @@ function CreateMeshCentralServer() {
 | 
			
		|||
    }
 | 
			
		||||
    obj.RemoveEventDispatchId = function (id) {
 | 
			
		||||
        obj.debug(3, 'RemoveEventDispatchId', id);
 | 
			
		||||
        if (obj.eventsDispatch[id] != undefined) { delete obj.eventsDispatch[id]; }
 | 
			
		||||
        if (obj.eventsDispatch[id] != null) { delete obj.eventsDispatch[id]; }
 | 
			
		||||
    }
 | 
			
		||||
    obj.RemoveAllEventDispatch = function (target) {
 | 
			
		||||
        obj.debug(3, 'RemoveAllEventDispatch');
 | 
			
		||||
| 
						 | 
				
			
			@ -420,13 +420,24 @@ function CreateMeshCentralServer() {
 | 
			
		|||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        if ((fromPeerServer == undefined) && (obj.multiServer != null) && (event.nopeers != 1)) { obj.multiServer.DispatchEvent(ids, source, event); }
 | 
			
		||||
        if ((fromPeerServer == null) && (obj.multiServer != null) && (event.nopeers != 1)) { obj.multiServer.DispatchEvent(ids, source, event); }
 | 
			
		||||
        delete targets;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Get the connection state of a node
 | 
			
		||||
    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) {
 | 
			
		||||
            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
 | 
			
		||||
    obj.UpdateConnectivityState = function (nodeids) {
 | 
			
		||||
| 
						 | 
				
			
			@ -501,7 +512,7 @@ function CreateMeshCentralServer() {
 | 
			
		|||
            if (connectType == 1) { state.agentPower = powerState; } else if (connectType == 2) { state.ciraPower = powerState; } else if (connectType == 4) { state.amtPower = powerState; }
 | 
			
		||||
            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 == undefined) || (state.powerState != powerState)) {
 | 
			
		||||
            if ((state.powerState == null) || (state.powerState != powerState)) {
 | 
			
		||||
                state.powerState = powerState;
 | 
			
		||||
                eventConnectChange = 1;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -531,7 +542,7 @@ function CreateMeshCentralServer() {
 | 
			
		|||
            if (connectType == 1) { state.agentPower = powerState; } else if (connectType == 2) { state.ciraPower = powerState; } else if (connectType == 4) { state.amtPower = powerState; }
 | 
			
		||||
            var powerState = 0;
 | 
			
		||||
            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 == undefined) || (state.powerState != powerState)) { state.powerState = powerState; }
 | 
			
		||||
            if ((state.powerState == null) || (state.powerState != powerState)) { state.powerState = powerState; }
 | 
			
		||||
 | 
			
		||||
            // Update the combined node state
 | 
			
		||||
            var x = {}; x[nodeid] = 1;
 | 
			
		||||
| 
						 | 
				
			
			@ -552,7 +563,7 @@ function CreateMeshCentralServer() {
 | 
			
		|||
 | 
			
		||||
            // Remove the agent connection from the nodes connection list
 | 
			
		||||
            var state = obj.connectivityByNode[nodeid];
 | 
			
		||||
            if (state == undefined) return;
 | 
			
		||||
            if (state == null) return;
 | 
			
		||||
 | 
			
		||||
            if ((state.connectivity & connectType) != 0) {
 | 
			
		||||
                state.connectivity -= connectType;
 | 
			
		||||
| 
						 | 
				
			
			@ -566,7 +577,7 @@ function CreateMeshCentralServer() {
 | 
			
		|||
            if (connectType == 1) { state.agentPower = 0; } else if (connectType == 2) { state.ciraPower = 0; } else if (connectType == 4) { state.amtPower = 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 == undefined) || (state.powerState != powerState)) {
 | 
			
		||||
            if ((state.powerState == null) || (state.powerState != powerState)) {
 | 
			
		||||
                state.powerState = powerState;
 | 
			
		||||
                eventConnectChange = 1;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -583,7 +594,7 @@ function CreateMeshCentralServer() {
 | 
			
		|||
            if (serverid == null) { serverid = obj.serverId; }
 | 
			
		||||
            if (obj.peerConnectivityByNode[serverid] == null) return; // Guard against unknown serverid's
 | 
			
		||||
            var state = obj.peerConnectivityByNode[serverid][nodeid];
 | 
			
		||||
            if (state == undefined) return;
 | 
			
		||||
            if (state == null) return;
 | 
			
		||||
 | 
			
		||||
            // If existing state exist, remove this connection
 | 
			
		||||
            if ((state.connectivity & connectType) != 0) {
 | 
			
		||||
| 
						 | 
				
			
			@ -597,7 +608,7 @@ function CreateMeshCentralServer() {
 | 
			
		|||
            if (connectType == 1) { state.agentPower = 0; } else if (connectType == 2) { state.ciraPower = 0; } else if (connectType == 4) { state.amtPower = 0; }
 | 
			
		||||
            var powerState = 0;
 | 
			
		||||
            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 == undefined) || (state.powerState != powerState)) { state.powerState = powerState; }
 | 
			
		||||
            if ((state.powerState == null) || (state.powerState != powerState)) { state.powerState = powerState; }
 | 
			
		||||
 | 
			
		||||
            // Update the combined node state
 | 
			
		||||
            var x = {}; x[nodeid] = 1;
 | 
			
		||||
| 
						 | 
				
			
			@ -619,7 +630,7 @@ function CreateMeshCentralServer() {
 | 
			
		|||
                    obj.parent.defaultMeshCore = null;
 | 
			
		||||
                    obj.parent.defaultMeshCoreHash = null;
 | 
			
		||||
                }
 | 
			
		||||
                if (func != undefined) { func(); }
 | 
			
		||||
                if (func != null) { func(); }
 | 
			
		||||
            });
 | 
			
		||||
        } else {
 | 
			
		||||
            // Load default mesh agent core from meshcentral path if present
 | 
			
		||||
| 
						 | 
				
			
			@ -632,7 +643,7 @@ function CreateMeshCentralServer() {
 | 
			
		|||
                    obj.parent.defaultMeshCore = null;
 | 
			
		||||
                    obj.parent.defaultMeshCoreHash = null;
 | 
			
		||||
                }
 | 
			
		||||
                if (func != undefined) { func(); }
 | 
			
		||||
                if (func != null) { func(); }
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -652,7 +663,7 @@ function CreateMeshCentralServer() {
 | 
			
		|||
                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] != undefined) { delete obj.meshAgentInstallScripts[this.info.id]; }
 | 
			
		||||
                    if (obj.meshAgentInstallScripts[this.info.id] != null) { delete obj.meshAgentInstallScripts[this.info.id]; }
 | 
			
		||||
                });
 | 
			
		||||
                stream.on('end', function () {
 | 
			
		||||
                    // Add the agent to the agent table with all information and the hash
 | 
			
		||||
| 
						 | 
				
			
			@ -710,7 +721,7 @@ function CreateMeshCentralServer() {
 | 
			
		|||
                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.meshAgentBinaries[this.info.id] != undefined) { delete obj.meshAgentBinaries[this.info.id]; }
 | 
			
		||||
                    if (obj.meshAgentBinaries[this.info.id] != null) { delete obj.meshAgentBinaries[this.info.id]; }
 | 
			
		||||
                });
 | 
			
		||||
                stream.on('end', function () {
 | 
			
		||||
                    // Add the agent to the agent table with all information and the hash
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										147
									
								
								mesherrors.txt
									
										
									
									
									
								
							
							
						
						
									
										147
									
								
								mesherrors.txt
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -1795,3 +1795,150 @@ TypeError: Cannot read property 'meshid' of null
 | 
			
		|||
    at emitErrorNT (net.js:1265:8)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
-------- 9/13/2017, 11:46:32 AM --------
 | 
			
		||||
 | 
			
		||||
C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\webserver.js:1075
 | 
			
		||||
                                        var r = obj.parent.GetRoutingServerId(command.nodeid, );
 | 
			
		||||
                                                                                              ^
 | 
			
		||||
SyntaxError: Unexpected token )
 | 
			
		||||
    at exports.runInThisContext (vm.js:53:16)
 | 
			
		||||
    at Module._compile (module.js:511:25)
 | 
			
		||||
    at Object.Module._extensions..js (module.js:550:10)
 | 
			
		||||
    at Module.load (module.js:456:32)
 | 
			
		||||
    at tryModuleLoad (module.js:415:12)
 | 
			
		||||
    at Function.Module._load (module.js:407:3)
 | 
			
		||||
    at Module.require (module.js:466:17)
 | 
			
		||||
    at require (internal/module.js:20:19)
 | 
			
		||||
    at InternalFieldObject.ondone (C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\meshcentral.js:304:45)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
-------- 9/13/2017, 11:46:34 AM --------
 | 
			
		||||
 | 
			
		||||
C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\webserver.js:1075
 | 
			
		||||
                                        var r = obj.parent.GetRoutingServerId(command.nodeid, );
 | 
			
		||||
                                                                                              ^
 | 
			
		||||
SyntaxError: Unexpected token )
 | 
			
		||||
    at exports.runInThisContext (vm.js:53:16)
 | 
			
		||||
    at Module._compile (module.js:511:25)
 | 
			
		||||
    at Object.Module._extensions..js (module.js:550:10)
 | 
			
		||||
    at Module.load (module.js:456:32)
 | 
			
		||||
    at tryModuleLoad (module.js:415:12)
 | 
			
		||||
    at Function.Module._load (module.js:407:3)
 | 
			
		||||
    at Module.require (module.js:466:17)
 | 
			
		||||
    at require (internal/module.js:20:19)
 | 
			
		||||
    at InternalFieldObject.ondone (C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\meshcentral.js:304:45)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
-------- 9/13/2017, 11:46:36 AM --------
 | 
			
		||||
 | 
			
		||||
C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\webserver.js:1075
 | 
			
		||||
                                        var r = obj.parent.GetRoutingServerId(command.nodeid, );
 | 
			
		||||
                                                                                              ^
 | 
			
		||||
SyntaxError: Unexpected token )
 | 
			
		||||
    at exports.runInThisContext (vm.js:53:16)
 | 
			
		||||
    at Module._compile (module.js:511:25)
 | 
			
		||||
    at Object.Module._extensions..js (module.js:550:10)
 | 
			
		||||
    at Module.load (module.js:456:32)
 | 
			
		||||
    at tryModuleLoad (module.js:415:12)
 | 
			
		||||
    at Function.Module._load (module.js:407:3)
 | 
			
		||||
    at Module.require (module.js:466:17)
 | 
			
		||||
    at require (internal/module.js:20:19)
 | 
			
		||||
    at InternalFieldObject.ondone (C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\meshcentral.js:304:45)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
-------- 9/14/2017, 10:48:18 AM --------
 | 
			
		||||
 | 
			
		||||
C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\multiserver.js:451
 | 
			
		||||
        console.log(ConnectToPeers);
 | 
			
		||||
                    ^
 | 
			
		||||
 | 
			
		||||
ReferenceError: ConnectToPeers is not defined
 | 
			
		||||
    at Object.obj.ConnectToPeers (C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\multiserver.js:451:21)
 | 
			
		||||
    at Timeout._onTimeout (C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\multiserver.js:531:34)
 | 
			
		||||
    at tryOnTimeout (timers.js:224:11)
 | 
			
		||||
    at Timer.listOnTimeout (timers.js:198:5)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
-------- 9/14/2017, 10:48:21 AM --------
 | 
			
		||||
 | 
			
		||||
C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\multiserver.js:451
 | 
			
		||||
        console.log(ConnectToPeers);
 | 
			
		||||
                    ^
 | 
			
		||||
 | 
			
		||||
ReferenceError: ConnectToPeers is not defined
 | 
			
		||||
    at Object.obj.ConnectToPeers (C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\multiserver.js:451:21)
 | 
			
		||||
    at Timeout._onTimeout (C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\multiserver.js:531:34)
 | 
			
		||||
    at tryOnTimeout (timers.js:224:11)
 | 
			
		||||
    at Timer.listOnTimeout (timers.js:198:5)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
-------- 9/14/2017, 10:48:24 AM --------
 | 
			
		||||
 | 
			
		||||
C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\multiserver.js:451
 | 
			
		||||
        console.log(ConnectToPeers);
 | 
			
		||||
                    ^
 | 
			
		||||
 | 
			
		||||
ReferenceError: ConnectToPeers is not defined
 | 
			
		||||
    at Object.obj.ConnectToPeers (C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\multiserver.js:451:21)
 | 
			
		||||
    at Timeout._onTimeout (C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\multiserver.js:531:34)
 | 
			
		||||
    at tryOnTimeout (timers.js:224:11)
 | 
			
		||||
    at Timer.listOnTimeout (timers.js:198:5)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
-------- 9/14/2017, 11:46:45 AM --------
 | 
			
		||||
 | 
			
		||||
C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\webserver.js:645
 | 
			
		||||
                var serverid = obj.GetRoutingServerId(req.query.host, 2); // Check for Intel CIRA connection
 | 
			
		||||
                                   ^
 | 
			
		||||
 | 
			
		||||
TypeError: obj.GetRoutingServerId is not a function
 | 
			
		||||
    at C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\webserver.js:645:36
 | 
			
		||||
    at newArguments.(anonymous function) (C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\node_modules\nedb\lib\executor.js:29:17)
 | 
			
		||||
    at Cursor.execFn (C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\node_modules\nedb\lib\datastore.js:484:12)
 | 
			
		||||
    at callback (C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\node_modules\nedb\lib\cursor.js:126:19)
 | 
			
		||||
    at C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\node_modules\nedb\lib\cursor.js:193:12
 | 
			
		||||
    at C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\node_modules\nedb\lib\datastore.js:329:14
 | 
			
		||||
    at Object.async.eachSeries (C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\node_modules\async\lib\async.js:130:20)
 | 
			
		||||
    at C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\node_modules\nedb\lib\datastore.js:323:11
 | 
			
		||||
    at fn (C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\node_modules\async\lib\async.js:582:34)
 | 
			
		||||
    at Immediate._onImmediate (C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\node_modules\async\lib\async.js:498:34)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
-------- 9/14/2017, 3:09:49 PM --------
 | 
			
		||||
 | 
			
		||||
C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\multiserver.js:573
 | 
			
		||||
                for (var i in peerTunnel.pendingWs1Data) { peerTunnel.ws2.send(peerTunnel.pendingWs1Data[i]); }
 | 
			
		||||
                                                                          ^
 | 
			
		||||
 | 
			
		||||
TypeError: peerTunnel.ws2.send is not a function
 | 
			
		||||
    at WebSocketClient.<anonymous> (C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\multiserver.js:573:75)
 | 
			
		||||
    at emitOne (events.js:96:13)
 | 
			
		||||
    at WebSocketClient.emit (events.js:188:7)
 | 
			
		||||
    at WebSocketClient.succeedHandshake (C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\node_modules\websocket\lib\WebSocketClient.js:335:10)
 | 
			
		||||
    at WebSocketClient.validateHandshake (C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\node_modules\websocket\lib\WebSocketClient.js:319:10)
 | 
			
		||||
    at ClientRequest.handleRequestUpgrade (C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\node_modules\websocket\lib\WebSocketClient.js:248:14)
 | 
			
		||||
    at emitThree (events.js:116:13)
 | 
			
		||||
    at ClientRequest.emit (events.js:194:7)
 | 
			
		||||
    at TLSSocket.socketOnData (_http_client.js:391:11)
 | 
			
		||||
    at emitOne (events.js:96:13)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
-------- 9/14/2017, 3:14:06 PM --------
 | 
			
		||||
 | 
			
		||||
C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\multiserver.js:573
 | 
			
		||||
                for (var i in peerTunnel.pendingWs1Data) { peerTunnel.ws2.send(peerTunnel.pendingWs1Data[i]); }
 | 
			
		||||
                                                                         ^
 | 
			
		||||
 | 
			
		||||
TypeError: Cannot read property 'send' of null
 | 
			
		||||
    at WebSocketClient.<anonymous> (C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\multiserver.js:573:74)
 | 
			
		||||
    at emitOne (events.js:96:13)
 | 
			
		||||
    at WebSocketClient.emit (events.js:188:7)
 | 
			
		||||
    at WebSocketClient.succeedHandshake (C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\node_modules\websocket\lib\WebSocketClient.js:335:10)
 | 
			
		||||
    at WebSocketClient.validateHandshake (C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\node_modules\websocket\lib\WebSocketClient.js:319:10)
 | 
			
		||||
    at ClientRequest.handleRequestUpgrade (C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\node_modules\websocket\lib\WebSocketClient.js:248:14)
 | 
			
		||||
    at emitThree (events.js:116:13)
 | 
			
		||||
    at ClientRequest.emit (events.js:194:7)
 | 
			
		||||
    at TLSSocket.socketOnData (_http_client.js:391:11)
 | 
			
		||||
    at emitOne (events.js:96:13)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										156
									
								
								multiserver.js
									
										
									
									
									
								
							
							
						
						
									
										156
									
								
								multiserver.js
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -13,6 +13,7 @@ module.exports.CreateMultiServer = function (parent, args) {
 | 
			
		|||
    obj.forge = require('node-forge');
 | 
			
		||||
    obj.outPeerServers = {}; // Outgoing peer servers
 | 
			
		||||
    obj.peerServers = {}; // All connected servers (in & out). Only present in this list if the connection is setup
 | 
			
		||||
    obj.serverid = null;
 | 
			
		||||
 | 
			
		||||
    // Create a mesh server module that will connect to other servers
 | 
			
		||||
    obj.CreatePeerOutServer = function (parent, serverid, url) {
 | 
			
		||||
| 
						 | 
				
			
			@ -70,7 +71,7 @@ module.exports.CreateMultiServer = function (parent, args) {
 | 
			
		|||
                obj.conn.on('close', function () { obj.parent.parent.debug(1, 'OutPeer ' + obj.serverid + ': Disconnected'); disconnect(); });
 | 
			
		||||
 | 
			
		||||
                // Get the peer server's certificate and compute the server public key hash
 | 
			
		||||
                if (obj.ws.socket == undefined) return;
 | 
			
		||||
                if (obj.ws.socket == null) return;
 | 
			
		||||
                var rawcertbuf = obj.ws.socket.getPeerCertificate().raw, rawcert = '';
 | 
			
		||||
                for (var i = 0; i < rawcertbuf.length; i++) { rawcert += String.fromCharCode(rawcertbuf[i]); }
 | 
			
		||||
                var serverCert = obj.forge.pki.certificateFromAsn1(obj.forge.asn1.fromDer(rawcert));
 | 
			
		||||
| 
						 | 
				
			
			@ -130,14 +131,14 @@ module.exports.CreateMultiServer = function (parent, args) {
 | 
			
		|||
                                obj.parent.parent.debug(1, 'OutPeer ' + obj.serverid + ': Verified peer connection to ' + obj.url);
 | 
			
		||||
 | 
			
		||||
                                // Send information about our server to the peer
 | 
			
		||||
                                if (obj.connectionState == 15) { obj.conn.send(JSON.stringify({ action: 'info', serverid: obj.parent.peerConfig.serverId, dbid: obj.parent.parent.db.identifier, key: obj.parent.serverKey })); }
 | 
			
		||||
                                if (obj.connectionState == 15) { obj.conn.send(JSON.stringify({ action: 'info', serverid: obj.parent.serverid, dbid: obj.parent.parent.db.identifier, key: obj.parent.serverKey })); }
 | 
			
		||||
                                //if ((obj.connectionState == 15) && (obj.connectHandler != null)) { obj.connectHandler(1); }
 | 
			
		||||
                                break;
 | 
			
		||||
                            }
 | 
			
		||||
                            case 4: {
 | 
			
		||||
                                // Server confirmed authentication, we are allowed to send commands to the server
 | 
			
		||||
                                obj.connectionState |= 8;
 | 
			
		||||
                                if (obj.connectionState == 15) { obj.conn.send(JSON.stringify({ action: 'info', serverid: obj.parent.peerConfig.serverId, dbid: obj.parent.parent.db.identifier, key: obj.parent.serverKey })); }
 | 
			
		||||
                                if (obj.connectionState == 15) { obj.conn.send(JSON.stringify({ action: 'info', serverid: obj.parent.serverid, dbid: obj.parent.parent.db.identifier, key: obj.parent.serverKey })); }
 | 
			
		||||
                                //if ((obj.connectionState == 15) && (obj.connectHandler != null)) { obj.connectHandler(1); }
 | 
			
		||||
                                break;
 | 
			
		||||
                            }
 | 
			
		||||
| 
						 | 
				
			
			@ -196,7 +197,7 @@ module.exports.CreateMultiServer = function (parent, args) {
 | 
			
		|||
                    if (obj.authenticated != 3) {
 | 
			
		||||
                        // We get the peer's serverid and database identifier.
 | 
			
		||||
                        if ((command.serverid != null) && (command.dbid != null)) {
 | 
			
		||||
                            if (command.serverid == obj.parent.peerConfig.serverId) { console.log('ERROR: Same server ID, trying to peer with self. (' + obj.url + ', ' + command.serverid + ').'); return; }
 | 
			
		||||
                            if (command.serverid == obj.parent.serverid) { console.log('ERROR: Same server ID, trying to peer with self. (' + obj.url + ', ' + command.serverid + ').'); return; }
 | 
			
		||||
                            if (command.dbid != obj.parent.parent.db.identifier) { console.log('ERROR: Database ID mismatch. Trying to peer to a server with the wrong database. (' + obj.url + ', ' + command.serverid + ').'); return; }
 | 
			
		||||
                            obj.peerServerId = command.serverid;
 | 
			
		||||
                            obj.peerServerKey = command.key;
 | 
			
		||||
| 
						 | 
				
			
			@ -282,7 +283,7 @@ module.exports.CreateMultiServer = function (parent, args) {
 | 
			
		|||
                    obj.send(obj.common.ShortToStr(2) + obj.common.ShortToStr(obj.agentCertificatAsn1.length) + obj.agentCertificatAsn1 + privateKey.sign(md)); // Command 2, certificate + signature
 | 
			
		||||
 | 
			
		||||
                    // Check the agent signature if we can
 | 
			
		||||
                    if (obj.unauthsign != undefined) {
 | 
			
		||||
                    if (obj.unauthsign != null) {
 | 
			
		||||
                        if (processAgentSignature(obj.unauthsign) == false) { disconnect(); return; } else { completePeerServerConnection(); }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
| 
						 | 
				
			
			@ -299,7 +300,7 @@ module.exports.CreateMultiServer = function (parent, args) {
 | 
			
		|||
                    obj.unauth.nodeid = obj.forge.pki.getPublicKeyFingerprint(obj.unauth.nodeCert.publicKey, { encoding: 'hex', md: obj.forge.md.sha256.create() });
 | 
			
		||||
 | 
			
		||||
                    // Check the agent signature if we can
 | 
			
		||||
                    if (obj.agentnonce == undefined) { obj.unauthsign = msg.substring(4 + certlen); } else { if (processAgentSignature(msg.substring(4 + certlen)) == false) { disconnect(); return; } }
 | 
			
		||||
                    if (obj.agentnonce == null) { obj.unauthsign = msg.substring(4 + certlen); } else { if (processAgentSignature(msg.substring(4 + certlen)) == false) { disconnect(); return; } }
 | 
			
		||||
                    completePeerServerConnection();
 | 
			
		||||
                }
 | 
			
		||||
                else if (cmd == 3) {
 | 
			
		||||
| 
						 | 
				
			
			@ -327,7 +328,7 @@ module.exports.CreateMultiServer = function (parent, args) {
 | 
			
		|||
        function completePeerServerConnection() {
 | 
			
		||||
            if (obj.authenticated != 1) return;
 | 
			
		||||
            obj.send(obj.common.ShortToStr(4));
 | 
			
		||||
            obj.send(JSON.stringify({ action: 'info', serverid: obj.parent.peerConfig.serverId, dbid: obj.parent.parent.db.identifier, key: obj.parent.serverKey }));
 | 
			
		||||
            obj.send(JSON.stringify({ action: 'info', serverid: obj.parent.serverid, dbid: obj.parent.parent.db.identifier, key: obj.parent.serverKey }));
 | 
			
		||||
            obj.authenticated = 2;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -359,7 +360,7 @@ module.exports.CreateMultiServer = function (parent, args) {
 | 
			
		|||
                    if (obj.authenticated != 3) {
 | 
			
		||||
                        // We get the peer's serverid and database identifier.
 | 
			
		||||
                        if ((command.serverid != null) && (command.dbid != null)) {
 | 
			
		||||
                            if (command.serverid == obj.parent.peerConfig.serverId) { console.log('ERROR: Same server ID, trying to peer with self. (' + obj.remoteaddr + ', ' + command.serverid + ').'); return; }
 | 
			
		||||
                            if (command.serverid == obj.parent.serverid) { console.log('ERROR: Same server ID, trying to peer with self. (' + obj.remoteaddr + ', ' + command.serverid + ').'); return; }
 | 
			
		||||
                            if (command.dbid != obj.parent.parent.db.identifier) { console.log('ERROR: Database ID mismatch. Trying to peer to a server with the wrong database. (' + obj.remoteaddr + ', ' + command.serverid + ').'); return; }
 | 
			
		||||
                            if (obj.parent.peerConfig.servers[command.serverid] == null) { console.log('ERROR: Unknown peer serverid: ' + command.serverid + ' (' + obj.remoteaddr + ').'); return; }
 | 
			
		||||
                            obj.peerServerId = command.serverid;
 | 
			
		||||
| 
						 | 
				
			
			@ -380,21 +381,32 @@ module.exports.CreateMultiServer = function (parent, args) {
 | 
			
		|||
 | 
			
		||||
    // If we have no peering configuration, don't setup this object
 | 
			
		||||
    if (obj.peerConfig == null) { return null; }
 | 
			
		||||
    obj.serverid = obj.parent.config.peers.serverId;
 | 
			
		||||
    if (obj.serverid == null) { obj.serverid = require("os").hostname(); }
 | 
			
		||||
    if (obj.parent.config.peers.servers[obj.serverid] == null) { console.log("Error: Unable to peer with other servers, \"" + obj.serverid + "\" not present in peer servers list."); return null; }
 | 
			
		||||
 | 
			
		||||
    // Generate a cryptographic key used to encode and decode cookies
 | 
			
		||||
    obj.generateCookieKey = function () {
 | 
			
		||||
        return new Buffer(obj.crypto.randomBytes(32), 'binary').toString('hex');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Return the private key of a peer server
 | 
			
		||||
    obj.getServerCookieKey = function (serverid) {
 | 
			
		||||
        var server = obj.peerServers[serverid];
 | 
			
		||||
        if (server && server.peerServerKey) return server.peerServerKey;
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Encode an object as a cookie using a key
 | 
			
		||||
    obj.encodeCookie = function (o, key) {
 | 
			
		||||
        try {
 | 
			
		||||
            if (key == undefined) { key = obj.serverKey; }
 | 
			
		||||
            if (key == null) { key = obj.serverKey; }
 | 
			
		||||
            key = require('./common.js').hex2rstr(key);
 | 
			
		||||
            o.time = Math.floor(Date.now() / 1000); // Add the cookie creation time
 | 
			
		||||
            var msg = JSON.stringify(o);
 | 
			
		||||
            msg = obj.crypto.createHmac('sha256', key.substring(16)).update(msg, 'binary', 'binary').digest('binary') + msg;
 | 
			
		||||
            var iv = new Buffer(obj.crypto.randomBytes(16), 'binary');
 | 
			
		||||
            var cipher = obj.crypto.createCipheriv('aes-128-cbc', key.substring(0, 16), iv);
 | 
			
		||||
            var cipher = obj.crypto.createCipheriv('aes-128-cbc', new Buffer(key.substring(0, 16), 'binary'), iv);
 | 
			
		||||
            crypted = cipher.update(msg, 'binary', 'binary');
 | 
			
		||||
            crypted += cipher.final('binary');
 | 
			
		||||
            var total = new Buffer(iv, 'binary').toString('hex') + new Buffer(crypted, 'binary').toString('hex'); // HEX: This is not an efficient concat, but it's very compatible.
 | 
			
		||||
| 
						 | 
				
			
			@ -406,11 +418,12 @@ module.exports.CreateMultiServer = function (parent, args) {
 | 
			
		|||
    // Decode a cookie back into an object using a key. Return null if it's not a valid cookie.
 | 
			
		||||
    obj.decodeCookie = function (cookie, key) {
 | 
			
		||||
        try {
 | 
			
		||||
            if (key == undefined) { key = obj.serverKey; }
 | 
			
		||||
            if (key == null) { key = obj.serverKey; }
 | 
			
		||||
            key = require('./common.js').hex2rstr(key);
 | 
			
		||||
            cookie = new Buffer(cookie.replace(/\@/g, '+').replace(/\$/g, '/'), 'base64').toString('hex'); // HEX: This is not an efficient split, but it's very compatible.
 | 
			
		||||
            var iv = new Buffer(cookie.substring(0, 32), 'hex');
 | 
			
		||||
            var msg = new Buffer(cookie.substring(32), 'hex');
 | 
			
		||||
            var decipher = obj.crypto.createDecipheriv('aes-128-cbc', key.substring(0, 16), iv)
 | 
			
		||||
            var decipher = obj.crypto.createDecipheriv('aes-128-cbc', new Buffer(key.substring(0, 16), 'binary'), iv)
 | 
			
		||||
            var dec = decipher.update(msg, 'binary', 'binary')
 | 
			
		||||
            dec += decipher.final('binary');
 | 
			
		||||
            var msg = dec.substring(32);
 | 
			
		||||
| 
						 | 
				
			
			@ -418,14 +431,14 @@ module.exports.CreateMultiServer = function (parent, args) {
 | 
			
		|||
            var hash2 = obj.crypto.createHmac('sha256', key.substring(16)).update(msg, 'binary', 'binary').digest('binary');
 | 
			
		||||
            if (hash1 !== hash2) { return null; }
 | 
			
		||||
            var o = JSON.parse(msg);
 | 
			
		||||
            if ((o.time == null) || (o.time == undefined) || (typeof o.time != 'number')) { return null; }
 | 
			
		||||
            if ((o.time == null) || (o.time == null) || (typeof o.time != 'number')) { return null; }
 | 
			
		||||
            o.time = o.time * 1000; // Decode the cookie creation time
 | 
			
		||||
            o.dtime = Date.now() - o.time; // Decode how long ago the cookie was created
 | 
			
		||||
            return o;
 | 
			
		||||
        } catch (e) { return null; }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Dispatch an event to other MeshCentral2 peer servers
 | 
			
		||||
    // 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); }
 | 
			
		||||
| 
						 | 
				
			
			@ -436,11 +449,17 @@ module.exports.CreateMultiServer = function (parent, args) {
 | 
			
		|||
        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) {
 | 
			
		||||
            // 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.peerConfig.serverId) && (obj.peerConfig.servers[serverId].url != null) && (obj.outPeerServers[serverId] == null)) {
 | 
			
		||||
            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);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -484,9 +503,116 @@ module.exports.CreateMultiServer = function (parent, args) {
 | 
			
		|||
                obj.parent.ClearConnectivityState(msg.meshid, msg.nodeid, msg.connectType, peerServerId);
 | 
			
		||||
                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)); }
 | 
			
		||||
                } else if (msg.nodeid != null) {
 | 
			
		||||
                    // Route this message to a connected agent
 | 
			
		||||
                    if (command.fromSessionid != null) { command.sessionid = command.fromSessionid; delete command.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
 | 
			
		||||
                        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); }
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Create a tunnel connection to a peer server
 | 
			
		||||
    obj.createPeerRelay = function (ws, req, serverid, user) {
 | 
			
		||||
        var server = obj.peerServers[serverid];
 | 
			
		||||
        if ((server == null) || (server.peerServerKey == null)) { return null; }
 | 
			
		||||
        var cookieKey = server.peerServerKey;
 | 
			
		||||
 | 
			
		||||
        // Build the connection URL
 | 
			
		||||
        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 = ''
 | 
			
		||||
        for (var i in req.query) { queryStr += ((queryStr == '') ? '?' : '&') + i + '=' + req.query[i]; }
 | 
			
		||||
        queryStr += ((queryStr == '') ? '?' : '&') + 'auth=' + obj.encodeCookie({ userid: user._id, domainid: user.domain }, cookieKey);
 | 
			
		||||
        var url = obj.peerConfig.servers[serverid].url + path + queryStr;
 | 
			
		||||
 | 
			
		||||
        // 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.
 | 
			
		||||
    obj.createPeerRelayEx = function (ws, url, serverid) {
 | 
			
		||||
        var peerTunnel = { parent: obj, ws1: ws, ws2: null, url: url, serverid: serverid };
 | 
			
		||||
 | 
			
		||||
        peerTunnel.connect = function () {
 | 
			
		||||
            // Get the web socket setup
 | 
			
		||||
            var WebSocketClient = require('websocket').client;
 | 
			
		||||
            peerTunnel.wsclient = new WebSocketClient();
 | 
			
		||||
 | 
			
		||||
            // Register the connection failed event
 | 
			
		||||
            peerTunnel.wsclient.on('connectFailed', function (error) { peerTunnel.parent.parent.debug(1, 'FTunnel ' + obj.serverid + ': Failed connection'); disconnect(); });
 | 
			
		||||
 | 
			
		||||
            // Register the connection event
 | 
			
		||||
            peerTunnel.wsclient.on('connect', function (connection) {
 | 
			
		||||
                peerTunnel.ws2 = connection;
 | 
			
		||||
 | 
			
		||||
                // If error, do nothing
 | 
			
		||||
                peerTunnel.ws2.on('error', function (err) { peerTunnel.parent.parent.debug(1, 'FTunnel: Connection Error: ' + err); peerTunnel.close(); });
 | 
			
		||||
 | 
			
		||||
                // If the mesh agent web socket is closed, clean up.
 | 
			
		||||
                peerTunnel.ws2.on('close', function (req) { peerTunnel.parent.parent.debug(1, 'FTunnel disconnect ' + peerTunnel.nodeid); peerTunnel.close(); });
 | 
			
		||||
 | 
			
		||||
                // If a message is received from the peer, Peer ---> Browser
 | 
			
		||||
                peerTunnel.ws2.on('message', function (msg) { if (msg.type == 'binary') { peerTunnel.ws2.pause(); peerTunnel.ws1.send(msg.binaryData, function () { peerTunnel.ws2.resume(); }); } });
 | 
			
		||||
 | 
			
		||||
                // Resume the web socket to start the data flow
 | 
			
		||||
                peerTunnel.ws1.resume();
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            // If a message is received from the browser, Browser ---> Peer
 | 
			
		||||
            peerTunnel.ws1.on('message', function (msg) { peerTunnel.ws1.pause(); peerTunnel.ws2.send(msg, function () { peerTunnel.ws1.resume(); }); });
 | 
			
		||||
 | 
			
		||||
            // If error, do nothing
 | 
			
		||||
            peerTunnel.ws1.on('error', function (err) { console.log(err); peerTunnel.close(); });
 | 
			
		||||
 | 
			
		||||
            // 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.nodeid); peerTunnel.close(); });
 | 
			
		||||
 | 
			
		||||
            peerTunnel.wsclient.connect(peerTunnel.url, null, null, null, { rejectUnauthorized: false });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Disconnect both sides of the tunnel
 | 
			
		||||
        peerTunnel.close = function (arg) {
 | 
			
		||||
            if (arg == 2) {
 | 
			
		||||
                // Hard close, close the TCP socket
 | 
			
		||||
                try { peerTunnel.ws1._socket._parent.end(); peerTunnel.parent.parent.debug(1, 'FTunnel1: Hard disconnect'); } catch (e) { console.log(e); }
 | 
			
		||||
                try { peerTunnel.ws2._socket._parent.end(); peerTunnel.parent.parent.debug(1, 'FTunnel2: Hard disconnect'); } catch (e) { console.log(e); }
 | 
			
		||||
            } else {
 | 
			
		||||
                // Soft close, close the websocket
 | 
			
		||||
                try { peerTunnel.ws1.close(); peerTunnel.parent.parent.debug(1, 'FTunnel1: Soft disconnect '); } catch (e) { console.log(e); }
 | 
			
		||||
                try { peerTunnel.ws2.close(); peerTunnel.parent.parent.debug(1, 'FTunnel2: Soft disconnect '); } catch (e) { console.log(e); }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return peerTunnel;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    obj.serverKey = obj.generateCookieKey();
 | 
			
		||||
    setTimeout(function () { obj.ConnectToPeers(); }, 1000); // Delay this a little to make sure we are ready on our side.
 | 
			
		||||
    return obj;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,6 @@
 | 
			
		|||
{
 | 
			
		||||
  "name": "meshcentral",
 | 
			
		||||
  "version": "0.0.7-u",
 | 
			
		||||
  "version": "0.0.7-w",
 | 
			
		||||
  "keywords": [
 | 
			
		||||
    "Remote Management",
 | 
			
		||||
    "Intel AMT",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -87,6 +87,10 @@
 | 
			
		|||
                                            <td align=right>Password Hint:</td>
 | 
			
		||||
                                            <td><input id=apasswordhint type=text name=apasswordhint autocomplete=off maxlength=250 /></td>
 | 
			
		||||
                                        </tr>
 | 
			
		||||
                                        <tr id=newAccountPass title="Enter the account creation token">
 | 
			
		||||
                                            <td align=right>Creation Token:</td>
 | 
			
		||||
                                            <td><input id=anewaccountpass type=password name=anewaccountpass autocomplete=off maxlength=250 onchange=validateCreate() onkeyup=validateCreate() /></td>
 | 
			
		||||
                                        </tr>
 | 
			
		||||
                                        <tr>
 | 
			
		||||
                                            <td colspan=2>
 | 
			
		||||
                                                <div style=float:right><input id=createButton type=submit value="Create Account" disabled="disabled" /></div>
 | 
			
		||||
| 
						 | 
				
			
			@ -136,6 +140,7 @@
 | 
			
		|||
    </div>
 | 
			
		||||
    <script>
 | 
			
		||||
        var passhint = "{{{passhint}}}";
 | 
			
		||||
        var newAccountPass = {{{newAccountPass}}};
 | 
			
		||||
 | 
			
		||||
        function startup() {
 | 
			
		||||
            window.onresize = center;
 | 
			
		||||
| 
						 | 
				
			
			@ -145,6 +150,7 @@
 | 
			
		|||
            if ('{{loginmode}}' != '') { go({{loginmode}}); } else { go(1); }
 | 
			
		||||
            QV('newAccountDiv', '{{{newAccount}}}' != '0' );
 | 
			
		||||
            if ((passhint != null) && (passhint.length > 0)) { QV("showPassHintLink", true); }
 | 
			
		||||
            QV("anewaccountpass", (newAccountPass == 1));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        function showPassHint() {
 | 
			
		||||
| 
						 | 
				
			
			@ -172,7 +178,8 @@
 | 
			
		|||
 | 
			
		||||
        function validateCreate() {
 | 
			
		||||
            setDialogMode(0);
 | 
			
		||||
            var ok = (Q('ausername').value.length > 0 && Q('aemail').value.length > 0 && Q('apassword1').value.length > 0 && Q('apassword2').value == Q('apassword1').value);
 | 
			
		||||
            var ok = (Q('ausername').value.length > 0 && Q('aemail').value.length > 0 && Q('apassword1').value.length > 0 && (Q('apassword2').value == Q('apassword1').value));
 | 
			
		||||
            if ((newAccountPass == 1) && (Q('anewaccountpass').value.length == 0)) { ok = false; }
 | 
			
		||||
            QE('createButton', ok);
 | 
			
		||||
            if (Q('apassword1').value == '') {
 | 
			
		||||
                QH('passWarning', '');
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										284
									
								
								webserver.js
									
										
									
									
									
								
							
							
						
						
									
										284
									
								
								webserver.js
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -108,7 +108,7 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
 | 
			
		|||
    
 | 
			
		||||
    // Session-persisted message middleware
 | 
			
		||||
    obj.app.use(function (req, res, next) {
 | 
			
		||||
        if (req.session != undefined) {
 | 
			
		||||
        if (req.session != null) {
 | 
			
		||||
            var err = req.session.error;
 | 
			
		||||
            var msg = req.session.success;
 | 
			
		||||
            var passhint = req.session.passhint;
 | 
			
		||||
| 
						 | 
				
			
			@ -146,7 +146,7 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
 | 
			
		|||
        // Query the db for the given username
 | 
			
		||||
        if (!user) return fn(new Error('cannot find user'));
 | 
			
		||||
        // Apply the same algorithm to the POSTed password, applying the hash against the pass / salt, if there is a match we found the user
 | 
			
		||||
        if (user.salt == undefined) {
 | 
			
		||||
        if (user.salt == null) {
 | 
			
		||||
            fn(new Error('invalid password'));
 | 
			
		||||
        } else {
 | 
			
		||||
            obj.hash(pass, user.salt, function (err, hash) {
 | 
			
		||||
| 
						 | 
				
			
			@ -250,6 +250,13 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
 | 
			
		|||
            req.session.error = '<b style=color:#8C001A>Unable to create account.</b>';;
 | 
			
		||||
            res.redirect(domain.url);
 | 
			
		||||
        } else {
 | 
			
		||||
            // Check if there is domain.newAccountToken, check if supplied token is valid
 | 
			
		||||
            if ((domain.newAccountsPass != null) && (domain.newAccountsPass != '') && (req.body.anewaccountpass != domain.newAccountsPass)) {
 | 
			
		||||
                req.session.loginmode = 2;
 | 
			
		||||
                req.session.error = '<b style=color:#8C001A>Invalid account creation token.</b>';
 | 
			
		||||
                res.redirect(domain.url);
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
            // Check if user exists
 | 
			
		||||
            if (obj.users['user/' + domain.id + '/' + req.body.username.toLowerCase()]) {
 | 
			
		||||
                req.session.loginmode = 2;
 | 
			
		||||
| 
						 | 
				
			
			@ -334,7 +341,7 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
 | 
			
		|||
            req.session.userid = 'user/' + domain.id + '/~';
 | 
			
		||||
            req.session.domainid = domain.id;
 | 
			
		||||
            req.session.currentNode = '';
 | 
			
		||||
            if (obj.users[req.session.userid] == undefined) {
 | 
			
		||||
            if (obj.users[req.session.userid] == null) {
 | 
			
		||||
                // Create the dummy user ~ with impossible password
 | 
			
		||||
                obj.users[req.session.userid] = { type: 'user', _id: req.session.userid, name: '~', email: '~', domain: domain.id, siteadmin: 0xFFFFFFFF };
 | 
			
		||||
                obj.db.SetUser(obj.users[req.session.userid]);
 | 
			
		||||
| 
						 | 
				
			
			@ -374,14 +381,14 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
 | 
			
		|||
            res.render(obj.path.join(__dirname, 'views/default'), { viewmode: viewmode, currentNode: currentNode, logoutControl: logoutcontrol, title: domain.title, title2: domain.title2, domainurl: domain.url, domain: domain.id, debuglevel: parent.debugLevel, serverDnsName: obj.certificates.CommonName, serverPublicPort: args.port, noServerBackup: (args.noserverbackup == 1 ? 1 : 0), features: features, mpspass: args.mpspass });
 | 
			
		||||
        } else {
 | 
			
		||||
            // Send back the login application
 | 
			
		||||
            res.render(obj.path.join(__dirname, 'views/login'), { loginmode: req.session.loginmode, rootCertLink: getRootCertLink(), title: domain.title, title2: domain.title2, newAccount: domain.newAccounts, serverDnsName: obj.certificates.CommonName, serverPublicPort: obj.args.port });
 | 
			
		||||
            res.render(obj.path.join(__dirname, 'views/login'), { loginmode: req.session.loginmode, rootCertLink: getRootCertLink(), title: domain.title, title2: domain.title2, newAccount: domain.newAccounts, newAccountPass: ((domain.newAccountsPass == null)?0:1), serverDnsName: obj.certificates.CommonName, serverPublicPort: obj.args.port });
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    // Get the link to the root certificate if needed
 | 
			
		||||
    function getRootCertLink() {
 | 
			
		||||
        // TODO: This is not quite right, we need to check if the HTTPS certificate is issued from MeshCentralRoot, if so, add this download link.
 | 
			
		||||
        if (obj.args.notls == undefined && obj.certificates.RootName.substring(0, 16) == 'MeshCentralRoot-') { return '<a href=/MeshServerRootCert.cer title="Download the root certificate for this server">Root Certificate</a>'; }
 | 
			
		||||
        if (obj.args.notls == null && obj.certificates.RootName.substring(0, 16) == 'MeshCentralRoot-') { return '<a href=/MeshServerRootCert.cer title="Download the root certificate for this server">Root Certificate</a>'; }
 | 
			
		||||
        return '';
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -436,7 +443,7 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
 | 
			
		|||
                    scriptFile.scriptBlocks[3].vars.password.value = obj.args.mpspass ? obj.args.mpspass : 'A@xew9rt'; // Set the password
 | 
			
		||||
                    scriptFile.scriptBlocks[4].vars.AccessInfo1.value = obj.certificates.CommonName + ':' + obj.args.mpsport; // Set the primary server name:port to set periodic timer
 | 
			
		||||
                    //scriptFile.scriptBlocks[4].vars.AccessInfo2.value = obj.certificates.CommonName + ':' + obj.args.mpsport; // Set the secondary server name:port to set periodic timer
 | 
			
		||||
                    if (obj.args.ciralocalfqdn != undefined) { scriptFile.scriptBlocks[6].vars.DetectionStrings.value = obj.args.ciralocalfqdn; } // Set the environment detection local FQDN's
 | 
			
		||||
                    if (obj.args.ciralocalfqdn != null) { scriptFile.scriptBlocks[6].vars.DetectionStrings.value = obj.args.ciralocalfqdn; } // Set the environment detection local FQDN's
 | 
			
		||||
 | 
			
		||||
                    // Compile the script
 | 
			
		||||
                    var scriptEngine = require('./amtscript.js').CreateAmtScriptEngine();
 | 
			
		||||
| 
						 | 
				
			
			@ -461,7 +468,7 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
 | 
			
		|||
                    scriptFile.scriptBlocks[3].vars.password.value = obj.args.mpspass ? obj.args.mpspass : 'A@xew9rt'; // Set the password
 | 
			
		||||
                    scriptFile.scriptBlocks[4].vars.AccessInfo1.value = obj.certificates.CommonName + ':' + obj.args.mpsport; // Set the primary server name:port to set periodic timer
 | 
			
		||||
                    //scriptFile.scriptBlocks[4].vars.AccessInfo2.value = obj.certificates.CommonName + ':' + obj.args.mpsport; // Set the secondary server name:port to set periodic timer
 | 
			
		||||
                    if (obj.args.ciralocalfqdn != undefined) { scriptFile.scriptBlocks[6].vars.DetectionStrings.value = obj.args.ciralocalfqdn; } // Set the environment detection local FQDN's
 | 
			
		||||
                    if (obj.args.ciralocalfqdn != null) { scriptFile.scriptBlocks[6].vars.DetectionStrings.value = obj.args.ciralocalfqdn; } // Set the environment detection local FQDN's
 | 
			
		||||
 | 
			
		||||
                    // Compile the script
 | 
			
		||||
                    var scriptEngine = require('./amtscript.js').CreateAmtScriptEngine();
 | 
			
		||||
| 
						 | 
				
			
			@ -509,9 +516,9 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
 | 
			
		|||
    // Download a file from the server
 | 
			
		||||
    function handleDownloadFile(req, res) {
 | 
			
		||||
        var domain = getDomain(req);
 | 
			
		||||
        if ((req.query.link == undefined) || (req.session == undefined) || (req.session.userid == undefined) || (domain == null) || (domain.userQuota == -1)) { res.sendStatus(404); return; }
 | 
			
		||||
        if ((req.query.link == null) || (req.session == null) || (req.session.userid == null) || (domain == null) || (domain.userQuota == -1)) { res.sendStatus(404); return; }
 | 
			
		||||
        var user = obj.users[req.session.userid];
 | 
			
		||||
        if (user == undefined) { res.sendStatus(404); return; }
 | 
			
		||||
        if (user == null) { res.sendStatus(404); return; }
 | 
			
		||||
        var file = getServerFilePath(user, domain, req.query.link);
 | 
			
		||||
        if (file == null) { res.sendStatus(404); return; }
 | 
			
		||||
        res.set({ 'Cache-Control': 'no-cache, no-store, must-revalidate', 'Pragma': 'no-cache', 'Expires': '0', 'Content-Type': 'application/octet-stream', 'Content-Disposition': 'attachment; filename=\"' + file.name + '\"' });
 | 
			
		||||
| 
						 | 
				
			
			@ -528,7 +535,7 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
 | 
			
		|||
        var multiparty = require('multiparty');
 | 
			
		||||
        var form = new multiparty.Form();
 | 
			
		||||
        form.parse(req, function (err, fields, files) {
 | 
			
		||||
            if ((fields == undefined) || (fields.attrib == undefined) || (fields.attrib.length != 1)) { res.sendStatus(404); return; }
 | 
			
		||||
            if ((fields == null) || (fields.attrib == null) || (fields.attrib.length != 1)) { res.sendStatus(404); return; }
 | 
			
		||||
            for (var i in files.files) {
 | 
			
		||||
                var file = files.files[i];
 | 
			
		||||
                readEntireTextFile(file.path, function (data) {
 | 
			
		||||
| 
						 | 
				
			
			@ -552,13 +559,13 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
 | 
			
		|||
        var multiparty = require('multiparty');
 | 
			
		||||
        var form = new multiparty.Form();
 | 
			
		||||
        form.parse(req, function (err, fields, files) {
 | 
			
		||||
            if ((fields == undefined) || (fields.link == undefined) || (fields.link.length != 1)) { res.sendStatus(404); return; }
 | 
			
		||||
            if ((fields == null) || (fields.link == null) || (fields.link.length != 1)) { res.sendStatus(404); return; }
 | 
			
		||||
            var xfile = getServerFilePath(user, domain, decodeURIComponent(fields.link[0]));
 | 
			
		||||
            if (xfile == null) { res.sendStatus(404); return; }
 | 
			
		||||
            // Get total bytes in the path
 | 
			
		||||
            var totalsize = readTotalFileSize(xfile.fullpath);
 | 
			
		||||
            if (totalsize < xfile.quota) { // Check if the quota is not already broken
 | 
			
		||||
                if (fields.name != undefined) {
 | 
			
		||||
                if (fields.name != null) {
 | 
			
		||||
                    // Upload method where all the file data is within the fields.
 | 
			
		||||
                    var names = fields.name[0].split('*'), sizes = fields.size[0].split('*'), types = fields.type[0].split('*'), datas = fields.data[0].split('*');
 | 
			
		||||
                    if ((names.length == sizes.length) && (types.length == datas.length) && (names.length == types.length)) {
 | 
			
		||||
| 
						 | 
				
			
			@ -591,11 +598,11 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
 | 
			
		|||
    obj.subscribe = function (userid, target) {
 | 
			
		||||
        var user = obj.users[userid];
 | 
			
		||||
        var subscriptions = [userid, 'server-global'];
 | 
			
		||||
        if (user.siteadmin != undefined) {
 | 
			
		||||
        if (user.siteadmin != null) {
 | 
			
		||||
            if (user.siteadmin == 0xFFFFFFFF) subscriptions.push('*');
 | 
			
		||||
            if ((user.siteadmin & 2) != 0) subscriptions.push('server-users');
 | 
			
		||||
        }
 | 
			
		||||
        if (user.links != undefined) {
 | 
			
		||||
        if (user.links != null) {
 | 
			
		||||
            for (var i in user.links) { subscriptions.push(i); }
 | 
			
		||||
        }
 | 
			
		||||
        obj.parent.RemoveAllEventDispatch(target);
 | 
			
		||||
| 
						 | 
				
			
			@ -607,12 +614,27 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
 | 
			
		|||
    function handleRelayWebSocket(ws, req) {
 | 
			
		||||
        var node, domain = getDomain(req);
 | 
			
		||||
        // Check if this is a logged in user
 | 
			
		||||
        if (!req.session || !req.session.userid) { return; } // Web socket attempt without login, disconnect.
 | 
			
		||||
        if (req.session.domainid != domain.id) { console.log('ERR: Invalid domain'); return; }
 | 
			
		||||
        var user = obj.users[req.session.userid];
 | 
			
		||||
        var user, peering = true;
 | 
			
		||||
        if (req.query.auth == null) {
 | 
			
		||||
            // Use ExpressJS session
 | 
			
		||||
            if (!req.session || !req.session.userid) { return; } // Web socket attempt without login, disconnect.
 | 
			
		||||
            if (req.session.domainid != domain.id) { console.log('ERR: Invalid domain'); return; }
 | 
			
		||||
            user = obj.users[req.session.userid];
 | 
			
		||||
        } else {
 | 
			
		||||
            // Get the session from the cookie
 | 
			
		||||
            if (obj.parent.multiServer == null) { return; }
 | 
			
		||||
            var session = obj.parent.multiServer.decodeCookie(req.query.auth);
 | 
			
		||||
            if (session == null) { console.log('ERR: Invalid cookie'); return; }
 | 
			
		||||
            if (session.domainid != domain.id) { console.log('ERR: Invalid domain'); return; }
 | 
			
		||||
            user = obj.users[session.userid];
 | 
			
		||||
            peering = false; // Don't allow the connection to jump again to a different server
 | 
			
		||||
        }
 | 
			
		||||
        if (!user) { console.log('ERR: Not a user'); return; }
 | 
			
		||||
        Debug(1, 'Websocket relay connected from ' + user.name + ' for ' + req.query.host + '.');
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
        // Hold this socket until we are ready.
 | 
			
		||||
        ws.pause();
 | 
			
		||||
 | 
			
		||||
        // Fetch information about the target
 | 
			
		||||
        obj.db.Get(req.query.host, function (err, docs) {
 | 
			
		||||
            if (docs.length == 0) { console.log('ERR: Node not found'); return; }
 | 
			
		||||
| 
						 | 
				
			
			@ -627,19 +649,33 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
 | 
			
		|||
            // Check what connectivity is available for this node
 | 
			
		||||
            var state = parent.GetConnectivityState(req.query.host);
 | 
			
		||||
            var conn = 0;
 | 
			
		||||
            if (!state || state.connectivity == 0) {
 | 
			
		||||
                conn = 4; // DEBUG: Allow local connections for now... change this later when we can monitor Intel AMT machines and confirm routing before connections.
 | 
			
		||||
                //Debug(1, 'ERR: No routing possible (1)');
 | 
			
		||||
                //try { ws.close(); } catch (e) { }
 | 
			
		||||
                //return;
 | 
			
		||||
            } else {
 | 
			
		||||
                conn = state.connectivity;
 | 
			
		||||
            if (!state || state.connectivity == 0) { Debug(1, 'ERR: No routing possible (1)'); try { ws.close(); } catch (e) { } return; } else { conn = state.connectivity; }
 | 
			
		||||
 | 
			
		||||
            // Check what server needs to handle this connection
 | 
			
		||||
            if ((obj.parent.multiServer != null) && (peering == true)) {
 | 
			
		||||
                var server = obj.parent.GetRoutingServerId(req.query.host, 2); // Check for Intel CIRA connection
 | 
			
		||||
                if (server != null) {
 | 
			
		||||
                    if (server.serverid != obj.parent.serverId) {
 | 
			
		||||
                        // Do local Intel CIRA routing using a different server
 | 
			
		||||
                        Debug(1, 'Route Intel AMT CIRA connection to peer server: ' + server.serverid);
 | 
			
		||||
                        obj.parent.multiServer.createPeerRelay(ws, req, server.serverid, user);
 | 
			
		||||
                        return;
 | 
			
		||||
                    }
 | 
			
		||||
                } else {
 | 
			
		||||
                    server = obj.parent.GetRoutingServerId(req.query.host, 4); // Check for local Intel AMT connection
 | 
			
		||||
                    if ((server != null) && (server.serverid != obj.parent.serverId)) {
 | 
			
		||||
                        // Do local Intel AMT routing using a different server
 | 
			
		||||
                        Debug(1, 'Route Intel AMT direct connection to peer server: ' + server.serverid);
 | 
			
		||||
                        obj.parent.multiServer.createPeerRelay(ws, req, server.serverid, user);
 | 
			
		||||
                        return;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
 | 
			
		||||
            // If Intel AMT CIRA connection is available, use it
 | 
			
		||||
            if (((conn & 2) != 0) && (parent.mpsserver.ciraConnections[req.query.host] != undefined)) {
 | 
			
		||||
            if (((conn & 2) != 0) && (parent.mpsserver.ciraConnections[req.query.host] != null)) {
 | 
			
		||||
                var ciraconn = parent.mpsserver.ciraConnections[req.query.host];
 | 
			
		||||
                
 | 
			
		||||
 | 
			
		||||
                // Compute target port, look at the CIRA port mappings, if non-TLS is allowed, use that, if not use TLS
 | 
			
		||||
                var port = 16993;
 | 
			
		||||
                //if (node.intelamt.tls == 0) port = 16992; // DEBUG: Allow TLS flag to set TLS mode within CIRA
 | 
			
		||||
| 
						 | 
				
			
			@ -679,7 +715,7 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
 | 
			
		|||
                    var TLSSocket = require('tls').TLSSocket;
 | 
			
		||||
                    var tlsock = new TLSSocket(ser, { secureProtocol: 'SSLv23_method', rejectUnauthorized: false }); // TLSv1_2_method
 | 
			
		||||
                    tlsock.on('error', function (err) { Debug(1, "CIRA TLS Connection Error ", err); });
 | 
			
		||||
                    tlsock.on('secureConnect', function () { Debug(2, "CIRA Secure TLS Connection"); });
 | 
			
		||||
                    tlsock.on('secureConnect', function () { Debug(2, "CIRA Secure TLS Connection"); ws.resume(); });
 | 
			
		||||
                        
 | 
			
		||||
                    // Decrypted tunnel from TLS communcation to be forwarded to websocket
 | 
			
		||||
                    tlsock.on('data', function (data) {
 | 
			
		||||
| 
						 | 
				
			
			@ -699,6 +735,7 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
 | 
			
		|||
                    // Without TLS
 | 
			
		||||
                    ws.forwardclient = parent.mpsserver.SetupCiraChannel(ciraconn, port);
 | 
			
		||||
                    ws.forwardclient.xtls = 0;
 | 
			
		||||
                    ws.resume();
 | 
			
		||||
                }
 | 
			
		||||
                
 | 
			
		||||
                // When data is received from the web socket, forward the data into the associated CIRA cahnnel.
 | 
			
		||||
| 
						 | 
				
			
			@ -753,7 +790,26 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
 | 
			
		|||
            // If Intel AMT direct connection is possible, option a direct socket
 | 
			
		||||
            if ((conn & 4) != 0) {   // We got a new web socket connection, initiate a TCP connection to the target Intel AMT host/port.
 | 
			
		||||
                Debug(2, 'Opening relay TCP socket connection to ' + req.query.host + '.');
 | 
			
		||||
                
 | 
			
		||||
 | 
			
		||||
                // When data is received from the web socket, forward the data into the associated TCP connection.
 | 
			
		||||
                ws.on('message', function (msg) {
 | 
			
		||||
                    Debug(1, 'TCP relay data to ' + node.host + ', ' + msg.length + ' bytes'); // DEBUG
 | 
			
		||||
                    // Convert a buffer into a string, "msg = msg.toString('ascii');" does not work
 | 
			
		||||
                    var msg2 = "";
 | 
			
		||||
                    for (var i = 0; i < msg.length; i++) { msg2 += String.fromCharCode(msg[i]); }
 | 
			
		||||
                    if (ws.interceptor) { msg2 = ws.interceptor.processBrowserData(msg2); } // Run data thru interceptor
 | 
			
		||||
                    ws.forwardclient.write(new Buffer(msg2, "ascii")); // Forward data to the associated TCP connection.
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                // If error, do nothing
 | 
			
		||||
                ws.on('error', function (err) { console.log(err); });
 | 
			
		||||
 | 
			
		||||
                // If the web socket is closed, close the associated TCP connection.
 | 
			
		||||
                ws.on('close', function (req) {
 | 
			
		||||
                    Debug(1, 'Closing relay web socket connection to ' + ws.upgradeReq.query.host + '.');
 | 
			
		||||
                    if (ws.forwardclient) { try { ws.forwardclient.destroy(); } catch (e) { } }
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                // Compute target port
 | 
			
		||||
                var port = 16992;
 | 
			
		||||
                if (node.intelamt.tls > 0) port = 16993; // This is a direct connection, use TLS when possible
 | 
			
		||||
| 
						 | 
				
			
			@ -765,55 +821,25 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
 | 
			
		|||
                    ws.forwardclient.setEncoding('binary');
 | 
			
		||||
                    ws.forwardclient.xstate = 0;
 | 
			
		||||
                    ws.forwardclient.forwardwsocket = ws;
 | 
			
		||||
                    ws.resume();
 | 
			
		||||
                } else {
 | 
			
		||||
                    // If TLS is going to be used, setup a TLS socket
 | 
			
		||||
                    ws.forwardclient = obj.tls.connect(port, node.host, { secureProtocol: 'TLSv1_method', rejectUnauthorized: false }, function () {
 | 
			
		||||
                        // The TLS connection method is the same as TCP, but located a bit differently.
 | 
			
		||||
                        Debug(2, 'TLS connected to ' + node.host + ':' + port + '.');
 | 
			
		||||
                        if (ws.xpendingdata && ws.xpendingdata.length > 0) {
 | 
			
		||||
                            //console.log('TLS sending pending data: ' + ws.xpendingdata.length);
 | 
			
		||||
                            ws.forwardclient.write(ws.xpendingdata);
 | 
			
		||||
                            delete ws.xpendingdata;
 | 
			
		||||
                        }
 | 
			
		||||
                        ws.forwardclient.xstate = 1;
 | 
			
		||||
                        ws.resume();
 | 
			
		||||
                    });
 | 
			
		||||
                    ws.forwardclient.setEncoding('binary');
 | 
			
		||||
                    ws.forwardclient.xstate = 0;
 | 
			
		||||
                    ws.forwardclient.forwardwsocket = ws;
 | 
			
		||||
                    ws.xpendingdata = '';
 | 
			
		||||
                }
 | 
			
		||||
                
 | 
			
		||||
                // When data is received from the web socket, forward the data into the associated TCP connection.
 | 
			
		||||
                // If the TCP connection is pending, buffer up the data until it connects.
 | 
			
		||||
                ws.on('message', function (msg) {
 | 
			
		||||
                    // Debug(1, 'TCP relay data to ' + node.host + ', ' + msg.length + ' bytes'); // DEBUG
 | 
			
		||||
                    // Convert a buffer into a string, "msg = msg.toString('ascii');" does not work
 | 
			
		||||
                    var msg2 = "";
 | 
			
		||||
                    for (var i = 0; i < msg.length; i++) { msg2 += String.fromCharCode(msg[i]); }
 | 
			
		||||
                    if (ws.interceptor) { msg2 = ws.interceptor.processBrowserData(msg2); } // Run data thru interceptor
 | 
			
		||||
                    if (ws.forwardclient == undefined || ws.forwardclient.xstate == 0) {
 | 
			
		||||
                        // TCP connection is pending, buffer up the data.
 | 
			
		||||
                        if (ws.xpendingdata) { ws.xpendingdata += msg2; } else { ws.xpendingdata = msg2; }
 | 
			
		||||
                    } else {
 | 
			
		||||
                        // Forward data to the associated TCP connection.
 | 
			
		||||
                        ws.forwardclient.write(new Buffer(msg2, "ascii"));
 | 
			
		||||
                    }
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                // If error, do nothing
 | 
			
		||||
                ws.on('error', function (err) { console.log(err); });
 | 
			
		||||
 | 
			
		||||
                // If the web socket is closed, close the associated TCP connection.
 | 
			
		||||
                ws.on('close', function (req) {
 | 
			
		||||
                    Debug(1, 'Closing relay web socket connection to ' + ws.upgradeReq.query.host + '.');
 | 
			
		||||
                    if (ws.forwardclient) { try { ws.forwardclient.destroy(); } catch (e) { } }
 | 
			
		||||
                });
 | 
			
		||||
                
 | 
			
		||||
                // When we receive data on the TCP connection, forward it back into the web socket connection.
 | 
			
		||||
                ws.forwardclient.on('data', function (data) {
 | 
			
		||||
                    //Debug(1, 'TCP relay data from ' + node.host + ', ' + data.length + ' bytes.'); // DEBUG
 | 
			
		||||
                    Debug(1, 'TCP relay data from ' + node.host + ', ' + data.length + ' bytes.'); // DEBUG
 | 
			
		||||
                    if (ws.interceptor) { data = ws.interceptor.processAmtData(data); } // Run data thru interceptor
 | 
			
		||||
                    try { ws.send(data); } catch (e) { }
 | 
			
		||||
                    try { ws.send(new Buffer(data, 'binary')); } catch (e) { }
 | 
			
		||||
                });
 | 
			
		||||
                
 | 
			
		||||
                // If the TCP connection closes, disconnect the associated web socket.
 | 
			
		||||
| 
						 | 
				
			
			@ -833,15 +859,11 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
 | 
			
		|||
                else if (req.query.p == 2) { ws.interceptor = obj.interceptor.CreateRedirInterceptor({ user: node.intelamt.user, pass: node.intelamt.pass }); }
 | 
			
		||||
                
 | 
			
		||||
                if (node.intelamt.tls == 0) {
 | 
			
		||||
                    // A TCP connection to Intel AMT just connected, send any pending data and start forwarding.
 | 
			
		||||
                    // A TCP connection to Intel AMT just connected, start forwarding.
 | 
			
		||||
                    ws.forwardclient.connect(port, node.host, function () {
 | 
			
		||||
                        Debug(1, 'TCP relay connected to ' + node.host + ':' + port + '.');
 | 
			
		||||
                        if (ws.xpendingdata && ws.xpendingdata.length > 0) {
 | 
			
		||||
                            //console.log('TCP sending pending data: ' + ws.xpendingdata.length);
 | 
			
		||||
                            ws.forwardclient.write(new Buffer(ws.xpendingdata, "ascii"));
 | 
			
		||||
                            delete ws.xpendingdata;
 | 
			
		||||
                        }
 | 
			
		||||
                        ws.forwardclient.xstate = 1;
 | 
			
		||||
                        ws.resume();
 | 
			
		||||
                    });
 | 
			
		||||
                }
 | 
			
		||||
                return;
 | 
			
		||||
| 
						 | 
				
			
			@ -911,7 +933,7 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
 | 
			
		|||
            req.session.ws.userid = req.session.userid;
 | 
			
		||||
            req.session.ws.domainid = domain.id;
 | 
			
		||||
            var user = obj.users[req.session.userid];
 | 
			
		||||
            if (user == undefined || user == null) { try { ws.close(); } catch (e) { } return; }
 | 
			
		||||
            if (user == null) { try { ws.close(); } catch (e) { } return; }
 | 
			
		||||
            
 | 
			
		||||
            // Add this web socket session to session list
 | 
			
		||||
            ws.sessionId = user._id + '/' + ('' + Math.random()).substring(2);
 | 
			
		||||
| 
						 | 
				
			
			@ -962,8 +984,8 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
 | 
			
		|||
                                    if (state) {
 | 
			
		||||
                                        docs[i].conn = state.connectivity;
 | 
			
		||||
                                        docs[i].pwr = state.powerState;
 | 
			
		||||
                                        if ((state.connectivity & 1) != 0) { var agent = obj.wsagents[docs[i]._id]; if (agent != undefined) { docs[i].agct = agent.connectTime; } }
 | 
			
		||||
                                        if ((state.connectivity & 2) != 0) { var cira = obj.parent.mpsserver.ciraConnections[docs[i]._id]; if (cira != undefined) { docs[i].cict = cira.tag.connectTime; } }
 | 
			
		||||
                                        if ((state.connectivity & 1) != 0) { var agent = obj.wsagents[docs[i]._id]; if (agent != null) { docs[i].agct = agent.connectTime; } }
 | 
			
		||||
                                        if ((state.connectivity & 2) != 0) { var cira = obj.parent.mpsserver.ciraConnections[docs[i]._id]; if (cira != null) { docs[i].cict = cira.tag.connectTime; } }
 | 
			
		||||
                                    }
 | 
			
		||||
                                    // Compress the meshid's
 | 
			
		||||
                                    var meshid = docs[i].meshid;
 | 
			
		||||
| 
						 | 
				
			
			@ -1018,7 +1040,7 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
 | 
			
		|||
                                } else {
 | 
			
		||||
                                    // No records found, send current state if we have it
 | 
			
		||||
                                    var state = obj.parent.GetConnectivityState(command.nodeid);
 | 
			
		||||
                                    if (state != undefined) { ws.send(JSON.stringify({ action: 'powertimeline', nodeid: command.nodeid, timeline: [state.powerState, Date.now(), state.powerState] })); }
 | 
			
		||||
                                    if (state != null) { ws.send(JSON.stringify({ action: 'powertimeline', nodeid: command.nodeid, timeline: [state.powerState, Date.now(), state.powerState] })); }
 | 
			
		||||
                                }
 | 
			
		||||
                            });
 | 
			
		||||
                            break;
 | 
			
		||||
| 
						 | 
				
			
			@ -1034,7 +1056,7 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
 | 
			
		|||
                            // Check permissions
 | 
			
		||||
                            if ((user.siteadmin & 8) != 0) {
 | 
			
		||||
                                // Perform a file operation (Create Folder, Delete Folder, Delete File...)
 | 
			
		||||
                                if ((command.path != undefined) && (typeof command.path == 'object') && command.path.length > 0) {
 | 
			
		||||
                                if ((command.path != null) && (typeof command.path == 'object') && command.path.length > 0) {
 | 
			
		||||
                                    var rootfolder = command.path[0];
 | 
			
		||||
                                    var rootfoldersplit = rootfolder.split('/'), domainx = 'domain';
 | 
			
		||||
                                    if (rootfoldersplit[1].length > 0) domainx = 'domain-' + rootfoldersplit[1];
 | 
			
		||||
| 
						 | 
				
			
			@ -1055,21 +1077,33 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
 | 
			
		|||
                        {
 | 
			
		||||
                            // Route a message.
 | 
			
		||||
                            // This this command has a nodeid, that is the target.
 | 
			
		||||
                            if (command.nodeid != undefined) {
 | 
			
		||||
                            if (command.nodeid != null) {
 | 
			
		||||
                                var splitnodeid = command.nodeid.split('/');
 | 
			
		||||
                                // Check that we are in the same domain and the user has rights over this node.
 | 
			
		||||
                                if ((splitnodeid[0] == 'node') && (splitnodeid[1] == domain.id)) {
 | 
			
		||||
                                    // See if the node is connected
 | 
			
		||||
                                    var agent = obj.wsagents[command.nodeid];
 | 
			
		||||
                                    if (agent != undefined) {
 | 
			
		||||
                                    if (agent != null) {
 | 
			
		||||
                                        // Check if we have permission to send a message to that node
 | 
			
		||||
                                        var rights = user.links[agent.dbMeshKey];
 | 
			
		||||
                                        if (rights != undefined || ((rights & 16) != 0)) { // TODO: 16 is console permission, may need more gradular permission checking
 | 
			
		||||
                                        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
 | 
			
		||||
                                            delete command.nodeid;              // Remove the nodeid since it's implyed.
 | 
			
		||||
                                            agent.send(JSON.stringify(command));
 | 
			
		||||
                                        }
 | 
			
		||||
                                    } else {
 | 
			
		||||
                                        // Check if a peer server is connected to this agent
 | 
			
		||||
                                        var routing = obj.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];
 | 
			
		||||
                                            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
 | 
			
		||||
                                                parent.multiServer.DispatchMessageSingleServer(command, routing.serverid);
 | 
			
		||||
                                            }
 | 
			
		||||
                                        }
 | 
			
		||||
                                    }
 | 
			
		||||
                                }
 | 
			
		||||
                            }
 | 
			
		||||
| 
						 | 
				
			
			@ -1112,7 +1146,7 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
 | 
			
		|||
                            // Delete a user account
 | 
			
		||||
                            if ((user.siteadmin & 2) == 0) break;
 | 
			
		||||
                            var delusername = command.username, deluserid = command.userid, deluser = obj.users[deluserid];
 | 
			
		||||
                            if ((deluser.siteadmin != undefined) && (deluser.siteadmin > 0) && (user.siteadmin != 0xFFFFFFFF)) break; // Need full admin to remote another administrator
 | 
			
		||||
                            if ((deluser.siteadmin != null) && (deluser.siteadmin > 0) && (user.siteadmin != 0xFFFFFFFF)) break; // Need full admin to remote another administrator
 | 
			
		||||
                            if ((deluserid.split('/').length != 3) || (deluserid.split('/')[1] != domain.id)) break; // Invalid domain, operation only valid for current domain
 | 
			
		||||
                            
 | 
			
		||||
                            // Delete all files on the server for this account
 | 
			
		||||
| 
						 | 
				
			
			@ -1159,8 +1193,8 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
 | 
			
		|||
                                var chguserid = 'user/' + domain.id + '/' + command.name.toLowerCase(), chguser = obj.users[chguserid], change = 0;
 | 
			
		||||
                                if (chguser) {
 | 
			
		||||
                                    if (command.email && chguser.email != command.email) { chguser.email = command.email; change = 1; }
 | 
			
		||||
                                    if (command.quota != chguser.quota) { chguser.quota = command.quota; if (chguser.quota == undefined) { delete chguser.quota; } change = 1; }
 | 
			
		||||
                                    if ((user.siteadmin == 0xFFFFFFFF) && (command.siteadmin != undefined) && (chguser.siteadmin != command.siteadmin)) { chguser.siteadmin = command.siteadmin; change = 1 }
 | 
			
		||||
                                    if (command.quota != chguser.quota) { chguser.quota = command.quota; if (chguser.quota == null) { delete chguser.quota; } change = 1; }
 | 
			
		||||
                                    if ((user.siteadmin == 0xFFFFFFFF) && (command.siteadmin != null) && (chguser.siteadmin != command.siteadmin)) { chguser.siteadmin = command.siteadmin; change = 1 }
 | 
			
		||||
                                    if (change == 1) {
 | 
			
		||||
                                        obj.db.Set(chguser);
 | 
			
		||||
                                        obj.parent.DispatchEvent([chguser._id], obj, 'resubscribe');
 | 
			
		||||
| 
						 | 
				
			
			@ -1201,7 +1235,7 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
 | 
			
		|||
                                    obj.db.Set(mesh);
 | 
			
		||||
                                    obj.meshes[meshid] = mesh;
 | 
			
		||||
                                    obj.parent.AddEventDispatch([meshid], ws);
 | 
			
		||||
                                    if (user.links == undefined) user.links = {};
 | 
			
		||||
                                    if (user.links == null) user.links = {};
 | 
			
		||||
                                    user.links[meshid] = { rights: 0xFFFFFFFF };
 | 
			
		||||
                                    user.subscriptions = obj.subscribe(user._id, ws);
 | 
			
		||||
                                    obj.db.SetUser(user);
 | 
			
		||||
| 
						 | 
				
			
			@ -1218,7 +1252,7 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
 | 
			
		|||
                                var mesh = meshes[0];
 | 
			
		||||
                                
 | 
			
		||||
                                // Check if this user has rights to do this
 | 
			
		||||
                                if (mesh.links[user._id] == undefined || mesh.links[user._id].rights != 0xFFFFFFFF) return;
 | 
			
		||||
                                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
 | 
			
		||||
| 
						 | 
				
			
			@ -1253,11 +1287,11 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
 | 
			
		|||
                            var mesh = obj.meshes[command.meshid], change = '';
 | 
			
		||||
                            if (mesh) {
 | 
			
		||||
                                // Check if this user has rights to do this
 | 
			
		||||
                                if (mesh.links[user._id] == undefined || ((mesh.links[user._id].rights & 1) == 0)) return;
 | 
			
		||||
                                if (mesh.links[user._id] == null || ((mesh.links[user._id].rights & 1) == 0)) return;
 | 
			
		||||
                                if ((command.meshid.split('/').length != 3) || (command.meshid.split('/')[1] != domain.id)) return; // Invalid domain, operation only valid for current domain
 | 
			
		||||
                                
 | 
			
		||||
                                if (command.meshname && command.meshname != '' && command.meshname != mesh.name) { change = 'Mesh name changed from "' + mesh.name + '" to "' + command.meshname + '"'; mesh.name = command.meshname; }
 | 
			
		||||
                                if (command.desc != undefined && command.desc != mesh.desc) { if (change != '') change += ' and description changed'; else change += 'Mesh "' + mesh.name + '" description changed'; mesh.desc = command.desc; }
 | 
			
		||||
                                if (command.desc != null && 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(mesh); obj.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;
 | 
			
		||||
| 
						 | 
				
			
			@ -1266,7 +1300,7 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
 | 
			
		|||
                        {
 | 
			
		||||
                            // Check if the user exists
 | 
			
		||||
                            var newuserid = 'user/' + domain.id + '/' + command.username.toLowerCase(), newuser = obj.users[newuserid];
 | 
			
		||||
                            if (newuser == undefined) {
 | 
			
		||||
                            if (newuser == null) {
 | 
			
		||||
                                // TODO: Send error back, user not found.
 | 
			
		||||
                                break;
 | 
			
		||||
                            }
 | 
			
		||||
| 
						 | 
				
			
			@ -1275,11 +1309,11 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
 | 
			
		|||
                            var mesh = obj.meshes[command.meshid], change = '';
 | 
			
		||||
                            if (mesh) {
 | 
			
		||||
                                // Check if this user has rights to do this
 | 
			
		||||
                                if (mesh.links[user._id] == undefined || ((mesh.links[user._id].rights & 2) == 0)) return;
 | 
			
		||||
                                if (mesh.links[user._id] == null || ((mesh.links[user._id].rights & 2) == 0)) return;
 | 
			
		||||
                                if ((command.meshid.split('/').length != 3) || (command.meshid.split('/')[1] != domain.id)) return; // Invalid domain, operation only valid for current domain
 | 
			
		||||
                                
 | 
			
		||||
                                // Add mesh to user
 | 
			
		||||
                                if (newuser.links == undefined) newuser.links = {};
 | 
			
		||||
                                if (newuser.links == null) newuser.links = {};
 | 
			
		||||
                                newuser.links[command.meshid] = { rights: command.meshadmin };
 | 
			
		||||
                                obj.db.Set(newuser);
 | 
			
		||||
                                obj.parent.DispatchEvent([newuser._id], obj, 'resubscribe');
 | 
			
		||||
| 
						 | 
				
			
			@ -1300,7 +1334,7 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
 | 
			
		|||
                            
 | 
			
		||||
                            // Check if the user exists
 | 
			
		||||
                            var deluserid = command.userid, deluser = obj.users[deluserid];
 | 
			
		||||
                            if (deluser == undefined) {
 | 
			
		||||
                            if (deluser == null) {
 | 
			
		||||
                                // TODO: Send error back, user not found.
 | 
			
		||||
                                break;
 | 
			
		||||
                            }
 | 
			
		||||
| 
						 | 
				
			
			@ -1309,10 +1343,10 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
 | 
			
		|||
                            var mesh = obj.meshes[command.meshid];
 | 
			
		||||
                            if (mesh) {
 | 
			
		||||
                                // Check if this user has rights to do this
 | 
			
		||||
                                if (mesh.links[user._id] == undefined || ((mesh.links[user._id].rights & 2) == 0)) return;
 | 
			
		||||
                                if (mesh.links[user._id] == null || ((mesh.links[user._id].rights & 2) == 0)) return;
 | 
			
		||||
                                
 | 
			
		||||
                                // Remove mesh from user
 | 
			
		||||
                                if (deluser.links != undefined && deluser.links[command.meshid] != undefined) {
 | 
			
		||||
                                if (deluser.links != null && deluser.links[command.meshid] != null) {
 | 
			
		||||
                                    var delmeshrights = deluser.links[command.meshid].rights;
 | 
			
		||||
                                    if ((delmeshrights == 0xFFFFFFFF) && (mesh.links[user._id].rights != 0xFFFFFFFF)) return; // A non-admin can't kick out an admin
 | 
			
		||||
                                    delete deluser.links[command.meshid];
 | 
			
		||||
| 
						 | 
				
			
			@ -1321,7 +1355,7 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
 | 
			
		|||
                                }
 | 
			
		||||
                                
 | 
			
		||||
                                // Remove user from the mesh
 | 
			
		||||
                                if (mesh.links[command.userid] != undefined) {
 | 
			
		||||
                                if (mesh.links[command.userid] != null) {
 | 
			
		||||
                                    delete mesh.links[command.userid];
 | 
			
		||||
                                    obj.db.Set(mesh);
 | 
			
		||||
                                }
 | 
			
		||||
| 
						 | 
				
			
			@ -1344,7 +1378,7 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
 | 
			
		|||
                                if (mesh.mtype != 1) return; // This operation is only allowed for mesh type 1, Intel AMT agentless mesh.
 | 
			
		||||
                                
 | 
			
		||||
                                // Check if this user has rights to do this
 | 
			
		||||
                                if (mesh.links[user._id] == undefined || ((mesh.links[user._id].rights & 4) == 0)) return;
 | 
			
		||||
                                if (mesh.links[user._id] == null || ((mesh.links[user._id].rights & 4) == 0)) return;
 | 
			
		||||
                                
 | 
			
		||||
                                // Create a new nodeid
 | 
			
		||||
                                obj.crypto.randomBytes(32, function (err, buf) {
 | 
			
		||||
| 
						 | 
				
			
			@ -1389,7 +1423,7 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
 | 
			
		|||
                                    var mesh = obj.meshes[node.meshid];
 | 
			
		||||
                                    if (mesh) {
 | 
			
		||||
                                        // Check if this user has rights to do this
 | 
			
		||||
                                        if (mesh.links[user._id] == undefined || ((mesh.links[user._id].rights & 4) == 0)) return;
 | 
			
		||||
                                        if (mesh.links[user._id] == null || ((mesh.links[user._id].rights & 4) == 0)) return;
 | 
			
		||||
 | 
			
		||||
                                        // Delete this node including network interface information and events
 | 
			
		||||
                                        obj.db.Remove(node._id);
 | 
			
		||||
| 
						 | 
				
			
			@ -1401,7 +1435,7 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
 | 
			
		|||
 | 
			
		||||
                                        // Disconnect all connections if needed
 | 
			
		||||
                                        var state = obj.parent.GetConnectivityState(command.nodeid);
 | 
			
		||||
                                        if ((state != undefined) && (state.connectivity != undefined)) {
 | 
			
		||||
                                        if ((state != null) && (state.connectivity != null)) {
 | 
			
		||||
                                            if ((state.connectivity & 1) != 0) { obj.wsagents[command.nodeid].close(); } // Disconnect mesh agent
 | 
			
		||||
                                            if ((state.connectivity & 2) != 0) { obj.parent.mpsserver.close(obj.parent.mpsserver.ciraConnections[command.nodeid]); } // Disconnect CIRA connection
 | 
			
		||||
                                        }
 | 
			
		||||
| 
						 | 
				
			
			@ -1430,7 +1464,7 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
 | 
			
		|||
                                        if (mesh) {
 | 
			
		||||
 | 
			
		||||
                                            // Check if this user has rights to do this
 | 
			
		||||
                                            if (mesh.links[user._id] != undefined && ((mesh.links[user._id].rights & 64) != 0)) {
 | 
			
		||||
                                            if (mesh.links[user._id] != null && ((mesh.links[user._id].rights & 64) != 0)) {
 | 
			
		||||
 | 
			
		||||
                                                // Get the device interface information
 | 
			
		||||
                                                obj.db.Get('if' + node._id, function (err, nodeifs) {
 | 
			
		||||
| 
						 | 
				
			
			@ -1484,7 +1518,7 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
 | 
			
		|||
                                        if (mesh) {
 | 
			
		||||
 | 
			
		||||
                                            // Check if this user has rights to do this
 | 
			
		||||
                                            if (mesh.links[user._id] != undefined && ((mesh.links[user._id].rights & 8) != 0)) { // "Remote Control permission"
 | 
			
		||||
                                            if (mesh.links[user._id] != null && ((mesh.links[user._id].rights & 8) != 0)) { // "Remote Control permission"
 | 
			
		||||
 | 
			
		||||
                                                // Get this device
 | 
			
		||||
                                                var agent = obj.wsagents[node._id];
 | 
			
		||||
| 
						 | 
				
			
			@ -1505,7 +1539,7 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
 | 
			
		|||
                    case 'getnetworkinfo':
 | 
			
		||||
                        {
 | 
			
		||||
                            // Argument validation
 | 
			
		||||
                            if ((command.nodeid == undefined) || (typeof command.nodeid != 'string') || (command.nodeid.split('/').length != 3) || (command.nodeid.split('/')[1] != domain.id)) return; // Invalid domain, operation only valid for current domain
 | 
			
		||||
                            if ((command.nodeid == null) || (typeof command.nodeid != 'string') || (command.nodeid.split('/').length != 3) || (command.nodeid.split('/')[1] != domain.id)) return; // Invalid domain, operation only valid for current domain
 | 
			
		||||
 | 
			
		||||
                            // Get the device
 | 
			
		||||
                            obj.db.Get(command.nodeid, function (err, nodes) {
 | 
			
		||||
| 
						 | 
				
			
			@ -1516,7 +1550,7 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
 | 
			
		|||
                                var mesh = obj.meshes[node.meshid];
 | 
			
		||||
                                if (mesh) {
 | 
			
		||||
                                    // Check if this user has rights to do this
 | 
			
		||||
                                    if (mesh.links[user._id] == undefined || (mesh.links[user._id].rights == 0)) { ws.send(JSON.stringify({ action: 'getnetworkinfo', nodeid: command.nodeid, netif: null })); return; }
 | 
			
		||||
                                    if (mesh.links[user._id] == null || (mesh.links[user._id].rights == 0)) { ws.send(JSON.stringify({ action: 'getnetworkinfo', nodeid: command.nodeid, netif: null })); return; }
 | 
			
		||||
 | 
			
		||||
                                    // Get network information about this node
 | 
			
		||||
                                    obj.db.Get('if' + command.nodeid, function (err, netinfos) {
 | 
			
		||||
| 
						 | 
				
			
			@ -1531,7 +1565,7 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
 | 
			
		|||
                    case 'changedevice':
 | 
			
		||||
                        {
 | 
			
		||||
                            // Argument validation
 | 
			
		||||
                            if ((command.nodeid == undefined) || (typeof command.nodeid != 'string') || (command.nodeid.split('/').length != 3) || (command.nodeid.split('/')[1] != domain.id)) return; // Invalid domain, operation only valid for current domain
 | 
			
		||||
                            if ((command.nodeid == null) || (typeof command.nodeid != 'string') || (command.nodeid.split('/').length != 3) || (command.nodeid.split('/')[1] != domain.id)) return; // Invalid domain, operation only valid for current domain
 | 
			
		||||
                            
 | 
			
		||||
                            // Change the device
 | 
			
		||||
                            obj.db.Get(command.nodeid, function (err, nodes) {
 | 
			
		||||
| 
						 | 
				
			
			@ -1542,7 +1576,7 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
 | 
			
		|||
                                var mesh = obj.meshes[node.meshid];
 | 
			
		||||
                                if (mesh) {
 | 
			
		||||
                                    // Check if this user has rights to do this
 | 
			
		||||
                                    if (mesh.links[user._id] == undefined || ((mesh.links[user._id].rights & 4) == 0)) return;
 | 
			
		||||
                                    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 };
 | 
			
		||||
| 
						 | 
				
			
			@ -1552,9 +1586,9 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
 | 
			
		|||
                                    if (command.icon && (command.icon != node.icon)) { change = 1; node.icon = command.icon; changes.push('icon'); }
 | 
			
		||||
                                    if (command.name && (command.name != node.name)) { change = 1; node.name = command.name; changes.push('name'); }
 | 
			
		||||
                                    if (command.host && (command.host != node.host)) { change = 1; node.host = command.host; changes.push('host'); }
 | 
			
		||||
                                    if (command.desc != undefined && (command.desc != node.desc)) { change = 1; node.desc = command.desc; changes.push('description'); }
 | 
			
		||||
                                    if ((command.intelamt != undefined) && (node.intelamt != undefined)) {
 | 
			
		||||
                                        if ((command.intelamt.user != undefined) && (command.intelamt.pass != undefined) && ((command.intelamt.user != node.intelamt.user) || (command.intelamt.pass != node.intelamt.pass))) { change = 1; node.intelamt.user = command.intelamt.user; node.intelamt.pass = command.intelamt.pass; changes.push('Intel AMT credentials'); }
 | 
			
		||||
                                    if (command.desc != null && (command.desc != node.desc)) { change = 1; node.desc = command.desc; changes.push('description'); }
 | 
			
		||||
                                    if (command.intelamt != null) {
 | 
			
		||||
                                        if ((command.intelamt.user != null) && (command.intelamt.pass != undefined) && ((command.intelamt.user != node.intelamt.user) || (command.intelamt.pass != node.intelamt.pass))) { change = 1; node.intelamt.user = command.intelamt.user; node.intelamt.pass = command.intelamt.pass; changes.push('Intel AMT credentials'); }
 | 
			
		||||
                                        if (command.intelamt.tls && (command.intelamt.tls != node.intelamt.tls)) { change = 1; node.intelamt.tls = command.intelamt.tls; changes.push('Intel AMT TLS'); }
 | 
			
		||||
                                    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1775,16 +1809,16 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
 | 
			
		|||
    
 | 
			
		||||
    // Handle a request to download a mesh agent
 | 
			
		||||
    obj.handleMeshAgentRequest = function (req, res) {
 | 
			
		||||
        if (req.query.id != undefined) {
 | 
			
		||||
        if (req.query.id != null) {
 | 
			
		||||
            // Send a specific mesh agent back
 | 
			
		||||
            var argentInfo = obj.parent.meshAgentBinaries[req.query.id];
 | 
			
		||||
            if (argentInfo == undefined) { res.sendStatus(404); return; }
 | 
			
		||||
            if (argentInfo == null) { res.sendStatus(404); return; }
 | 
			
		||||
            res.set({ 'Cache-Control': 'no-cache, no-store, must-revalidate', 'Pragma': 'no-cache', 'Expires': '0', 'Content-Type': 'application/octet-stream', 'Content-Disposition': 'attachment; filename=' + argentInfo.rname });
 | 
			
		||||
            res.sendFile(argentInfo.path);
 | 
			
		||||
        } else if (req.query.script != undefined) {
 | 
			
		||||
        } else if (req.query.script != null) {
 | 
			
		||||
            // Send a specific mesh install script back
 | 
			
		||||
            var scriptInfo = obj.parent.meshAgentInstallScripts[req.query.script];
 | 
			
		||||
            if (scriptInfo == undefined) { res.sendStatus(404); return; }
 | 
			
		||||
            if (scriptInfo == null) { res.sendStatus(404); return; }
 | 
			
		||||
            res.set({ 'Cache-Control': 'no-cache, no-store, must-revalidate', 'Pragma': 'no-cache', 'Expires': '0', 'Content-Type': 'text/plain', 'Content-Disposition': 'attachment; filename=' + scriptInfo.rname });
 | 
			
		||||
            res.sendFile(scriptInfo.path);
 | 
			
		||||
        } else {
 | 
			
		||||
| 
						 | 
				
			
			@ -1814,7 +1848,7 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
 | 
			
		|||
            
 | 
			
		||||
            // Check if this user has rights to do this
 | 
			
		||||
            //var user = obj.users[req.session.userid];
 | 
			
		||||
            //if ((user == undefined) || (mesh.links[user._id] == undefined) || ((mesh.links[user._id].rights & 1) == 0)) { res.sendStatus(401); return; }
 | 
			
		||||
            //if ((user == null) || (mesh.links[user._id] == null) || ((mesh.links[user._id].rights & 1) == 0)) { res.sendStatus(401); return; }
 | 
			
		||||
            //if (domain.id != mesh.domain) { res.sendStatus(401); return; }
 | 
			
		||||
                        
 | 
			
		||||
            var xdomain = domain.id;
 | 
			
		||||
| 
						 | 
				
			
			@ -1971,29 +2005,29 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
 | 
			
		|||
 | 
			
		||||
    // Force mesh agent disconnection
 | 
			
		||||
    function forceMeshAgentDisconnect(user, domain, nodeid, disconnectMode) {
 | 
			
		||||
        if ((nodeid == undefined) || (nodeid == null)) return;
 | 
			
		||||
        if (nodeid == null) return;
 | 
			
		||||
        var splitnode = nodeid.split('/');
 | 
			
		||||
        if ((splitnode.length != 3) || (splitnode[1] != domain.id)) return; // Check that nodeid is valid and part of our domain
 | 
			
		||||
        var agent = obj.wsagents[nodeid];
 | 
			
		||||
        if (agent == undefined) return;
 | 
			
		||||
        if (agent == null) return;
 | 
			
		||||
 | 
			
		||||
        // Check we have agent rights
 | 
			
		||||
        var rights = user.links[agent.dbMeshKey].rights;
 | 
			
		||||
        if ((rights != undefined) && ((rights & 16) != 0) && (user.siteadmin == 0xFFFFFFFF)) { agent.close(disconnectMode); }
 | 
			
		||||
        if ((rights != null) && ((rights & 16) != 0) && (user.siteadmin == 0xFFFFFFFF)) { agent.close(disconnectMode); }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Send the core module to the mesh agent
 | 
			
		||||
    function sendMeshAgentCore(user, domain, nodeid, core) {
 | 
			
		||||
        if ((nodeid == undefined) || (nodeid == null)) return;
 | 
			
		||||
        if (nodeid == null) return;
 | 
			
		||||
        var splitnode = nodeid.split('/');
 | 
			
		||||
        if ((splitnode.length != 3) || (splitnode[1] != domain.id)) return; // Check that nodeid is valid and part of our domain
 | 
			
		||||
        var agent = obj.wsagents[nodeid];
 | 
			
		||||
        if (agent == undefined) return;
 | 
			
		||||
        if (agent == null) return;
 | 
			
		||||
 | 
			
		||||
        // Check we have agent rights
 | 
			
		||||
        var rights = user.links[agent.dbMeshKey].rights;
 | 
			
		||||
        if ((rights != undefined) && ((rights & 16) != 0) && (user.siteadmin == 0xFFFFFFFF)) {
 | 
			
		||||
            if ((core == null) || (core == undefined)) {
 | 
			
		||||
        if ((rights != null) && ((rights & 16) != 0) && (user.siteadmin == 0xFFFFFFFF)) {
 | 
			
		||||
            if (core == null) {
 | 
			
		||||
                // Clear the mesh agent core
 | 
			
		||||
                agent.agentCoreCheck = 1000; // Tell the agent object we are not using a custom core.
 | 
			
		||||
                agent.send(obj.common.ShortToStr(10) + obj.common.ShortToStr(0));
 | 
			
		||||
| 
						 | 
				
			
			@ -2016,18 +2050,18 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
 | 
			
		|||
 | 
			
		||||
    // Return the maximum number of bytes allowed in the user account "My Files".
 | 
			
		||||
    function getQuota(objid, domain) {
 | 
			
		||||
        if ((objid == undefined) || (objid == null)) return 0;
 | 
			
		||||
        if (objid == null) return 0;
 | 
			
		||||
        if (objid.startsWith('user/')) {
 | 
			
		||||
            var user = obj.users[objid];
 | 
			
		||||
            if (user == undefined) return 0;
 | 
			
		||||
            if ((user.quota != undefined) && (typeof user.quota == 'number')) { return user.quota; }
 | 
			
		||||
            if ((domain != undefined) && (domain.userQuota != undefined) && (typeof domain.userQuota == 'number')) { return domain.userQuota; }
 | 
			
		||||
            if (user == null) return 0;
 | 
			
		||||
            if ((user.quota != null) && (typeof user.quota == 'number')) { return user.quota; }
 | 
			
		||||
            if ((domain != null) && (domain.userQuota != null) && (typeof domain.userQuota == 'number')) { return domain.userQuota; }
 | 
			
		||||
            return 1048576; // By default, the server will have a 1 meg limit on user accounts
 | 
			
		||||
        } else if (objid.startsWith('mesh/')) {
 | 
			
		||||
            var mesh = obj.meshes[objid];
 | 
			
		||||
            if (mesh == undefined) return 0;
 | 
			
		||||
            if ((mesh.quota != undefined) && (typeof mesh.quota == 'number')) { return mesh.quota; }
 | 
			
		||||
            if ((domain != undefined) && (domain.meshQuota != undefined) && (typeof domain.meshQuota == 'number')) { return domain.meshQuota; }
 | 
			
		||||
            if (mesh == null) return 0;
 | 
			
		||||
            if ((mesh.quota != null) && (typeof mesh.quota == 'number')) { return mesh.quota; }
 | 
			
		||||
            if ((domain != null) && (domain.meshQuota != null) && (typeof domain.meshQuota == 'number')) { return domain.meshQuota; }
 | 
			
		||||
            return 1048576; // By default, the server will have a 1 meg limit on mesh accounts
 | 
			
		||||
        }
 | 
			
		||||
        return 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -2035,7 +2069,7 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
 | 
			
		|||
    
 | 
			
		||||
    // Get the server path of a user or mesh object
 | 
			
		||||
    function getServerRootFilePath(obj) {
 | 
			
		||||
        if ((typeof obj != 'object') || (obj.domain == undefined) || (obj._id == undefined)) return null;
 | 
			
		||||
        if ((typeof obj != 'object') || (obj.domain == null) || (obj._id == null)) return null;
 | 
			
		||||
        var domainname = 'domain', splitname = obj._id.split('/');
 | 
			
		||||
        if (splitname.length != 3) return null;
 | 
			
		||||
        if (obj.domain !== '') domainname = 'domain-' + obj.domain;
 | 
			
		||||
| 
						 | 
				
			
			@ -2048,7 +2082,7 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
 | 
			
		|||
        if ((splitpath.length < 3) || (splitpath[0] != 'user' && splitpath[0] != 'mesh') || (splitpath[1] != domain.id)) return null; // Basic validation
 | 
			
		||||
        var objid = splitpath[0] + '/' + splitpath[1] + '/' + splitpath[2];
 | 
			
		||||
        if (splitpath[0] == 'user' && (objid != user._id)) return null; // User validation, only self allowed
 | 
			
		||||
        if (splitpath[0] == 'mesh') { var link = user.links[objid]; if ((link == undefined) || (link.rights == undefined) || ((link.rights & 32) == 0)) { return null; } } // Check mesh server file rights
 | 
			
		||||
        if (splitpath[0] == 'mesh') { var link = user.links[objid]; if ((link == null) || (link.rights == null) || ((link.rights & 32) == 0)) { return null; } } // Check mesh server file rights
 | 
			
		||||
        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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue