From 040440db79c9af4b5b9cba71f1cc55e8fccbe501 Mon Sep 17 00:00:00 2001 From: Ylian Saint-Hilaire Date: Fri, 15 Sep 2017 11:45:06 -0700 Subject: [PATCH] Added new account creation and server peering flow control --- meshagent.js | 56 ++++---- meshcentral.js | 69 +++++----- mesherrors.txt | 147 +++++++++++++++++++++ multiserver.js | 156 +++++++++++++++++++--- package.json | 2 +- views/login.handlebars | 9 +- webserver.js | 284 +++++++++++++++++++++++------------------ 7 files changed, 530 insertions(+), 193 deletions(-) diff --git a/meshagent.js b/meshagent.js index fe1cb97b..fc421427 100644 --- a/meshagent.js +++ b/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; diff --git a/meshcentral.js b/meshcentral.js index da3c7424..c9ac3915 100644 --- a/meshcentral.js +++ b/meshcentral.js @@ -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 diff --git a/mesherrors.txt b/mesherrors.txt index 68975771..4cc15d4a 100644 --- a/mesherrors.txt +++ b/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. (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. (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) + + diff --git a/multiserver.js b/multiserver.js index a8e8cda9..ce4334a9 100644 --- a/multiserver.js +++ b/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; diff --git a/package.json b/package.json index 53f0dab4..8b41d3b4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "meshcentral", - "version": "0.0.7-u", + "version": "0.0.7-w", "keywords": [ "Remote Management", "Intel AMT", diff --git a/views/login.handlebars b/views/login.handlebars index d7abde47..b5fb7ef1 100644 --- a/views/login.handlebars +++ b/views/login.handlebars @@ -87,6 +87,10 @@ Password Hint: + + Creation Token: + +
@@ -136,6 +140,7 @@