diff --git a/amtevents.js b/amtevents.js index c37de185..18c1608a 100644 --- a/amtevents.js +++ b/amtevents.js @@ -70,12 +70,6 @@ module.exports.CreateAmtEventsHandler = function (parent) { return r; } - // Private method - function _turnToXml(text) { - var DOMParser = require('xmldom').DOMParser; - return new DOMParser().parseFromString(text, 'text/xml'); - } - // Parse and handle an event coming from Intel AMT obj.handleAmtEvent = function (data, nodeid, amthost) { var x = ParseWsman(data); @@ -90,5 +84,85 @@ module.exports.CreateAmtEventsHandler = function (parent) { // 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'); + // This is a drop-in replacement to _turnToXml() that works without xml parser dependency. + try { Object.defineProperty(Array.prototype, "peek", { value: function () { return (this.length > 0 ? this[this.length - 1] : null); } }); } catch (ex) { } + function _treeBuilder() { + this.tree = []; + this.push = function (element) { this.tree.push(element); }; + this.pop = function () { var element = this.tree.pop(); if (this.tree.length > 0) { var x = this.tree.peek(); x.childNodes.push(element); x.childElementCount = x.childNodes.length; } return (element); }; + this.peek = function () { return (this.tree.peek()); } + this.addNamespace = function (prefix, namespace) { this.tree.peek().nsTable[prefix] = namespace; if (this.tree.peek().attributes.length > 0) { for (var i = 0; i < this.tree.peek().attributes; ++i) { var a = this.tree.peek().attributes[i]; if (prefix == '*' && a.name == a.localName) { a.namespace = namespace; } else if (prefix != '*' && a.name != a.localName) { var pfx = a.name.split(':')[0]; if (pfx == prefix) { a.namespace = namespace; } } } } } + this.getNamespace = function (prefix) { for (var i = this.tree.length - 1; i >= 0; --i) { if (this.tree[i].nsTable[prefix] != null) { return (this.tree[i].nsTable[prefix]); } } return null; } + } + function _turnToXml(text) { if (text == null) return null; return ({ childNodes: [_turnToXmlRec(text)], getElementsByTagName: _getElementsByTagName, getChildElementsByTagName: _getChildElementsByTagName, getElementsByTagNameNS: _getElementsByTagNameNS }); } + function _getElementsByTagNameNS(ns, name) { var ret = []; _xmlTraverseAllRec(this.childNodes, function (node) { if (node.localName == name && (node.namespace == ns || ns == '*')) { ret.push(node); } }); return ret; } + function _getElementsByTagName(name) { var ret = []; _xmlTraverseAllRec(this.childNodes, function (node) { if (node.localName == name) { ret.push(node); } }); return ret; } + function _getChildElementsByTagName(name) { var ret = []; if (this.childNodes != null) { for (var node in this.childNodes) { if (this.childNodes[node].localName == name) { ret.push(this.childNodes[node]); } } } return (ret); } + function _getChildElementsByTagNameNS(ns, name) { var ret = []; if (this.childNodes != null) { for (var node in this.childNodes) { if (this.childNodes[node].localName == name && (ns == '*' || this.childNodes[node].namespace == ns)) { ret.push(this.childNodes[node]); } } } return (ret); } + function _xmlTraverseAllRec(nodes, func) { for (var i in nodes) { func(nodes[i]); if (nodes[i].childNodes) { _xmlTraverseAllRec(nodes[i].childNodes, func); } } } + function _turnToXmlRec(text) { + var elementStack = new _treeBuilder(), lastElement = null, x1 = text.split('<'), ret = [], element = null, currentElementName = null; + for (var i in x1) { + var x2 = x1[i].split('>'), x3 = x2[0].split(' '), elementName = x3[0]; + if ((elementName.length > 0) && (elementName[0] != '?')) { + if (elementName[0] != '/') { + var attributes = [], localName, localname2 = elementName.split(' ')[0].split(':'), localName = (localname2.length > 1) ? localname2[1] : localname2[0]; + Object.defineProperty(attributes, "get", + { + value: function () { + if (arguments.length == 1) { + for (var a in this) { if (this[a].name == arguments[0]) { return (this[a]); } } + } + else if (arguments.length == 2) { + for (var a in this) { if (this[a].name == arguments[1] && (arguments[0] == '*' || this[a].namespace == arguments[0])) { return (this[a]); } } + } + else { + throw ('attributes.get(): Invalid number of parameters'); + } + } + }); + elementStack.push({ name: elementName, localName: localName, getChildElementsByTagName: _getChildElementsByTagName, getElementsByTagNameNS: _getElementsByTagNameNS, getChildElementsByTagNameNS: _getChildElementsByTagNameNS, attributes: attributes, childNodes: [], nsTable: {} }); + // Parse Attributes + if (x3.length > 0) { + var skip = false; + for (var j in x3) { + if (x3[j] == '/') { + // This is an empty Element + elementStack.peek().namespace = elementStack.peek().name == elementStack.peek().localName ? elementStack.getNamespace('*') : elementStack.getNamespace(elementStack.peek().name.substring(0, elementStack.peek().name.indexOf(':'))); + elementStack.peek().textContent = ''; + lastElement = elementStack.pop(); + skip = true; + break; + } + var k = x3[j].indexOf('='); + if (k > 0) { + var attrName = x3[j].substring(0, k); + var attrValue = x3[j].substring(k + 2, x3[j].length - 1); + var attrNS = elementStack.getNamespace('*'); + + if (attrName == 'xmlns') { + elementStack.addNamespace('*', attrValue); + attrNS = attrValue; + } else if (attrName.startsWith('xmlns:')) { + elementStack.addNamespace(attrName.substring(6), attrValue); + } else { + var ax = attrName.split(':'); + if (ax.length == 2) { attrName = ax[1]; attrNS = elementStack.getNamespace(ax[0]); } + } + var x = { name: attrName, value: attrValue } + if (attrNS != null) x.namespace = attrNS; + elementStack.peek().attributes.push(x); + } + } + if (skip) { continue; } + } + elementStack.peek().namespace = elementStack.peek().name == elementStack.peek().localName ? elementStack.getNamespace('*') : elementStack.getNamespace(elementStack.peek().name.substring(0, elementStack.peek().name.indexOf(':'))); + if (x2[1]) { elementStack.peek().textContent = x2[1]; } + } else { lastElement = elementStack.pop(); } + } + } + return lastElement; + } + return obj; }; diff --git a/dependencies.txt b/dependencies.txt index c71d40cf..4c1b0ae8 100644 --- a/dependencies.txt +++ b/dependencies.txt @@ -11,5 +11,4 @@ "nedb": "^1.8.0", "node-forge": "^0.10.0", "ws": "^5.2.3", - "xmldom": "^0.5.0", "yauzl": "^2.10.0" \ No newline at end of file diff --git a/meshcentral-config-schema.json b/meshcentral-config-schema.json index f781533b..005f3075 100644 --- a/meshcentral-config-schema.json +++ b/meshcentral-config-schema.json @@ -102,7 +102,7 @@ "agentsInRam": { "type": "boolean", "default": false, "description": "Loads all agent binaries in RAM for faster agent updates." }, "agentPing": { "type": "integer", "minimum": 1, "description": "When specified, sends data to the agent at x seconds interval and expects a response from the agent." }, "agentPong": { "type": "integer", "minimum": 1, "description": "When specified, sends data to the agent at x seconds interval." }, - "amtmanager": { "type": "boolean", "default": true, "description": "When enabled, MeshCentral will automatically monitor and manage Intel AMT devices." }, + "amtManager": { "type": "boolean", "default": true, "description": "When enabled, MeshCentral will automatically monitor and manage Intel AMT devices." }, "orphanAgentUser": { "type": "string", "default": null, "description": "If an agent attempts to connect to a unknown device group, automatically create a new device group and grant access to the specified user. Example: admin" }, "agentIdleTimeout": { "type": "integer", "minimum": 1, "default": 150 ,"description": "How much time in seconds with no traffic from an agent before dropping the agent connection." }, "compression": { "type": "boolean", "default": true, "description": "Enables GZIP compression for web requests." }, diff --git a/meshcentral.js b/meshcentral.js index abdad0fa..3afc3caa 100644 --- a/meshcentral.js +++ b/meshcentral.js @@ -3220,7 +3220,7 @@ function mainStart() { } // Build the list of required modules - var modules = ['ws@5.2.3', 'cbor@5.2.0', 'nedb', 'https', 'yauzl', 'xmldom', 'ipcheck', 'express', 'archiver@4.0.2', 'multiparty', 'node-forge', 'express-ws@4.0.0', 'compression', 'body-parser', 'cookie-session', 'express-handlebars']; + var modules = ['ws@5.2.3', 'cbor@5.2.0', 'nedb', 'https', 'yauzl', 'ipcheck', 'express', 'archiver@4.0.2', 'multiparty', 'node-forge', 'express-ws@4.0.0', 'compression', 'body-parser', 'cookie-session', 'express-handlebars']; if (require('os').platform() == 'win32') { modules.push('node-windows'); modules.push('loadavg-windows'); if (sspi == true) { modules.push('node-sspi'); } } // Add Windows modules if (ldap == true) { modules.push('ldapauth-fork'); } if (mstsc == true) { modules.push('node-rdpjs-2'); } diff --git a/package.json b/package.json index b7a31e68..89c79e90 100644 --- a/package.json +++ b/package.json @@ -36,8 +36,6 @@ "sample-config-advanced.json" ], "dependencies": { - "archiver": "^4.0.2", - "archiver-zip-encrypted": "^1.0.10", "body-parser": "^1.19.0", "cbor": "~5.2.0", "compression": "^1.7.4", @@ -45,27 +43,13 @@ "express": "^4.17.0", "express-handlebars": "^3.1.0", "express-ws": "^4.0.0", - "html-minifier": "^4.0.0", - "image-size": "^1.0.0", "ipcheck": "^0.1.0", - "jsdom": "^17.0.0", - "loadavg-windows": "^1.1.1", - "minify-js": "^0.0.4", "minimist": "^1.2.0", - "mongodb": "^4.1.0", "multiparty": "^4.2.1", "nedb": "^1.8.0", "node-forge": "^0.10.0", - "node-rdpjs-2": "^0.3.5", - "node-windows": "^1.0.0-beta.5", - "otplib": "^10.2.3", - "saslprep": "^1.0.3", - "ssh2": "^1.3.0", - "web-push": "^3.4.5", "ws": "^5.2.3", - "xmldom": "^0.5.0", - "yauzl": "^2.10.0", - "yubikeyotp": "^0.2.0" + "yauzl": "^2.10.0" }, "repository": { "type": "git", diff --git a/webserver.js b/webserver.js index 57197129..582ece31 100644 --- a/webserver.js +++ b/webserver.js @@ -4522,7 +4522,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) { } } - parent.amtEventHandler.handleAmtEvent(eventData, nodeid, amthost); + if (parent.amtEventHandler) { parent.amtEventHandler.handleAmtEvent(eventData, nodeid, amthost); } //res.send('OK'); return;