mirror of
https://github.com/Ylianst/MeshCentral.git
synced 2024-12-22 13:21:31 +03:00
Partinally ran code thru JsHint
This commit is contained in:
parent
312b937e62
commit
c531b64643
25
amtevents.js
25
amtevents.js
@ -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="CIM_ComputerSystem",Name="Intel(r) AMT"</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;
|
||||
}
|
||||
};
|
||||
|
@ -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;
|
||||
}
|
||||
};
|
51
amtscript.js
51
amtscript.js
@ -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;
|
||||
}
|
||||
};
|
@ -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
128
common.js
@ -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 += ' '; } 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 += ' '; } 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 { '&': '&', '<': '<', '>': '>', '"': '"', "'": ''', '/': '/', '`': '`', '=': '=' }[s]; }); }
|
||||
module.exports.escapeHtmlBreaks = function (string) { return String(string).replace(/[&<>"'`=\/]/g, function (s) { return { '&': '&', '<': '<', '>': '>', '"': '"', "'": ''', '/': '/', '`': '`', '=': '=', '\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 { '&': '&', '<': '<', '>': '>', '"': '"', "'": ''', '/': '/', '`': '`', '=': '=' }[s]; }); };
|
||||
module.exports.escapeHtmlBreaks = function (string) { return String(string).replace(/[&<>"'`=\/]/g, function (s) { return { '&': '&', '<': '<', '>': '>', '"': '"', "'": ''', '/': '/', '`': '`', '=': '=', '\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
79
db.js
@ -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;
|
||||
}
|
||||
};
|
@ -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);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
156
interceptor.js
156
interceptor.js
@ -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;
|
||||
}
|
||||
};
|
@ -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;
|
||||
};
|
@ -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;
|
||||
|
77
meshagent.js
77
meshagent.js
@ -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;
|
||||
}
|
||||
};
|
||||
|
30
meshmail.js
30
meshmail.js
@ -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, '&').replace(/>/g, '>').replace(/</g, '<').replace(/"/g, '"').replace(/'/g, '''); if (typeof x == "boolean") return x; if (typeof x == "number") return x; }
|
||||
function EscapeHtmlBreaks(x) { if (typeof x == "string") return x.replace(/&/g, '&').replace(/>/g, '>').replace(/</g, '<').replace(/"/g, '"').replace(/'/g, ''').replace(/\r/g, '<br />').replace(/\n/g, '').replace(/\t/g, ' '); if (typeof x == "boolean") return x; if (typeof x == "number") return x; }
|
||||
//function EscapeHtmlBreaks(x) { if (typeof x == "string") return x.replace(/&/g, '&').replace(/>/g, '>').replace(/</g, '<').replace(/"/g, '"').replace(/'/g, ''').replace(/\r/g, '<br />').replace(/\n/g, '').replace(/\t/g, ' '); if (typeof x == "boolean") return x; if (typeof x == "number") return x; }
|
||||
|
||||
// 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;
|
||||
};
|
351
mpsserver.js
351
mpsserver.js
@ -6,7 +6,12 @@
|
||||
* @version v0.0.1
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
/*jslint node: true */
|
||||
/*jshint node: true */
|
||||
/*jshint strict:false */
|
||||
/*jshint -W097 */
|
||||
/*jshint esversion: 6 */
|
||||
"use strict";
|
||||
|
||||
// Construct a 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® 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® 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;
|
||||
}
|
||||
};
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "meshcentral",
|
||||
"version": "0.1.9-r",
|
||||
"version": "0.1.9-v",
|
||||
"keywords": [
|
||||
"Remote Management",
|
||||
"Intel AMT",
|
||||
|
@ -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) {
|
||||
|
@ -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
@ -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
@ -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);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user