Partinally ran code thru JsHint

This commit is contained in:
Ylian Saint-Hilaire 2018-08-29 17:40:30 -07:00
parent 312b937e62
commit c531b64643
22 changed files with 821 additions and 792 deletions

View File

@ -6,13 +6,18 @@
* @version v0.0.1
*/
'use strict';
/*jslint node: true */
/*jshint node: true */
/*jshint strict:false */
/*jshint -W097 */
/*jshint esversion: 6 */
"use strict";
// Construct a MeshAgent object, called upon connection
module.exports.CreateAmtEventsHandler = function (parent) {
var obj = {};
obj.parent = parent;
// Private method
function ParseWsman(xml) {
try {
@ -30,7 +35,7 @@ module.exports.CreateAmtEventsHandler = function (parent) {
if (body.childNodes.length > 0) {
t = body.childNodes[0].localName;
if (t.indexOf("_OUTPUT") == t.length - 7) { t = t.substring(0, t.length - 7); }
r.Header['Method'] = t;
r.Header.Method = t;
r.Body = _ParseWsmanRec(body.childNodes[0]);
}
return r;
@ -39,7 +44,7 @@ module.exports.CreateAmtEventsHandler = function (parent) {
return null;
}
}
// Private method
function _ParseWsmanRec(node) {
var data, r = {};
@ -48,7 +53,7 @@ module.exports.CreateAmtEventsHandler = function (parent) {
if (child.childNodes == null) { data = child.textContent; } else { data = _ParseWsmanRec(child); }
if (data == 'true') data = true; // Convert 'true' into true
if (data == 'false') data = false; // Convert 'false' into false
var childObj = data;
if (child.attributes != null) {
childObj = { 'Value': data };
@ -56,14 +61,14 @@ module.exports.CreateAmtEventsHandler = function (parent) {
childObj['@' + child.attributes[j].name] = child.attributes[j].value;
}
}
if (r[child.localName] instanceof Array) { r[child.localName].push(childObj); }
else if (r[child.localName] == undefined) { r[child.localName] = childObj; }
else { r[child.localName] = [r[child.localName], childObj]; }
}
return r;
}
// Private method
function _turnToXml(text) {
var DOMParser = require('xmldom').DOMParser;
@ -79,10 +84,10 @@ module.exports.CreateAmtEventsHandler = function (parent) {
//console.log(x);
}
return x;
}
};
// DEBUG: This is an example event, to test parsing and dispatching
//obj.handleAmtEvent('<?xml version="1.0" encoding="UTF-8"?><a:Envelope xmlns:a="http://www.w3.org/2003/05/soap-envelope" xmlns:b="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:c="http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd" xmlns:d="http://schemas.xmlsoap.org/ws/2005/02/trust" xmlns:e="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:f="http://schemas.dmtf.org/wbem/wsman/1/cimbinding.xsd" xmlns:g="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_AlertIndication" xmlns:h="http://schemas.dmtf.org/wbem/wscim/1/common" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><a:Header><b:To>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</b:To><b:ReplyTo><b:Address>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</b:Address></b:ReplyTo><c:AckRequested></c:AckRequested><b:Action a:mustUnderstand="true">http://schemas.dmtf.org/wbem/wsman/1/wsman/Event</b:Action><b:MessageID>uuid:00000000-8086-8086-8086-000000128538</b:MessageID><c:ResourceURI>http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_AlertIndication</c:ResourceURI></a:Header><a:Body><g:CIM_AlertIndication><g:AlertType>8</g:AlertType><g:AlertingElementFormat>2</g:AlertingElementFormat><g:AlertingManagedElement>Interop:CIM_ComputerSystem.CreationClassName=&quot;CIM_ComputerSystem&quot;,Name=&quot;Intel(r) AMT&quot;</g:AlertingManagedElement><g:IndicationFilterName>Intel(r) AMT:AllEvents</g:IndicationFilterName><g:IndicationIdentifier>Intel(r):2950234687</g:IndicationIdentifier><g:IndicationTime><h:Datetime>2017-01-31T15:40:09.000Z</h:Datetime></g:IndicationTime><g:Message></g:Message><g:MessageArguments>0</g:MessageArguments><g:MessageArguments>Interop:CIM_ComputerSystem.CreationClassName=CIM_ComputerSystem,Name=Intel(r) AMT</g:MessageArguments><g:MessageID>iAMT0005</g:MessageID><g:OtherAlertingElementFormat></g:OtherAlertingElementFormat><g:OtherSeverity></g:OtherSeverity><g:OwningEntity>Intel(r) AMT</g:OwningEntity><g:PerceivedSeverity>2</g:PerceivedSeverity><g:ProbableCause>0</g:ProbableCause><g:SystemName>Intel(r) AMT</g:SystemName></g:CIM_AlertIndication></a:Body></a:Envelope>', 'aabbccdd', '1.2.3.4');
return obj;
}
};

View File

@ -6,7 +6,12 @@
* @version v0.0.1
*/
'use strict';
/*jslint node: true */
/*jshint node: true */
/*jshint strict:false */
/*jshint -W097 */
/*jshint esversion: 6 */
"use strict";
// Construct a Intel AMT Scanner object
module.exports.CreateAmtScanner = function (parent) {
@ -37,7 +42,7 @@ module.exports.CreateAmtScanner = function (parent) {
var packet = new Buffer(obj.common.hex2rstr('06000006000011BE80000000'), 'ascii');
packet[9] = tag;
return packet;
}
};
// Start scanning for local network Intel AMT computers
obj.start = function () {
@ -45,7 +50,7 @@ module.exports.CreateAmtScanner = function (parent) {
obj.performScan();
obj.mainTimer = setInterval(obj.performScan, PeriodicScanTime);
return obj;
}
};
// Stop scanning for local network Intel AMT computers
obj.stop = function () {
@ -53,7 +58,7 @@ module.exports.CreateAmtScanner = function (parent) {
for (var i in obj.servers) { obj.servers[i].close(); } // Stop all servers
obj.servers = {};
if (obj.mainTimer != null) { clearInterval(obj.mainTimer); obj.mainTimer = null; }
}
};
// Scan for Intel AMT computers using network multicast
obj.performRangeScan = function (userid, rangestr) {
@ -76,7 +81,7 @@ module.exports.CreateAmtScanner = function (parent) {
delete rangeinfo.server;
}, 3000);
return true;
}
};
// Parse range, used to parse "ip", "ip/mask" or "ip-ip" notation.
// Return the start and end value of the scan
@ -95,19 +100,19 @@ module.exports.CreateAmtScanner = function (parent) {
x = obj.parseIpv4Addr(range);
if (x == null) return null;
return { min: x, max: x };
}
};
// Parse IP address. Takes a
obj.parseIpv4Addr = function (addr) {
var x = addr.split('.');
if (x.length == 4) { return (parseInt(x[0]) << 24) + (parseInt(x[1]) << 16) + (parseInt(x[2]) << 8) + (parseInt(x[3]) << 0); }
return null;
}
};
// IP address number to string
obj.IPv4NumToStr = function (num) {
return ((num >> 24) & 0xFF) + '.' + ((num >> 16) & 0xFF) + '.' + ((num >> 8) & 0xFF) + '.' + (num & 0xFF);
}
};
/*
// Sample we could use to optimize DNS resolving, may not be needed at all.
@ -144,14 +149,14 @@ module.exports.CreateAmtScanner = function (parent) {
}
});
return r;
}
};
*/
obj.ResolveName = function (hostname, func) {
if ((hostname == '127.0.0.1') || (hostname == '::1') || (hostname == 'localhost')) { func(hostname, null); } // Don't scan localhost
if (obj.net.isIP(hostname) > 0) { func(hostname, hostname); return; } // This is an IP address, already resolved.
obj.dns.lookup(hostname, function (err, address, family) { if (err == null) { func(hostname, address); } else { func(hostname, null); } });
}
};
// Look for all Intel AMT computers that may be locally reachable and poll their presence
obj.performScan = function () {
@ -178,6 +183,7 @@ module.exports.CreateAmtScanner = function (parent) {
} else if ((scaninfo.tcp == null) && ((scaninfo.state == 0) || isNaN(delta) || (delta > PeriodicScanTime))) {
// More than 30 seconds without a response, try TCP detection
obj.checkTcpPresence(host, (doc.intelamt.tls == 1) ? 16993 : 16992, scaninfo, function (tag, result, version) {
// TODO: It is bad that "obj" is being accessed within this function.
if (result == false) return;
tag.lastpong = Date.now();
if (tag.state == 0) {
@ -192,7 +198,7 @@ module.exports.CreateAmtScanner = function (parent) {
scaninfo.lastping = Date.now();
obj.checkAmtPresence(host, scaninfo.tag);
}
}
}
}
for (var i in obj.scanTable) {
if (obj.scanTable[i].present == false) {
@ -203,10 +209,10 @@ module.exports.CreateAmtScanner = function (parent) {
}
});
return true;
}
};
// Check the presense of a specific Intel AMT computer using RMCP
obj.checkAmtPresence = function (host, tag) { obj.ResolveName(host, function (hostname, ip) { obj.checkAmtPresenceEx(ip, tag); }); }
obj.checkAmtPresence = function (host, tag) { obj.ResolveName(host, function (hostname, ip) { obj.checkAmtPresenceEx(ip, tag); }); };
// Check the presense of a specific Intel AMT computer using RMCP
obj.checkAmtPresenceEx = function (host, tag) {
@ -221,20 +227,20 @@ module.exports.CreateAmtScanner = function (parent) {
server.on('error', (err) => { });
server.on('message', (data, rinfo) => { obj.parseRmcpPacket(data, rinfo, serverid, obj.changeConnectState, null); });
server.on('listening', () => {
obj.pendingSends.push([ server, packet, host ]);
obj.pendingSends.push([server, packet, host]);
if (obj.pendingSendTimer == null) { obj.pendingSendTimer = setInterval(obj.sendPendingPacket, 10); }
});
server.bind(0);
obj.servers[serverid] = server;
} else {
// Use existing server
obj.pendingSends.push([ server, packet, host ]);
obj.pendingSends.push([server, packet, host]);
if (obj.pendingSendTimer == null) { obj.pendingSendTimer = setInterval(obj.sendPendingPacket, 10); }
}
}
};
// Send a pending RMCP packet
obj.sendPendingPacket = function() {
obj.sendPendingPacket = function () {
try {
var p = obj.pendingSends.shift();
if (p != undefined) {
@ -245,7 +251,7 @@ module.exports.CreateAmtScanner = function (parent) {
obj.pendingSendTimer = null;
}
} catch (e) { }
}
};
// Parse RMCP packet
obj.parseRmcpPacket = function (data, rinfo, serverid, func, user) {
@ -256,14 +262,14 @@ module.exports.CreateAmtScanner = function (parent) {
var minorVersion = data[18] & 0x0F;
var majorVersion = (data[18] >> 4) & 0x0F;
var provisioningState = data[19] & 0x03; // Pre = 0, In = 1, Post = 2
var openPort = (data[16] * 256) + data[17];
var dualPorts = ((data[19] & 0x04) != 0) ? true : false;
var openPorts = [openPort];
if (dualPorts == true) { openPorts = [16992, 16993]; }
if (provisioningState <= 2) { func(tag, minorVersion, majorVersion, provisioningState, openPort, dualPorts, rinfo, user); }
}
}
};
// Use the RMCP packet to change the computer state
obj.changeConnectState = function (tag, minorVersion, majorVersion, provisioningState, openPort, dualPorts, rinfo, user) {
@ -282,21 +288,21 @@ module.exports.CreateAmtScanner = function (parent) {
obj.changeAmtState(scaninfo.nodeinfo._id, scaninfo.nodeinfo.intelamt.ver, provisioningState, scaninfo.nodeinfo.intelamt.tls);
}
}
}
};
// Use the RMCP packet to change the computer state
obj.reportMachineState = function (tag, minorVersion, majorVersion, provisioningState, openPort, dualPorts, rinfo, user) {
//var provisioningStates = { 0: 'Pre', 1: 'in', 2: 'Post' };
//var provisioningStateStr = provisioningStates[provisioningState];
//console.log(rinfo.address + ': Intel AMT ' + majorVersion + '.' + minorVersion + ', ' + provisioningStateStr + '-Provisioning, Open Ports: [' + openPorts.join(', ') + ']');
// Use the RMCP packet to change the computer state
obj.reportMachineState = function (tag, minorVersion, majorVersion, provisioningState, openPort, dualPorts, rinfo, user) {
//var provisioningStates = { 0: 'Pre', 1: 'in', 2: 'Post' };
//var provisioningStateStr = provisioningStates[provisioningState];
//console.log(rinfo.address + ': Intel AMT ' + majorVersion + '.' + minorVersion + ', ' + provisioningStateStr + '-Provisioning, Open Ports: [' + openPorts.join(', ') + ']');
obj.dns.reverse(rinfo.address, function (err, hostname) {
if ((err != undefined) && (hostname != undefined)) {
user.results[rinfo.address] = { ver: majorVersion + '.' + minorVersion, tls: (((openPort == 16993) || (dualPorts == true)) ? 1 : 0), state: provisioningState, hostname: hostname[0] };
} else {
user.results[rinfo.address] = { ver: majorVersion + '.' + minorVersion, tls: (((openPort == 16993) || (dualPorts == true)) ? 1 : 0), state: provisioningState, hostname: rinfo.address };
}
});
}
user.results[rinfo.address] = { ver: majorVersion + '.' + minorVersion, tls: (((openPort == 16993) || (dualPorts == true)) ? 1 : 0), state: provisioningState, hostname: hostname[0] };
} else {
user.results[rinfo.address] = { ver: majorVersion + '.' + minorVersion, tls: (((openPort == 16993) || (dualPorts == true)) ? 1 : 0), state: provisioningState, hostname: rinfo.address };
}
});
};
// Change Intel AMT information in the database and event the changes
obj.changeAmtState = function (nodeid, version, provisioningState, tls) {
@ -317,7 +323,7 @@ module.exports.CreateAmtScanner = function (parent) {
// Make the change & save
var change = false;
if (node.intelamt == undefined) { node.intelamt = {}; }
if (node.intelamt.tls != tls) { node.intelamt.tls = tls; change = true; changes.push(tls==1?'TLS':'NoTLS'); }
if (node.intelamt.tls != tls) { node.intelamt.tls = tls; change = true; changes.push(tls == 1 ? 'TLS' : 'NoTLS'); }
if (obj.compareAmtVersionStr(node.intelamt.ver, version)) { node.intelamt.ver = version; change = true; changes.push('AMT Version ' + version); }
if (node.intelamt.state != provisioningState) { node.intelamt.state = provisioningState; change = true; changes.push('AMT State'); }
if (change == true) {
@ -333,7 +339,7 @@ module.exports.CreateAmtScanner = function (parent) {
}
});
});
}
};
// Return true if we should change the Intel AMT version number
obj.compareAmtVersionStr = function (oldVer, newVer) {
@ -347,10 +353,10 @@ module.exports.CreateAmtScanner = function (parent) {
if (newVerArr.length > oldVerArr.length) return true;
if ((newVerArr.length == 3) && (oldVerArr.length == 3) && (oldVerArr[2] != newVerArr[2])) return true;
return false;
}
};
// Check the presense of a specific Intel AMT computer using RMCP
obj.checkTcpPresence = function (host, port, scaninfo, func) { obj.ResolveName(host, function (hostname, ip) { obj.checkTcpPresenceEx(ip, port, scaninfo, func); }); }
obj.checkTcpPresence = function (host, port, scaninfo, func) { obj.ResolveName(host, function (hostname, ip) { obj.checkTcpPresenceEx(ip, port, scaninfo, func); }); };
// Check that we can connect TCP to a given port
obj.checkTcpPresenceEx = function (host, port, scaninfo, func) {
@ -378,7 +384,7 @@ module.exports.CreateAmtScanner = function (parent) {
client.on('end', function () { if (this.scaninfo.tcp != null) { delete this.scaninfo.tcp; try { this.destroy(); } catch (ex) { } this.func(this.scaninfo, false); } });
scaninfo.tcp = client;
} catch (ex) { console.log(ex); }
}
};
// Return the Intel AMT version from the HTTP headers. Return null if nothing is found.
obj.getIntelAmtVersionFromHeaders = function (headers) {
@ -393,9 +399,9 @@ module.exports.CreateAmtScanner = function (parent) {
}
}
return null;
}
};
//console.log(obj.getIntelAmtVersionFromHeaders("HTTP/1.1 303 See Other\r\nLocation: /logon.htm\r\nContent-Length: 0\r\nServer: Intel(R) Active Management Technology 7.1.91\r\n\r\n"));
return obj;
}
};

View File

@ -6,7 +6,12 @@
* @version v0.1.0e
*/
'use strict';
/*jslint node: true */
/*jshint node: true */
/*jshint strict:false */
/*jshint -W097 */
/*jshint esversion: 6 */
"use strict";
module.exports.CreateAmtScriptEngine = function () {
var o = {};
@ -284,14 +289,14 @@ module.exports.CreateAmtScriptEngine = function () {
if (obj.state == 1 && obj.ip >= obj.script.length) { obj.state = 0; obj.stop(); }
if (obj.onStep) obj.onStep(obj);
return obj;
}
};
obj.xxStepDialogOk = function (button) {
obj.variables['DialogSelect'] = button;
obj.state = 1;
obj.dialog = false;
if (obj.onStep) obj.onStep(obj);
}
};
// ###BEGIN###{**ClosureAdvancedMode}
obj.xxWsmanReturnFix = function (x) {
@ -301,7 +306,7 @@ module.exports.CreateAmtScriptEngine = function () {
if (x.Responses) { x['Responses'] = x.Responses; delete x.Responses; }
if (x.Response) { x['Response'] = x.Response; delete x.Response; }
if (x.ReturnValueStr) { x['ReturnValueStr'] = x.ReturnValueStr; delete x.ReturnValueStr; }
}
};
// ###END###{**ClosureAdvancedMode}
obj.xxWsmanReturn = function (stack, name, responses, status) {
@ -320,34 +325,34 @@ module.exports.CreateAmtScriptEngine = function () {
obj.setVar('wsman_result_str', ((httpErrorTable[status]) ? (httpErrorTable[status]) : ('Error #' + status)));
obj.state = 1;
if (obj.onStep) obj.onStep(obj);
}
};
// ###BEGIN###{Certificates}
obj.xxSignWithDummyCaReturn = function (cert) {
obj.setVar('signed_cert', btoa(_arrayBufferToString(cert)));
obj.state = 1;
if (obj.onStep) obj.onStep(obj);
}
};
// ###END###{Certificates}
obj.toString = function (x) { if (typeof x == 'object') return JSON.stringify(x); return x; }
obj.toString = function (x) { if (typeof x == 'object') return JSON.stringify(x); return x; };
obj.reset();
return obj;
}
*/
ReadShort = function (v, p) { return (v.charCodeAt(p) << 8) + v.charCodeAt(p + 1); }
ReadShortX = function (v, p) { return (v.charCodeAt(p + 1) << 8) + v.charCodeAt(p); }
ReadInt = function (v, p) { return (v.charCodeAt(p) * 0x1000000) + (v.charCodeAt(p + 1) << 16) + (v.charCodeAt(p + 2) << 8) + v.charCodeAt(p + 3); } // We use "*0x1000000" instead of "<<24" because the shift converts the number to signed int32.
ReadIntX = function (v, p) { return (v.charCodeAt(p + 3) * 0x1000000) + (v.charCodeAt(p + 2) << 16) + (v.charCodeAt(p + 1) << 8) + v.charCodeAt(p); }
ShortToStr = function (v) { return String.fromCharCode((v >> 8) & 0xFF, v & 0xFF); }
ShortToStrX = function (v) { return String.fromCharCode(v & 0xFF, (v >> 8) & 0xFF); }
IntToStr = function (v) { return String.fromCharCode((v >> 24) & 0xFF, (v >> 16) & 0xFF, (v >> 8) & 0xFF, v & 0xFF); }
IntToStrX = function (v) { return String.fromCharCode(v & 0xFF, (v >> 8) & 0xFF, (v >> 16) & 0xFF, (v >> 24) & 0xFF); }
var ReadShort = function (v, p) { return (v.charCodeAt(p) << 8) + v.charCodeAt(p + 1); };
var ReadShortX = function (v, p) { return (v.charCodeAt(p + 1) << 8) + v.charCodeAt(p); };
var ReadInt = function (v, p) { return (v.charCodeAt(p) * 0x1000000) + (v.charCodeAt(p + 1) << 16) + (v.charCodeAt(p + 2) << 8) + v.charCodeAt(p + 3); }; // We use "*0x1000000" instead of "<<24" because the shift converts the number to signed int32.
var ReadIntX = function (v, p) { return (v.charCodeAt(p + 3) * 0x1000000) + (v.charCodeAt(p + 2) << 16) + (v.charCodeAt(p + 1) << 8) + v.charCodeAt(p); };
var ShortToStr = function (v) { return String.fromCharCode((v >> 8) & 0xFF, v & 0xFF); };
var ShortToStrX = function (v) { return String.fromCharCode(v & 0xFF, (v >> 8) & 0xFF); };
var IntToStr = function (v) { return String.fromCharCode((v >> 24) & 0xFF, (v >> 16) & 0xFF, (v >> 8) & 0xFF, v & 0xFF); };
var IntToStrX = function (v) { return String.fromCharCode(v & 0xFF, (v >> 8) & 0xFF, (v >> 16) & 0xFF, (v >> 24) & 0xFF); };
// Argument types: 0 = Variable, 1 = String, 2 = Integer, 3 = Label
o.script_compile = function(script, onmsg) {
o.script_compile = function (script, onmsg) {
var r = '', scriptlines = script.split('\n'), labels = {}, labelswap = [], swaps = [];
// Go thru each script line and encode it
for (var i in scriptlines) {
@ -392,11 +397,11 @@ module.exports.CreateAmtScriptEngine = function () {
r = r.substr(0, position) + IntToStr(target) + r.substr(position + 4);
}
return IntToStr(0x247D2945) + ShortToStr(1) + r;
}
};
// Decompile the script, intended for debugging only
o.script_decompile = function(binary, onecmd) {
var r = '', ptr = 6, labelcount = 0, labels = {};
o.script_decompile = function (binary, onecmd) {
var r = '', ptr = 6, labels = {};
if (onecmd >= 0) {
ptr = onecmd; // If we are decompiling just one command, set the ptr to that command.
} else {
@ -413,7 +418,7 @@ module.exports.CreateAmtScriptEngine = function () {
var argcount = ReadShort(binary, ptr + 4);
var argptr = ptr + 6;
var argstr = '';
if (!(onecmd >= 0)) r += ":label" + (ptr - 6) + "\n";
if (!(onecmd >= 0)) { r += ":label" + (ptr - 6) + "\n"; }
// Loop on each argument, moving forward by the argument length each time
for (var i = 0; i < argcount; i++) {
var arglen = ReadShort(binary, argptr);
@ -451,7 +456,7 @@ module.exports.CreateAmtScriptEngine = function () {
if (line[0] != ':') { r += line + '\n'; } else { if (labels[line]) { r += line + '\n'; } }
}
return r;
}
};
// Convert the list of blocks into a script that can be compiled
o.script_blocksToScript = function (script_BuildingBlocks, script_BlockScript) {
@ -467,7 +472,7 @@ module.exports.CreateAmtScriptEngine = function () {
if (script_BuildingBlocks['_end']) { script += '##### Ending Block #####\r\n' + script_BuildingBlocks['_end']['code'] + '\r\nHighlightBlock\r\n'; }
}
return script;
}
};
return o;
}
};

View File

@ -6,268 +6,214 @@
* @version v0.0.1
*/
'use strict';
/*xjslint node: true */
/*xjslint plusplus: true */
/*xjslint maxlen: 256 */
/*jshint node: true */
/*jshint strict: false */
/*jshint esversion: 6 */
"use strict";
module.exports.CertificateOperations = function () {
var obj = {};
obj.fs = require('fs');
obj.forge = require('node-forge');
obj.crypto = require('crypto');
obj.fs = require("fs");
obj.forge = require("node-forge");
obj.crypto = require("crypto");
obj.pki = obj.forge.pki;
obj.dirExists = function (filePath) { try { return obj.fs.statSync(filePath).isDirectory(); } catch (err) { return false; } }
obj.getFilesizeInBytes = function(filename) { try { return obj.fs.statSync(filename)["size"]; } catch (err) { return -1; } }
obj.fileExists = function(filePath) { try { return obj.fs.statSync(filePath).isFile(); } catch (err) { return false; } }
obj.dirExists = function (filePath) { try { return obj.fs.statSync(filePath).isDirectory(); } catch (err) { return false; } };
obj.getFilesizeInBytes = function (filename) { try { return obj.fs.statSync(filename).size; } catch (err) { return -1; } };
obj.fileExists = function (filePath) { try { return obj.fs.statSync(filePath).isFile(); } catch (err) { return false; } };
// Return the SHA386 hash of the certificate public key
obj.getPublicKeyHash = function (cert) {
var publickey = obj.pki.certificateFromPem(cert).publicKey;
return obj.pki.getPublicKeyFingerprint(publickey, { encoding: 'hex', md: obj.forge.md.sha384.create() });
}
return obj.pki.getPublicKeyFingerprint(publickey, { encoding: "hex", md: obj.forge.md.sha384.create() });
};
// Create a self-signed certificate
obj.GenerateRootCertificate = function (addThumbPrintToName, commonName, country, organization, strong) {
var keys = obj.pki.rsa.generateKeyPair((strong == true) ? 3072 : 2048);
var keys = obj.pki.rsa.generateKeyPair((strong === true) ? 3072 : 2048);
var cert = obj.pki.createCertificate();
cert.publicKey = keys.publicKey;
cert.serialNumber = '' + Math.floor((Math.random() * 100000) + 1); ;
cert.serialNumber = String(Math.floor((Math.random() * 100000) + 1));
cert.validity.notBefore = new Date();
cert.validity.notBefore.setFullYear(cert.validity.notBefore.getFullYear() - 1); // Create a certificate that is valid one year before, to make sure out-of-sync clocks don't reject this cert.
cert.validity.notBefore.setFullYear(cert.validity.notBefore.getFullYear() - 1); // Create a certificate that is valid one year before, to make sure out-of-sync clocks don"t reject this cert.
cert.validity.notAfter = new Date();
cert.validity.notAfter.setFullYear(cert.validity.notAfter.getFullYear() + 30);
if (addThumbPrintToName == true) { commonName += '-' + obj.pki.getPublicKeyFingerprint(cert.publicKey, { encoding: 'hex' }).substring(0, 6); }
if (country == undefined) { country = 'unknown'; }
if (organization == undefined) { organization = 'unknown'; }
var attrs = [{ name: 'commonName', value: commonName }, { name: 'organizationName', value: organization }, { name: 'countryName', value: country }];
if (addThumbPrintToName === true) { commonName += "-" + obj.pki.getPublicKeyFingerprint(cert.publicKey, { encoding: "hex" }).substring(0, 6); }
if (country === undefined) { country = "unknown"; }
if (organization === undefined) { organization = "unknown"; }
var attrs = [{ name: "commonName", value: commonName }, { name: "organizationName", value: organization }, { name: "countryName", value: country }];
cert.setSubject(attrs);
cert.setIssuer(attrs);
// Create a root certificate
cert.setExtensions([{
name: 'basicConstraints',
cA: true
}, {
name: 'nsCertType',
sslCA: true,
emailCA: true,
objCA: true
}, {
name: 'subjectKeyIdentifier'
}]);
cert.setExtensions([{ name: "basicConstraints", cA: true }, { name: "nsCertType", sslCA: true, emailCA: true, objCA: true }, { name: "subjectKeyIdentifier" }]);
cert.sign(keys.privateKey, obj.forge.md.sha384.create());
return { cert: cert, key: keys.privateKey };
}
};
// Issue a certificate from a root
obj.IssueWebServerCertificate = function (rootcert, addThumbPrintToName, commonName, country, organization, extKeyUsage, strong) {
var keys = obj.pki.rsa.generateKeyPair((strong == true) ? 3072 : 2048);
var keys = obj.pki.rsa.generateKeyPair((strong === true) ? 3072 : 2048);
var cert = obj.pki.createCertificate();
cert.publicKey = keys.publicKey;
cert.serialNumber = '' + Math.floor((Math.random() * 100000) + 1); ;
cert.serialNumber = String(Math.floor((Math.random() * 100000) + 1));
cert.validity.notBefore = new Date();
cert.validity.notBefore.setFullYear(cert.validity.notAfter.getFullYear() - 1); // Create a certificate that is valid one year before, to make sure out-of-sync clocks don't reject this cert.
cert.validity.notBefore.setFullYear(cert.validity.notAfter.getFullYear() - 1); // Create a certificate that is valid one year before, to make sure out-of-sync clocks don"t reject this cert.
cert.validity.notAfter = new Date();
cert.validity.notAfter.setFullYear(cert.validity.notAfter.getFullYear() + 30);
if (addThumbPrintToName == true) { commonName += '-' + obj.pki.getPublicKeyFingerprint(cert.publicKey, { encoding: 'hex' }).substring(0, 6); }
var attrs = [ { name: 'commonName', value: commonName }];
if (country != undefined) attrs.push({ name: 'countryName', value: country });
if (organization != undefined) attrs.push({ name: 'organizationName', value: organization });
if (addThumbPrintToName === true) { commonName += "-" + obj.pki.getPublicKeyFingerprint(cert.publicKey, { encoding: "hex" }).substring(0, 6); }
var attrs = [{ name: "commonName", value: commonName }];
if (country != undefined) { attrs.push({ name: "countryName", value: country }); }
if (organization != undefined) { attrs.push({ name: "organizationName", value: organization }); }
cert.setSubject(attrs);
cert.setIssuer(rootcert.cert.subject.attributes);
if (extKeyUsage == null) { extKeyUsage = { name: 'extKeyUsage', serverAuth: true, } } else { extKeyUsage.name = 'extKeyUsage'; }
if (extKeyUsage == null) { extKeyUsage = { name: "extKeyUsage", serverAuth: true }; } else { extKeyUsage.name = "extKeyUsage"; }
var subjectAltName = null;
if (extKeyUsage.serverAuth == true) {
subjectAltName = {
name: 'subjectAltName',
altNames: [{
type: 6, // URI
value: 'http://' + commonName + '/'
}, {
type: 6, // URL
value: 'http://localhost/'
}]
}
}
/*
{
name: 'extKeyUsage',
serverAuth: true,
clientAuth: true,
codeSigning: true,
emailProtection: true,
timeStamping: true,
'2.16.840.1.113741.1.2.1': true
}
*/
var extensions = [{
name: 'basicConstraints',
cA: false
}, {
name: 'keyUsage',
keyCertSign: true,
digitalSignature: true,
nonRepudiation: true,
keyEncipherment: true,
dataEncipherment: true
}, extKeyUsage, {
name: 'nsCertType',
client: false,
server: true,
email: false,
objsign: false,
sslCA: false,
emailCA: false,
objCA: false
}, {
name: 'subjectKeyIdentifier'
}]
if (subjectAltName != null) extensions.push(subjectAltName);
if (extKeyUsage.serverAuth === true) { subjectAltName = { name: "subjectAltName", altNames: [{ type: 6, value: "http://" + commonName + "/" }, { type: 6, value: "http://localhost/" }] }; }
var extensions = [{ name: "basicConstraints", cA: false }, { name: "keyUsage", keyCertSign: true, digitalSignature: true, nonRepudiation: true, keyEncipherment: true, dataEncipherment: true }, extKeyUsage, { name: "nsCertType", client: false, server: true, email: false, objsign: false, sslCA: false, emailCA: false, objCA: false }, { name: "subjectKeyIdentifier" }];
if (subjectAltName != null) { extensions.push(subjectAltName); }
cert.setExtensions(extensions);
cert.sign(rootcert.key, obj.forge.md.sha384.create());
return { cert: cert, key: keys.privateKey };
}
};
// Returns the web server TLS certificate and private key, if not present, create demonstration ones.
obj.GetMeshServerCertificate = function (parent, args, config, func) {
var i = 0;
var certargs = args.cert;
var mpscertargs = args.mpscert;
var strongCertificate = (args.fastcert ? false : true);
var rcountmax = 5;
var caindex = 1;
var caok = false;
var calist = [];
var dnsname = null;
// commonName, country, organization
// If the certificates directory does not exist, create it.
if (!obj.dirExists(parent.datapath)) { obj.fs.mkdirSync(parent.datapath); }
var r = {}, rcount = 0;
var r = {};
var rcount = 0;
// If the root certificate already exist, load it
if (obj.fileExists(parent.getConfigFilePath('root-cert-public.crt')) && obj.fileExists(parent.getConfigFilePath('root-cert-private.key'))) {
var rootCertificate = obj.fs.readFileSync(parent.getConfigFilePath('root-cert-public.crt'), 'utf8');
var rootPrivateKey = obj.fs.readFileSync(parent.getConfigFilePath('root-cert-private.key'), 'utf8');
if (obj.fileExists(parent.getConfigFilePath("root-cert-public.crt")) && obj.fileExists(parent.getConfigFilePath("root-cert-private.key"))) {
var rootCertificate = obj.fs.readFileSync(parent.getConfigFilePath("root-cert-public.crt"), "utf8");
var rootPrivateKey = obj.fs.readFileSync(parent.getConfigFilePath("root-cert-private.key"), "utf8");
r.root = { cert: rootCertificate, key: rootPrivateKey };
rcount++;
}
if (args.tlsoffload == true) {
if (args.tlsoffload === true) {
// If the web certificate already exist, load it. Load just the certificate since we are in TLS offload situation
if (obj.fileExists(parent.getConfigFilePath('webserver-cert-public.crt'))) {
var webCertificate = obj.fs.readFileSync(parent.getConfigFilePath('webserver-cert-public.crt'), 'utf8');
r.web = { cert: webCertificate };
if (obj.fileExists(parent.getConfigFilePath("webserver-cert-public.crt"))) {
r.web = { cert: obj.fs.readFileSync(parent.getConfigFilePath("webserver-cert-public.crt"), "utf8") };
rcount++;
}
} else {
// If the web certificate already exist, load it. Load both certificate and private key
if (obj.fileExists(parent.getConfigFilePath('webserver-cert-public.crt')) && obj.fileExists(parent.getConfigFilePath('webserver-cert-private.key'))) {
var webCertificate = obj.fs.readFileSync(parent.getConfigFilePath('webserver-cert-public.crt'), 'utf8');
var webPrivateKey = obj.fs.readFileSync(parent.getConfigFilePath('webserver-cert-private.key'), 'utf8');
r.web = { cert: webCertificate, key: webPrivateKey };
if (obj.fileExists(parent.getConfigFilePath("webserver-cert-public.crt")) && obj.fileExists(parent.getConfigFilePath("webserver-cert-private.key"))) {
r.web = { cert: obj.fs.readFileSync(parent.getConfigFilePath("webserver-cert-public.crt"), "utf8"), key: obj.fs.readFileSync(parent.getConfigFilePath("webserver-cert-private.key"), "utf8") };
rcount++;
}
}
// If the mps certificate already exist, load it
if (obj.fileExists(parent.getConfigFilePath('mpsserver-cert-public.crt')) && obj.fileExists(parent.getConfigFilePath('mpsserver-cert-private.key'))) {
var mpsCertificate = obj.fs.readFileSync(parent.getConfigFilePath('mpsserver-cert-public.crt'), 'utf8');
var mpsPrivateKey = obj.fs.readFileSync(parent.getConfigFilePath('mpsserver-cert-private.key'), 'utf8');
r.mps = { cert: mpsCertificate, key: mpsPrivateKey };
if (obj.fileExists(parent.getConfigFilePath("mpsserver-cert-public.crt")) && obj.fileExists(parent.getConfigFilePath("mpsserver-cert-private.key"))) {
r.mps = { cert: obj.fs.readFileSync(parent.getConfigFilePath("mpsserver-cert-public.crt"), "utf8"), key: obj.fs.readFileSync(parent.getConfigFilePath("mpsserver-cert-private.key"), "utf8") };
rcount++;
}
// If the agent certificate already exist, load it
if (obj.fileExists(parent.getConfigFilePath('agentserver-cert-public.crt')) && obj.fileExists(parent.getConfigFilePath('agentserver-cert-private.key'))) {
var agentCertificate = obj.fs.readFileSync(parent.getConfigFilePath('agentserver-cert-public.crt'), 'utf8');
var agentPrivateKey = obj.fs.readFileSync(parent.getConfigFilePath('agentserver-cert-private.key'), 'utf8');
r.agent = { cert: agentCertificate, key: agentPrivateKey };
if (obj.fileExists(parent.getConfigFilePath("agentserver-cert-public.crt")) && obj.fileExists(parent.getConfigFilePath("agentserver-cert-private.key"))) {
r.agent = { cert: obj.fs.readFileSync(parent.getConfigFilePath("agentserver-cert-public.crt"), "utf8"), key: obj.fs.readFileSync(parent.getConfigFilePath("agentserver-cert-private.key"), "utf8") };
rcount++;
}
// If the console certificate already exist, load it
if (obj.fileExists(parent.getConfigFilePath('amtconsole-cert-public.crt')) && obj.fileExists(parent.getConfigFilePath('agentserver-cert-private.key'))) {
var amtConsoleCertificate = obj.fs.readFileSync(parent.getConfigFilePath('amtconsole-cert-public.crt'), 'utf8');
var amtConsolePrivateKey = obj.fs.readFileSync(parent.getConfigFilePath('amtconsole-cert-private.key'), 'utf8');
r.console = { cert: amtConsoleCertificate, key: amtConsolePrivateKey };
if (obj.fileExists(parent.getConfigFilePath("amtconsole-cert-public.crt")) && obj.fileExists(parent.getConfigFilePath("agentserver-cert-private.key"))) {
r.console = { cert: obj.fs.readFileSync(parent.getConfigFilePath("amtconsole-cert-public.crt"), "utf8"), key: obj.fs.readFileSync(parent.getConfigFilePath("amtconsole-cert-private.key"), "utf8") };
rcount++;
}
// If the swarm server certificate exist, load it (This is an optional certificate)
if (obj.fileExists(parent.getConfigFilePath('swarmserver-cert-public.crt')) && obj.fileExists(parent.getConfigFilePath('swarmserver-cert-private.key'))) {
var swarmServerCertificate = obj.fs.readFileSync(parent.getConfigFilePath('swarmserver-cert-public.crt'), 'utf8');
var swarmServerPrivateKey = obj.fs.readFileSync(parent.getConfigFilePath('swarmserver-cert-private.key'), 'utf8');
r.swarmserver = { cert: swarmServerCertificate, key: swarmServerPrivateKey };
if (obj.fileExists(parent.getConfigFilePath("swarmserver-cert-public.crt")) && obj.fileExists(parent.getConfigFilePath("swarmserver-cert-private.key"))) {
r.swarmserver = { cert: obj.fs.readFileSync(parent.getConfigFilePath("swarmserver-cert-public.crt"), "utf8"), key: obj.fs.readFileSync(parent.getConfigFilePath("swarmserver-cert-private.key"), "utf8") };
}
// If the swarm server root certificate exist, load it (This is an optional certificate)
if (obj.fileExists(parent.getConfigFilePath('swarmserverroot-cert-public.crt'))) {
var swarmServerRootCertificate = obj.fs.readFileSync(parent.getConfigFilePath('swarmserverroot-cert-public.crt'), 'utf8');
r.swarmserverroot = { cert: swarmServerRootCertificate };
if (obj.fileExists(parent.getConfigFilePath("swarmserverroot-cert-public.crt"))) {
r.swarmserverroot = { cert: obj.fs.readFileSync(parent.getConfigFilePath("swarmserverroot-cert-public.crt"), "utf8") };
}
// If CA certificates are present, load them
if (r.web != null) {
var caok, caindex = 1, calist = [];
do {
caok = false;
if (obj.fileExists(parent.getConfigFilePath('webserver-cert-chain' + caindex + '.crt'))) {
var caCertificate = obj.fs.readFileSync(parent.getConfigFilePath('webserver-cert-chain' + caindex + '.crt'), 'utf8');
calist.push(caCertificate);
caok = true;
}
caindex++;
} while (caok == true);
r.web.ca = calist;
}
do {
caok = false;
if (obj.fileExists(parent.getConfigFilePath("webserver-cert-chain" + caindex + ".crt"))) {
calist.push(obj.fs.readFileSync(parent.getConfigFilePath("webserver-cert-chain" + caindex + ".crt"), "utf8"));
caok = true;
}
caindex++;
} while (caok === true);
if (r.web != null) { r.web.ca = calist; }
// Decode certificate arguments
var commonName = 'un-configured', country, organization, forceWebCertGen = 0, forceMpsCertGen = 0;
var commonName = "un-configured";
var country = null;
var organization = null;
var forceWebCertGen = 0;
var forceMpsCertGen = 0;
if (certargs != undefined) {
var args = certargs.split(',');
if (args.length > 0) commonName = args[0];
if (args.length > 1) country = args[1];
if (args.length > 2) organization = args[2];
var xargs = certargs.split(",");
if (xargs.length > 0) { commonName = xargs[0]; }
if (xargs.length > 1) { country = xargs[1]; }
if (xargs.length > 2) { organization = xargs[2]; }
}
// Decode MPS certificate arguments, this is for the Intel AMT CIRA server
var mpsCommonName = commonName, mpsCountry = country, mpsOrganization = organization;
if (mpscertargs != undefined) {
var args = mpscertargs.split(',');
if (args.length > 0) mpsCommonName = args[0];
if (args.length > 1) mpsCountry = args[1];
if (args.length > 2) mpsOrganization = args[2];
var mpsCommonName = commonName;
var mpsCountry = country;
var mpsOrganization = organization;
if (mpscertargs !== undefined) {
var xxargs = mpscertargs.split(",");
if (xxargs.length > 0) { mpsCommonName = xxargs[0]; }
if (xxargs.length > 1) { mpsCountry = xxargs[1]; }
if (xxargs.length > 2) { mpsOrganization = xxargs[2]; }
}
// Look for domains that have DNS names and load their certificates
r.dns = {};
for (var i in config.domains) {
if ((i != '') && (config.domains[i] != null) && (config.domains[i].dns != null)) {
var dnsname = config.domains[i].dns;
if (args.tlsoffload == true) {
for (i = 0; i < config.domains.length; i++) {
if ((i != "") && (config.domains[i] != null) && (config.domains[i].dns != null)) {
dnsname = config.domains[i].dns;
if (args.tlsoffload === true) {
// If the web certificate already exist, load it. Load just the certificate since we are in TLS offload situation
if (obj.fileExists(parent.getConfigFilePath('webserver-' + i + '-cert-public.crt'))) {
r.dns[i] = { cert: obj.fs.readFileSync(parent.getConfigFilePath('webserver-' + i + '-cert-public.crt'), 'utf8') };
if (obj.fileExists(parent.getConfigFilePath("webserver-" + i + "-cert-public.crt"))) {
r.dns[i] = { cert: obj.fs.readFileSync(parent.getConfigFilePath("webserver-" + i + "-cert-public.crt"), "utf8") };
config.domains[i].certs = r.dns[i];
} else {
console.log('WARNING: File "webserver-' + i + '-cert-public.crt" missing, domain "' + i + '" will not work correctly.');
console.log("WARNING: File \"webserver-" + i + "-cert-public.crt\" missing, domain \"" + i + "\" will not work correctly.");
}
} else {
// If the web certificate already exist, load it. Load both certificate and private key
if (obj.fileExists(parent.getConfigFilePath('webserver-' + i + '-cert-public.crt')) && obj.fileExists(parent.getConfigFilePath('webserver-' + i + '-cert-private.key'))) {
r.dns[i] = { cert: obj.fs.readFileSync(parent.getConfigFilePath('webserver-' + i + '-cert-public.crt'), 'utf8'), key: obj.fs.readFileSync(parent.getConfigFilePath('webserver-' + i + '-cert-private.key'), 'utf8') };
if (obj.fileExists(parent.getConfigFilePath("webserver-" + i + "-cert-public.crt")) && obj.fileExists(parent.getConfigFilePath("webserver-" + i + "-cert-private.key"))) {
r.dns[i] = { cert: obj.fs.readFileSync(parent.getConfigFilePath("webserver-" + i + "-cert-public.crt"), "utf8"), key: obj.fs.readFileSync(parent.getConfigFilePath("webserver-" + i + "-cert-private.key"), "utf8") };
config.domains[i].certs = r.dns[i];
// If CA certificates are present, load them
var caok, caindex = 1, calist = [];
caindex = 1;
r.dns[i].ca = [];
do {
caok = false;
if (obj.fileExists(parent.getConfigFilePath('webserver-' + i + '-cert-chain' + caindex + '.crt'))) {
var caCertificate = obj.fs.readFileSync(parent.getConfigFilePath('webserver-' + i + '-cert-chain' + caindex + '.crt'), 'utf8');
calist.push(caCertificate);
if (obj.fileExists(parent.getConfigFilePath("webserver-" + i + "-cert-chain" + caindex + ".crt"))) {
r.dns[i].ca.push(obj.fs.readFileSync(parent.getConfigFilePath("webserver-" + i + "-cert-chain" + caindex + ".crt"), "utf8"));
caok = true;
}
caindex++;
} while (caok == true);
r.dns[i].ca = calist;
} while (caok === true);
} else {
rcountmax++; // This certificate must be generated
}
@ -275,205 +221,201 @@ module.exports.CertificateOperations = function () {
}
}
if (rcount == rcountmax) {
if (rcount === rcountmax) {
// Fetch the Intel AMT console name
var consoleCertificate = obj.pki.certificateFromPem(r.console.cert);
r.AmtConsoleName = consoleCertificate.subject.getField('CN').value;
r.AmtConsoleName = obj.pki.certificateFromPem(r.console.cert).subject.getField("CN").value;
// Fetch the Intel AMT MPS common name
var mpsCertificate = obj.pki.certificateFromPem(r.mps.cert);
r.AmtMpsName = mpsCertificate.subject.getField('CN').value;
r.AmtMpsName = obj.pki.certificateFromPem(r.mps.cert).subject.getField("CN").value;
// Fetch the name of the server
var webCertificate = obj.pki.certificateFromPem(r.web.cert);
r.CommonName = webCertificate.subject.getField('CN').value;
r.CommonNames = [ r.CommonName.toLowerCase() ];
var altNames = webCertificate.getExtension('subjectAltName')
if (altNames) { for (var i in altNames.altNames) { r.CommonNames.push(altNames.altNames[i].value.toLowerCase()); } }
r.WebIssuer = webCertificate.issuer.getField("CN").value;
r.CommonName = webCertificate.subject.getField("CN").value;
r.CommonNames = [r.CommonName.toLowerCase()];
var altNames = webCertificate.getExtension("subjectAltName");
if (altNames) { for (i = 0; i < altNames.altNames.length; i++) { r.CommonNames.push(altNames.altNames[i].value.toLowerCase()); } }
var rootCertificate = obj.pki.certificateFromPem(r.root.cert);
r.RootName = rootCertificate.subject.getField('CN').value;
r.RootName = rootCertificate.subject.getField("CN").value;
if ((certargs == null) && (mpscertargs == null)) { if (func != undefined) { func(r); } return r }; // If no certificate arguments are given, keep the certificate
var xcountry, xcountryField = webCertificate.subject.getField('C');
if ((certargs == null) && (mpscertargs == null)) { if (func != undefined) { func(r); } return r; } // If no certificate arguments are given, keep the certificate
var xcountry, xcountryField = webCertificate.subject.getField("C");
if (xcountryField != null) { xcountry = xcountryField.value; }
var xorganization, xorganizationField = webCertificate.subject.getField('O');
var xorganization, xorganizationField = webCertificate.subject.getField("O");
if (xorganizationField != null) { xorganization = xorganizationField.value; }
if (certargs == null) { commonName = r.CommonName; country = xcountry; organization = xorganization; }
// Check if we have correct certificates
if ((r.CommonNames.indexOf(commonName.toLowerCase()) >= 0) && (r.AmtMpsName == mpsCommonName)) {
// Certificate matches what we want, keep it.
if (func != undefined) { func(r); } return r;
if (func !== undefined) { func(r); }
return r;
} else {
// Check what certificates we really need to re-generate.
if ((r.CommonNames.indexOf(commonName.toLowerCase()) < 0)) { forceWebCertGen = 1; }
if (r.AmtMpsName != mpsCommonName) { forceMpsCertGen = 1; }
}
}
console.log('Generating certificates, may take a few minutes...');
parent.updateServerState('state', 'generatingcertificates');
console.log("Generating certificates, may take a few minutes...");
parent.updateServerState("state", "generatingcertificates");
// If a certificate is missing, but web certificate is present and --cert is not used, set the names to be the same as the web certificate
if ((certargs == null) && (r.web != null)) {
var webCertificate = obj.pki.certificateFromPem(r.web.cert);
commonName = webCertificate.subject.getField('CN').value;
var xcountryField = webCertificate.subject.getField('C');
commonName = webCertificate.subject.getField("CN").value;
var xcountryField = webCertificate.subject.getField("C");
if (xcountryField != null) { country = xcountryField.value; }
var xorganizationField = webCertificate.subject.getField('O');
var xorganizationField = webCertificate.subject.getField("O");
if (xorganizationField != null) { organization = xorganizationField.value; }
}
var rootCertAndKey, rootCertificate, rootPrivateKey, rootName;
if (r.root == undefined) {
if (r.root === undefined) {
// If the root certificate does not exist, create one
console.log('Generating root certificate...');
rootCertAndKey = obj.GenerateRootCertificate(true, 'MeshCentralRoot', null, null, strongCertificate);
console.log("Generating root certificate...");
rootCertAndKey = obj.GenerateRootCertificate(true, "MeshCentralRoot", null, null, strongCertificate);
rootCertificate = obj.pki.certificateToPem(rootCertAndKey.cert);
rootPrivateKey = obj.pki.privateKeyToPem(rootCertAndKey.key);
obj.fs.writeFileSync(parent.getConfigFilePath('root-cert-public.crt'), rootCertificate);
obj.fs.writeFileSync(parent.getConfigFilePath('root-cert-private.key'), rootPrivateKey);
obj.fs.writeFileSync(parent.getConfigFilePath("root-cert-public.crt"), rootCertificate);
obj.fs.writeFileSync(parent.getConfigFilePath("root-cert-private.key"), rootPrivateKey);
} else {
// Keep the root certificate we have
rootCertAndKey = { cert: obj.pki.certificateFromPem(r.root.cert), key: obj.pki.privateKeyFromPem(r.root.key) };
rootCertificate = r.root.cert
rootPrivateKey = r.root.key
rootCertificate = r.root.cert;
rootPrivateKey = r.root.key;
}
var rootName = rootCertAndKey.cert.subject.getField('CN').value;
var rootName = rootCertAndKey.cert.subject.getField("CN").value;
// If the web certificate does not exist, create one
var webCertAndKey, webCertificate, webPrivateKey;
if ((r.web == null) || (forceWebCertGen == 1)) {
console.log('Generating HTTPS certificate...');
console.log("Generating HTTPS certificate...");
webCertAndKey = obj.IssueWebServerCertificate(rootCertAndKey, false, commonName, country, organization, null, strongCertificate);
webCertificate = obj.pki.certificateToPem(webCertAndKey.cert);
webPrivateKey = obj.pki.privateKeyToPem(webCertAndKey.key);
obj.fs.writeFileSync(parent.getConfigFilePath('webserver-cert-public.crt'), webCertificate);
obj.fs.writeFileSync(parent.getConfigFilePath('webserver-cert-private.key'), webPrivateKey);
obj.fs.writeFileSync(parent.getConfigFilePath("webserver-cert-public.crt"), webCertificate);
obj.fs.writeFileSync(parent.getConfigFilePath("webserver-cert-private.key"), webPrivateKey);
} else {
// Keep the console certificate we have
webCertAndKey = { cert: obj.pki.certificateFromPem(r.web.cert), key: obj.pki.privateKeyFromPem(r.web.key) };
webCertificate = r.web.cert
webPrivateKey = r.web.key
webCertificate = r.web.cert;
webPrivateKey = r.web.key;
}
var webIssuer = webCertAndKey.cert.issuer.getField("CN").value;
// If the mesh agent server certificate does not exist, create one
var agentCertAndKey, agentCertificate, agentPrivateKey;
if (r.agent == null) {
console.log('Generating MeshAgent certificate...');
agentCertAndKey = obj.IssueWebServerCertificate(rootCertAndKey, true, 'MeshCentralAgentServer', null, strongCertificate);
console.log("Generating MeshAgent certificate...");
agentCertAndKey = obj.IssueWebServerCertificate(rootCertAndKey, true, "MeshCentralAgentServer", null, strongCertificate);
agentCertificate = obj.pki.certificateToPem(agentCertAndKey.cert);
agentPrivateKey = obj.pki.privateKeyToPem(agentCertAndKey.key);
obj.fs.writeFileSync(parent.getConfigFilePath('agentserver-cert-public.crt'), agentCertificate);
obj.fs.writeFileSync(parent.getConfigFilePath('agentserver-cert-private.key'), agentPrivateKey);
obj.fs.writeFileSync(parent.getConfigFilePath("agentserver-cert-public.crt"), agentCertificate);
obj.fs.writeFileSync(parent.getConfigFilePath("agentserver-cert-private.key"), agentPrivateKey);
} else {
// Keep the mesh agent server certificate we have
agentCertAndKey = { cert: obj.pki.certificateFromPem(r.agent.cert), key: obj.pki.privateKeyFromPem(r.agent.key) };
agentCertificate = r.agent.cert
agentPrivateKey = r.agent.key
agentCertificate = r.agent.cert;
agentPrivateKey = r.agent.key;
}
// If the Intel AMT MPS certificate does not exist, create one
var mpsCertAndKey, mpsCertificate, mpsPrivateKey;
if ((r.mps == null) || (forceMpsCertGen == 1)) {
console.log('Generating Intel AMT MPS certificate...');
console.log("Generating Intel AMT MPS certificate...");
mpsCertAndKey = obj.IssueWebServerCertificate(rootCertAndKey, false, mpsCommonName, mpsCountry, mpsOrganization, null, false);
mpsCertificate = obj.pki.certificateToPem(mpsCertAndKey.cert);
mpsPrivateKey = obj.pki.privateKeyToPem(mpsCertAndKey.key);
obj.fs.writeFileSync(parent.getConfigFilePath('mpsserver-cert-public.crt'), mpsCertificate);
obj.fs.writeFileSync(parent.getConfigFilePath('mpsserver-cert-private.key'), mpsPrivateKey);
obj.fs.writeFileSync(parent.getConfigFilePath("mpsserver-cert-public.crt"), mpsCertificate);
obj.fs.writeFileSync(parent.getConfigFilePath("mpsserver-cert-private.key"), mpsPrivateKey);
} else {
// Keep the console certificate we have
mpsCertAndKey = { cert: obj.pki.certificateFromPem(r.mps.cert), key: obj.pki.privateKeyFromPem(r.mps.key) };
mpsCertificate = r.mps.cert
mpsPrivateKey = r.mps.key
mpsCertificate = r.mps.cert;
mpsPrivateKey = r.mps.key;
}
// If the Intel AMT console certificate does not exist, create one
var consoleCertAndKey, consoleCertificate, consolePrivateKey, amtConsoleName = 'MeshCentral';
var consoleCertAndKey, consoleCertificate, consolePrivateKey, amtConsoleName = "MeshCentral";
if (r.console == null) {
console.log('Generating Intel AMT console certificate...');
consoleCertAndKey = obj.IssueWebServerCertificate(rootCertAndKey, false, amtConsoleName, country, organization, { name: 'extKeyUsage', clientAuth: true, '2.16.840.1.113741.1.2.1': true, '2.16.840.1.113741.1.2.2': true, '2.16.840.1.113741.1.2.3': true }, false); // Intel AMT Remote, Agent and Activation usages
console.log("Generating Intel AMT console certificate...");
consoleCertAndKey = obj.IssueWebServerCertificate(rootCertAndKey, false, amtConsoleName, country, organization, { name: "extKeyUsage", clientAuth: true, "2.16.840.1.113741.1.2.1": true, "2.16.840.1.113741.1.2.2": true, "2.16.840.1.113741.1.2.3": true }, false); // Intel AMT Remote, Agent and Activation usages
consoleCertificate = obj.pki.certificateToPem(consoleCertAndKey.cert);
consolePrivateKey = obj.pki.privateKeyToPem(consoleCertAndKey.key);
obj.fs.writeFileSync(parent.getConfigFilePath('amtconsole-cert-public.crt'), consoleCertificate);
obj.fs.writeFileSync(parent.getConfigFilePath('amtconsole-cert-private.key'), consolePrivateKey);
obj.fs.writeFileSync(parent.getConfigFilePath("amtconsole-cert-public.crt"), consoleCertificate);
obj.fs.writeFileSync(parent.getConfigFilePath("amtconsole-cert-private.key"), consolePrivateKey);
} else {
// Keep the console certificate we have
consoleCertAndKey = { cert: obj.pki.certificateFromPem(r.console.cert), key: obj.pki.privateKeyFromPem(r.console.key) };
consoleCertificate = r.console.cert
consolePrivateKey = r.console.key
amtConsoleName = consoleCertAndKey.cert.subject.getField('CN').value;
consoleCertificate = r.console.cert;
consolePrivateKey = r.console.key;
amtConsoleName = consoleCertAndKey.cert.subject.getField("CN").value;
}
var r = { root: { cert: rootCertificate, key: rootPrivateKey }, web: { cert: webCertificate, key: webPrivateKey, ca: [] }, mps: { cert: mpsCertificate, key: mpsPrivateKey }, agent: { cert: agentCertificate, key: agentPrivateKey }, console: { cert: consoleCertificate, key: consolePrivateKey }, ca: calist, CommonName: commonName, RootName: rootName, AmtConsoleName: amtConsoleName, AmtMpsName: mpsCommonName, dns: {} };
r = { root: { cert: rootCertificate, key: rootPrivateKey }, web: { cert: webCertificate, key: webPrivateKey, ca: [] }, mps: { cert: mpsCertificate, key: mpsPrivateKey }, agent: { cert: agentCertificate, key: agentPrivateKey }, console: { cert: consoleCertificate, key: consolePrivateKey }, ca: calist, CommonName: commonName, RootName: rootName, AmtConsoleName: amtConsoleName, AmtMpsName: mpsCommonName, dns: {}, WebIssuer: webIssuer };
// Look for domains with DNS names that have no certificates and generated them.
for (var i in config.domains) {
if ((i != '') && (config.domains[i] != null) && (config.domains[i].dns != null)) {
var dnsname = config.domains[i].dns;
for (i = 0; i < config.domains.length; i++) {
if ((i != "") && (config.domains[i] != null) && (config.domains[i].dns != null)) {
dnsname = config.domains[i].dns;
if (args.tlsoffload != true) {
// If the web certificate does not exist, create it
if ((obj.fileExists(parent.getConfigFilePath('webserver-' + i + '-cert-public.crt')) == false) || (obj.fileExists(parent.getConfigFilePath('webserver-' + i + '-cert-private.key')) == false)) {
console.log('Generating HTTPS certificate for ' + i + '...');
if ((obj.fileExists(parent.getConfigFilePath("webserver-" + i + "-cert-public.crt")) === false) || (obj.fileExists(parent.getConfigFilePath("webserver-" + i + "-cert-private.key")) === false)) {
console.log("Generating HTTPS certificate for " + i + "...");
var xwebCertAndKey = obj.IssueWebServerCertificate(rootCertAndKey, false, dnsname, country, organization, null, strongCertificate);
var xwebCertificate = obj.pki.certificateToPem(xwebCertAndKey.cert);
var xwebPrivateKey = obj.pki.privateKeyToPem(xwebCertAndKey.key);
obj.fs.writeFileSync(parent.getConfigFilePath('webserver-' + i + '-cert-public.crt'), xwebCertificate);
obj.fs.writeFileSync(parent.getConfigFilePath('webserver-' + i + '-cert-private.key'), xwebPrivateKey);
obj.fs.writeFileSync(parent.getConfigFilePath("webserver-" + i + "-cert-public.crt"), xwebCertificate);
obj.fs.writeFileSync(parent.getConfigFilePath("webserver-" + i + "-cert-private.key"), xwebPrivateKey);
r.dns[i] = { cert: xwebCertificate, key: xwebPrivateKey };
config.domains[i].certs = r.dns[i];
// If CA certificates are present, load them
var caok, caindex = 1, calist = [];
caindex = 1;
r.dns[i].ca = [];
do {
caok = false;
if (obj.fileExists(parent.getConfigFilePath('webserver-' + i + '-cert-chain' + caindex + '.crt'))) {
var caCertificate = obj.fs.readFileSync(parent.getConfigFilePath('webserver-' + i + '-cert-chain' + caindex + '.crt'), 'utf8');
calist.push(caCertificate);
if (obj.fileExists(parent.getConfigFilePath("webserver-" + i + "-cert-chain" + caindex + ".crt"))) {
r.dns[i].ca.push(obj.fs.readFileSync(parent.getConfigFilePath("webserver-" + i + "-cert-chain" + caindex + ".crt"), "utf8"));
caok = true;
}
caindex++;
} while (caok == true);
r.dns[i].ca = calist;
} while (caok === true);
}
}
}
}
// If the swarm server certificate exist, load it (This is an optional certificate)
if (obj.fileExists(parent.getConfigFilePath('swarmserver-cert-public.crt')) && obj.fileExists(parent.getConfigFilePath('swarmserver-cert-private.key'))) {
var swarmServerCertificate = obj.fs.readFileSync(parent.getConfigFilePath('swarmserver-cert-public.crt'), 'utf8');
var swarmServerPrivateKey = obj.fs.readFileSync(parent.getConfigFilePath('swarmserver-cert-private.key'), 'utf8');
r.swarmserver = { cert: swarmServerCertificate, key: swarmServerPrivateKey };
if (obj.fileExists(parent.getConfigFilePath("swarmserver-cert-public.crt")) && obj.fileExists(parent.getConfigFilePath("swarmserver-cert-private.key"))) {
r.swarmserver = { cert: obj.fs.readFileSync(parent.getConfigFilePath("swarmserver-cert-public.crt"), "utf8"), key: obj.fs.readFileSync(parent.getConfigFilePath("swarmserver-cert-private.key"), "utf8") };
}
// If the swarm server root certificate exist, load it (This is an optional certificate)
if (obj.fileExists(parent.getConfigFilePath('swarmserverroot-cert-public.crt'))) {
var swarmServerRootCertificate = obj.fs.readFileSync(parent.getConfigFilePath('swarmserverroot-cert-public.crt'), 'utf8');
r.swarmserverroot = { cert: swarmServerRootCertificate };
if (obj.fileExists(parent.getConfigFilePath("swarmserverroot-cert-public.crt"))) {
r.swarmserverroot = { cert: obj.fs.readFileSync(parent.getConfigFilePath("swarmserverroot-cert-public.crt"), "utf8") };
}
// If CA certificates are present, load them
if (r.web != null) {
var caok, caindex = 1, calist = [];
caindex = 1;
r.web.ca = [];
do {
caok = false;
if (obj.fileExists(parent.getConfigFilePath('webserver-cert-chain' + caindex + '.crt'))) {
var caCertificate = obj.fs.readFileSync(parent.getConfigFilePath('webserver-cert-chain' + caindex + '.crt'), 'utf8');
calist.push(caCertificate);
if (obj.fileExists(parent.getConfigFilePath("webserver-cert-chain" + caindex + ".crt"))) {
r.web.ca.push(obj.fs.readFileSync(parent.getConfigFilePath("webserver-cert-chain" + caindex + ".crt"), "utf8"));
caok = true;
}
caindex++;
} while (caok == true);
r.web.ca = calist;
} while (caok === true);
}
if (func != undefined) { func(r); }
return r;
}
};
// Accelerators, used to dispatch work to other processes
const fork = require('child_process').fork;
const program = require('path').join(__dirname, 'meshaccelerator.js');
const acceleratorTotalCount = require('os').cpus().length;
const fork = require("child_process").fork;
const program = require("path").join(__dirname, "meshaccelerator.js");
const acceleratorTotalCount = require("os").cpus().length;
var acceleratorCreateCount = acceleratorTotalCount;
var freeAccelerators = [];
var pendingAccelerator = [];
@ -485,9 +427,9 @@ module.exports.CertificateOperations = function () {
if (freeAccelerators.length > 0) { return freeAccelerators.pop(); }
if (acceleratorCreateCount > 0) {
acceleratorCreateCount--;
var accelerator = fork(program, [], { stdio: ['pipe', 'pipe', 'pipe', 'ipc'] });
var accelerator = fork(program, [], { stdio: ["pipe", "pipe", "pipe", "ipc"] });
accelerator.accid = acceleratorCreateCount;
accelerator.on('message', function (message) {
accelerator.on("message", function (message) {
this.func(this.tag, message);
delete this.tag;
if (pendingAccelerator.length > 0) {
@ -496,40 +438,41 @@ module.exports.CertificateOperations = function () {
accelerator.send(x);
} else { freeAccelerators.push(this); }
});
accelerator.send({ action: 'setState', certs: obj.acceleratorCertStore });
accelerator.send({ action: "setState", certs: obj.acceleratorCertStore });
return accelerator;
}
return null;
}
};
// Set the state of the accelerators. This way, we don't have to send certificate & keys to them each time.
// Set the state of the accelerators. This way, we don"t have to send certificate & keys to them each time.
obj.acceleratorStart = function (certificates) {
if (obj.acceleratorCertStore != null) { console.error('ERROR: Accelerators can only be started once.'); return; }
if (obj.acceleratorCertStore != null) { console.error("ERROR: Accelerators can only be started once."); return; }
obj.acceleratorCertStore = [{ cert: certificates.agent.cert, key: certificates.agent.key }];
if (certificates.swarmserver != null) { obj.acceleratorCertStore.push({ cert: certificates.swarmserver.cert, key: certificates.swarmserver.key }); }
}
};
// Perform any RSA signature, just pass in the private key and data.
obj.acceleratorPerformSignature = function (privatekey, data, tag, func) {
if (acceleratorTotalCount <= 1) {
// No accelerators available
if (typeof privatekey == 'number') { privatekey = obj.acceleratorCertStore[privatekey].key; }
const sign = obj.crypto.createSign('SHA384');
sign.end(new Buffer(data, 'binary'));
func(tag, sign.sign(privatekey).toString('binary'));
if (typeof privatekey == "number") { privatekey = obj.acceleratorCertStore[privatekey].key; }
const sign = obj.crypto.createSign("SHA384");
sign.end(new Buffer(data, "binary"));
func(tag, sign.sign(privatekey).toString("binary"));
} else {
var acc = obj.getAccelerator();
if (acc == null) {
// Add to pending accelerator workload
pendingAccelerator.push({ action: 'sign', key: privatekey, data: data, tag: tag });
pendingAccelerator.push({ action: "sign", key: privatekey, data: data, tag: tag });
} else {
// Send to accelerator now
acc.func = func;
acc.tag = tag;
acc.send({ action: 'sign', key: privatekey, data: data });
acc.send({ action: "sign", key: privatekey, data: data });
}
}
}
};
return obj;
};

128
common.js
View File

@ -6,86 +6,92 @@
* @version v0.0.1
*/
'use strict';
/*xjslint node: true */
/*xjslint plusplus: true */
/*xjslint maxlen: 256 */
/*jshint node: true */
/*jshint strict: false */
/*jshint esversion: 6 */
"use strict";
const crypto = require('crypto');
const crypto = require("crypto");
// Binary encoding and decoding functions
module.exports.ReadShort = function(v, p) { return (v.charCodeAt(p) << 8) + v.charCodeAt(p + 1); }
module.exports.ReadShortX = function(v, p) { return (v.charCodeAt(p + 1) << 8) + v.charCodeAt(p); }
module.exports.ReadInt = function(v, p) { return (v.charCodeAt(p) * 0x1000000) + (v.charCodeAt(p + 1) << 16) + (v.charCodeAt(p + 2) << 8) + v.charCodeAt(p + 3); } // We use "*0x1000000" instead of "<<24" because the shift converts the number to signed int32.
module.exports.ReadIntX = function(v, p) { return (v.charCodeAt(p + 3) * 0x1000000) + (v.charCodeAt(p + 2) << 16) + (v.charCodeAt(p + 1) << 8) + v.charCodeAt(p); }
module.exports.ShortToStr = function(v) { return String.fromCharCode((v >> 8) & 0xFF, v & 0xFF); }
module.exports.ShortToStrX = function(v) { return String.fromCharCode(v & 0xFF, (v >> 8) & 0xFF); }
module.exports.IntToStr = function(v) { return String.fromCharCode((v >> 24) & 0xFF, (v >> 16) & 0xFF, (v >> 8) & 0xFF, v & 0xFF); }
module.exports.IntToStrX = function(v) { return String.fromCharCode(v & 0xFF, (v >> 8) & 0xFF, (v >> 16) & 0xFF, (v >> 24) & 0xFF); }
module.exports.MakeToArray = function(v) { if (!v || v == null || typeof v == 'object') return v; return [v]; }
module.exports.SplitArray = function(v) { return v.split(','); }
module.exports.Clone = function(v) { return JSON.parse(JSON.stringify(v)); }
module.exports.IsFilenameValid = (function () { var x1 = /^[^\\/:\*\?"<>\|]+$/, x2 = /^\./, x3 = /^(nul|prn|con|lpt[0-9]|com[0-9])(\.|$)/i; return function isFilenameValid(fname) { return module.exports.validateString(fname, 1, 4096) && x1.test(fname) && !x2.test(fname) && !x3.test(fname) && (fname[0] != '.'); } })();
module.exports.ReadShort = function (v, p) { return (v.charCodeAt(p) << 8) + v.charCodeAt(p + 1); };
module.exports.ReadShortX = function (v, p) { return (v.charCodeAt(p + 1) << 8) + v.charCodeAt(p); };
module.exports.ReadInt = function (v, p) { return (v.charCodeAt(p) * 0x1000000) + (v.charCodeAt(p + 1) << 16) + (v.charCodeAt(p + 2) << 8) + v.charCodeAt(p + 3); }; // We use "*0x1000000" instead of "<<24" because the shift converts the number to signed int32.
module.exports.ReadIntX = function (v, p) { return (v.charCodeAt(p + 3) * 0x1000000) + (v.charCodeAt(p + 2) << 16) + (v.charCodeAt(p + 1) << 8) + v.charCodeAt(p); };
module.exports.ShortToStr = function (v) { return String.fromCharCode((v >> 8) & 0xFF, v & 0xFF); };
module.exports.ShortToStrX = function (v) { return String.fromCharCode(v & 0xFF, (v >> 8) & 0xFF); };
module.exports.IntToStr = function (v) { return String.fromCharCode((v >> 24) & 0xFF, (v >> 16) & 0xFF, (v >> 8) & 0xFF, v & 0xFF); };
module.exports.IntToStrX = function (v) { return String.fromCharCode(v & 0xFF, (v >> 8) & 0xFF, (v >> 16) & 0xFF, (v >> 24) & 0xFF); };
module.exports.MakeToArray = function (v) { if (!v || v == null || typeof v == "object") return v; return [v]; };
module.exports.SplitArray = function (v) { return v.split(","); };
module.exports.Clone = function (v) { return JSON.parse(JSON.stringify(v)); };
module.exports.IsFilenameValid = (function () { var x1 = /^[^\\/:\*\?"<>\|]+$/, x2 = /^\./, x3 = /^(nul|prn|con|lpt[0-9]|com[0-9])(\.|$)/i; return function isFilenameValid(fname) { return module.exports.validateString(fname, 1, 4096) && x1.test(fname) && !x2.test(fname) && !x3.test(fname) && (fname[0] != '.'); }; })();
// Move an element from one position in an array to a new position
module.exports.ArrayElementMove = function(arr, from, to) { arr.splice(to, 0, arr.splice(from, 1)[0]); };
// Print object for HTML
module.exports.ObjectToStringEx = function(x, c) {
var r = "";
module.exports.ObjectToStringEx = function (x, c) {
var r = "", i;
if (x != 0 && (!x || x == null)) return "(Null)";
if (x instanceof Array) { for (var i in x) { r += '<br />' + gap(c) + "Item #" + i + ": " + module.exports.ObjectToStringEx(x[i], c + 1); } }
else if (x instanceof Object) { for (var i in x) { r += '<br />' + gap(c) + i + " = " + module.exports.ObjectToStringEx(x[i], c + 1); } }
if (x instanceof Array) { for (i in x) { r += '<br />' + gap(c) + "Item #" + i + ": " + module.exports.ObjectToStringEx(x[i], c + 1); } }
else if (x instanceof Object) { for (i in x) { r += '<br />' + gap(c) + i + " = " + module.exports.ObjectToStringEx(x[i], c + 1); } }
else { r += x; }
return r;
}
};
// Print object for console
module.exports.ObjectToStringEx2 = function(x, c) {
var r = "";
module.exports.ObjectToStringEx2 = function (x, c) {
var r = "", i;
if (x != 0 && (!x || x == null)) return "(Null)";
if (x instanceof Array) { for (var i in x) { r += '\r\n' + gap2(c) + "Item #" + i + ": " + module.exports.ObjectToStringEx2(x[i], c + 1); } }
else if (x instanceof Object) { for (var i in x) { r += '\r\n' + gap2(c) + i + " = " + module.exports.ObjectToStringEx2(x[i], c + 1); } }
if (x instanceof Array) { for (i in x) { r += '\r\n' + gap2(c) + "Item #" + i + ": " + module.exports.ObjectToStringEx2(x[i], c + 1); } }
else if (x instanceof Object) { for (i in x) { r += '\r\n' + gap2(c) + i + " = " + module.exports.ObjectToStringEx2(x[i], c + 1); } }
else { r += x; }
return r;
}
};
// Create an ident gap
module.exports.gap = function(c) { var x = ''; for (var i = 0; i < (c * 4) ; i++) { x += '&nbsp;'; } return x; }
module.exports.gap2 = function(c) { var x = ''; for (var i = 0; i < (c * 4) ; i++) { x += ' '; } return x; }
module.exports.gap = function (c) { var x = ''; for (var i = 0; i < (c * 4); i++) { x += '&nbsp;'; } return x; };
module.exports.gap2 = function (c) { var x = ''; for (var i = 0; i < (c * 4); i++) { x += ' '; } return x; };
// Print an object in html
module.exports.ObjectToString = function(x) { return module.exports.ObjectToStringEx(x, 0); }
module.exports.ObjectToString2 = function(x) { return module.exports.ObjectToStringEx2(x, 0); }
module.exports.ObjectToString = function (x) { return module.exports.ObjectToStringEx(x, 0); };
module.exports.ObjectToString2 = function (x) { return module.exports.ObjectToStringEx2(x, 0); };
// Convert a hex string to a raw string
module.exports.hex2rstr = function(d) {
module.exports.hex2rstr = function (d) {
var r = '', m = ('' + d).match(/../g), t;
while (t = m.shift()) r += String.fromCharCode('0x' + t);
return r
}
while (t = m.shift()) { r += String.fromCharCode('0x' + t); }
return r;
};
// Convert decimal to hex
module.exports.char2hex = function(i) { return (i + 0x100).toString(16).substr(-2).toUpperCase(); }
module.exports.char2hex = function (i) { return (i + 0x100).toString(16).substr(-2).toUpperCase(); };
// Convert a raw string to a hex string
module.exports.rstr2hex = function(input) {
module.exports.rstr2hex = function (input) {
var r = '', i;
for (i = 0; i < input.length; i++) { r += module.exports.char2hex(input.charCodeAt(i)); }
return r;
}
};
// UTF-8 encoding & decoding functions
module.exports.encode_utf8 = function(s) { return unescape(encodeURIComponent(s)); }
module.exports.decode_utf8 = function(s) { return decodeURIComponent(escape(s)); }
module.exports.encode_utf8 = function (s) { return unescape(encodeURIComponent(s)); };
module.exports.decode_utf8 = function (s) { return decodeURIComponent(escape(s)); };
// Convert a string into a blob
module.exports.data2blob = function(data) {
module.exports.data2blob = function (data) {
var bytes = new Array(data.length);
for (var i = 0; i < data.length; i++) bytes[i] = data.charCodeAt(i);
var blob = new Blob([new Uint8Array(bytes)]);
return blob;
}
};
// Generate random numbers
module.exports.random = function (max) { return Math.floor(Math.random() * max); }
module.exports.random = function (max) { return Math.floor(Math.random() * max); };
// Split a comma seperated string, ignoring commas in quotes.
module.exports.quoteSplit = function (str) {
@ -93,7 +99,7 @@ module.exports.quoteSplit = function (str) {
for (var i in str) { if (str[i] == '"') { quote = (quote + 1) % 2; } if ((str[i] == ',') && (quote == 0)) { tmp = tmp.trim(); result.push(tmp); tmp = ''; } else { tmp += str[i]; } }
if (tmp.length > 0) result.push(tmp.trim());
return result;
}
};
// Convert list of "name = value" into object
module.exports.parseNameValueList = function (list) {
@ -107,43 +113,43 @@ module.exports.parseNameValueList = function (list) {
}
}
return result;
}
};
// Compute the MD5 digest hash for a set of values
module.exports.ComputeDigesthash = function (username, password, realm, method, path, qop, nonce, nc, cnonce) {
var ha1 = crypto.createHash('md5').update(username + ":" + realm + ":" + password).digest("hex");
var ha2 = crypto.createHash('md5').update(method + ":" + path).digest("hex");
return crypto.createHash('md5').update(ha1 + ":" + nonce + ":" + nc + ":" + cnonce + ":" + qop + ":" + ha2).digest("hex");
}
};
module.exports.toNumber = function (str) { var x = parseInt(str); if (x == str) return x; return str; }
module.exports.escapeHtml = function (string) { return String(string).replace(/[&<>"'`=\/]/g, function (s) { return { '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;', '/': '&#x2F;', '`': '&#x60;', '=': '&#x3D;' }[s]; }); }
module.exports.escapeHtmlBreaks = function (string) { return String(string).replace(/[&<>"'`=\/]/g, function (s) { return { '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;', '/': '&#x2F;', '`': '&#x60;', '=': '&#x3D;', '\r': '<br />', '\n': '' }[s]; }); }
module.exports.toNumber = function (str) { var x = parseInt(str); if (x == str) return x; return str; };
module.exports.escapeHtml = function (string) { return String(string).replace(/[&<>"'`=\/]/g, function (s) { return { '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;', '/': '&#x2F;', '`': '&#x60;', '=': '&#x3D;' }[s]; }); };
module.exports.escapeHtmlBreaks = function (string) { return String(string).replace(/[&<>"'`=\/]/g, function (s) { return { '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;', '/': '&#x2F;', '`': '&#x60;', '=': '&#x3D;', '\r': '<br />', '\n': '' }[s]; }); };
// Lowercase all the names in a object recursively
module.exports.objKeysToLower = function (obj) {
for (var i in obj) {
if (i.toLowerCase() !== i) { obj[i.toLowerCase()] = obj[i]; delete obj[i]; } // LowerCase all key names
if (typeof obj[i] == 'object') { module.exports.objKeysToLower(obj[i]); } // LowerCase all key names in the child object
}
}
return obj;
}
};
// Escape and unexcape feild names so there are no invalid characters for MongoDB
module.exports.escapeFieldName = function (name) { return name.split('%').join('%25').split('.').join('%2E').split('$').join('%24'); }
module.exports.unEscapeFieldName = function (name) { return name.split('%2E').join('.').split('%24').join('$').split('%25').join('%'); }
module.exports.escapeFieldName = function (name) { return name.split('%').join('%25').split('.').join('%2E').split('$').join('%24'); };
module.exports.unEscapeFieldName = function (name) { return name.split('%2E').join('.').split('%24').join('$').split('%25').join('%'); };
// Escape all links
module.exports.escapeLinksFieldName = function (docx) { var doc = module.exports.Clone(docx); if (doc.links != null) { for (var j in doc.links) { var ue = module.exports.escapeFieldName(j); if (ue !== j) { doc.links[ue] = doc.links[j]; delete doc.links[j]; } } } return doc; }
module.exports.unEscapeLinksFieldName = function (doc) { if (doc.links != null) { for (var j in doc.links) { var ue = module.exports.unEscapeFieldName(j); if (ue !== j) { doc.links[ue] = doc.links[j]; delete doc.links[j]; } } } return doc; }
//module.exports.escapeAllLinksFieldName = function (docs) { for (var i in docs) { module.exports.escapeLinksFieldName(docs[i]); } }
module.exports.unEscapeAllLinksFieldName = function (docs) { for (var i in docs) { docs[i] = module.exports.unEscapeLinksFieldName(docs[i]); } }
module.exports.escapeLinksFieldName = function (docx) { var doc = module.exports.Clone(docx); if (doc.links != null) { for (var j in doc.links) { var ue = module.exports.escapeFieldName(j); if (ue !== j) { doc.links[ue] = doc.links[j]; delete doc.links[j]; } } } return doc; };
module.exports.unEscapeLinksFieldName = function (doc) { if (doc.links != null) { for (var j in doc.links) { var ue = module.exports.unEscapeFieldName(j); if (ue !== j) { doc.links[ue] = doc.links[j]; delete doc.links[j]; } } } return doc; };
//module.exports.escapeAllLinksFieldName = function (docs) { for (var i in docs) { module.exports.escapeLinksFieldName(docs[i]); } };
module.exports.unEscapeAllLinksFieldName = function (docs) { for (var i in docs) { docs[i] = module.exports.unEscapeLinksFieldName(docs[i]); } };
// Validation methods
module.exports.validateString = function(str, minlen, maxlen) { return ((str != null) && (typeof str == 'string') && ((minlen == null) || (str.length >= minlen)) && ((maxlen == null) || (str.length <= maxlen))); }
module.exports.validateInt = function(int, minval, maxval) { return ((int != null) && (typeof int == 'number') && ((minval == null) || (int >= minval)) && ((maxval == null) || (int <= maxval))); }
module.exports.validateArray = function (array, minlen, maxlen) { return ((array != null) && Array.isArray(array) && ((minlen == null) || (array.length >= minlen)) && ((maxlen == null) || (array.length <= maxlen))); }
module.exports.validateStrArray = function (array, minlen, maxlen) { if (((array != null) && Array.isArray(array)) == false) return false; for (var i in array) { if ((typeof array[i] != 'string') && ((minlen == null) || (array[i].length >= minlen)) && ((maxlen == null) || (array[i].length <= maxlen))) return false; } return true; }
module.exports.validateObject = function (obj) { return ((obj != null) && (typeof obj == 'object')); }
module.exports.validateEmail = function (email, minlen, maxlen) { if (module.exports.validateString(email, minlen, maxlen) == false) return false; var emailReg = /^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$/; return emailReg.test(email); }
module.exports.validateUsername = function (username, minlen, maxlen) { return (module.exports.validateString(username, minlen, maxlen) && (username.indexOf(' ') == -1)); }
module.exports.validateString = function (str, minlen, maxlen) { return ((str != null) && (typeof str == 'string') && ((minlen == null) || (str.length >= minlen)) && ((maxlen == null) || (str.length <= maxlen))); };
module.exports.validateInt = function (int, minval, maxval) { return ((int != null) && (typeof int == 'number') && ((minval == null) || (int >= minval)) && ((maxval == null) || (int <= maxval))); };
module.exports.validateArray = function (array, minlen, maxlen) { return ((array != null) && Array.isArray(array) && ((minlen == null) || (array.length >= minlen)) && ((maxlen == null) || (array.length <= maxlen))); };
module.exports.validateStrArray = function (array, minlen, maxlen) { if (((array != null) && Array.isArray(array)) == false) return false; for (var i in array) { if ((typeof array[i] != 'string') && ((minlen == null) || (array[i].length >= minlen)) && ((maxlen == null) || (array[i].length <= maxlen))) return false; } return true; };
module.exports.validateObject = function (obj) { return ((obj != null) && (typeof obj == 'object')); };
module.exports.validateEmail = function (email, minlen, maxlen) { if (module.exports.validateString(email, minlen, maxlen) == false) return false; var emailReg = /^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$/; return emailReg.test(email); };
module.exports.validateUsername = function (username, minlen, maxlen) { return (module.exports.validateString(username, minlen, maxlen) && (username.indexOf(' ') == -1)); };

79
db.js
View File

@ -6,7 +6,13 @@
* @version v0.0.2
*/
'use strict';
/*xjslint node: true */
/*xjslint plusplus: true */
/*xjslint maxlen: 256 */
/*jshint node: true */
/*jshint strict: false */
/*jshint esversion: 6 */
"use strict";
//
// Construct Meshcentral database object
@ -21,6 +27,7 @@
//
module.exports.CreateDB = function (parent) {
var obj = {};
var Datastore = null;
obj.path = require('path');
obj.parent = parent;
obj.identifier = null;
@ -28,7 +35,7 @@ module.exports.CreateDB = function (parent) {
if (obj.parent.args.mongodb) {
// Use MongoDB
obj.databaseType = 2;
var Datastore = require('mongojs');
Datastore = require('mongojs');
var db = Datastore(obj.parent.args.mongodb);
var dbcollection = 'meshcentral';
if (obj.parent.args.mongodbcol) { dbcollection = obj.parent.args.mongodbcol; }
@ -36,11 +43,11 @@ module.exports.CreateDB = function (parent) {
} else {
// Use NeDB (The default)
obj.databaseType = 1;
var Datastore = require('nedb');
Datastore = require('nedb');
obj.file = new Datastore({ filename: obj.parent.getConfigFilePath('meshcentral.db'), autoload: true });
obj.file.persistence.setAutocompactionInterval(3600);
}
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.
@ -64,7 +71,7 @@ module.exports.CreateDB = function (parent) {
func(ver);
});
}
};
obj.cleanup = function () {
// TODO: Remove all mesh links to invalid users
@ -83,41 +90,41 @@ module.exports.CreateDB = function (parent) {
for (var i in docs) { if (docs[i].subscriptions != null) { console.log('Clean user: ' + docs[i].name); obj.SetUser(docs[i]); } } // Remove "subscriptions" that should not be there.
});
*/
}
};
obj.Set = function (data, func) { obj.file.update({ _id: data._id }, data, { upsert: true }, func); }
obj.Get = function (id, func) { obj.file.find({ _id: id }, func); }
obj.GetAll = function (func) { obj.file.find({}, func); }
obj.GetAllTypeNoTypeField = function (type, domain, func) { obj.file.find({ type: type, domain: domain }, { type : 0 }, func); }
obj.GetAllTypeNoTypeFieldMeshFiltered = function (meshes, domain, type, func) { obj.file.find({ type: type, domain: domain, meshid: { $in: meshes } }, { type : 0 }, func); }
obj.GetAllType = function (type, func) { obj.file.find({ type: type }, func); }
obj.GetAllIdsOfType = function (ids, domain, type, func) { obj.file.find({ type: type, domain: domain, _id: { $in: ids } }, func); }
obj.GetUserWithEmail = function (domain, email, func) { obj.file.find({ type: 'user', domain: domain, email: email }, { type: 0 }, func); }
obj.GetUserWithVerifiedEmail = function (domain, email, func) { obj.file.find({ type: 'user', domain: domain, email: email, emailVerified: true }, { type: 0 }, func); }
obj.Remove = function (id) { obj.file.remove({ _id: id }); }
obj.RemoveNode = function (id) { obj.file.remove({ node: id }, { multi: true }); }
obj.RemoveAll = function (func) { obj.file.remove({}, { multi: true }, func); }
obj.RemoveAllOfType = function (type, func) { obj.file.remove({ type: type }, { multi: true }, func); }
obj.InsertMany = function (data, func) { obj.file.insert(data, func); }
obj.StoreEvent = function (ids, source, event) { obj.file.insert(event); }
obj.GetEvents = function (ids, domain, func) { if (obj.databaseType == 1) { obj.file.find({ type: 'event', domain: domain, ids: { $in: ids } }, { type: 0, _id: 0, domain: 0, ids: 0, node: 0 }).sort({ time: -1 }).exec(func); } else { obj.file.find({ type: 'event', domain: domain, ids: { $in: ids } }, { type: 0, _id: 0, domain: 0, ids: 0, node: 0 }).sort({ time: -1 }, func) } }
obj.GetEventsWithLimit = function (ids, domain, limit, func) { if (obj.databaseType == 1) { obj.file.find({ type: 'event', domain: domain, ids: { $in: ids } }, { type: 0, _id: 0, domain: 0, ids: 0, node: 0 }).sort({ time: -1 }).limit(limit).exec(func); } else { obj.file.find({ type: 'event', domain: domain, ids: { $in: ids } }, { type: 0, _id: 0, domain: 0, ids: 0, node: 0 }).sort({ time: -1 }).limit(limit, func); } }
obj.GetNodeEventsWithLimit = function (nodeid, domain, limit, func) { if (obj.databaseType == 1) { obj.file.find({ type: 'event', domain: domain, nodeid: nodeid }, { type: 0, _id: 0, domain: 0, ids: 0, node: 0 }).sort({ time: -1 }).limit(limit).exec(func); } else { obj.file.find({ type: 'event', domain: domain, nodeid: nodeid }, { type: 0, _id: 0, domain: 0, ids: 0, node: 0 }).sort({ time: -1 }).limit(limit, func); } }
obj.RemoveMesh = function (id) { obj.file.remove({ mesh: id }, { multi: true }); obj.file.remove({ _id: id }); obj.file.remove({ _id: 'nt' + id }); }
obj.RemoveAllEvents = function (domain) { obj.file.remove({ type: 'event', domain: domain }, { multi: true }); }
obj.MakeSiteAdmin = function (username, domain) { obj.Get('user/' + domain + '/' + username, function (err, docs) { if (docs.length == 1) { docs[0].siteadmin = 0xFFFFFFFF; obj.Set(docs[0]); } }); }
obj.DeleteDomain = function (domain, func) { obj.file.remove({ domain: domain }, { multi: true }, func); }
obj.SetUser = function(user) { var u = Clone(user); if (u.subscriptions) { delete u.subscriptions; } obj.Set(u); }
obj.dispose = function () { for (var x in obj) { if (obj[x].close) { obj[x].close(); } delete obj[x]; } }
obj.clearOldEntries = function (type, days, domain) { var cutoff = Date.now() - (1000 * 60 * 60 * 24 * days); obj.file.remove({ type: type, time: { $lt: cutoff } }, { multi: true }); }
obj.getPowerTimeline = function (nodeid, func) { if (obj.databaseType == 1) { obj.file.find({ type: 'power', node: { $in: ['*', nodeid] } }).sort({ time: 1 }).exec(func); } else { obj.file.find({ type: 'power', node: { $in: ['*', nodeid] } }).sort({ time: 1 }, func); } }
obj.getLocalAmtNodes = function (func) { obj.file.find({ type: 'node', host: { $exists: true, $ne: null }, intelamt: { $exists: true } }, func); }
obj.getAmtUuidNode = function (meshid, uuid, func) { obj.file.find({ type: 'node', meshid: meshid, 'intelamt.uuid': uuid }, func); }
obj.Set = function (data, func) { obj.file.update({ _id: data._id }, data, { upsert: true }, func); };
obj.Get = function (id, func) { obj.file.find({ _id: id }, func); };
obj.GetAll = function (func) { obj.file.find({}, func); };
obj.GetAllTypeNoTypeField = function (type, domain, func) { obj.file.find({ type: type, domain: domain }, { type: 0 }, func); };
obj.GetAllTypeNoTypeFieldMeshFiltered = function (meshes, domain, type, func) { obj.file.find({ type: type, domain: domain, meshid: { $in: meshes } }, { type: 0 }, func); };
obj.GetAllType = function (type, func) { obj.file.find({ type: type }, func); };
obj.GetAllIdsOfType = function (ids, domain, type, func) { obj.file.find({ type: type, domain: domain, _id: { $in: ids } }, func); };
obj.GetUserWithEmail = function (domain, email, func) { obj.file.find({ type: 'user', domain: domain, email: email }, { type: 0 }, func); };
obj.GetUserWithVerifiedEmail = function (domain, email, func) { obj.file.find({ type: 'user', domain: domain, email: email, emailVerified: true }, { type: 0 }, func); };
obj.Remove = function (id) { obj.file.remove({ _id: id }); };
obj.RemoveNode = function (id) { obj.file.remove({ node: id }, { multi: true }); };
obj.RemoveAll = function (func) { obj.file.remove({}, { multi: true }, func); };
obj.RemoveAllOfType = function (type, func) { obj.file.remove({ type: type }, { multi: true }, func); };
obj.InsertMany = function (data, func) { obj.file.insert(data, func); };
obj.StoreEvent = function (ids, source, event) { obj.file.insert(event); };
obj.GetEvents = function (ids, domain, func) { if (obj.databaseType == 1) { obj.file.find({ type: 'event', domain: domain, ids: { $in: ids } }, { type: 0, _id: 0, domain: 0, ids: 0, node: 0 }).sort({ time: -1 }).exec(func); } else { obj.file.find({ type: 'event', domain: domain, ids: { $in: ids } }, { type: 0, _id: 0, domain: 0, ids: 0, node: 0 }).sort({ time: -1 }, func); } };
obj.GetEventsWithLimit = function (ids, domain, limit, func) { if (obj.databaseType == 1) { obj.file.find({ type: 'event', domain: domain, ids: { $in: ids } }, { type: 0, _id: 0, domain: 0, ids: 0, node: 0 }).sort({ time: -1 }).limit(limit).exec(func); } else { obj.file.find({ type: 'event', domain: domain, ids: { $in: ids } }, { type: 0, _id: 0, domain: 0, ids: 0, node: 0 }).sort({ time: -1 }).limit(limit, func); } };
obj.GetNodeEventsWithLimit = function (nodeid, domain, limit, func) { if (obj.databaseType == 1) { obj.file.find({ type: 'event', domain: domain, nodeid: nodeid }, { type: 0, _id: 0, domain: 0, ids: 0, node: 0 }).sort({ time: -1 }).limit(limit).exec(func); } else { obj.file.find({ type: 'event', domain: domain, nodeid: nodeid }, { type: 0, _id: 0, domain: 0, ids: 0, node: 0 }).sort({ time: -1 }).limit(limit, func); } };
obj.RemoveMesh = function (id) { obj.file.remove({ mesh: id }, { multi: true }); obj.file.remove({ _id: id }); obj.file.remove({ _id: 'nt' + id }); };
obj.RemoveAllEvents = function (domain) { obj.file.remove({ type: 'event', domain: domain }, { multi: true }); };
obj.MakeSiteAdmin = function (username, domain) { obj.Get('user/' + domain + '/' + username, function (err, docs) { if (docs.length == 1) { docs[0].siteadmin = 0xFFFFFFFF; obj.Set(docs[0]); } }); };
obj.DeleteDomain = function (domain, func) { obj.file.remove({ domain: domain }, { multi: true }, func); };
obj.SetUser = function (user) { var u = Clone(user); if (u.subscriptions) { delete u.subscriptions; } obj.Set(u); };
obj.dispose = function () { for (var x in obj) { if (obj[x].close) { obj[x].close(); } delete obj[x]; } };
obj.clearOldEntries = function (type, days, domain) { var cutoff = Date.now() - (1000 * 60 * 60 * 24 * days); obj.file.remove({ type: type, time: { $lt: cutoff } }, { multi: true }); };
obj.getPowerTimeline = function (nodeid, func) { if (obj.databaseType == 1) { obj.file.find({ type: 'power', node: { $in: ['*', nodeid] } }).sort({ time: 1 }).exec(func); } else { obj.file.find({ type: 'power', node: { $in: ['*', nodeid] } }).sort({ time: 1 }, func); } };
obj.getLocalAmtNodes = function (func) { obj.file.find({ type: 'node', host: { $exists: true, $ne: null }, intelamt: { $exists: true } }, func); };
obj.getAmtUuidNode = function (meshid, uuid, func) { obj.file.find({ type: 'node', meshid: meshid, 'intelamt.uuid': uuid }, func); };
// This is used to rate limit a number of operation per day. Returns a startValue each new days, but you can substract it and save the value in the db.
obj.getValueOfTheDay = function (id, startValue, func) { obj.Get(id, function (err, docs) { var date = new Date(), t = date.toLocaleDateString(); if (docs.length == 1) { var r = docs[0]; if (r.day == t) { func({ _id: id, value: r.value, day: t }); return; } } func({ _id: id, value: startValue, day: t }); }); }
obj.getValueOfTheDay = function (id, startValue, func) { obj.Get(id, function (err, docs) { var date = new Date(), t = date.toLocaleDateString(); if (docs.length == 1) { var r = docs[0]; if (r.day == t) { func({ _id: id, value: r.value, day: t }); return; } } func({ _id: id, value: startValue, day: t }); }); };
function Clone(v) { return JSON.parse(JSON.stringify(v)); }
return obj;
}
};

View File

@ -14,7 +14,13 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
'use strict';
/*xjslint node: true */
/*xjslint plusplus: true */
/*xjslint maxlen: 256 */
/*jshint node: true */
/*jshint strict: false */
/*jshint esversion: 6 */
"use strict";
const exeJavaScriptGuid = 'B996015880544A19B7F7E9BE44914C18';
const exeMeshPolicyGuid = 'B996015880544A19B7F7E9BE44914C19';
@ -59,7 +65,7 @@ module.exports.streamExeWithJavaScript = function (options) {
} else {
throw ('js content not specified');
}
}
};
// Changes a Windows Executable to add the MSH inside of it.
@ -144,7 +150,7 @@ module.exports.streamExeWithMeshPolicy = function (options) {
});
options.destinationStream.sourceStream.pipe(options.destinationStream, { end: false });
}
}
};
// Return information about this executable
@ -157,6 +163,7 @@ module.exports.parseWindowsExecutable = function (exePath) {
var dosHeader = Buffer.alloc(64);
var ntHeader = Buffer.alloc(24);
var optHeader;
var numRVA;
// Read the DOS header
bytesRead = fs.readSync(fd, dosHeader, 0, 64, 0);
@ -185,7 +192,6 @@ module.exports.parseWindowsExecutable = function (exePath) {
// Read the optional header
optHeader = Buffer.alloc(ntHeader.readUInt16LE(20));
bytesRead = fs.readSync(fd, optHeader, 0, optHeader.length, dosHeader.readUInt32LE(60) + 24);
var numRVA = undefined;
retVal.CheckSumPos = dosHeader.readUInt32LE(60) + 24 + 64;
retVal.SizeOfCode = optHeader.readUInt32LE(4);
@ -223,7 +229,7 @@ module.exports.parseWindowsExecutable = function (exePath) {
}
fs.closeSync(fd);
return (retVal);
}
};
//
@ -254,8 +260,7 @@ module.exports.hashExecutableFile = function (options) {
// Setup initial state
options.state = { endIndex: 0, checkSumIndex: 0, tableIndex: 0, stats: fs.statSync(options.sourcePath) };
if (options.platform == 'win32')
{
if (options.platform == 'win32') {
if (options.peinfo.CertificateTableAddress != 0) { options.state.endIndex = options.peinfo.CertificateTableAddress; }
options.state.tableIndex = options.peinfo.CertificateTableSizePos - 4;
options.state.checkSumIndex = options.peinfo.CheckSumPos;
@ -299,4 +304,4 @@ module.exports.hashExecutableFile = function (options) {
options.state.source = fs.createReadStream(options.sourcePath, { flags: 'r', start: 0, end: options.state.endIndex - 1 });
options.state.source.pipe(options.targetStream);
}
}
};

View File

@ -6,29 +6,35 @@
* @version v0.0.3
*/
'use strict';
/*xjslint node: true */
/*xjslint plusplus: true */
/*xjslint maxlen: 256 */
/*jshint node: true */
/*jshint strict: false */
/*jshint esversion: 6 */
"use strict";
const crypto = require('crypto');
const common = require('./common.js');
const crypto = require("crypto");
const common = require("./common.js");
var HttpInterceptorAuthentications = {};
var RedirInterceptorAuthentications = {};
//var RedirInterceptorAuthentications = {};
// Construct a HTTP interceptor object
module.exports.CreateHttpInterceptor = function (args) {
var obj = {};
// Create a random hex string of a given length
obj.randomValueHex = function (len) { return crypto.randomBytes(Math.ceil(len / 2)).toString('hex').slice(0, len); }
obj.randomValueHex = function (len) { return crypto.randomBytes(Math.ceil(len / 2)).toString('hex').slice(0, len); };
obj.args = args;
obj.amt = { acc: "", mode: 0, count: 0, error: false }; // mode: 0:Header, 1:LengthBody, 2:ChunkedBody, 3:UntilClose
obj.ws = { acc: "", mode: 0, count: 0, error: false, authCNonce: obj.randomValueHex(10), authCNonceCount: 1 };
obj.blockAmtStorage = false;
// Private method
obj.Debug = function (msg) { console.log(msg); }
obj.Debug = function (msg) { console.log(msg); };
// Process data coming from Intel AMT
obj.processAmtData = function (data) {
obj.amt.acc += data; // Add data to accumulator
@ -39,13 +45,14 @@ module.exports.CreateHttpInterceptor = function (args) {
data += obj.processAmtDataEx();
} while (datalen != data.length); // Process as much data as possible
return data;
}
};
// Process data coming from AMT in the accumulator
obj.processAmtDataEx = function () {
var i, r, headerend;
if (obj.amt.mode == 0) { // Header Mode
// Decode the HTTP header
var headerend = obj.amt.acc.indexOf('\r\n\r\n');
headerend = obj.amt.acc.indexOf('\r\n\r\n');
if (headerend < 0) return "";
var headerlines = obj.amt.acc.substring(0, headerend).split('\r\n');
obj.amt.acc = obj.amt.acc.substring(headerend + 4);
@ -53,7 +60,7 @@ module.exports.CreateHttpInterceptor = function (args) {
var headers = headerlines.slice(1);
obj.amt.headers = {};
obj.amt.mode = 3; // UntilClose
for (var i in headers) {
for (i in headers) {
var j = headers[i].indexOf(':');
if (j > 0) {
var v1 = headers[i].substring(0, j).trim().toLowerCase();
@ -73,46 +80,46 @@ module.exports.CreateHttpInterceptor = function (args) {
}
}
}
// Reform the HTTP header
var r = obj.amt.directive.join(' ') + '\r\n';
for (var i in obj.amt.headers) { r += (i + ': ' + obj.amt.headers[i] + '\r\n'); }
r = obj.amt.directive.join(' ') + '\r\n';
for (i in obj.amt.headers) { r += (i + ': ' + obj.amt.headers[i] + '\r\n'); }
r += '\r\n';
return r;
} else if (obj.amt.mode == 1) { // Length Body Mode
// Send the body of content-length size
var rl = obj.amt.count;
if (rl < obj.amt.acc.length) rl = obj.amt.acc.length;
var r = obj.amt.acc.substring(0, rl);
r = obj.amt.acc.substring(0, rl);
obj.amt.acc = obj.amt.acc.substring(rl);
obj.amt.count -= rl;
if (obj.amt.count == 0) { obj.amt.mode = 0; }
return r;
} else if (obj.amt.mode == 2) { // Chunked Body Mode
// Send data one chunk at a time
var headerend = obj.amt.acc.indexOf('\r\n');
headerend = obj.amt.acc.indexOf('\r\n');
if (headerend < 0) return "";
var chunksize = parseInt(obj.amt.acc.substring(0, headerend), 16);
if ((chunksize == 0) && (obj.amt.acc.length >= headerend + 4)) {
// Send the ending chunk (NOTE: We do not support trailing headers)
var r = obj.amt.acc.substring(0, headerend + 4);
r = obj.amt.acc.substring(0, headerend + 4);
obj.amt.acc = obj.amt.acc.substring(headerend + 4);
obj.amt.mode = 0;
return r;
} else if ((chunksize > 0) && (obj.amt.acc.length >= (headerend + 4 + chunksize))) {
// Send a chunk
var r = obj.amt.acc.substring(0, headerend + chunksize + 4);
r = obj.amt.acc.substring(0, headerend + chunksize + 4);
obj.amt.acc = obj.amt.acc.substring(headerend + chunksize + 4);
return r;
}
} else if (obj.amt.mode == 3) { // Until Close Mode
var r = obj.amt.acc;
r = obj.amt.acc;
obj.amt.acc = "";
return r;
}
return "";
}
};
// Process data coming from the Browser
obj.processBrowserData = function (data) {
obj.ws.acc += data; // Add data to accumulator
@ -123,13 +130,14 @@ module.exports.CreateHttpInterceptor = function (args) {
data += obj.processBrowserDataEx();
} while (datalen != data.length); // Process as much data as possible
return data;
}
};
// Process data coming from the Browser in the accumulator
obj.processBrowserDataEx = function () {
var i, r, headerend;
if (obj.ws.mode == 0) { // Header Mode
// Decode the HTTP header
var headerend = obj.ws.acc.indexOf('\r\n\r\n');
headerend = obj.ws.acc.indexOf('\r\n\r\n');
if (headerend < 0) return "";
var headerlines = obj.ws.acc.substring(0, headerend).split('\r\n');
obj.ws.acc = obj.ws.acc.substring(headerend + 4);
@ -139,7 +147,7 @@ module.exports.CreateHttpInterceptor = function (args) {
var headers = headerlines.slice(1);
obj.ws.headers = {};
obj.ws.mode = 3; // UntilClose
for (var i in headers) {
for (i in headers) {
var j = headers[i].indexOf(':');
if (j > 0) {
var v1 = headers[i].substring(0, j).trim().toLowerCase();
@ -159,14 +167,14 @@ module.exports.CreateHttpInterceptor = function (args) {
}
}
}
// Insert authentication
if (obj.args.user && obj.args.pass && HttpInterceptorAuthentications[obj.args.host + ':' + obj.args.port]) {
// We have authentication data, lets use it.
var AuthArgs = obj.GetAuthArgs(HttpInterceptorAuthentications[obj.args.host + ':' + obj.args.port]);
var hash = obj.ComputeDigesthash(obj.args.user, obj.args.pass, AuthArgs.realm, obj.ws.directive[0], obj.ws.directive[1], AuthArgs.qop, AuthArgs.nonce, obj.ws.authCNonceCount, obj.ws.authCNonce);
var authstr = 'Digest username="' + obj.args.user + '",realm="' + AuthArgs.realm + '",nonce="' + AuthArgs.nonce + '",uri="' + obj.ws.directive[1] + '",qop=' + AuthArgs.qop + ',nc=' + obj.ws.authCNonceCount + ',cnonce="' + obj.ws.authCNonce + '",response="' + hash + '"';
if (AuthArgs.opaque) { authstr += ',opaque="' + AuthArgs.opaque + '"'}
if (AuthArgs.opaque) { authstr += (',opaque="' + AuthArgs.opaque + '"'); }
obj.ws.headers.authorization = authstr;
obj.ws.authCNonceCount++;
} else {
@ -175,27 +183,27 @@ module.exports.CreateHttpInterceptor = function (args) {
}
// Reform the HTTP header
var r = obj.ws.directive.join(' ') + '\r\n';
for (var i in obj.ws.headers) { r += (i + ': ' + obj.ws.headers[i] + '\r\n'); }
r = obj.ws.directive.join(' ') + '\r\n';
for (i in obj.ws.headers) { r += (i + ': ' + obj.ws.headers[i] + '\r\n'); }
r += '\r\n';
return r;
} else if (obj.ws.mode == 1) { // Length Body Mode
// Send the body of content-length size
var rl = obj.ws.count;
if (rl < obj.ws.acc.length) rl = obj.ws.acc.length;
var r = obj.ws.acc.substring(0, rl);
r = obj.ws.acc.substring(0, rl);
obj.ws.acc = obj.ws.acc.substring(rl);
obj.ws.count -= rl;
if (obj.ws.count == 0) { obj.ws.mode = 0; }
return r;
} else if (obj.amt.mode == 2) { // Chunked Body Mode
// Send data one chunk at a time
var headerend = obj.amt.acc.indexOf('\r\n');
headerend = obj.amt.acc.indexOf('\r\n');
if (headerend < 0) return "";
var chunksize = parseInt(obj.amt.acc.substring(0, headerend), 16);
if (isNaN(chunksize)) { // TODO: Check this path
// Chunk is not in this batch, move one
var r = obj.amt.acc.substring(0, headerend + 2);
r = obj.amt.acc.substring(0, headerend + 2);
obj.amt.acc = obj.amt.acc.substring(headerend + 2);
// Peek if we next is the end of chunked transfer
headerend = obj.amt.acc.indexOf('\r\n');
@ -206,24 +214,24 @@ module.exports.CreateHttpInterceptor = function (args) {
return r;
} else if (chunksize == 0 && obj.amt.acc.length >= headerend + 4) {
// Send the ending chunk (NOTE: We do not support trailing headers)
var r = obj.amt.acc.substring(0, headerend + 4);
r = obj.amt.acc.substring(0, headerend + 4);
obj.amt.acc = obj.amt.acc.substring(headerend + 4);
obj.amt.mode = 0;
return r;
} else if (chunksize > 0 && obj.amt.acc.length >= headerend + 4) {
// Send a chunk
var r = obj.amt.acc.substring(0, headerend + chunksize + 4);
r = obj.amt.acc.substring(0, headerend + chunksize + 4);
obj.amt.acc = obj.amt.acc.substring(headerend + chunksize + 4);
return r;
}
} else if (obj.ws.mode == 3) { // Until Close Mode
var r = obj.ws.acc;
r = obj.ws.acc;
obj.ws.acc = "";
return r;
}
return "";
}
};
// Parse authentication values from the HTTP header
obj.GetAuthArgs = function (authheader) {
var authargs = {};
@ -233,42 +241,42 @@ module.exports.CreateHttpInterceptor = function (args) {
var i = argstr.indexOf('=');
var k = argstr.substring(0, i).trim().toLowerCase();
var v = argstr.substring(i + 1).trim();
if (v.substring(0,1) == '\"') { v = v.substring(1, v.length - 1); }
if (v.substring(0, 1) == '\"') { v = v.substring(1, v.length - 1); }
if (i > 0) authargs[k] = v;
}
return authargs;
}
};
// Compute the MD5 digest hash for a set of values
obj.ComputeDigesthash = function (username, password, realm, method, path, qop, nonce, nc, cnonce) {
var ha1 = crypto.createHash('md5').update(username + ":" + realm + ":" + password).digest("hex");
var ha2 = crypto.createHash('md5').update(method + ":" + path).digest("hex");
return crypto.createHash('md5').update(ha1 + ":" + nonce + ":" + nc + ":" + cnonce + ":" + qop + ":" + ha2).digest("hex");
}
};
return obj;
}
};
// Construct a redirection interceptor object
module.exports.CreateRedirInterceptor = function (args) {
var obj = {};
// Create a random hex string of a given length
obj.randomValueHex = function (len) { return crypto.randomBytes(Math.ceil(len / 2)).toString('hex').slice(0, len); }
obj.randomValueHex = function (len) { return crypto.randomBytes(Math.ceil(len / 2)).toString('hex').slice(0, len); };
obj.args = args;
obj.amt = { acc: "", mode: 0, count: 0, error: false, direct: false};
obj.ws = { acc: "", mode: 0, count: 0, error: false, direct: false, authCNonce: obj.randomValueHex(10), authCNonceCount: 1 };
obj.amt = { acc: "", mode: 0, count: 0, error: false, direct: false };
obj.ws = { acc: "", mode: 0, count: 0, error: false, direct: false, authCNonce: obj.randomValueHex(10), authCNonceCount: 1 };
obj.RedirectCommands = { StartRedirectionSession: 0x10, StartRedirectionSessionReply: 0x11, EndRedirectionSession: 0x12, AuthenticateSession: 0x13, AuthenticateSessionReply: 0x14 };
obj.StartRedirectionSessionReplyStatus = { SUCCESS: 0, TYPE_UNKNOWN: 1, BUSY: 2, UNSUPPORTED: 3, ERROR: 0xFF };
obj.AuthenticationStatus = { SUCCESS: 0, FALIURE: 1, NOTSUPPORTED: 2 };
obj.AuthenticationType = { QUERY: 0, USERPASS: 1, KERBEROS: 2, BADDIGEST: 3, DIGEST: 4 };
// Private method
obj.Debug = function (msg) { console.log(msg); }
obj.Debug = function (msg) { console.log(msg); };
// Process data coming from Intel AMT
obj.processAmtData = function (data) {
obj.amt.acc += data; // Add data to accumulator
@ -276,10 +284,11 @@ module.exports.CreateRedirInterceptor = function (args) {
var datalen = 0;
do { datalen = data.length; data += obj.processAmtDataEx(); } while (datalen != data.length); // Process as much data as possible
return data;
}
};
// Process data coming from AMT in the accumulator
obj.processAmtDataEx = function () {
var r;
if (obj.amt.acc.length == 0) return "";
if (obj.amt.direct == true) {
var data = obj.amt.acc;
@ -294,7 +303,7 @@ module.exports.CreateRedirInterceptor = function (args) {
if (obj.amt.acc.length < 13) return "";
var oemlen = obj.amt.acc.charCodeAt(12);
if (obj.amt.acc.length < 13 + oemlen) return "";
var r = obj.amt.acc.substring(0, 13 + oemlen);
r = obj.amt.acc.substring(0, 13 + oemlen);
obj.amt.acc = obj.amt.acc.substring(13 + oemlen);
return r;
}
@ -306,7 +315,7 @@ module.exports.CreateRedirInterceptor = function (args) {
if (obj.amt.acc.length < 9 + l) return "";
var authstatus = obj.amt.acc.charCodeAt(1);
var authType = obj.amt.acc.charCodeAt(4);
if (authType == obj.AuthenticationType.DIGEST && authstatus == obj.AuthenticationStatus.FALIURE) {
// Grab and keep all authentication parameters
var realmlen = obj.amt.acc.charCodeAt(9);
@ -322,7 +331,7 @@ module.exports.CreateRedirInterceptor = function (args) {
obj.amt.direct = true;
}
var r = obj.amt.acc.substring(0, 9 + l);
r = obj.amt.acc.substring(0, 9 + l);
obj.amt.acc = obj.amt.acc.substring(9 + l);
return r;
}
@ -333,8 +342,8 @@ module.exports.CreateRedirInterceptor = function (args) {
}
}
return "";
}
};
// Process data coming from the Browser
obj.processBrowserData = function (data) {
obj.ws.acc += data; // Add data to accumulator
@ -342,10 +351,11 @@ module.exports.CreateRedirInterceptor = function (args) {
var datalen = 0;
do { datalen = data.length; data += obj.processBrowserDataEx(); } while (datalen != data.length); // Process as much data as possible
return data;
}
};
// Process data coming from the Browser in the accumulator
obj.processBrowserDataEx = function () {
var r;
if (obj.ws.acc.length == 0) return "";
if (obj.ws.direct == true) {
var data = obj.ws.acc;
@ -355,13 +365,13 @@ module.exports.CreateRedirInterceptor = function (args) {
switch (obj.ws.acc.charCodeAt(0)) {
case obj.RedirectCommands.StartRedirectionSession: {
if (obj.ws.acc.length < 8) return "";
var r = obj.ws.acc.substring(0, 8);
r = obj.ws.acc.substring(0, 8);
obj.ws.acc = obj.ws.acc.substring(8);
return r;
}
case obj.RedirectCommands.EndRedirectionSession: {
if (obj.ws.acc.length < 4) return "";
var r = obj.ws.acc.substring(0, 4);
r = obj.ws.acc.substring(0, 4);
obj.ws.acc = obj.ws.acc.substring(4);
return r;
}
@ -369,7 +379,7 @@ module.exports.CreateRedirInterceptor = function (args) {
if (obj.ws.acc.length < 9) return "";
var l = common.ReadIntX(obj.ws.acc, 5);
if (obj.ws.acc.length < 9 + l) return "";
var authType = obj.ws.acc.charCodeAt(4);
if (authType == obj.AuthenticationType.DIGEST && obj.args.user && obj.args.pass) {
var authurl = "/RedirectionService";
@ -379,10 +389,10 @@ module.exports.CreateRedirInterceptor = function (args) {
var nc = obj.ws.authCNonceCount;
obj.ws.authCNonceCount++;
var digest = obj.ComputeDigesthash(obj.args.user, obj.args.pass, obj.amt.digestRealm, "POST", authurl, obj.amt.digestQOP, obj.amt.digestNonce, nc, obj.ws.authCNonce);
// Replace this authentication digest with a server created one
// We have everything we need to authenticate
var r = String.fromCharCode(0x13, 0x00, 0x00, 0x00, 0x04);
r = String.fromCharCode(0x13, 0x00, 0x00, 0x00, 0x04);
r += common.IntToStrX(obj.args.user.length + obj.amt.digestRealm.length + obj.amt.digestNonce.length + authurl.length + obj.ws.authCNonce.length + nc.toString().length + digest.length + obj.amt.digestQOP.length + 8);
r += String.fromCharCode(obj.args.user.length); // Username Length
r += obj.args.user; // Username
@ -400,13 +410,13 @@ module.exports.CreateRedirInterceptor = function (args) {
r += digest; // Response
r += String.fromCharCode(obj.amt.digestQOP.length); // QOP Length
r += obj.amt.digestQOP; // QOP
obj.ws.acc = obj.ws.acc.substring(9 + l); // Don't relay the original message
return r;
} else {
// Replace this authentication digest with a server created one
// Since we don't have authentication parameters, fill them in with blanks to get an error back what that info.
var r = String.fromCharCode(0x13, 0x00, 0x00, 0x00, 0x04);
r = String.fromCharCode(0x13, 0x00, 0x00, 0x00, 0x04);
r += common.IntToStrX(obj.args.user.length + authurl.length + 8);
r += String.fromCharCode(obj.args.user.length);
r += obj.args.user;
@ -418,7 +428,7 @@ module.exports.CreateRedirInterceptor = function (args) {
}
}
var r = obj.ws.acc.substring(0, 9 + l);
r = obj.ws.acc.substring(0, 9 + l);
obj.ws.acc = obj.ws.acc.substring(9 + l);
return r;
}
@ -429,14 +439,14 @@ module.exports.CreateRedirInterceptor = function (args) {
}
}
return "";
}
};
// Compute the MD5 digest hash for a set of values
obj.ComputeDigesthash = function (username, password, realm, method, path, qop, nonce, nc, cnonce) {
var ha1 = crypto.createHash('md5').update(username + ":" + realm + ":" + password).digest("hex");
var ha2 = crypto.createHash('md5').update(method + ":" + path).digest("hex");
return crypto.createHash('md5').update(ha1 + ":" + nonce + ":" + nc + ":" + cnonce + ":" + qop + ":" + ha2).digest("hex");
}
};
return obj;
}
};

View File

@ -6,12 +6,17 @@
* @version v0.0.2
*/
'use strict';
/*xjslint node: true */
/*xjslint plusplus: true */
/*xjslint maxlen: 256 */
/*jshint node: true */
/*jshint strict: false */
/*jshint esversion: 6 */
"use strict";
module.exports.CreateLetsEncrypt = function (parent) {
try {
const greenlock = require('greenlock');;
const path = require('path');
const greenlock = require('greenlock');
var obj = {};
obj.parent = parent;
@ -42,8 +47,8 @@ module.exports.CreateLetsEncrypt = function (parent) {
challengeType: 'http-01',
agreeToTerms: leAgree,
debug: obj.parent.args.debug > 0
}
if (obj.parent.args.debug == null) { greenlockargs.log = function (debug) { } } // If not in debug mode, ignore all console output from greenlock (makes things clean).
};
if (obj.parent.args.debug == null) { greenlockargs.log = function (debug) { }; } // If not in debug mode, ignore all console output from greenlock (makes things clean).
obj.le = greenlock.create(greenlockargs);
// Hook up GreenLock to the redirection server
@ -61,7 +66,7 @@ module.exports.CreateLetsEncrypt = function (parent) {
obj.leDomains = [certs.CommonName];
if (obj.parent.config.letsencrypt.names != null) {
if (typeof obj.parent.config.letsencrypt.names == 'string') { obj.parent.config.letsencrypt.names = obj.parent.config.letsencrypt.names.split(','); }
obj.parent.config.letsencrypt.names.map(function (s) { return s.trim() }); // Trim each name
obj.parent.config.letsencrypt.names.map(function (s) { return s.trim(); }); // Trim each name
if ((typeof obj.parent.config.letsencrypt.names != 'object') || (obj.parent.config.letsencrypt.names.length == null)) { console.log("ERROR: Let's Encrypt names must be an array in config.json."); func(certs); return; }
obj.leDomains = obj.parent.config.letsencrypt.names;
obj.leDomains.sort(); // Sort the array so it's always going to be in the same order.
@ -106,7 +111,7 @@ module.exports.CreateLetsEncrypt = function (parent) {
console.error("ERROR: Let's encrypt error: ", err);
});
});
}
};
// Check if we need to renew the certificate, call this every day.
obj.checkRenewCertificate = function () {
@ -116,8 +121,9 @@ module.exports.CreateLetsEncrypt = function (parent) {
obj.le.renew({ duplicate: false, domains: obj.leDomains, email: obj.parent.config.letsencrypt.email }, obj.leResults).then(function (xresults) {
obj.parent.performServerCertUpdate(); // Reset the server, TODO: Reset all peers
}, function (err) { }); // If we can't renew, ignore.
}
};
} catch (e) { console.error(e); return null; } // Unable to start Let's Encrypt
return obj;
}
return obj;
} catch (e) { console.error(e); } // Unable to start Let's Encrypt
return null;
};

View File

@ -6,7 +6,13 @@
* @version v0.0.1
*/
'use strict';
/*xjslint node: true */
/*xjslint plusplus: true */
/*xjslint maxlen: 256 */
/*jshint node: true */
/*jshint strict: false */
/*jshint esversion: 6 */
"use strict";
const crypto = require('crypto');
var certStore = null;

View File

@ -6,7 +6,13 @@
* @version v0.0.1
*/
'use strict';
/*xjslint node: true */
/*xjslint plusplus: true */
/*xjslint maxlen: 256 */
/*jshint node: true */
/*jshint strict: false */
/*jshint esversion: 6 */
"use strict";
var AgentConnectCount = 0;
@ -29,7 +35,7 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
obj.receivedCommands = 0;
obj.connectTime = null;
obj.agentCoreCheck = 0;
obj.agentInfo;
obj.agentInfo = null;
obj.agentUpdate = null;
const agentUpdateBlockSize = 65520;
obj.remoteaddr = obj.ws._socket.remoteAddress;
@ -39,7 +45,7 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
ws._socket.setKeepAlive(true, 240000); // Set TCP keep alive, 4 minutes
// Send a message to the mesh agent
obj.send = function (data) { try { if (typeof data == 'string') { obj.ws.send(new Buffer(data, 'binary')); } else { obj.ws.send(data); } } catch (e) { } }
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
obj.close = function (arg) {
@ -61,7 +67,7 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
obj.db.RemoveNode(obj.dbNodeKey); // Remove all entries with node:id
// Event node deletion
obj.parent.parent.DispatchEvent(['*', obj.dbMeshKey], obj, { etype: 'node', action: 'removenode', nodeid: obj.dbNodeKey, domain: obj.domain.id, nolog: 1 })
obj.parent.parent.DispatchEvent(['*', obj.dbMeshKey], obj, { etype: 'node', action: 'removenode', nodeid: obj.dbNodeKey, domain: obj.domain.id, nolog: 1 });
// Disconnect all connections if needed
var state = obj.parent.parent.GetConnectivityState(obj.dbNodeKey);
@ -71,7 +77,7 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
}
}
delete obj.nodeid;
}
};
// When data is received from the mesh agent web socket
ws.on('message', function (msg) {
@ -296,37 +302,33 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
// Event the new node
if (obj.agentInfo.capabilities & 0x20) {
// This is a temporary agent, don't log.
obj.parent.parent.DispatchEvent(['*', obj.dbMeshKey], obj, { etype: 'node', action: 'addnode', node: device, domain: domain.id, nolog: 1 })
obj.parent.parent.DispatchEvent(['*', obj.dbMeshKey], obj, { etype: 'node', action: 'addnode', node: device, domain: domain.id, nolog: 1 });
} else {
var change = 'Added device ' + obj.agentInfo.computerName + ' to mesh ' + mesh.name;
obj.parent.parent.DispatchEvent(['*', obj.dbMeshKey], obj, { etype: 'node', action: 'addnode', node: device, msg: change, domain: domain.id })
obj.parent.parent.DispatchEvent(['*', obj.dbMeshKey], obj, { etype: 'node', action: 'addnode', node: device, msg: ('Added device ' + obj.agentInfo.computerName + ' to mesh ' + mesh.name), domain: domain.id });
}
} else {
// Device already exists, look if changes has occured
device = nodes[0];
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, log = 0;
if (device.rname != obj.agentInfo.computerName) { device.rname = obj.agentInfo.computerName; change = 1; changes.push('computer name'); }
if (device.agent.ver != obj.agentInfo.agentVersion) { device.agent.ver = obj.agentInfo.agentVersion; change = 1; changes.push('agent version'); }
if (device.agent.id != obj.agentInfo.agentId) { device.agent.id = obj.agentInfo.agentId; change = 1; changes.push('agent type'); }
if ((device.agent.caps & 24) != (obj.agentInfo.capabilities & 24)) { device.agent.caps = obj.agentInfo.capabilities; change = 1; changes.push('agent capabilities'); } // If agent console or javascript support changes, update capabilities
if (device.meshid != obj.dbMeshKey) { device.meshid = obj.dbMeshKey; change = 1; log = 1; changes.push('agent meshid'); } // TODO: If the meshid changes, we need to event a device add/remove on both meshes
if (change == 1) {
obj.db.Set(device);
var changes = [], change = 0, log = 0;
if (device.agent == null) { device.agent = { ver: obj.agentInfo.agentVersion, id: obj.agentInfo.agentId, caps: obj.agentInfo.capabilities }; change = 1; }
if (device.rname != obj.agentInfo.computerName) { device.rname = obj.agentInfo.computerName; change = 1; changes.push('computer name'); }
if (device.agent.ver != obj.agentInfo.agentVersion) { device.agent.ver = obj.agentInfo.agentVersion; change = 1; changes.push('agent version'); }
if (device.agent.id != obj.agentInfo.agentId) { device.agent.id = obj.agentInfo.agentId; change = 1; changes.push('agent type'); }
if ((device.agent.caps & 24) != (obj.agentInfo.capabilities & 24)) { device.agent.caps = obj.agentInfo.capabilities; change = 1; changes.push('agent capabilities'); } // If agent console or javascript support changes, update capabilities
if (device.meshid != obj.dbMeshKey) { device.meshid = obj.dbMeshKey; change = 1; log = 1; changes.push('agent meshid'); } // TODO: If the meshid changes, we need to event a device add/remove on both meshes
if (change == 1) {
obj.db.Set(device);
// If this is a temporary device, don't log changes
if (obj.agentInfo.capabilities & 0x20) { log = 0; }
// If this is a temporary device, don't log changes
if (obj.agentInfo.capabilities & 0x20) { log = 0; }
// Event the node change
var event = { etype: 'node', action: 'changenode', nodeid: obj.dbNodeKey, domain: domain.id };
if (log == 0) { event.nolog = 1; } else { event.msg = 'Changed device ' + device.name + ' from mesh ' + mesh.name + ': ' + changes.join(', '); }
var device2 = obj.common.Clone(device);
if (device2.intelamt && device2.intelamt.pass) delete device2.intelamt.pass; // Remove the Intel AMT password before eventing this.
event.node = device;
obj.parent.parent.DispatchEvent(['*', device.meshid], obj, event);
}
// Event the node change
var event = { etype: 'node', action: 'changenode', nodeid: obj.dbNodeKey, domain: domain.id };
if (log == 0) { event.nolog = 1; } else { event.msg = 'Changed device ' + device.name + ' from mesh ' + mesh.name + ': ' + changes.join(', '); }
var device2 = obj.common.Clone(device);
if (device2.intelamt && device2.intelamt.pass) delete device2.intelamt.pass; // Remove the Intel AMT password before eventing this.
event.node = device;
obj.parent.parent.DispatchEvent(['*', device.meshid], obj, event);
}
}
@ -425,9 +427,10 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
// Process incoming agent JSON data
function processAgentData(msg) {
var i;
var str = msg.toString('utf8'), command = null;
if (str[0] == '{') {
try { command = JSON.parse(str) } catch (ex) { console.log('Unable to parse agent JSON (' + obj.remoteaddr + '): ' + str, ex); return; } // If the command can't be parsed, ignore it.
try { command = JSON.parse(str); } catch (ex) { console.log('Unable to parse agent JSON (' + obj.remoteaddr + '): ' + str, ex); return; } // If the command can't be parsed, ignore it.
if (typeof command != 'object') { return; }
switch (command.action) {
case 'msg':
@ -441,7 +444,7 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
if ((splitsessionid[0] == 'user') && (splitsessionid[1] == domain.id)) {
// Check if this user has rights to get this message
//if (mesh.links[user._id] == null || ((mesh.links[user._id].rights & 16) == 0)) return; // TODO!!!!!!!!!!!!!!!!!!!!!
// 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];
if (ws != null) {
@ -472,7 +475,7 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
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)); }
for (i in sessions) { sessions[i].send(JSON.stringify(command)); }
}
if (obj.parent.parent.multiServer != null) {
@ -487,9 +490,9 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
if ((user != null) && (user.links != null)) {
var rights = user.links[obj.dbMeshKey];
if (rights != null) { // TODO: Look at what rights are needed for message routing
var sessions = obj.parent.wssessions[userid];
var xsessions = obj.parent.wssessions[userid];
// Send the message to all users on this server
for (var i in sessions) { try { sessions[i].send(cmdstr); } catch (e) { } }
for (i in xsessions) { try { xsessions[i].send(cmdstr); } catch (e) { } }
}
}
}
@ -530,7 +533,7 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
if ((command.type == 'publicip') && (command.value != null) && (typeof command.value == 'object') && (command.value.ip) && (command.value.loc)) {
var x = {};
x.publicip = command.value.ip;
x.iploc = command.value.loc + ',' + (Math.floor(Date.now() / 1000) );
x.iploc = command.value.loc + ',' + (Math.floor(Date.now() / 1000));
ChangeAgentLocationInfo(x);
command.value._id = 'iploc_' + command.value.ip;
command.value.type = 'iploc';
@ -559,7 +562,7 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
// Event node deletion
var change = 'Migrated device ' + node.name;
obj.parent.parent.DispatchEvent(['*', node.meshid], obj, { etype: 'node', action: 'removenode', nodeid: node._id, msg: change, domain: node.domain })
obj.parent.parent.DispatchEvent(['*', node.meshid], obj, { etype: 'node', action: 'removenode', nodeid: node._id, msg: change, domain: node.domain });
}
});
break;
@ -678,4 +681,4 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
}
return obj;
}
};

View File

@ -6,7 +6,13 @@
* @version v0.0.1
*/
'use strict';
/*xjslint node: true */
/*xjslint plusplus: true */
/*xjslint maxlen: 256 */
/*jshint node: true */
/*jshint strict: false */
/*jshint esversion: 6 */
"use strict";
// Construct a MeshAgent object, called upon connection
module.exports.CreateMeshMain = function (parent) {
@ -34,7 +40,7 @@ module.exports.CreateMeshMain = function (parent) {
const accountInviteMailText = '[[[SERVERNAME]]] - Agent Installation Invitation\r\n\r\nUser [[[USERNAME]]] on server [[[SERVERNAME]]] ([[[SERVERURL]]]) is requesting you install a remote management agent. WARNING: This will allow the requester to take control of your computer. If you wish to do this, click on the following link to download the agent: [[[CALLBACKURL]]]\r\nIf you do not know about this request, please ignore this mail.\r\n';
function EscapeHtml(x) { if (typeof x == "string") return x.replace(/&/g, '&amp;').replace(/>/g, '&gt;').replace(/</g, '&lt;').replace(/"/g, '&quot;').replace(/'/g, '&apos;'); if (typeof x == "boolean") return x; if (typeof x == "number") return x; }
function EscapeHtmlBreaks(x) { if (typeof x == "string") return x.replace(/&/g, '&amp;').replace(/>/g, '&gt;').replace(/</g, '&lt;').replace(/"/g, '&quot;').replace(/'/g, '&apos;').replace(/\r/g, '<br />').replace(/\n/g, '').replace(/\t/g, '&nbsp;&nbsp;'); if (typeof x == "boolean") return x; if (typeof x == "number") return x; }
//function EscapeHtmlBreaks(x) { if (typeof x == "string") return x.replace(/&/g, '&amp;').replace(/>/g, '&gt;').replace(/</g, '&lt;').replace(/"/g, '&quot;').replace(/'/g, '&apos;').replace(/\r/g, '<br />').replace(/\n/g, '').replace(/\t/g, '&nbsp;&nbsp;'); if (typeof x == "boolean") return x; if (typeof x == "number") return x; }
// Setup mail server
var options = { host: parent.config.smtp.host, secure: (parent.config.smtp.tls == true), tls: { rejectUnauthorized: false } };
@ -53,8 +59,8 @@ module.exports.CreateMeshMain = function (parent) {
url = 'http' + ((obj.parent.args.notls == null) ? 's' : '') + '://' + domain.dns + ':' + obj.parent.args.port + domain.url;
}
if (options) {
if (options.cookie != null) { text = text.split('[[[CALLBACKURL]]]').join(url + 'checkmail?c=' + options.cookie) }
if (options.meshid != null) { text = text.split('[[[CALLBACKURL]]]').join(url + 'meshagents?id=3&meshid=' + options.meshid.split('/')[2] + '&tag=mailto:' + EscapeHtml(email)) }
if (options.cookie != null) { text = text.split('[[[CALLBACKURL]]]').join(url + 'checkmail?c=' + options.cookie); }
if (options.meshid != null) { text = text.split('[[[CALLBACKURL]]]').join(url + 'meshagents?id=3&meshid=' + options.meshid.split('/')[2] + '&tag=mailto:' + EscapeHtml(email)); }
}
return text.split('[[[USERNAME]]]').join(username).split('[[[SERVERURL]]]').join(url).split('[[[SERVERNAME]]]').join(domain.title);
}
@ -63,7 +69,7 @@ module.exports.CreateMeshMain = function (parent) {
obj.sendMail = function (to, subject, text, html) {
obj.pendingMails.push({ to: to, from: parent.config.smtp.from, subject: subject, text: text, html: html });
sendNextMail();
}
};
// Send account check mail
obj.sendAccountCheckMail = function (domain, username, email) {
@ -71,7 +77,7 @@ module.exports.CreateMeshMain = function (parent) {
var cookie = obj.parent.encodeCookie({ u: domain.id + '/' + username, e: email, a: 1 }, obj.mailCookieEncryptionKey);
obj.pendingMails.push({ to: email, from: parent.config.smtp.from, subject: mailReplacements(accountCheckSubject, domain, username, email), text: mailReplacements(accountCheckMailText, domain, username, email, { cookie: cookie }), html: mailReplacements(accountCheckMailHtml, domain, username, email, { cookie: cookie }) });
sendNextMail();
}
};
// Send account reset mail
obj.sendAccountResetMail = function (domain, username, email) {
@ -79,14 +85,14 @@ module.exports.CreateMeshMain = function (parent) {
var cookie = obj.parent.encodeCookie({ u: domain.id + '/' + username, e: email, a: 2 }, obj.mailCookieEncryptionKey);
obj.pendingMails.push({ to: email, from: parent.config.smtp.from, subject: mailReplacements(accountResetSubject, domain, username, email), text: mailReplacements(accountResetMailText, domain, username, email, { cookie: cookie }), html: mailReplacements(accountResetMailHtml, domain, username, email, { cookie: cookie }) });
sendNextMail();
}
};
// Send agent invite mail
obj.sendAgentInviteMail = function (domain, username, email, meshid) {
if ((parent.certificates == null) || (parent.certificates.CommonName == null) || (parent.certificates.CommonName == 'un-configured')) return; // If the server name is not set, can't do this.
obj.pendingMails.push({ to: email, from: parent.config.smtp.from, subject: mailReplacements(accountInviteSubject, domain, username, email), text: mailReplacements(accountInviteMailText, domain, username, email, { meshid: meshid }), html: mailReplacements(accountInviteMailHtml, domain, username, email, { meshid: meshid }) });
sendNextMail();
}
};
// Send out the next mail in the pending list
function sendNextMail() {
@ -111,7 +117,7 @@ module.exports.CreateMeshMain = function (parent) {
}
// Send out the next mail in the pending list
obj.verify = function() {
obj.verify = function () {
obj.smtpServer.verify(function (err, info) {
if (err == null) {
console.log('SMTP mail server ' + parent.config.smtp.host + ' working as expected.');
@ -119,7 +125,7 @@ module.exports.CreateMeshMain = function (parent) {
console.log('SMTP mail server ' + parent.config.smtp.host + ' failed: ' + JSON.stringify(err));
}
});
}
};
// Load the cookie encryption key from the database
obj.parent.db.Get('MailCookieEncryptionKey', function (err, docs) {
@ -133,5 +139,5 @@ module.exports.CreateMeshMain = function (parent) {
}
});
return obj;
}
return obj;
};

View File

@ -6,7 +6,12 @@
* @version v0.0.1
*/
'use strict';
/*jslint node: true */
/*jshint node: true */
/*jshint strict:false */
/*jshint -W097 */
/*jshint esversion: 6 */
"use strict";
// Construct a Intel AMT MPS server object
module.exports.CreateMpsServer = function (parent, db, args, certificates) {
@ -16,9 +21,9 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
obj.args = args;
obj.certificates = certificates;
obj.ciraConnections = {};
const common = require('./common.js');
const net = require('net');
const tls = require('tls');
const common = require("./common.js");
const net = require("net");
const tls = require("tls");
const MAX_IDLE = 90000; // 90 seconds max idle time, higher than the typical KEEP-ALIVE periode of 60 seconds
if (obj.args.tlsoffload) {
@ -27,10 +32,10 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
obj.server = tls.createServer({ key: certificates.mps.key, cert: certificates.mps.cert, requestCert: true, rejectUnauthorized: false }, onConnection);
}
obj.server.listen(args.mpsport, function () { console.log('MeshCentral Intel(R) AMT server running on ' + certificates.AmtMpsName + ':' + args.mpsport + ((args.mpsaliasport != null) ? (', alias port ' + args.mpsaliasport):'') + '.'); }).on('error', function (err) { console.error('ERROR: MeshCentral Intel(R) AMT server port ' + args.mpsport + ' is not available.'); if (args.exactports) { process.exit(); } });
obj.parent.updateServerState('mps-port', args.mpsport);
obj.parent.updateServerState('mps-name', certificates.AmtMpsName);
if (args.mpsaliasport != null) { obj.parent.updateServerState('mps-alias-port', args.mpsaliasport); }
obj.server.listen(args.mpsport, function () { console.log("MeshCentral Intel(R) AMT server running on " + certificates.AmtMpsName + ":" + args.mpsport + ((args.mpsaliasport != null) ? (", alias port " + args.mpsaliasport) : "") + "."); }).on("error", function (err) { console.error("ERROR: MeshCentral Intel(R) AMT server port " + args.mpsport + " is not available."); if (args.exactports) { process.exit(); } });
obj.parent.updateServerState("mps-port", args.mpsport);
obj.parent.updateServerState("mps-name", certificates.AmtMpsName);
if (args.mpsaliasport != null) { obj.parent.updateServerState("mps-alias-port", args.mpsaliasport); }
const APFProtocol = {
UNKNOWN: 0,
@ -54,8 +59,9 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
KEEPALIVE_REPLY: 209,
KEEPALIVE_OPTIONS_REQUEST: 210,
KEEPALIVE_OPTIONS_REPLY: 211
}
};
/*
const APFDisconnectCode = {
HOST_NOT_ALLOWED_TO_CONNECT: 1,
PROTOCOL_ERROR: 2,
@ -75,46 +81,47 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
CONNECTION_TIMED_OUT: 16,
BY_POLICY: 17,
TEMPORARILY_UNAVAILABLE: 18
}
};
const APFChannelOpenFailCodes = {
ADMINISTRATIVELY_PROHIBITED: 1,
CONNECT_FAILED: 2,
UNKNOWN_CHANNEL_TYPE: 3,
RESOURCE_SHORTAGE: 4,
}
};
*/
const APFChannelOpenFailureReasonCode = {
AdministrativelyProhibited: 1,
ConnectFailed: 2,
UnknownChannelType: 3,
ResourceShortage: 4,
}
};
function onConnection(socket) {
if (obj.args.tlsoffload) {
socket.tag = { first: true, clientCert: null, accumulator: "", activetunnels: 0, boundPorts: [], socket: socket, host: null, nextchannelid: 4, channels: {}, nextsourceport: 0 };
} else {
socket.tag = { first: true, clientCert: socket.getPeerCertificate(true), accumulator: "", activetunnels: 0, boundPorts: [], socket: socket, host: null, nextchannelid: 4, channels: {}, nextsourceport: 0 };
}
socket.setEncoding('binary');
Debug(1, 'MPS:New CIRA connection');
socket.setEncoding("binary");
Debug(1, "MPS:New CIRA connection");
// Setup the CIRA keep alive timer
socket.setTimeout(MAX_IDLE);
socket.on('timeout', () => { Debug(1, "MPS:CIRA timeout, disconnecting."); try { socket.end(); } catch (e) { } });
socket.on("timeout", () => { Debug(1, "MPS:CIRA timeout, disconnecting."); try { socket.end(); } catch (e) { } });
socket.addListener("data", function (data) {
if (args.mpsdebug) { var buf = new Buffer(data, "binary"); console.log('MPS <-- (' + buf.length + '):' + buf.toString('hex')); } // Print out received bytes
if (args.mpsdebug) { var buf = new Buffer(data, "binary"); console.log("MPS <-- (" + buf.length + "):" + buf.toString('hex')); } // Print out received bytes
socket.tag.accumulator += data;
// Detect if this is an HTTPS request, if it is, return a simple answer and disconnect. This is useful for debugging access to the MPS port.
if (socket.tag.first == true) {
if (socket.tag.accumulator.length < 3) return;
//if (!socket.tag.clientCert.subject) { console.log("MPS Connection, no client cert: " + socket.remoteAddress); socket.write('HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\nConnection: close\r\n\r\nMeshCentral2 MPS server.\r\nNo client certificate given.'); socket.end(); return; }
if (socket.tag.accumulator.substring(0, 3) == 'GET') { console.log("MPS Connection, HTTP GET detected: " + socket.remoteAddress); socket.write('HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nConnection: close\r\n\r\n<!DOCTYPE html><html><head><meta charset="UTF-8"></head><body>MeshCentral2 MPS server.<br />Intel&reg; AMT computers should connect here.</body></html>'); socket.end(); return; }
if (socket.tag.accumulator.substring(0, 3) == "GET") { console.log("MPS Connection, HTTP GET detected: " + socket.remoteAddress); socket.write("HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nConnection: close\r\n\r\n<!DOCTYPE html><html><head><meta charset=\"UTF-8\"></head><body>MeshCentral2 MPS server.<br />Intel&reg; AMT computers should connect here.</body></html>"); socket.end(); return; }
socket.tag.first = false;
// Setup this node with certificate authentication
if (socket.tag.clientCert && socket.tag.clientCert.subject && socket.tag.clientCert.subject.O && socket.tag.clientCert.subject.O.length == 64) {
// This is a node where the MeshID is indicated within the CIRA certificate
@ -144,7 +151,7 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
var device2 = common.Clone(device);
if (device2.intelamt.pass != undefined) delete device2.intelamt.pass; // Remove the Intel AMT password before eventing this.
var change = 'CIRA added device ' + socket.tag.name + ' to mesh ' + mesh.name;
obj.parent.DispatchEvent(['*', socket.tag.meshid], obj, { etype: 'node', action: 'addnode', node: device2, msg: change, domain: domainid })
obj.parent.DispatchEvent(['*', socket.tag.meshid], obj, { etype: 'node', action: 'addnode', node: device2, msg: change, domain: domainid });
} else {
// New CIRA connection for unknown node, disconnect.
console.log('CIRA connection for unknown node with incorrect mesh type. meshid: ' + socket.tag.meshid);
@ -258,7 +265,7 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
var device2 = common.Clone(device);
if (device2.intelamt.pass != undefined) delete device2.intelamt.pass; // Remove the Intel AMT password before eventing this.
var change = 'CIRA added device ' + socket.tag.name + ' to mesh ' + mesh.name;
obj.parent.DispatchEvent(['*', socket.tag.meshid], obj, { etype: 'node', action: 'addnode', node: device2, msg: change, domain: mesh.domain })
obj.parent.DispatchEvent(['*', socket.tag.meshid], obj, { etype: 'node', action: 'addnode', node: device2, msg: change, domain: mesh.domain });
} else {
// New CIRA connection for unknown node, disconnect.
console.log('CIRA connection for unknown node with incorrect mesh type. meshid: ' + socket.tag.meshid);
@ -309,20 +316,20 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
}
case APFProtocol.SERVICE_REQUEST: {
if (len < 5) return 0;
var serviceNameLen = common.ReadInt(data, 1);
if (len < 5 + serviceNameLen) return 0;
var serviceName = data.substring(5, 5 + serviceNameLen);
Debug(3, 'MPS:SERVICE_REQUEST', serviceName);
if (serviceName == "pfwd@amt.intel.com") { SendServiceAccept(socket, "pfwd@amt.intel.com"); }
if (serviceName == "auth@amt.intel.com") { SendServiceAccept(socket, "auth@amt.intel.com"); }
return 5 + serviceNameLen;
var xserviceNameLen = common.ReadInt(data, 1);
if (len < 5 + xserviceNameLen) return 0;
var xserviceName = data.substring(5, 5 + xserviceNameLen);
Debug(3, 'MPS:SERVICE_REQUEST', xserviceName);
if (xserviceName == "pfwd@amt.intel.com") { SendServiceAccept(socket, "pfwd@amt.intel.com"); }
if (xserviceName == "auth@amt.intel.com") { SendServiceAccept(socket, "auth@amt.intel.com"); }
return 5 + xserviceNameLen;
}
case APFProtocol.GLOBAL_REQUEST: {
if (len < 14) return 0;
var requestLen = common.ReadInt(data, 1);
if (len < 14 + requestLen) return 0;
var request = data.substring(5, 5 + requestLen);
var wantResponse = data.charCodeAt(5 + requestLen);
//var wantResponse = data.charCodeAt(5 + requestLen);
if (request == "tcpip-forward") {
var addrLen = common.ReadInt(data, 6 + requestLen);
@ -388,7 +395,7 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
if (len < (33 + ChannelTypeLength + TargetLen + SourceLen)) return 0;
var Source = data.substring(29 + ChannelTypeLength + TargetLen, 29 + ChannelTypeLength + TargetLen + SourceLen);
var SourcePort = common.ReadInt(data, 29 + ChannelTypeLength + TargetLen + SourceLen);
Debug(3, 'MPS:CHANNEL_OPEN', ChannelType, SenderChannel, WindowSize, Target + ':' + TargetPort, Source + ':' + SourcePort);
// Check if we understand this channel type
@ -398,7 +405,7 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
SendChannelOpenFailure(socket, SenderChannel, APFChannelOpenFailureReasonCode.UnknownChannelType);
return 33 + ChannelTypeLength + TargetLen + SourceLen;
}
/*
// This is a correct connection. Lets get it setup
var MeshAmtEventEndpoint = { ServerChannel: GetNextBindId(), AmtChannel: SenderChannel, MaxWindowSize: 2048, CurrentWindowSize:2048, SendWindow: WindowSize, InfoHeader: "Target: " + Target + ":" + TargetPort + ", Source: " + Source + ":" + SourcePort};
@ -408,25 +415,84 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
return 33 + ChannelTypeLength + TargetLen + SourceLen;
}
case APFProtocol.CHANNEL_OPEN_CONFIRMATION:
{
if (len < 17) return 0;
var RecipientChannel = common.ReadInt(data, 1);
var SenderChannel = common.ReadInt(data, 5);
var WindowSize = common.ReadInt(data, 9);
socket.tag.activetunnels++;
var cirachannel = socket.tag.channels[RecipientChannel];
if (cirachannel == undefined) { /*console.log("MPS Error in CHANNEL_OPEN_CONFIRMATION: Unable to find channelid " + RecipientChannel);*/ return 17; }
cirachannel.amtchannelid = SenderChannel;
cirachannel.sendcredits = cirachannel.amtCiraWindow = WindowSize;
Debug(3, 'MPS:CHANNEL_OPEN_CONFIRMATION', RecipientChannel, SenderChannel, WindowSize);
if (cirachannel.closing == 1) {
// Close this channel
SendChannelClose(cirachannel.socket, cirachannel.amtchannelid);
} else {
cirachannel.state = 2;
// Send any pending data
if (cirachannel.sendBuffer != undefined) {
case APFProtocol.CHANNEL_OPEN_CONFIRMATION:
{
if (len < 17) return 0;
var RecipientChannel = common.ReadInt(data, 1);
var SenderChannel = common.ReadInt(data, 5);
var WindowSize = common.ReadInt(data, 9);
socket.tag.activetunnels++;
var cirachannel = socket.tag.channels[RecipientChannel];
if (cirachannel == undefined) { /*console.log("MPS Error in CHANNEL_OPEN_CONFIRMATION: Unable to find channelid " + RecipientChannel);*/ return 17; }
cirachannel.amtchannelid = SenderChannel;
cirachannel.sendcredits = cirachannel.amtCiraWindow = WindowSize;
Debug(3, 'MPS:CHANNEL_OPEN_CONFIRMATION', RecipientChannel, SenderChannel, WindowSize);
if (cirachannel.closing == 1) {
// Close this channel
SendChannelClose(cirachannel.socket, cirachannel.amtchannelid);
} else {
cirachannel.state = 2;
// Send any pending data
if (cirachannel.sendBuffer != undefined) {
if (cirachannel.sendBuffer.length <= cirachannel.sendcredits) {
// Send the entire pending buffer
SendChannelData(cirachannel.socket, cirachannel.amtchannelid, cirachannel.sendBuffer);
cirachannel.sendcredits -= cirachannel.sendBuffer.length;
delete cirachannel.sendBuffer;
if (cirachannel.onSendOk) { cirachannel.onSendOk(cirachannel); }
} else {
// Send a part of the pending buffer
SendChannelData(cirachannel.socket, cirachannel.amtchannelid, cirachannel.sendBuffer.substring(0, cirachannel.sendcredits));
cirachannel.sendBuffer = cirachannel.sendBuffer.substring(cirachannel.sendcredits);
cirachannel.sendcredits = 0;
}
}
// Indicate the channel is open
if (cirachannel.onStateChange) { cirachannel.onStateChange(cirachannel, cirachannel.state); }
}
return 17;
}
case APFProtocol.CHANNEL_OPEN_FAILURE:
{
if (len < 17) return 0;
var RecipientChannel = common.ReadInt(data, 1);
var ReasonCode = common.ReadInt(data, 5);
Debug(3, 'MPS:CHANNEL_OPEN_FAILURE', RecipientChannel, ReasonCode);
var cirachannel = socket.tag.channels[RecipientChannel];
if (cirachannel == undefined) { console.log("MPS Error in CHANNEL_OPEN_FAILURE: Unable to find channelid " + RecipientChannel); return 17; }
if (cirachannel.state > 0) {
cirachannel.state = 0;
if (cirachannel.onStateChange) { cirachannel.onStateChange(cirachannel, cirachannel.state); }
delete socket.tag.channels[RecipientChannel];
}
return 17;
}
case APFProtocol.CHANNEL_CLOSE:
{
if (len < 5) return 0;
var RecipientChannel = common.ReadInt(data, 1);
Debug(3, 'MPS:CHANNEL_CLOSE', RecipientChannel);
var cirachannel = socket.tag.channels[RecipientChannel];
if (cirachannel == undefined) { console.log("MPS Error in CHANNEL_CLOSE: Unable to find channelid " + RecipientChannel); return 5; }
socket.tag.activetunnels--;
if (cirachannel.state > 0) {
cirachannel.state = 0;
if (cirachannel.onStateChange) { cirachannel.onStateChange(cirachannel, cirachannel.state); }
delete socket.tag.channels[RecipientChannel];
}
return 5;
}
case APFProtocol.CHANNEL_WINDOW_ADJUST:
{
if (len < 9) return 0;
var RecipientChannel = common.ReadInt(data, 1);
var ByteToAdd = common.ReadInt(data, 5);
var cirachannel = socket.tag.channels[RecipientChannel];
if (cirachannel == undefined) { console.log("MPS Error in CHANNEL_WINDOW_ADJUST: Unable to find channelid " + RecipientChannel); return 9; }
cirachannel.sendcredits += ByteToAdd;
Debug(3, 'MPS:CHANNEL_WINDOW_ADJUST', RecipientChannel, ByteToAdd, cirachannel.sendcredits);
if (cirachannel.state == 2 && cirachannel.sendBuffer != undefined) {
// Compute how much data we can send
if (cirachannel.sendBuffer.length <= cirachannel.sendcredits) {
// Send the entire pending buffer
SendChannelData(cirachannel.socket, cirachannel.amtchannelid, cirachannel.sendBuffer);
@ -440,170 +506,117 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
cirachannel.sendcredits = 0;
}
}
// Indicate the channel is open
if (cirachannel.onStateChange) { cirachannel.onStateChange(cirachannel, cirachannel.state); }
return 9;
}
return 17;
}
case APFProtocol.CHANNEL_OPEN_FAILURE:
{
if (len < 17) return 0;
var RecipientChannel = common.ReadInt(data, 1);
var ReasonCode = common.ReadInt(data, 5);
Debug(3, 'MPS:CHANNEL_OPEN_FAILURE', RecipientChannel, ReasonCode);
var cirachannel = socket.tag.channels[RecipientChannel];
if (cirachannel == undefined) { console.log("MPS Error in CHANNEL_OPEN_FAILURE: Unable to find channelid " + RecipientChannel); return 17; }
if (cirachannel.state > 0) {
cirachannel.state = 0;
if (cirachannel.onStateChange) { cirachannel.onStateChange(cirachannel, cirachannel.state); }
delete socket.tag.channels[RecipientChannel];
}
return 17;
}
case APFProtocol.CHANNEL_CLOSE:
{
if (len < 5) return 0;
var RecipientChannel = common.ReadInt(data, 1);
Debug(3, 'MPS:CHANNEL_CLOSE', RecipientChannel);
var cirachannel = socket.tag.channels[RecipientChannel];
if (cirachannel == undefined) { console.log("MPS Error in CHANNEL_CLOSE: Unable to find channelid " + RecipientChannel); return 5; }
socket.tag.activetunnels--;
if (cirachannel.state > 0) {
cirachannel.state = 0;
if (cirachannel.onStateChange) { cirachannel.onStateChange(cirachannel, cirachannel.state); }
delete socket.tag.channels[RecipientChannel];
}
return 5;
}
case APFProtocol.CHANNEL_WINDOW_ADJUST:
{
if (len < 9) return 0;
var RecipientChannel = common.ReadInt(data, 1);
var ByteToAdd = common.ReadInt(data, 5);
var cirachannel = socket.tag.channels[RecipientChannel];
if (cirachannel == undefined) { console.log("MPS Error in CHANNEL_WINDOW_ADJUST: Unable to find channelid " + RecipientChannel); return 9; }
cirachannel.sendcredits += ByteToAdd;
Debug(3, 'MPS:CHANNEL_WINDOW_ADJUST', RecipientChannel, ByteToAdd, cirachannel.sendcredits);
if (cirachannel.state == 2 && cirachannel.sendBuffer != undefined) {
// Compute how much data we can send
if (cirachannel.sendBuffer.length <= cirachannel.sendcredits) {
// Send the entire pending buffer
SendChannelData(cirachannel.socket, cirachannel.amtchannelid, cirachannel.sendBuffer);
cirachannel.sendcredits -= cirachannel.sendBuffer.length;
delete cirachannel.sendBuffer;
if (cirachannel.onSendOk) { cirachannel.onSendOk(cirachannel); }
} else {
// Send a part of the pending buffer
SendChannelData(cirachannel.socket, cirachannel.amtchannelid, cirachannel.sendBuffer.substring(0, cirachannel.sendcredits));
cirachannel.sendBuffer = cirachannel.sendBuffer.substring(cirachannel.sendcredits);
cirachannel.sendcredits = 0;
case APFProtocol.CHANNEL_DATA:
{
if (len < 9) return 0;
var RecipientChannel = common.ReadInt(data, 1);
var LengthOfData = common.ReadInt(data, 5);
if (len < (9 + LengthOfData)) return 0;
Debug(4, 'MPS:CHANNEL_DATA', RecipientChannel, LengthOfData);
var cirachannel = socket.tag.channels[RecipientChannel];
if (cirachannel == undefined) { console.log("MPS Error in CHANNEL_DATA: Unable to find channelid " + RecipientChannel); return 9 + LengthOfData; }
cirachannel.amtpendingcredits += LengthOfData;
if (cirachannel.onData) cirachannel.onData(cirachannel, data.substring(9, 9 + LengthOfData));
if (cirachannel.amtpendingcredits > (cirachannel.ciraWindow / 2)) {
SendChannelWindowAdjust(cirachannel.socket, cirachannel.amtchannelid, cirachannel.amtpendingcredits); // Adjust the buffer window
cirachannel.amtpendingcredits = 0;
}
return 9 + LengthOfData;
}
return 9;
}
case APFProtocol.CHANNEL_DATA:
{
if (len < 9) return 0;
var RecipientChannel = common.ReadInt(data, 1);
var LengthOfData = common.ReadInt(data, 5);
if (len < (9 + LengthOfData)) return 0;
Debug(4, 'MPS:CHANNEL_DATA', RecipientChannel, LengthOfData);
var cirachannel = socket.tag.channels[RecipientChannel];
if (cirachannel == undefined) { console.log("MPS Error in CHANNEL_DATA: Unable to find channelid " + RecipientChannel); return 9 + LengthOfData; }
cirachannel.amtpendingcredits += LengthOfData;
if (cirachannel.onData) cirachannel.onData(cirachannel, data.substring(9, 9 + LengthOfData));
if (cirachannel.amtpendingcredits > (cirachannel.ciraWindow / 2)) {
SendChannelWindowAdjust(cirachannel.socket, cirachannel.amtchannelid, cirachannel.amtpendingcredits); // Adjust the buffer window
cirachannel.amtpendingcredits = 0;
case APFProtocol.DISCONNECT:
{
if (len < 7) return 0;
var ReasonCode = common.ReadInt(data, 1);
Debug(3, 'MPS:DISCONNECT', ReasonCode);
try { delete obj.ciraConnections[socket.tag.nodeid]; } catch (e) { }
obj.parent.ClearConnectivityState(socket.tag.meshid, socket.tag.nodeid, 2);
return 7;
}
default:
{
Debug(1, 'MPS:Unknown CIRA command: ' + cmd);
return -1;
}
return 9 + LengthOfData;
}
case APFProtocol.DISCONNECT:
{
if (len < 7) return 0;
var ReasonCode = common.ReadInt(data, 1);
Debug(3, 'MPS:DISCONNECT', ReasonCode);
try { delete obj.ciraConnections[socket.tag.nodeid]; } catch (e) { }
obj.parent.ClearConnectivityState(socket.tag.meshid, socket.tag.nodeid, 2);
return 7;
}
default:
{
Debug(1, 'MPS:Unknown CIRA command: ' + cmd);
return -1;
}
}
}
socket.addListener("close", function () {
Debug(1, 'MPS:CIRA connection closed');
try { delete obj.ciraConnections[socket.tag.nodeid]; } catch (e) { }
obj.parent.ClearConnectivityState(socket.tag.meshid, socket.tag.nodeid, 2);
});
socket.addListener("error", function () {
//console.log("MPS Error: " + socket.remoteAddress);
});
}
// Disconnect CIRA tunnel
obj.close = function (socket) {
try { socket.end(); } catch (e) { }
try { delete obj.ciraConnections[socket.tag.nodeid]; } catch (e) { }
obj.parent.ClearConnectivityState(socket.tag.meshid, socket.tag.nodeid, 2);
}
};
function SendServiceAccept(socket, service) {
Write(socket, String.fromCharCode(APFProtocol.SERVICE_ACCEPT) + common.IntToStr(service.length) + service);
}
function SendTcpForwardSuccessReply(socket, port) {
Write(socket, String.fromCharCode(APFProtocol.REQUEST_SUCCESS) + common.IntToStr(port));
}
function SendTcpForwardCancelReply(socket) {
Write(socket, String.fromCharCode(APFProtocol.REQUEST_SUCCESS));
}
/*
function SendKeepAliveRequest(socket, cookie) {
Write(socket, String.fromCharCode(APFProtocol.KEEPALIVE_REQUEST) + common.IntToStr(cookie));
}
*/
function SendKeepAliveReply(socket, cookie) {
Write(socket, String.fromCharCode(APFProtocol.KEEPALIVE_REPLY) + common.IntToStr(cookie));
}
function SendChannelOpenFailure(socket, senderChannel, reasonCode) {
Write(socket, String.fromCharCode(APFProtocol.CHANNEL_OPEN_FAILURE) + common.IntToStr(senderChannel) + common.IntToStr(reasonCode) + common.IntToStr(0) + common.IntToStr(0));
}
/*
function SendChannelOpenConfirmation(socket, recipientChannelId, senderChannelId, initialWindowSize) {
Write(socket, String.fromCharCode(APFProtocol.CHANNEL_OPEN_CONFIRMATION) + common.IntToStr(recipientChannelId) + common.IntToStr(senderChannelId) + common.IntToStr(initialWindowSize) + common.IntToStr(-1));
}
*/
function SendChannelOpen(socket, direct, channelid, windowsize, target, targetport, source, sourceport) {
var connectionType = ((direct == true) ? "direct-tcpip" : "forwarded-tcpip");
if ((target == null) || (target == undefined)) target = ''; // TODO: Reports of target being undefined that causes target.length to fail. This is a hack.
Write(socket, String.fromCharCode(APFProtocol.CHANNEL_OPEN) + common.IntToStr(connectionType.length) + connectionType + common.IntToStr(channelid) + common.IntToStr(windowsize) + common.IntToStr(-1) + common.IntToStr(target.length) + target + common.IntToStr(targetport) + common.IntToStr(source.length) + source + common.IntToStr(sourceport));
}
function SendChannelClose(socket, channelid) {
Write(socket, String.fromCharCode(APFProtocol.CHANNEL_CLOSE) + common.IntToStr(channelid));
}
function SendChannelData(socket, channelid, data) {
Write(socket, String.fromCharCode(APFProtocol.CHANNEL_DATA) + common.IntToStr(channelid) + common.IntToStr(data.length) + data);
}
function SendChannelWindowAdjust(socket, channelid, bytestoadd) {
Debug(3, 'MPS:SendChannelWindowAdjust', channelid, bytestoadd);
Write(socket, String.fromCharCode(APFProtocol.CHANNEL_WINDOW_ADJUST) + common.IntToStr(channelid) + common.IntToStr(bytestoadd));
}
/*
function SendDisconnect(socket, reasonCode) {
Write(socket, String.fromCharCode(APFProtocol.DISCONNECT) + common.IntToStr(ReasonCode) + common.ShortToStr(0));
Write(socket, String.fromCharCode(APFProtocol.DISCONNECT) + common.IntToStr(reasonCode) + common.ShortToStr(0));
}
*/
function SendUserAuthFail(socket) {
Write(socket, String.fromCharCode(APFProtocol.USERAUTH_FAILURE) + common.IntToStr(8) + 'password' + common.ShortToStr(0));
@ -623,12 +636,12 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
socket.write(new Buffer(data, "binary"));
}
}
obj.SetupCiraChannel = function (socket, targetport) {
var sourceport = (socket.tag.nextsourceport++ % 30000) + 1024;
var cirachannel = { targetport: targetport, channelid: socket.tag.nextchannelid++, socket: socket, state: 1, sendcredits: 0, amtpendingcredits: 0, amtCiraWindow: 0, ciraWindow: 32768 };
SendChannelOpen(socket, false, cirachannel.channelid, cirachannel.ciraWindow, socket.tag.host, targetport, "1.2.3.4", sourceport);
// This function writes data to this CIRA channel
cirachannel.write = function (data) {
if (cirachannel.state == 0) return false;
@ -649,8 +662,8 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
SendChannelData(cirachannel.socket, cirachannel.amtchannelid, data.substring(0, cirachannel.sendcredits));
cirachannel.sendcredits = 0;
return false;
}
};
// This function closes this CIRA channel
cirachannel.close = function () {
if (cirachannel.state == 0 || cirachannel.closing == 1) return;
@ -659,16 +672,16 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
cirachannel.closing = 1;
SendChannelClose(cirachannel.socket, cirachannel.amtchannelid);
if (cirachannel.onStateChange) { cirachannel.onStateChange(cirachannel, cirachannel.state); }
}
};
socket.tag.channels[cirachannel.channelid] = cirachannel;
return cirachannel;
}
};
function ChangeHostname(socket, host) {
if (socket.tag.host == host) return; // Nothing to change
socket.tag.host = host;
// Change the device
obj.db.Get(socket.tag.nodeid, function (err, nodes) {
if (nodes.length != 1) return;
@ -676,7 +689,7 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
// See if any changes need to be made
if ((node.intelamt != undefined) && (node.intelamt.host == host) && (node.name != '') && (node.intelamt.state == 2)) return;
// Get the mesh for this device
obj.db.Get(node.meshid, function (err, meshes) {
if (meshes.length != 1) return;
@ -685,7 +698,7 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
// Ready the node change event
var changes = ['host'], event = { etype: 'node', action: 'changenode', nodeid: node._id };
event.msg = +": ";
// Make the change & save
if (node.intelamt == undefined) node.intelamt = {};
node.intelamt.host = host;
@ -704,7 +717,7 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
}
function guidToStr(g) { return g.substring(6, 8) + g.substring(4, 6) + g.substring(2, 4) + g.substring(0, 2) + "-" + g.substring(10, 12) + g.substring(8, 10) + "-" + g.substring(14, 16) + g.substring(12, 14) + "-" + g.substring(16, 20) + "-" + g.substring(20); }
// Debug
function Debug(lvl) {
if (lvl > obj.parent.debugLevel) return;
@ -717,4 +730,4 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
}
return obj;
}
};

View File

@ -1,6 +1,6 @@
{
"name": "meshcentral",
"version": "0.1.9-r",
"version": "0.1.9-v",
"keywords": [
"Remote Management",
"Intel AMT",

View File

@ -159,7 +159,7 @@ var CreateAgentRemoteDesktop = function (canvasid, scrolldiv) {
}
obj.ProcessScreenMsg = function (width, height) {
//obj.Debug("ScreenSize: " + width + " x " + height);
if (obj.debugmode == 1) { console.log("ScreenSize: " + width + " x " + height); }
obj.Canvas.setTransform(1, 0, 0, 1, 0, 0);
obj.rotation = 0;
obj.FirstDraw = true;
@ -190,7 +190,7 @@ var CreateAgentRemoteDesktop = function (canvasid, scrolldiv) {
cmdmsg = str.substring(4, cmdsize);
X = ((cmdmsg.charCodeAt(0) & 0xFF) << 8) + (cmdmsg.charCodeAt(1) & 0xFF);
Y = ((cmdmsg.charCodeAt(2) & 0xFF) << 8) + (cmdmsg.charCodeAt(3) & 0xFF);
//if (obj.debugmode == 1) { console.log("X=" + X + " Y=" + Y); }
if (obj.debugmode == 1) { console.log("CMD" + command + " at X=" + X + " Y=" + Y); }
}
switch (command) {

View File

@ -3,10 +3,15 @@
* @author Ylian Saint-Hilaire
* @copyright Intel Corporation 2018
* @license Apache-2.0
* @version v0.0.1
* @version v0.0.2
*/
'use strict';
/*jslint node: true */
/*jshint node: true */
/*jshint strict:false */
/*jshint -W097 */
/*jshint esversion: 6 */
"use strict";
// ExpressJS login sample
// https://github.com/expressjs/express/blob/master/examples/auth/index.js
@ -18,93 +23,95 @@ module.exports.CreateRedirServer = function (parent, db, args, func) {
obj.db = db;
obj.args = args;
obj.certificates = null;
obj.express = require('express');
obj.net = require('net');
obj.express = require("express");
obj.net = require("net");
obj.app = obj.express();
obj.tcpServer;
obj.tcpServer = null;
obj.port = null;
// Perform an HTTP to HTTPS redirection
function performRedirection(req, res) {
var host = req.headers.host;
if (obj.certificates != null) {
host = obj.certificates.CommonName;
if ((obj.certificates.CommonName == 'sample.org') || (obj.certificates.CommonName == 'un-configured')) { host = req.headers.host; }
if ((obj.certificates.CommonName == "sample.org") || (obj.certificates.CommonName == "un-configured")) { host = req.headers.host; }
}
var httpsPort = ((obj.args.aliasport == null) ? obj.args.port : obj.args.aliasport); // Use HTTPS alias port is specified
if (req.headers && req.headers.host && (req.headers.host.split(':')[0].toLowerCase() == 'localhost')) { res.redirect('https://localhost:' + httpsPort + req.url); } else { res.redirect('https://' + host + ':' + httpsPort + req.url); }
}
// Return the current domain of the request
function getDomain(req) {
var x = req.url.split('/');
if (x.length < 2) return parent.config.domains[''];
if (parent.config.domains[x[1].toLowerCase()]) return parent.config.domains[x[1].toLowerCase()];
return parent.config.domains[''];
if (req.headers && req.headers.host && (req.headers.host.split(":")[0].toLowerCase() == "localhost")) { res.redirect("https://localhost:" + httpsPort + req.url); } else { res.redirect("https://" + host + ":" + httpsPort + req.url); }
}
/*
// Return the current domain of the request
function getDomain(req) {
var x = req.url.split("/");
if (x.length < 2) { return parent.config.domains[""]; }
if (parent.config.domains[x[1].toLowerCase()]) { return parent.config.domains[x[1].toLowerCase()]; }
return parent.config.domains[""];
}
*/
// Renter the terms of service.
obj.app.get('/MeshServerRootCert.cer', function (req, res) {
res.set({ 'Cache-Control': 'no-cache, no-store, must-revalidate', 'Pragma': 'no-cache', 'Expires': '0', 'Content-Type': 'application/octet-stream', 'Content-Disposition': 'attachment; filename=' + certificates.RootName + '.cer' });
obj.app.get("/MeshServerRootCert.cer", function (req, res) {
res.set({ "Cache-Control": "no-cache, no-store, must-revalidate", "Pragma": "no-cache", "Expires": "0", "Content-Type": "application/octet-stream", "Content-Disposition": "attachment; filename=" + obj.certificates.RootName + ".cer" });
var rootcert = obj.certificates.root.cert;
var i = rootcert.indexOf("-----BEGIN CERTIFICATE-----\r\n");
if (i >= 0) { rootcert = rootcert.substring(i + 29); }
i = rootcert.indexOf("-----END CERTIFICATE-----");
if (i >= 0) { rootcert = rootcert.substring(i, 0); }
res.send(new Buffer(rootcert, 'base64'));
res.send(new Buffer(rootcert, "base64"));
});
// Add HTTP security headers to all responses
obj.app.use(function (req, res, next) {
res.removeHeader("X-Powered-By");
res.set({ 'strict-transport-security': 'max-age=60000; includeSubDomains', 'Referrer-Policy': 'no-referrer', 'x-frame-options': 'SAMEORIGIN', 'X-XSS-Protection': '1; mode=block', 'X-Content-Type-Options': 'nosniff', 'Content-Security-Policy': "default-src http: ws: 'self' 'unsafe-inline'" });
res.set({ "strict-transport-security": "max-age=60000; includeSubDomains", "Referrer-Policy": "no-referrer", "x-frame-options": "SAMEORIGIN", "X-XSS-Protection": "1; mode=block", "X-Content-Type-Options": "nosniff", "Content-Security-Policy": "default-src http: ws: \"self\" \"unsafe-inline\"" });
return next();
});
// Once the main web server is started, call this to hookup additional handlers
obj.hookMainWebServer = function (certs) {
obj.certificates = certs;
for (var i in parent.config.domains) {
for (var i = 0; i < parent.config.domains.length; i++) {
if (parent.config.domains[i].dns != null) { continue; }
var url = parent.config.domains[i].url;
obj.app.post(url + 'amtevents.ashx', obj.parent.webserver.handleAmtEventRequest);
obj.app.get(url + 'meshsettings', obj.parent.webserver.handleMeshSettingsRequest);
obj.app.get(url + 'meshagents', obj.parent.webserver.handleMeshAgentRequest);
obj.app.post(url + "amtevents.ashx", obj.parent.webserver.handleAmtEventRequest);
obj.app.get(url + "meshsettings", obj.parent.webserver.handleMeshSettingsRequest);
obj.app.get(url + "meshagents", obj.parent.webserver.handleMeshAgentRequest);
}
}
};
// Setup all HTTP redirection handlers
//obj.app.set('etag', false);
for (var i in parent.config.domains) {
//obj.app.set("etag", false);
for (var i = 0; i < parent.config.domains; i++) {
if (parent.config.domains[i].dns != null) { continue; }
var url = parent.config.domains[i].url;
obj.app.get(url, performRedirection);
obj.app.use(url + 'clickonce', obj.express.static(obj.parent.path.join(__dirname, 'public/clickonce'))); // Indicates the clickonce folder is public
obj.app.use(url + "clickonce", obj.express.static(obj.parent.path.join(__dirname, "public/clickonce"))); // Indicates the clickonce folder is public
}
// Find a free port starting with the specified one and going up.
function CheckListenPort(port, func) {
var s = obj.net.createServer(function (socket) { });
obj.tcpServer = s.listen(port, function () { s.close(function () { if (func) { func(port); } }); }).on('error', function (err) {
if (args.exactports) { console.error('ERROR: MeshCentral HTTP web server port ' + port + ' not available.'); process.exit(); }
obj.tcpServer = s.listen(port, function () { s.close(function () { if (func) { func(port); } }); }).on("error", function (err) {
if (args.exactports) { console.error("ERROR: MeshCentral HTTP web server port " + port + " not available."); process.exit(); }
else { if (port < 65535) { CheckListenPort(port + 1, func); } else { if (func) { func(0); } } }
});
}
// Start the ExpressJS web server, if the port is busy try the next one.
function StartRedirServer(port) {
if (port == 0 || port == 65535) return;
if (port == 0 || port == 65535) { return; }
obj.tcpServer = obj.app.listen(port, function () {
obj.port = port;
console.log('MeshCentral HTTP redirection web server running on port ' + port + '.');
obj.parent.updateServerState('redirect-port', port);
console.log("MeshCentral HTTP redirection web server running on port " + port + ".");
obj.parent.updateServerState("redirect-port", port);
func(obj.port);
}).on('error', function (err) {
if ((err.code == 'EACCES') && (port < 65535)) { StartRedirServer(port + 1); } else { console.log(err); func(obj.port); }
}).on("error", function (err) {
if ((err.code == "EACCES") && (port < 65535)) { StartRedirServer(port + 1); } else { console.log(err); func(obj.port); }
});
}
CheckListenPort(args.redirport, StartRedirServer);
return obj;
}
};

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1016,8 +1016,9 @@
case 'nodes': {
nodes = [];
for (var m in message.nodes) {
if (!meshes[m]) { console.log('Invalid mesh (1): ' + m); continue; }
for (var n in message.nodes[m]) {
if (!meshes[m]) { console.log('Invalid mesh (1): ' + m); continue; }
if (message.nodes[m][n]._id == null) { console.log('Invalid node (' + n + '): ' + JSON.stringify(message.nodes)); continue; }
message.nodes[m][n].namel = message.nodes[m][n].name.toLowerCase();
if (message.nodes[m][n].rname) { message.nodes[m][n].rnamel = message.nodes[m][n].rname.toLowerCase(); } else { message.nodes[m][n].rnamel = message.nodes[m][n].namel; }
message.nodes[m][n].meshnamel = meshes[m].name.toLowerCase();
@ -2253,9 +2254,7 @@
var loc = map_parseNodeLoc(nodes[i]);
var feature = xxmap.markersSource.getFeatureById(nodes[i]._id);
if ((loc != null) && ((nodes[i].meshid == selectedMesh) || (selectedMesh == null))) { // Draw markers for devices with locations
lat = loc[0];
lon = loc[1];
var type = loc[2];
var lat = loc[0], lon = loc[1], type = loc[2];
if (boundingBox == null) { boundingBox = [ lat, lon, lat, lon, 0 ]; } else { if (lat < boundingBox[0]) { boundingBox[0] = lat; } if (lon < boundingBox[1]) { boundingBox[1] = lon; } if (lat > boundingBox[2]) { boundingBox[2] = lat; } if (lon > boundingBox[3]) { boundingBox[3] = lon; } }
if (feature == null) { addFeature(nodes[i]); boundingBox[4] = 1; } else { updateFeature(nodes[i], feature); feature.setStyle(markerStyle(nodes[i], loc[2])); } // Update Feature
} else {
@ -2373,7 +2372,7 @@
var coord = feature.getGeometry().getCoordinates();
// map_cm_popup.setPosition(evt.coordinate);
map_cm_popup.setPosition(coord);
featid = feature.getId();
var featid = feature.getId();
if (featid) {
QH('xmap-info-window', feature.get('name'));
} else {
@ -2387,7 +2386,7 @@
});
// Initialize context menu for openlayers
contextmenu = new ContextMenu({
var contextmenu = new ContextMenu({
width: 160,
defaultItems: false, // defaultItems are Zoom In/Zoom Out
items: contextmenu_items
@ -2411,7 +2410,8 @@
if (xxmap.contextmenu == null) { xxmap.contextmenu = contextmenu; }
xxmap.map.addControl(xxmap.contextmenu);
//addMeshOptions(); // Adds Mesh names to mesh dropdown
} catch (e) {
} catch (ex) {
console.log(ex);
QV('viewselectmapoption', false);
xxmap = null;
}
@ -5709,7 +5709,7 @@
// Remove one notification
function notificationDelete(id) {
var j = -1; e = Q('notifyx' + id);
var j = -1, e = Q('notifyx' + id);
if (e != null) {
for (var i in notifications) { if (notifications[i].id == id) { j = i; } }
if (j != -1) {

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -776,8 +776,8 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
// Get the link to the root certificate if needed
function getRootCertLink() {
// TODO: This is not quite right, we need to check if the HTTPS certificate is issued from MeshCentralRoot, if so, add this download link.
if (obj.args.notls == null && obj.certificates.RootName.substring(0, 16) == 'MeshCentralRoot-') { return '<a href=/MeshServerRootCert.cer title="Download the root certificate for this server">Root Certificate</a>'; }
// Check if the HTTPS certificate is issued from MeshCentralRoot, if so, add download link to root certificate.
if ((obj.args.notls == null) && (obj.tlsSniCredentials == null) && (obj.certificates.WebIssuer.indexOf('MeshCentralRoot-') == 0) && (obj.certificates.CommonName != 'un-configured')) { return '<a href=/MeshServerRootCert.cer title="Download the root certificate for this server">Root Certificate</a>'; }
return '';
}
@ -1938,6 +1938,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
function isMobileBrowser(req) {
//var ua = req.headers['user-agent'].toLowerCase();
//return (/(android|bb\d+|meego).+mobile|mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(ua) || /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(ua.substr(0, 4)));
if (typeof req.headers['user-agent'] != 'string') return false;
return (req.headers['user-agent'].toLowerCase().indexOf('mobile') >= 0);
}