diff --git a/amtevents.js b/amtevents.js index e3e37ef8..ddb4fdff 100644 --- a/amtevents.js +++ b/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('http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymoushttp://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymoushttp://schemas.dmtf.org/wbem/wsman/1/wsman/Eventuuid:00000000-8086-8086-8086-000000128538http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_AlertIndication82Interop:CIM_ComputerSystem.CreationClassName="CIM_ComputerSystem",Name="Intel(r) AMT"Intel(r) AMT:AllEventsIntel(r):29502346872017-01-31T15:40:09.000Z0Interop:CIM_ComputerSystem.CreationClassName=CIM_ComputerSystem,Name=Intel(r) AMTiAMT0005Intel(r) AMT20Intel(r) AMT', 'aabbccdd', '1.2.3.4'); return obj; -} +}; diff --git a/amtscanner.js b/amtscanner.js index fb7db186..73a1d14f 100644 --- a/amtscanner.js +++ b/amtscanner.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 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; -} \ No newline at end of file +}; \ No newline at end of file diff --git a/amtscript.js b/amtscript.js index f2e4ade9..6aa69fbd 100644 --- a/amtscript.js +++ b/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; -} \ No newline at end of file +}; \ No newline at end of file diff --git a/certoperations.js b/certoperations.js index 7dd41f0f..ae9541bf 100644 --- a/certoperations.js +++ b/certoperations.js @@ -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; }; diff --git a/common.js b/common.js index b4453375..7bd0862e 100644 --- a/common.js +++ b/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 += '
' + gap(c) + "Item #" + i + ": " + module.exports.ObjectToStringEx(x[i], c + 1); } } - else if (x instanceof Object) { for (var i in x) { r += '
' + gap(c) + i + " = " + module.exports.ObjectToStringEx(x[i], c + 1); } } + if (x instanceof Array) { for (i in x) { r += '
' + gap(c) + "Item #" + i + ": " + module.exports.ObjectToStringEx(x[i], c + 1); } } + else if (x instanceof Object) { for (i in x) { r += '
' + 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': '
', '\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': '
', '\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)); } \ No newline at end of file +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)); }; \ No newline at end of file diff --git a/db.js b/db.js index 8c1b1ae0..5922cb49 100644 --- a/db.js +++ b/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; -} \ No newline at end of file +}; \ No newline at end of file diff --git a/exeHandler.js b/exeHandler.js index 10b7d51a..ce5d65a8 100644 --- a/exeHandler.js +++ b/exeHandler.js @@ -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); } -} +}; diff --git a/interceptor.js b/interceptor.js index 6fb93c8f..df7d9d14 100644 --- a/interceptor.js +++ b/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; -} \ No newline at end of file +}; \ No newline at end of file diff --git a/letsEncrypt.js b/letsEncrypt.js index 769a7698..f8c4a2fc 100644 --- a/letsEncrypt.js +++ b/letsEncrypt.js @@ -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; -} \ No newline at end of file + return obj; + } catch (e) { console.error(e); } // Unable to start Let's Encrypt + return null; +}; \ No newline at end of file diff --git a/meshaccelerator.js b/meshaccelerator.js index 43563abe..cf3a0f19 100644 --- a/meshaccelerator.js +++ b/meshaccelerator.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"; const crypto = require('crypto'); var certStore = null; diff --git a/meshagent.js b/meshagent.js index 71fce3d5..32c94884 100644 --- a/meshagent.js +++ b/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; -} +}; diff --git a/meshmail.js b/meshmail.js index c38dcf5a..96ba7e3a 100644 --- a/meshmail.js +++ b/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(/').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(/').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; -} \ No newline at end of file + return obj; +}; \ No newline at end of file diff --git a/mpsserver.js b/mpsserver.js index 5b4f2385..3ea365a1 100644 --- a/mpsserver.js +++ b/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\nMeshCentral2 MPS server.
Intel® AMT computers should connect here.'); 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\nMeshCentral2 MPS server.
Intel® AMT computers should connect here."); 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; -} +}; diff --git a/package.json b/package.json index a417bf99..ee3eb6b7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "meshcentral", - "version": "0.1.9-r", + "version": "0.1.9-v", "keywords": [ "Remote Management", "Intel AMT", diff --git a/public/scripts/agent-desktop-0.0.2.js b/public/scripts/agent-desktop-0.0.2.js index 30ec62f6..0c943aea 100644 --- a/public/scripts/agent-desktop-0.0.2.js +++ b/public/scripts/agent-desktop-0.0.2.js @@ -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) { diff --git a/redirserver.js b/redirserver.js index 1e8b279d..ef8aa699 100644 --- a/redirserver.js +++ b/redirserver.js @@ -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; -} +}; diff --git a/views/default-min.handlebars b/views/default-min.handlebars index 29846464..d2ccc139 100644 --- a/views/default-min.handlebars +++ b/views/default-min.handlebars @@ -1 +1 @@ - MeshCentral
{{{title}}}
{{{title2}}}

{{{logoutControl}}}


\ No newline at end of file + MeshCentral
{{{title}}}
{{{title2}}}

{{{logoutControl}}}


\ No newline at end of file diff --git a/views/default-mobile-min.handlebars b/views/default-mobile-min.handlebars index 03beab2e..ea6639cf 100644 --- a/views/default-mobile-min.handlebars +++ b/views/default-mobile-min.handlebars @@ -1 +1 @@ - MeshCentral - Login
{{{title}}}
{{{title2}}}
\ No newline at end of file + MeshCentral - Login
{{{title}}}
{{{title2}}}
\ No newline at end of file diff --git a/views/default.handlebars b/views/default.handlebars index a1420c90..b187cbd3 100644 --- a/views/default.handlebars +++ b/views/default.handlebars @@ -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) { diff --git a/views/login-min.handlebars b/views/login-min.handlebars index 4d1fbba4..d6168bdf 100644 --- a/views/login-min.handlebars +++ b/views/login-min.handlebars @@ -1 +1 @@ - MeshCentral - Login
{{{title}}}
{{{title2}}}

Welcome

Connect to your home or office devices from anywhere in the world using MeshCentral, the remote monitoring and management web site. You will need to download and install a special management agent on your computers. Once installed, each mesh enabled computer will show up in the "My Devices" section of this web site and you will be able to monitor them, power them on and off and take control of them.


\ No newline at end of file + MeshCentral - Login
{{{title}}}
{{{title2}}}

Welcome

Connect to your home or office devices from anywhere in the world using MeshCentral, the remote monitoring and management web site. You will need to download and install a special management agent on your computers. Once installed, each mesh enabled computer will show up in the "My Devices" section of this web site and you will be able to monitor them, power them on and off and take control of them.


\ No newline at end of file diff --git a/views/login-mobile-min.handlebars b/views/login-mobile-min.handlebars index 3594a124..8b72fe22 100644 --- a/views/login-mobile-min.handlebars +++ b/views/login-mobile-min.handlebars @@ -1 +1 @@ - MeshCentral - Login
{{{title}}}
{{{title2}}}
\ No newline at end of file + MeshCentral - Login
{{{title}}}
{{{title2}}}
\ No newline at end of file diff --git a/webserver.js b/webserver.js index dbf6677c..6e4eeded 100644 --- a/webserver.js +++ b/webserver.js @@ -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 'Root Certificate'; } + // 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 'Root Certificate'; } 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); }