Added a lot of the load-balancing support

This commit is contained in:
Ylian Saint-Hilaire 2017-09-13 11:25:57 -07:00
parent 6347eb7e4a
commit fb5114399f
10 changed files with 2198 additions and 108 deletions

View File

@ -776,6 +776,12 @@ function createMeshCore(agent) {
} }
break; break;
} }
case 'location': {
getIpLocationData(function (location) {
sendConsoleText(objToString({ "action": "iplocation", "type": "publicip", "value": location }, 0, '.'));
});
break;
}
default: { // This is an unknown command, return an error message default: { // This is an unknown command, return an error message
response = 'Unknown command \"' + cmd + '\", type \"help\" for list of avaialble commands.'; response = 'Unknown command \"' + cmd + '\", type \"help\" for list of avaialble commands.';
break; break;

13
db.js
View File

@ -18,6 +18,8 @@
module.exports.CreateDB = function (args, datapath) { module.exports.CreateDB = function (args, datapath) {
var obj = {}; var obj = {};
obj.path = require('path'); obj.path = require('path');
obj.identifier = null;
if (args.mongodb) { if (args.mongodb) {
// Use MongoDB // Use MongoDB
obj.databaseType = 2; obj.databaseType = 2;
@ -35,6 +37,17 @@ module.exports.CreateDB = function (args, datapath) {
} }
obj.SetupDatabase = function (func) { obj.SetupDatabase = function (func) {
// Check if the database unique identifier is present
// This is used to check that in server peering mode, everyone is using the same database.
obj.Get('DatabaseIdentifier', function (err, docs) {
if ((docs.length == 1) && (docs[0].value != null)) {
obj.identifier = docs[0].value;
} else {
obj.identifier = new Buffer(require('crypto').randomBytes(32), 'binary').toString('hex');
obj.Set({ _id: 'DatabaseIdentifier', value: obj.identifier });
}
});
// Load database schema version and check if we need to update // Load database schema version and check if we need to update
obj.Get('SchemaVersion', function (err, docs) { obj.Get('SchemaVersion', function (err, docs) {
var ver = 0; var ver = 0;

View File

@ -30,7 +30,7 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
if (obj.remoteaddr.startsWith('::ffff:')) { obj.remoteaddr = obj.remoteaddr.substring(7); } if (obj.remoteaddr.startsWith('::ffff:')) { obj.remoteaddr = obj.remoteaddr.substring(7); }
// Send a message to the mesh agent // Send a message to the mesh agent
obj.send = function (data) { if (typeof data == 'string') { obj.ws.send(new Buffer(data, 'binary')); } else { obj.ws.send(data); } } obj.send = function (data) { try { if (typeof data == 'string') { obj.ws.send(new Buffer(data, 'binary')); } else { obj.ws.send(data); } } catch (e) { } }
// Disconnect this agent // Disconnect this agent
obj.close = function (arg) { obj.close = function (arg) {
@ -92,7 +92,7 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
if (err) { return console.error(err); } if (err) { return console.error(err); }
obj.agentUpdate = { oldHash: agenthash, ptr: 0, buf: new Buffer(agentUpdateBlockSize + 4), fd: fd }; obj.agentUpdate = { oldHash: agenthash, ptr: 0, buf: new Buffer(agentUpdateBlockSize + 4), fd: fd };
// We got the agent file open ont he server side, tell the agent we are sending an update starting with the SHA256 hash of the result // We got the agent file open on the server side, tell the agent we are sending an update starting with the SHA256 hash of the result
//console.log("Agent update file open."); //console.log("Agent update file open.");
obj.send(obj.common.ShortToStr(13) + obj.common.ShortToStr(0)); // Command 13, start mesh agent download obj.send(obj.common.ShortToStr(13) + obj.common.ShortToStr(0)); // Command 13, start mesh agent download

View File

@ -21,8 +21,8 @@ function CreateMeshCentralServer() {
obj.args = require('minimist')(process.argv.slice(2)); obj.args = require('minimist')(process.argv.slice(2));
obj.common = require('./common.js'); obj.common = require('./common.js');
obj.certificates = null; obj.certificates = null;
obj.connectivityByMesh = {}; // This object keeps a list of all connected CIRA and agents, by meshid->nodeid->value (value: 1 = Agent, 2 = CIRA, 4 = AmtDirect)
obj.connectivityByNode = {}; // This object keeps a list of all connected CIRA and agents, by nodeid->value (value: 1 = Agent, 2 = CIRA, 4 = AmtDirect) obj.connectivityByNode = {}; // This object keeps a list of all connected CIRA and agents, by nodeid->value (value: 1 = Agent, 2 = CIRA, 4 = AmtDirect)
obj.peerConnectivityByNode = {}; // This object keeps a list of all connected CIRA and agents of peers, by serverid->nodeid->value (value: 1 = Agent, 2 = CIRA, 4 = AmtDirect)
obj.debugLevel = 0; obj.debugLevel = 0;
obj.config = {}; // Configuration file obj.config = {}; // Configuration file
obj.dbconfig = {}; // Persistance values, loaded from database obj.dbconfig = {}; // Persistance values, loaded from database
@ -36,6 +36,7 @@ function CreateMeshCentralServer() {
obj.multiServer = null; obj.multiServer = null;
obj.currentVer = null; obj.currentVer = null;
obj.maintenanceTimer = null; obj.maintenanceTimer = null;
obj.serverId = null;
// Create data and files folders if needed // Create data and files folders if needed
try { obj.fs.mkdirSync(obj.datapath); } catch (e) { } try { obj.fs.mkdirSync(obj.datapath); } catch (e) { }
@ -136,6 +137,7 @@ function CreateMeshCentralServer() {
} else { } else {
if (error != null) { if (error != null) {
// This is an un-expected restart // This is an un-expected restart
console.log(error);
console.log('ERROR: MeshCentral failed with critical error, check MeshErrors.txt. Restarting...'); console.log('ERROR: MeshCentral failed with critical error, check MeshErrors.txt. Restarting...');
setTimeout(function () { obj.launchChildServer(startLine); }, 1000); setTimeout(function () { obj.launchChildServer(startLine); }, 1000);
} }
@ -289,6 +291,10 @@ function CreateMeshCentralServer() {
require('crypto').randomBytes(32, function (err, buf) { require('crypto').randomBytes(32, function (err, buf) {
// Setup Mesh Multi-Server if needed // Setup Mesh Multi-Server if needed
obj.multiServer = require('./multiserver.js').CreateMultiServer(obj, obj.args); obj.multiServer = require('./multiserver.js').CreateMultiServer(obj, obj.args);
if (obj.multiServer != null) {
obj.serverId = obj.config.peers.serverId;
for (var serverid in obj.config.peers.servers) { obj.peerConnectivityByNode[serverid] = {}; }
}
if (obj.args.secret) { if (obj.args.secret) {
// This secret is used to encrypt HTTP session information, if specified, user it. // This secret is used to encrypt HTTP session information, if specified, user it.
@ -414,10 +420,54 @@ function CreateMeshCentralServer() {
} }
} }
} }
if ((fromPeerServer == undefined) && (obj.multiServer != null)) { obj.multiServer.DispatchEvent(ids, source, event); } if ((fromPeerServer == undefined) && (obj.multiServer != null) && (event.nopeers != 1)) { obj.multiServer.DispatchEvent(ids, source, event); }
delete targets; delete targets;
} }
// Get the connection state of a node
obj.GetConnectivityState = function (nodeid) { return obj.connectivityByNode[nodeid]; }
// 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) {
for (var nodeid in nodeids) {
var meshid = null, state = null, oldConnectivity = 0, oldPowerState = 0, newConnectivity = 0, newPowerState = 0;
var oldState = obj.connectivityByNode[nodeid];
if (oldState != null) { meshid = oldState.meshid; oldConnectivity = oldState.connectivity; oldPowerState = oldState.powerState; }
for (serverid in obj.peerConnectivityByNode) {
var peerState = obj.peerConnectivityByNode[serverid][nodeid];
if (peerState != null) {
if (state == null) {
// Copy the state
state = {};
newConnectivity = state.connectivity = peerState.connectivity;
newPowerState = state.powerState = peerState.powerState;
meshid = state.meshid = peerState.meshid;
//if (peerState.agentPower) { state.agentPower = peerState.agentPower; }
//if (peerState.ciraPower) { state.ciraPower = peerState.ciraPower; }
//if (peerState.amtPower) { state.amtPower = peerState.amtPower; }
} else {
// Merge the state
state.connectivity |= peerState.connectivity;
newConnectivity = state.connectivity;
if ((peerState.powerState != 0) && ((state.powerState == 0) || (peerState.powerState < state.powerState))) { newPowerState = state.powerState = peerState.powerState; }
meshid = state.meshid = peerState.meshid;
//if (peerState.agentPower) { state.agentPower = peerState.agentPower; }
//if (peerState.ciraPower) { state.ciraPower = peerState.ciraPower; }
//if (peerState.amtPower) { state.amtPower = peerState.amtPower; }
}
}
}
obj.connectivityByNode[nodeid] = state;
//console.log('xx', nodeid, meshid, newConnectivity, oldPowerState, newPowerState, oldPowerState);
// Event any changes on this server only
if ((newConnectivity != oldPowerState) || (newPowerState != oldPowerState)) {
obj.DispatchEvent(['*', meshid], obj, { action: 'nodeconnect', meshid: meshid, nodeid: nodeid, conn: newConnectivity, pwr: newPowerState, nolog: 1, nopeers: 1 });
}
}
}
// Set the connectivity state of a node and setup the server so that messages can be routed correctly. // Set the connectivity state of a node and setup the server so that messages can be routed correctly.
// meshId: mesh identifier of format mesh/domain/meshidhex // meshId: mesh identifier of format mesh/domain/meshidhex
@ -427,79 +477,132 @@ function CreateMeshCentralServer() {
// powerState: Value, 0 = Unknown, 1 = S0 power on, 2 = S1 Sleep, 3 = S2 Sleep, 4 = S3 Sleep, 5 = S4 Hibernate, 6 = S5 Soft-Off, 7 = Present // powerState: Value, 0 = Unknown, 1 = S0 power on, 2 = S1 Sleep, 3 = S2 Sleep, 4 = S3 Sleep, 5 = S4 Hibernate, 6 = S5 Soft-Off, 7 = Present
var connectTypeStrings = ['', 'MeshAgent', 'Intel AMT CIRA', '', 'Intel AMT local']; var connectTypeStrings = ['', 'MeshAgent', 'Intel AMT CIRA', '', 'Intel AMT local'];
var powerStateStrings = ['Unknown', 'Powered', 'Sleep', 'Sleep', 'Deep Sleep', 'Hibernating', 'Soft-Off', 'Present']; var powerStateStrings = ['Unknown', 'Powered', 'Sleep', 'Sleep', 'Deep Sleep', 'Hibernating', 'Soft-Off', 'Present'];
obj.SetConnectivityState = function (meshid, nodeid, connectTime, connectType, powerState) { obj.SetConnectivityState = function (meshid, nodeid, connectTime, connectType, powerState, serverid) {
//console.log('SetConnectivity for ' + nodeid.substring(0, 16) + ', Type: ' + connectTypeStrings[connectType] + ', Power: ' + powerStateStrings[powerState]); //console.log('SetConnectivity for ' + nodeid.substring(0, 16) + ', Type: ' + connectTypeStrings[connectType] + ', Power: ' + powerStateStrings[powerState] + (serverid == null ? ('') : (', ServerId: ' + serverid)));
if ((serverid == null) && (obj.multiServer != null)) { obj.multiServer.DispatchMessage({ action: 'SetConnectivityState', meshid: meshid, nodeid: nodeid, connectTime: connectTime, connectType: connectType, powerState: powerState }); }
// Change the node connection state if (obj.multiServer == null) {
var eventConnectChange = 0; // Single server mode
var state = obj.connectivityByNode[nodeid];
if (state) { // Change the node connection state
// Change the connection in the node and mesh state lists var eventConnectChange = 0;
if ((state.connectivity & connectType) == 0) { var state = obj.connectivityByNode[nodeid];
state.connectivity |= connectType; if (state) {
// Change the connection in the node and mesh state lists
if ((state.connectivity & connectType) == 0) { state.connectivity |= connectType; eventConnectChange = 1; }
state.meshid = meshid;
} else {
// Add the connection to the node and mesh state list
obj.connectivityByNode[nodeid] = state = { connectivity: connectType, meshid: meshid };
eventConnectChange = 1; eventConnectChange = 1;
} }
// Set node power state
if (connectType == 1) { state.agentPower = powerState; } else if (connectType == 2) { state.ciraPower = powerState; } else if (connectType == 4) { state.amtPower = powerState; }
var powerState = 0, 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)) {
state.powerState = powerState;
eventConnectChange = 1;
// Set new power state in database
obj.db.file.insert({ type: 'power', time: connectTime, node: nodeid, power: powerState, oldPower: oldPowerState });
}
// Event the node connection change
if (eventConnectChange == 1) { obj.DispatchEvent(['*', meshid], obj, { action: 'nodeconnect', meshid: meshid, nodeid: nodeid, conn: state.connectivity, pwr: state.powerState, ct: connectTime, nolog: 1, nopeers: 1 }); }
} else { } else {
// Add the connection to the node and mesh state list // Multi server mode
obj.connectivityByNode[nodeid] = state = { connectivity: connectType };
if (!obj.connectivityByMesh[meshid]) { obj.connectivityByMesh[meshid] = {}; } // Change the node connection state
obj.connectivityByMesh[meshid][nodeid] = state; if (serverid == null) { serverid = obj.serverId; }
eventConnectChange = 1; if (obj.peerConnectivityByNode[serverid] == null) return; // Guard against unknown serverid's
var state = obj.peerConnectivityByNode[serverid][nodeid];
if (state) {
// Change the connection in the node and mesh state lists
if ((state.connectivity & connectType) == 0) { state.connectivity |= connectType; }
state.meshid = meshid;
} else {
// Add the connection to the node and mesh state list
obj.peerConnectivityByNode[serverid][nodeid] = state = { connectivity: connectType, meshid: meshid };
}
// Set node power state
if (connectType == 1) { state.agentPower = powerState; } else if (connectType == 2) { state.ciraPower = powerState; } else if (connectType == 4) { state.amtPower = powerState; }
var powerState = 0;
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; }
// Update the combined node state
var x = {}; x[nodeid] = 1;
obj.UpdateConnectivityState(x);
} }
// Set node power state
if (connectType == 1) { state.agentPower = powerState; } else if (connectType == 2) { state.ciraPower = powerState; } else if (connectType == 4) { state.amtPower = powerState; }
var powerState = 0, 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)) {
state.powerState = powerState;
eventConnectChange = 1;
// Set new power state in database
obj.db.file.insert({ type: 'power', time: connectTime, node: nodeid, power: powerState, oldPower: oldPowerState });
}
// Event the node connection change
if (eventConnectChange == 1) { obj.DispatchEvent(['*', meshid], obj, { action: 'nodeconnect', meshid: meshid, nodeid: nodeid, conn: state.connectivity, pwr: state.powerState, ct: connectTime, nolog: 1 }); }
} }
// Clear the connectivity state of a node and setup the server so that messages can be routed correctly. // Clear the connectivity state of a node and setup the server so that messages can be routed correctly.
// meshId: mesh identifier of format mesh/domain/meshidhex // meshId: mesh identifier of format mesh/domain/meshidhex
// nodeId: node identifier of format node/domain/nodeidhex // nodeId: node identifier of format node/domain/nodeidhex
// connectType: Bitmask, 1 = MeshAgent, 2 = Intel AMT CIRA, 3 = Intel AMT local. // connectType: Bitmask, 1 = MeshAgent, 2 = Intel AMT CIRA, 3 = Intel AMT local.
obj.ClearConnectivityState = function (meshid, nodeid, connectType) { obj.ClearConnectivityState = function (meshid, nodeid, connectType, serverid) {
//console.log('ClearConnectivity for ' + nodeid.substring(0, 16) + ', Type: ' + connectTypeStrings[connectType]); //console.log('ClearConnectivity for ' + nodeid.substring(0, 16) + ', Type: ' + connectTypeStrings[connectType] + (serverid == null?(''):(', ServerId: ' + serverid)));
if ((serverid == null) && (obj.multiServer != null)) { obj.multiServer.DispatchMessage({ action: 'ClearConnectivityState', meshid: meshid, nodeid: nodeid, connectType: connectType }); }
// Remove the agent connection from the nodes connection list if (obj.multiServer == null) {
var state = obj.connectivityByNode[nodeid]; // Single server mode
if (state == undefined) return;
if ((state.connectivity & connectType) != 0) { // Remove the agent connection from the nodes connection list
state.connectivity -= connectType; var state = obj.connectivityByNode[nodeid];
if (state == undefined) return;
// If the node is completely disconnected, clean it up completely if ((state.connectivity & connectType) != 0) {
if (state.connectivity == 0) { state.connectivity -= connectType;
delete obj.connectivityByNode[nodeid];
delete obj.connectivityByMesh[meshid][nodeid]; // If the node is completely disconnected, clean it up completely
state.powerState = 0; if (state.connectivity == 0) { delete obj.connectivityByNode[nodeid]; state.powerState = 0; }
eventConnectChange = 1;
} }
eventConnectChange = 1;
// Clear node power state
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)) {
state.powerState = powerState;
eventConnectChange = 1;
// Set new power state in database
obj.db.file.insert({ type: 'power', time: Date.now(), node: nodeid, power: powerState, oldPower: oldPowerState });
}
// Event the node connection change
if (eventConnectChange == 1) { obj.DispatchEvent(['*', meshid], obj, { action: 'nodeconnect', meshid: meshid, nodeid: nodeid, conn: state.connectivity, pwr: state.powerState, nolog: 1, nopeers: 1 }); }
} else {
// Multi server mode
// Remove the agent connection from the nodes connection list
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 existing state exist, remove this connection
if ((state.connectivity & connectType) != 0) {
state.connectivity -= connectType; // Remove one connectivity mode
// If the node is completely disconnected, clean it up completely
if (state.connectivity == 0) { delete obj.peerConnectivityByNode[serverid][nodeid]; state.powerState = 0; }
}
// Clear node power state
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; }
// Update the combined node state
var x = {}; x[nodeid] = 1;
obj.UpdateConnectivityState(x);
} }
// Clear node power state
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)) {
state.powerState = powerState;
eventConnectChange = 1;
// Set new power state in database
obj.db.file.insert({ type: 'power', time: Date.now(), node: nodeid, power: powerState, oldPower: oldPowerState });
}
// Event the node connection change
if (eventConnectChange == 1) { obj.DispatchEvent(['*', meshid], obj, { action: 'nodeconnect', meshid: meshid, nodeid: nodeid, conn: state.connectivity, pwr: state.powerState, nolog: 1 }); }
} }
// Update the default mesh core // Update the default mesh core
@ -689,7 +792,7 @@ function InstallModule(modulename, func, tag1, tag2) {
process.on('SIGINT', function () { if (meshserver != null) { meshserver.Stop(); meshserver = null; } console.log('Server Ctrl-C exit...'); process.exit(); }); process.on('SIGINT', function () { if (meshserver != null) { meshserver.Stop(); meshserver = null; } console.log('Server Ctrl-C exit...'); process.exit(); });
// Build the list of required modules // Build the list of required modules
var modules = ['nedb', 'https', 'unzip', 'xmldom', 'express', 'mongojs', 'archiver', 'minimist', 'multiparty', 'node-forge', 'express-ws', 'compression', 'body-parser', 'connect-redis', 'express-session', 'express-handlebars']; var modules = ['nedb', 'https', 'unzip', 'xmldom', 'express', 'mongojs', 'archiver', 'websocket', 'minimist', 'multiparty', 'node-forge', 'express-ws', 'compression', 'body-parser', 'connect-redis', 'express-session', 'express-handlebars'];
if (require('os').platform() == 'win32') { modules.push("node-windows"); } if (require('os').platform() == 'win32') { modules.push("node-windows"); }
// Run as a command line, if we are not using service arguments, don't need to install the service package. // Run as a command line, if we are not using service arguments, don't need to install the service package.

File diff suppressed because it is too large Load Diff

View File

@ -9,10 +9,381 @@ module.exports.CreateMultiServer = function (parent, args) {
var obj = {}; var obj = {};
obj.parent = parent; obj.parent = parent;
obj.crypto = require('crypto'); obj.crypto = require('crypto');
obj.peerConfig = parent.config.peers;
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
// Create a mesh server module that will connect to other servers
obj.CreatePeerOutServer = function (parent, serverid, url) {
var obj = {};
obj.parent = parent;
obj.serverid = serverid;
obj.url = url;
obj.ws = null;
obj.conn = null;
obj.certificates = parent.parent.certificates;
obj.common = require('./common.js');
obj.forge = require('node-forge');
obj.crypto = require('crypto');
obj.pki = obj.forge.pki;
obj.connectionState = 0;
obj.retryTimer = null;
obj.retryBackoff = 0;
obj.connectHandler = null;
obj.webCertificatHash = obj.parent.parent.webserver.webCertificatHash;
obj.agentCertificatHashHex = obj.parent.parent.webserver.agentCertificatHashHex;
obj.agentCertificatAsn1 = obj.parent.parent.webserver.agentCertificatAsn1;
obj.peerServerId = null;
obj.authenticated = 0;
// Disconnect from the server and/or stop trying
obj.stop = function () {
obj.connectionState = 0;
disconnect();
}
// Make one attempt at connecting to the server
function connect() {
obj.retryTimer = null;
obj.connectionState = 1;
// Get the web socket setup
const WebSocket = require('websocket');
var WebSocketClient = require('websocket').client;
obj.ws = new WebSocketClient();
obj.parent.parent.debug(1, 'OutPeer ' + obj.serverid + ': Connecting to: ' + url + 'meshserver.ashx');
// Register the connection failed event
obj.ws.on('connectFailed', function (error) { obj.parent.parent.debug(1, 'OutPeer ' + obj.serverid + ': Failed connection'); disconnect(); });
// Register the connection event
obj.ws.on('connect', function (connection) {
obj.parent.parent.debug(1, 'OutPeer ' + obj.serverid + ': Connected');
if (obj.meshScanner != null) { obj.meshScanner.stop(); }
obj.connectionState |= 2;
obj.conn = connection;
obj.nonce = obj.forge.random.getBytesSync(32);
// If the connection has an error or closes
obj.conn.on('error', function (error) { obj.parent.parent.debug(1, 'OutPeer ' + obj.serverid + ': Error: ' + error); disconnect(); });
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;
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));
obj.serverCertHash = obj.forge.pki.getPublicKeyFingerprint(serverCert.publicKey, { encoding: 'binary', md: obj.forge.md.sha256.create() });
// If a message is received
obj.conn.on('message', function (msg) {
if (msg.type == 'binary') { var msg2 = ""; for (var i = 0; i < msg.binaryData.length; i++) { msg2 += String.fromCharCode(msg.binaryData[i]); } msg = msg2; }
else if (msg.type == 'utf8') { msg = msg.utf8Data; }
if (msg.length < 2) return;
if (msg.charCodeAt(0) == 123) {
if (obj.connectionState == 15) { processServerData(msg); }
} else {
var cmd = obj.common.ReadShort(msg, 0);
switch (cmd) {
case 1: {
// Server authentication request
if (msg.length != 66) { obj.parent.parent.debug(1, 'OutPeer: BAD MESSAGE(A1)'); return; }
// Check that the server hash matches the TLS server certificate public key hash
if (obj.serverCertHash != msg.substring(2, 34)) { obj.parent.parent.debug(1, 'OutPeer: Server hash mismatch.'); disconnect(); return; }
obj.servernonce = msg.substring(34);
// Use our agent root private key to sign the ServerHash + ServerNonce + AgentNonce
var privateKey = obj.forge.pki.privateKeyFromPem(obj.certificates.agent.key);
var md = obj.forge.md.sha256.create();
md.update(msg.substring(2), 'binary');
md.update(obj.nonce, 'binary');
// Send back our certificate + signature
agentRootCertificatAsn1 = obj.forge.asn1.toDer(obj.forge.pki.certificateToAsn1(obj.forge.pki.certificateFromPem(obj.certificates.agent.cert))).getBytes();
obj.conn.send(obj.common.ShortToStr(2) + obj.common.ShortToStr(agentRootCertificatAsn1.length) + agentRootCertificatAsn1 + privateKey.sign(md)); // Command 3, signature
break;
}
case 2: {
// Server certificate
var certlen = obj.common.ReadShort(msg, 2), serverCert = null;
try { serverCert = obj.forge.pki.certificateFromAsn1(obj.forge.asn1.fromDer(msg.substring(4, 4 + certlen))); } catch (e) { }
if (serverCert == null) { obj.parent.parent.debug(1, 'OutPeer: Invalid server certificate.'); disconnect(); return; }
var serverid = obj.forge.pki.getPublicKeyFingerprint(serverCert.publicKey, { encoding: 'hex', md: obj.forge.md.sha256.create() });
if (serverid !== obj.agentCertificatHashHex) { obj.parent.parent.debug(1, 'OutPeer: Server hash mismatch.'); disconnect(); return; }
// Server signature, verify it
var md = obj.forge.md.sha256.create();
md.update(obj.serverCertHash, 'binary');
md.update(obj.nonce, 'binary');
md.update(obj.servernonce, 'binary');
if (serverCert.publicKey.verify(md.digest().bytes(), msg.substring(4 + certlen)) == false) { obj.parent.parent.debug(1, 'OutPeer: Server sign check failed.'); disconnect(); return; }
// Connection is a success, clean up
delete obj.nonce;
delete obj.servernonce;
delete obj.serverCertHash;
obj.connectionState |= 4;
obj.retryBackoff = 0; // Set backoff connection timer back to fast.
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.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.connectHandler != null)) { obj.connectHandler(1); }
break;
}
default: {
obj.parent.parent.debug(1, 'OutPeer ' + obj.serverid + ': Un-handled command: ' + cmd);
break;
}
}
}
});
// Not sure why, but we need to delay the first send
setTimeout(function () {
if ((obj.ws == null) || (obj.conn == null)) return;
// Start authenticate the mesh agent by sending a auth nonce & server TLS cert hash.
// Send 256 bits SHA256 hash of TLS cert public key + 256 bits nonce
obj.conn.send(obj.common.ShortToStr(1) + obj.serverCertHash + obj.nonce); // Command 1, hash + nonce
}, 10);
});
obj.ws.connect(obj.url + 'meshserver.ashx', null, null, null, { rejectUnauthorized: false, cert: obj.certificates.agent.cert, key: obj.certificates.agent.key });
}
// Disconnect from the server, if we need to, try again with a delay.
function disconnect() {
if (obj.authenticated == 3) { obj.parent.ClearPeerServer(obj, obj.peerServerId); obj.authenticated = 0; }
if ((obj.connectionState == 15) && (obj.connectHandler != null)) { obj.connectHandler(0); }
if (obj.conn != null) { obj.conn.close(); obj.conn = null; }
if (obj.ws != null) { obj.ws = null; }
if (obj.retryTimer != null) { clearTimeout(obj.retryTimer); obj.retryTimer = null; }
// Re-try connection
if (obj.connectionState >= 1) { obj.connectionState = 1; if (obj.retryTimer == null) { obj.retryTimer = setTimeout(connect, getConnectRetryTime()); } }
}
// Get the next retry time in milliseconds
function getConnectRetryTime() {
if (obj.retryBackoff < 30000) { obj.retryBackoff += Math.floor((Math.random() * 3000) + 1000); }
return obj.retryBackoff;
}
// Send a JSON message to the peer server
obj.send = function (msg) {
try {
if (obj.ws == null || obj.conn == null || obj.connectionState != 15) { return; }
if (typeof msg == 'object') { obj.conn.send(JSON.stringify(msg)); return; }
if (typeof msg == 'string') { obj.conn.send(msg); return; }
} catch (e) { }
}
// Process incoming peer server JSON data
function processServerData(msg) {
var str = msg.toString('utf8');
if (str[0] == '{') {
try { command = JSON.parse(str) } catch (e) { obj.parent.parent.debug(1, 'Unable to parse JSON (' + obj.remoteaddr + ').'); return; } // If the command can't be parsed, ignore it.
if (command.action == 'info') {
if (obj.authenticated != 3) {
// We get the peer's serverid and database identifier.
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.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;
obj.authenticated = 3;
obj.parent.SetupPeerServer(obj, obj.peerServerId);
}
}
} else if (obj.authenticated == 3) {
// Pass the message to the parent object for processing.
obj.parent.ProcessPeerServerMessage(obj, obj.peerServerId, command);
}
}
}
connect();
return obj;
}
// Create a mesh server module that received a connection to another server
obj.CreatePeerInServer = function (parent, ws, req) {
var obj = {};
obj.ws = ws;
obj.parent = parent;
obj.common = require('./common.js');
obj.forge = require('node-forge');
obj.crypto = require('crypto');
obj.authenticated = 0;
obj.remoteaddr = obj.ws._socket.remoteAddress;
obj.receivedCommands = 0;
obj.webCertificatHash = obj.parent.parent.webserver.webCertificatHash;
obj.agentCertificatHashHex = obj.parent.parent.webserver.agentCertificatHashHex;
obj.agentCertificatAsn1 = obj.parent.parent.webserver.agentCertificatAsn1;
obj.infoSent = 0;
obj.peerServerId = null;
if (obj.remoteaddr.startsWith('::ffff:')) { obj.remoteaddr = obj.remoteaddr.substring(7); }
// Send a message to the peer server
obj.send = function (data) {
try {
if (typeof data == 'string') { obj.ws.send(new Buffer(data, 'binary')); return; }
if (typeof data == 'object') { obj.ws.send(JSON.stringify(data)); return; }
obj.ws.send(data);
} catch (e) { }
}
// Disconnect this server
obj.close = function (arg) {
if ((arg == 1) || (arg == null)) { try { obj.ws.close(); obj.parent.parent.debug(1, 'InPeer: Soft disconnect ' + obj.peerServerId + ' (' + obj.remoteaddr + ')'); } catch (e) { console.log(e); } } // Soft close, close the websocket
if (arg == 2) { try { obj.ws._socket._parent.end(); obj.parent.parent.debug(1, 'InPeer: Hard disconnect ' + obj.peerServerId + ' (' + obj.remoteaddr + ')'); } catch (e) { console.log(e); } } // Hard close, close the TCP socket
if (obj.authenticated == 3) { obj.parent.ClearPeerServer(obj, obj.peerServerId); obj.authenticated = 0; }
}
// When data is received from the mesh agent web socket
ws.on('message', function (msg) {
if (msg.type == 'binary') { var msg2 = ""; for (var i = 0; i < msg.binaryData.length; i++) { msg2 += String.fromCharCode(msg.binaryData[i]); } msg = msg2; }
else if (msg.type == 'utf8') { msg = msg.utf8Data; }
if (msg.length < 2) return;
if (obj.authenticated >= 2) { // We are authenticated
if (msg.charCodeAt(0) == 123) { processServerData(msg); }
if (msg.length < 2) return;
var cmdid = obj.common.ReadShort(msg, 0);
// Process binary commands (if any). None right now.
}
else if (obj.authenticated < 2) { // We are not authenticated
var cmd = obj.common.ReadShort(msg, 0);
if (cmd == 1) {
// Agent authentication request
if ((msg.length != 66) || ((obj.receivedCommands & 1) != 0)) return;
obj.receivedCommands += 1; // Agent can't send the same command twice on the same connection ever. Block DOS attack path.
// Check that the server hash matches out own web certificate hash
if (obj.webCertificatHash != msg.substring(2, 34)) { obj.close(); return; }
// Use our server private key to sign the ServerHash + AgentNonce + ServerNonce
var privateKey = obj.forge.pki.privateKeyFromPem(obj.parent.parent.certificates.agent.key);
var md = obj.forge.md.sha256.create();
md.update(msg.substring(2), 'binary');
md.update(obj.nonce, 'binary');
obj.agentnonce = msg.substring(34);
// Send back our certificate + signature
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 (processAgentSignature(obj.unauthsign) == false) { disconnect(); return; } else { completePeerServerConnection(); }
}
}
else if (cmd == 2) {
// Agent certificate
if ((msg.length < 4) || ((obj.receivedCommands & 2) != 0)) return;
obj.receivedCommands += 2; // Agent can't send the same command twice on the same connection ever. Block DOS attack path.
// Decode the certificate
var certlen = obj.common.ReadShort(msg, 2);
obj.unauth = {};
obj.unauth.nodeCert = null;
try { obj.unauth.nodeCert = obj.forge.pki.certificateFromAsn1(obj.forge.asn1.fromDer(msg.substring(4, 4 + certlen))); } catch (e) { return; }
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; } }
completePeerServerConnection();
}
else if (cmd == 3) {
// Agent meshid
if ((msg.length < 56) || ((obj.receivedCommands & 4) != 0)) return;
obj.receivedCommands += 4; // Agent can't send the same command twice on the same connection ever. Block DOS attack path.
completePeerServerConnection();
}
}
});
// If error, do nothing
ws.on('error', function (err) { obj.parent.parent.debug(1, 'InPeer: Connection Error: ' + err); });
// If the mesh agent web socket is closed, clean up.
ws.on('close', function (req) { obj.parent.parent.debug(1, 'InPeer disconnect ' + obj.nodeid + ' (' + obj.remoteaddr + ')'); obj.close(0); });
// obj.ws._socket._parent.on('close', function (req) { obj.parent.parent.debug(1, 'Agent TCP disconnect ' + obj.nodeid + ' (' + obj.remoteaddr + ')'); });
// Start authenticate the mesh agent by sending a auth nonce & server TLS cert hash.
// Send 256 bits SHA256 hash of TLS cert public key + 256 bits nonce
obj.nonce = obj.forge.random.getBytesSync(32);
obj.send(obj.common.ShortToStr(1) + obj.webCertificatHash + obj.nonce); // Command 1, hash + nonce
// Once we get all the information about an agent, run this to hook everything up to the server
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.authenticated = 2;
}
// Verify the agent signature
function processAgentSignature(msg) {
var md = obj.forge.md.sha256.create(); // TODO: Switch this to SHA256 on node instead of forge.
md.update(obj.parent.parent.webserver.webCertificatHash, 'binary');
md.update(obj.nonce, 'binary');
md.update(obj.agentnonce, 'binary');
if (obj.unauth.nodeCert.publicKey.verify(md.digest().bytes(), msg) == false) { return false; }
if (obj.unauth.nodeid !== obj.agentCertificatHashHex) { return false; }
// Connection is a success, clean up
obj.nodeid = obj.unauth.nodeid.toUpperCase();
delete obj.nonce;
delete obj.agentnonce;
delete obj.unauth;
if (obj.unauthsign) delete obj.unauthsign;
obj.authenticated = 1;
return true;
}
// Process incoming peer server JSON data
function processServerData(msg) {
var str = msg.toString('utf8');
if (str[0] == '{') {
try { command = JSON.parse(str) } catch (e) { obj.parent.parent.debug(1, 'Unable to parse JSON (' + obj.remoteaddr + ').'); return; } // If the command can't be parsed, ignore it.
if (command.action == 'info') {
if (obj.authenticated != 3) {
// We get the peer's serverid and database identifier.
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.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;
obj.peerServerKey = command.key;
obj.authenticated = 3;
obj.parent.SetupPeerServer(obj, obj.peerServerId);
}
}
} else if (obj.authenticated == 3) {
// Pass the message to the parent object for processing.
obj.parent.ProcessPeerServerMessage(obj, obj.peerServerId, command);
}
}
}
return obj;
}
// If we have no peering configuration, don't setup this object
if (obj.peerConfig == null) { return null; }
// Generate a cryptographic key used to encode and decode cookies // Generate a cryptographic key used to encode and decode cookies
obj.generateCookieKey = function () { obj.generateCookieKey = function () {
return new Buffer(obj.crypto.randomBytes(32), 'binary').toString('ascii'); return new Buffer(obj.crypto.randomBytes(32), 'binary').toString('hex');
} }
// Encode an object as a cookie using a key // Encode an object as a cookie using a key
@ -56,29 +427,67 @@ module.exports.CreateMultiServer = function (parent, args) {
// Dispatch an event to other MeshCentral2 peer servers // Dispatch an event to other MeshCentral2 peer servers
obj.DispatchEvent = function (ids, source, event) { obj.DispatchEvent = function (ids, source, event) {
// TODO var busmsg = JSON.stringify({ action: 'bus', ids: ids, event: event });
for (var serverid in obj.peerServers) { obj.peerServers[serverid].send(busmsg); }
} }
// Handle websocket requests on "/meshserver.ashx" from other MeshCentral2 peer servers. // Dispatch a message to other MeshCentral2 peer servers
obj.handleServerWebSocket = function (ws, req) { obj.DispatchMessage = function (msg) {
Debug(1, 'MeshServer connection open.'); for (var serverid in obj.peerServers) { obj.peerServers[serverid].send(msg); }
}
// Handle data from another mesh server // Attempt to connect to all peers
ws.on('message', function (msg) { obj.ConnectToPeers = function () {
Debug(1, 'MeshServer data of length ' + msg.length); for (serverId in obj.peerConfig.servers) {
// TODO // 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)) {
obj.outPeerServers[serverId] = obj.CreatePeerOutServer(obj, serverId, obj.peerConfig.servers[serverId].url);
}
}
}
// If error, do nothing // We connected to a peer server, setup everything
ws.on('error', function (err) { console.log(err); }); obj.SetupPeerServer = function (server, peerServerId) {
console.log('Connected to peer server ' + peerServerId + '.');
obj.peerServers[peerServerId] = server;
server.send(JSON.stringify({ action: 'connectivityTable', connectivityTable: obj.parent.peerConnectivityByNode[obj.parent.serverId] }));
}
// Another mesh server connection has closed // We disconnected to a peer server, clean up everything
ws.on('close', function (req) { obj.ClearPeerServer = function (server, peerServerId) {
Debug(1, 'MeshServer connection closed.'); console.log('Disconnected from peer server ' + peerServerId + '.');
// TODO delete obj.peerServers[peerServerId];
}); //delete obj.parent.peerConnectivityByMesh[peerServerId]; // TODO: We will need to re-adjust all of the node power states.
var oldList = obj.parent.peerConnectivityByNode[peerServerId];
obj.parent.peerConnectivityByNode[peerServerId] = {};
obj.parent.UpdateConnectivityState(oldList);
}
// Process a message coming from a peer server
obj.ProcessPeerServerMessage = function (server, peerServerId, msg) {
//console.log('ProcessPeerServerMessage', peerServerId, msg.action, typeof msg, msg);
switch (msg.action) {
case 'bus': {
obj.parent.DispatchEvent(msg.ids, null, msg.event, true); // Dispatch the peer event
break;
}
case 'connectivityTable': {
obj.parent.peerConnectivityByNode[peerServerId] = msg.connectivityTable;
obj.parent.UpdateConnectivityState(msg.connectivityTable);
break;
}
case 'SetConnectivityState': {
obj.parent.SetConnectivityState(msg.meshid, msg.nodeid, msg.connectTime, msg.connectType, msg.powerState, peerServerId);
break;
}
case 'ClearConnectivityState': {
obj.parent.ClearConnectivityState(msg.meshid, msg.nodeid, msg.connectType, peerServerId);
break;
}
}
} }
obj.serverKey = obj.generateCookieKey(); obj.serverKey = obj.generateCookieKey();
setTimeout(function () { obj.ConnectToPeers(); }, 1000); // Delay this a little to make sure we are ready on our side.
return obj; return obj;
} }

View File

@ -1,6 +1,6 @@
{ {
"name": "meshcentral", "name": "meshcentral",
"version": "0.0.7-p", "version": "0.0.7-u",
"keywords": [ "keywords": [
"Remote Management", "Remote Management",
"Intel AMT", "Intel AMT",
@ -25,7 +25,6 @@
"bin" "bin"
], ],
"dependencies": { "dependencies": {
"meshcentral": "*",
"archiver": "^1.3.0", "archiver": "^1.3.0",
"body-parser": "^1.17.1", "body-parser": "^1.17.1",
"compression": "^1.6.2", "compression": "^1.6.2",
@ -34,11 +33,13 @@
"express-handlebars": "^3.0.0", "express-handlebars": "^3.0.0",
"express-session": "^1.15.1", "express-session": "^1.15.1",
"express-ws": "^2.0.0", "express-ws": "^2.0.0",
"meshcentral": "*",
"minimist": "^1.2.0", "minimist": "^1.2.0",
"multiparty": "^4.1.3", "multiparty": "^4.1.3",
"nedb": "^1.8.0", "nedb": "^1.8.0",
"node-forge": "^0.6.49", "node-forge": "^0.6.49",
"unzip": "^0.1.11", "unzip": "^0.1.11",
"websocket": "^1.0.24",
"xmldom": "^0.1.27" "xmldom": "^0.1.27"
}, },
"optionalDependencies": { "optionalDependencies": {

View File

@ -340,13 +340,13 @@ th {
<div id="storagelinks" style="margin-top:4px"></div> <div id="storagelinks" style="margin-top:4px"></div>
</div> </div>
<div id="id_mainarea" class="maincell"> <div id="id_mainarea" class="maincell">
<div id="id_scriptstatus" style="height:21px;background:#8fac8d;padding:5px;margin-bottom:1px;display:none"> <div id="id_scriptstatus" style="height:21px;background:#8fac8d;padding:5px;margin-bottom:1px;display:none;overflow:hidden">
<div style="float:right"><input type="button" value="Stop Script" onclick="script_Stop()"></div> <div style="float:right"><input type="button" value="Stop Script" onclick="script_Stop()"></div>
<div style="font-size:16px;padding-top:2px">&nbsp;<b>Running Script</b><span id="id_scriptstatusstr"></span></div> <div style="font-size:16px;padding-top:2px;overflow:hidden">&nbsp;<b>Running Script</b><span style="overflow:hidden" id="id_scriptstatusstr"></span></div>
</div> </div>
<div id="id_versionWarning" style="height:21px;background:#8fac8d;padding:5px;margin-bottom:1px;display:none"> <div id="id_versionWarning" style="height:21px;background:#8fac8d;padding:5px;margin-bottom:1px;display:none">
<div style="font-size:16px;float:right;cursor:pointer;padding-right:5px;padding-left:5px;padding-top:2px" onclick="QV('id_versionWarning', false)"><b>X</b></div> <div style="font-size:16px;float:right;cursor:pointer;padding-right:5px;padding-left:5px;padding-top:2px" onclick="QV('id_versionWarning', false)"><b>X</b></div>
<div style="font-size:14px;padding-top:2px">&nbsp;<b>This computer's firmware should be updated, <a style="cursor:pointer" onclick="require('nw.gui').Shell.openExternal('https://security-center.intel.com/advisory.aspx?intelid=INTEL-SA-00075&languageid=en-fr')"><u>please check here</u></a>.</b><span id="id_scriptstatusstr"></span></div> <div style="font-size:14px;padding-top:2px">&nbsp;<b>This computer's firmware should be updated, <a style="cursor:pointer" onclick="require('nw.gui').Shell.openExternal('https://security-center.intel.com/advisory.aspx?intelid=INTEL-SA-00075&languageid=en-fr')"><u>please check here</u></a>.</b></div>
</div> </div>
<div id="id_mainarea_frame" style="width:100%;height:100%"> <div id="id_mainarea_frame" style="width:100%;height:100%">
<iframe id="id_StorageIFrame" style="width:100%;height:100%;border:0"></iframe> <iframe id="id_StorageIFrame" style="width:100%;height:100%;border:0"></iframe>
@ -2103,7 +2103,9 @@ function AmtStackCreateService(wsmanStack) {
e = null; e = null;
try { try {
// NodeJS detection // NodeJS detection
} catch (ex) { }
e = window.atob(ra[i]);
} catch (ex) { }
if (e != null) { if (e != null) {
TimeStamp = ReadIntX(e, 0); TimeStamp = ReadIntX(e, 0);
if ((TimeStamp > 0) && (TimeStamp < 0xFFFFFFFF)) { if ((TimeStamp > 0) && (TimeStamp < 0xFFFFFFFF)) {
@ -35687,13 +35689,9 @@ if (typeof module !== "undefined" && module.exports) {
} }
function editEnvironmentDetectionDlg2(stack, name, response, status) { function editEnvironmentDetectionDlg2(stack, name, response, status) {
if (status != 200) { if (status != 200) { messagebox('Environment Detection', 'Failed to add server, status ' + status); }
messagebox('Environment Detection', 'Failed to add server, status ' + status); else if ((response.Body["ReturnValue"]) && (response.Body["ReturnValue"] != 0)) { messagebox('Environment Detection', response.Body.ReturnValueStr.replace(/_/g, ' ')); }
} else if (response.Body["ReturnValue"] != 0) { else { PullRemoteAccess(); }
messagebox('Environment Detection', response.Body.ReturnValueStr.replace(/_/g, ' '));
} else {
PullRemoteAccess();
}
} }
function edInputChg() { function edInputChg() {
@ -36134,7 +36132,8 @@ if (typeof module !== "undefined" && module.exports) {
addOption('d5actionSelect', 'Power down', 8); addOption('d5actionSelect', 'Power down', 8);
addOption('d5actionSelect', 'Reset', 10); addOption('d5actionSelect', 'Reset', 10);
if (amtPowerBootCapabilities["ForceDiagnosticBoot"] == true) { if (amtPowerBootCapabilities["ForceDiagnosticBoot"] == true) {
addOption('d5actionSelect', 'Diagnostic', 11); addOption('d5actionSelect', 'Power on to diagnostic', 300);
addOption('d5actionSelect', 'Reset to diagnostic', 301);
} }
if (amtversion > 9) { if (amtversion > 9) {
addOption('d5actionSelect', 'Soft-off', 12); addOption('d5actionSelect', 'Soft-off', 12);
@ -36267,7 +36266,7 @@ if (typeof module !== "undefined" && module.exports) {
consentChanged(); consentChanged();
return; return;
} }
// console.log("Opt-in Required.", response.Body["OptInRequired"]); //console.log("Opt-in Required.", response.Body["OptInRequired"]);
statusbox("Power Action", "Starting opt-in..."); statusbox("Power Action", "Starting opt-in...");
amtstack.IPS_OptInService_StartOptIn(powerActionResponseC1, 0, 1); amtstack.IPS_OptInService_StartOptIn(powerActionResponseC1, 0, 1);
} else { } else {
@ -36366,8 +36365,8 @@ if (typeof module !== "undefined" && module.exports) {
r["LockResetButton"] = false; r["LockResetButton"] = false;
r["LockSleepButton"] = false; r["LockSleepButton"] = false;
r["ReflashBIOS"] = false; r["ReflashBIOS"] = false;
r["UseIDER"] = (action > 199); r["UseIDER"] = ((action > 199) && (action < 300));
r["UseSOL"] = ((currentView == 13) && (action != 8)); // If we are looking at the terminal, turn on SOL. r["UseSOL"] = ((currentView == 13) && (action != 8) && (action != 300) && (action != 301)); // If we are looking at the terminal, turn on SOL. SOL can't be used with diagnostic mode (300/301)
r["UseSafeMode"] = false; r["UseSafeMode"] = false;
r["UserPasswordBypass"] = false; r["UserPasswordBypass"] = false;
if (r["SecureErase"]) { r["SecureErase"] = ((action == 104) && (amtPowerBootCapabilities["SecureErase"] == true)); } if (r["SecureErase"]) { r["SecureErase"] = ((action == 104) && (amtPowerBootCapabilities["SecureErase"] == true)); }
@ -36386,7 +36385,15 @@ if (typeof module !== "undefined" && module.exports) {
//if (errcheck(status, stack)) return; //if (errcheck(status, stack)) return;
//console.log("Setup next boot..."); //console.log("Setup next boot...");
statusbox("Power Action", "Setting next boot..."); statusbox("Power Action", "Setting next boot...");
amtstack.SetBootConfigRole(1, powerActionResponse3, 0, 1); amtstack.SetBootConfigRole(1, powerActionResponse3x, 0, 1);
}
function powerActionResponse3x(stack, name, response, status) {
//console.log("powerActionResponse3x(" + name + "," + response + "," + status + ")");
var action = d5actionSelect.value;
var bootSource = null;
if (action == 300 || action == 301) { bootSource = '<Address xmlns="http://schemas.xmlsoap.org/ws/2004/08/addressing">http://schemas.xmlsoap.org/ws/2004/08/addressing</Address><ReferenceParameters xmlns="http://schemas.xmlsoap.org/ws/2004/08/addressing"><ResourceURI xmlns="http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd">http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_BootSourceSetting</ResourceURI><SelectorSet xmlns="http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd"><Selector Name="InstanceID">Intel(r) AMT: Force Diagnostic Boot</Selector></SelectorSet></ReferenceParameters>'; }
amtstack.CIM_BootConfigSetting_ChangeBootOrder(bootSource, powerActionResponse3);
} }
var targetPowerAction = 0; var targetPowerAction = 0;
@ -36396,12 +36403,14 @@ if (typeof module !== "undefined" && module.exports) {
//console.log("Performing Power State Change..."); //console.log("Performing Power State Change...");
statusbox("Power Action", "Performing power action..."); statusbox("Power Action", "Performing power action...");
var action = d5actionSelect.value; var action = d5actionSelect.value;
if (action == 100 || action == 201 || action == 203) action = 2; // Power up if (action == 100 || action == 201 || action == 203 || action == 300) action = 2; // Power up
if (action == 101 || action == 200 || action == 202) action = 10; // Reset if (action == 101 || action == 200 || action == 202 || action == 301) action = 10; // Reset
if (action == 104) action = 10; // Reset with Remote Secure Erase if (action == 104) action = 10; // Reset with Remote Secure Erase
if (action == 999) action = AvdPowerDlg.Action; if (action == 999) action = AvdPowerDlg.Action;
targetPowerAction = action; targetPowerAction = action;
//console.log('RequestPowerStateChange:' + action);
if (action == 11) { action = 10; }
if (action < 999) { amtstack.RequestPowerStateChange(action, powerActionResponse4); } else { messagebox("Power Action", "Next boot action set."); } if (action < 999) { amtstack.RequestPowerStateChange(action, powerActionResponse4); } else { messagebox("Power Action", "Next boot action set."); }
} }
@ -36910,6 +36919,9 @@ if (typeof module !== "undefined" && module.exports) {
// Called by a running script to update the console. The last message in the console is displayed in the top green bar. // Called by a running script to update the console. The last message in the console is displayed in the top green bar.
function script_console(msg) { function script_console(msg) {
if (msg.indexOf("INFO: ") == 0) { msg = msg.substring(6); }
if (msg.indexOf("SUCCESS: ") == 0) { msg = msg.substring(9); }
if (msg.indexOf("ERROR: ") == 0) { msg = msg.substring(7); }
QH('id_scriptstatusstr', ', ' + msg); QH('id_scriptstatusstr', ', ' + msg);
} }
@ -37062,7 +37074,8 @@ if (typeof module !== "undefined" && module.exports) {
function script_fonkeypress(e) { function script_fonkeypress(e) {
if (xxdialogMode) return; if (xxdialogMode) return;
if (e.key == 'Delete' && script_BlockScriptSelectedId != null) { if (e.key == 'Delete' && script_BlockScriptSelectedId != null) {
delete script_BlockScript[script_BlockScriptSelectedId]; //delete script_BlockScript[script_BlockScriptSelectedId];
script_BlockScript.splice(script_BlockScriptSelectedId, 1);
script_BlockScriptSelectedId = null; script_BlockScriptSelectedId = null;
fupdatescript(); fupdatescript();
} }
@ -37182,7 +37195,7 @@ if (typeof module !== "undefined" && module.exports) {
if (xxdialogMode) return; if (xxdialogMode) return;
if (button == 2) { if (button == 2) {
// Delete this block // Delete this block
delete script_BlockScript[tag]; script_BlockScript.splice(tag, 1);
if (script_BlockScriptSelectedId == tag) { script_BlockScriptSelectedId = null; } if (script_BlockScriptSelectedId == tag) { script_BlockScriptSelectedId = null; }
} else { } else {
// Change this block with new arguments // Change this block with new arguments

View File

@ -158,6 +158,7 @@
} }
function go(x) { function go(x) {
setDialogMode(0);
QV("showPassHintLink", false); QV("showPassHintLink", false);
QV('loginpanel', x == 1); QV('loginpanel', x == 1);
QV('createpanel', x == 2); QV('createpanel', x == 2);
@ -166,11 +167,11 @@
function validateLogin() { function validateLogin() {
var ok = (Q('username').value.length > 0 && Q('password').value.length > 0); var ok = (Q('username').value.length > 0 && Q('password').value.length > 0);
QE('loginButton', ok); QE('loginButton', ok);
QV("showPassHintLink", false); setDialogMode(0);
} }
function validateCreate() { function validateCreate() {
QV("showPassHintLink", false); 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);
QE('createButton', ok); QE('createButton', ok);
if (Q('apassword1').value == '') { if (Q('apassword1').value == '') {

View File

@ -625,7 +625,7 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
if ((meshlinks.rights & 8) == 0) { console.log('ERR: Access denied (2)'); return; } if ((meshlinks.rights & 8) == 0) { console.log('ERR: Access denied (2)'); return; }
// Check what connectivity is available for this node // Check what connectivity is available for this node
var state = parent.connectivityByNode[req.query.host]; var state = parent.GetConnectivityState(req.query.host);
var conn = 0; var conn = 0;
if (!state || state.connectivity == 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. conn = 4; // DEBUG: Allow local connections for now... change this later when we can monitor Intel AMT machines and confirm routing before connections.
@ -958,7 +958,7 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
var r = {}; var r = {};
for (var i in docs) { for (var i in docs) {
// Add the connection state // Add the connection state
var state = parent.connectivityByNode[docs[i]._id]; var state = parent.GetConnectivityState(docs[i]._id);
if (state) { if (state) {
docs[i].conn = state.connectivity; docs[i].conn = state.connectivity;
docs[i].pwr = state.powerState; docs[i].pwr = state.powerState;
@ -1017,7 +1017,7 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
ws.send(JSON.stringify({ action: 'powertimeline', nodeid: command.nodeid, timeline: timeline })); ws.send(JSON.stringify({ action: 'powertimeline', nodeid: command.nodeid, timeline: timeline }));
} else { } else {
// No records found, send current state if we have it // No records found, send current state if we have it
var state = obj.parent.connectivityByNode[command.nodeid]; 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 != undefined) { ws.send(JSON.stringify({ action: 'powertimeline', nodeid: command.nodeid, timeline: [state.powerState, Date.now(), state.powerState] })); }
} }
}); });
@ -1400,7 +1400,7 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
obj.parent.DispatchEvent(['*', node.meshid], obj, { etype: 'node', username: user.name, action: 'removenode', nodeid: node._id, msg: change, domain: domain.id }) obj.parent.DispatchEvent(['*', node.meshid], obj, { etype: 'node', username: user.name, action: 'removenode', nodeid: node._id, msg: change, domain: domain.id })
// Disconnect all connections if needed // Disconnect all connections if needed
var state = obj.parent.connectivityByNode[command.nodeid]; var state = obj.parent.GetConnectivityState(command.nodeid);
if ((state != undefined) && (state.connectivity != undefined)) { if ((state != undefined) && (state.connectivity != undefined)) {
if ((state.connectivity & 1) != 0) { obj.wsagents[command.nodeid].close(); } // Disconnect mesh agent 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 if ((state.connectivity & 2) != 0) { obj.parent.mpsserver.close(obj.parent.mpsserver.ciraConnections[command.nodeid]); } // Disconnect CIRA connection
@ -1895,7 +1895,7 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
// Setup all HTTP handlers // Setup all HTTP handlers
obj.app.get('/backup.zip', handleBackupRequest); obj.app.get('/backup.zip', handleBackupRequest);
obj.app.post('/restoreserver.ashx', handleRestoreRequest); obj.app.post('/restoreserver.ashx', handleRestoreRequest);
if (parent.multiServer != null) { obj.app.ws('/meshserver.ashx', parent.multiServer.handleServerWebSocket); } if (parent.multiServer != null) { obj.app.ws('/meshserver.ashx', function (ws, req) { parent.multiServer.CreatePeerInServer(parent.multiServer, ws, req); } ); }
for (var i in parent.config.domains) { for (var i in parent.config.domains) {
var url = parent.config.domains[i].url; var url = parent.config.domains[i].url;
obj.app.get(url, handleRootRequest); obj.app.get(url, handleRootRequest);