From 759a7bbaf591a7350f3472d8c28ed4753ab24ea4 Mon Sep 17 00:00:00 2001 From: Ylian Saint-Hilaire Date: Tue, 13 Oct 2020 17:46:29 -0700 Subject: [PATCH] Added TLS support to APF tunnels. --- agents/modules_meshcore/apfclient.js | 108 ++++++++++++-------------- amt/amt-wsman-comm.js | 91 +++++++++++++++++++--- amtmanager.js | 5 +- mpsserver.js | 24 +++--- public/scripts/amt-wsman-0.2.0-min.js | 2 +- views/default.handlebars | 1 + 6 files changed, 147 insertions(+), 84 deletions(-) diff --git a/agents/modules_meshcore/apfclient.js b/agents/modules_meshcore/apfclient.js index 6ee9a9f2..e72dac0d 100644 --- a/agents/modules_meshcore/apfclient.js +++ b/agents/modules_meshcore/apfclient.js @@ -17,7 +17,7 @@ limitations under the License. /** * @description APF/CIRA Client for Duktape * @author Joko Sastriawan & Ylian Saint-Hilaire -* @copyright Intel Corporation 2019 +* @copyright Intel Corporation 2020 * @license Apache-2.0 * @version v0.0.2 */ @@ -139,12 +139,12 @@ function CreateAPFClient(parent, args) { } obj.onSecureConnect = function onSecureConnect(resp, ws, head) { - Debug("APF Secure WebSocket connected."); + //Debug("APF Secure WebSocket connected."); //console.log(JSON.stringify(resp)); obj.forwardClient.tag = { accumulator: [] }; obj.forwardClient.ws = ws; obj.forwardClient.ws.on('end', function () { - Debug("APF: Connection is closing."); + //Debug("APF: Connection is closing."); if (obj.timer != null) { clearInterval(obj.timer); obj.timer = null; @@ -157,11 +157,9 @@ function CreateAPFClient(parent, args) { var len = 0; do { len = ProcessData(obj.forwardClient); - if (len > 0) { - obj.forwardClient.tag.accumulator = obj.forwardClient.tag.accumulator.slice(len); - } + if (len > 0) { obj.forwardClient.tag.accumulator = obj.forwardClient.tag.accumulator.slice(len); } if (obj.cirastate == CIRASTATE.FAILED) { - Debug("APF: in a failed state, destroying socket.") + //Debug("APF: in a failed state, destroying socket."); obj.forwardClient.ws.end(); } } while (len > 0); @@ -171,7 +169,7 @@ function CreateAPFClient(parent, args) { }); obj.forwardClient.ws.on('error', function (e) { - Debug("APF: Connection error, ending connecting."); + //Debug("APF: Connection error, ending connecting."); if (obj.timer != null) { clearInterval(obj.timer); obj.timer = null; @@ -187,20 +185,20 @@ function CreateAPFClient(parent, args) { function SendJsonControl(socket, o) { var data = JSON.stringify(o) socket.write(String.fromCharCode(APFProtocol.JSON_CONTROL) + IntToStr(data.length) + data); - Debug("APF: Send JSON control: " + data); + //Debug("APF: Send JSON control: " + data); } function SendProtocolVersion(socket, uuid) { var data = String.fromCharCode(APFProtocol.PROTOCOLVERSION) + IntToStr(1) + IntToStr(0) + IntToStr(0) + hex2rstr(strToGuid(uuid)) + binzerostring(64); socket.write(data); - Debug("APF: Send protocol version 1 0 " + uuid); + //Debug("APF: Send protocol version 1 0 " + uuid); obj.cirastate = CIRASTATE.PROTOCOL_VERSION_SENT; } function SendServiceRequest(socket, service) { var data = String.fromCharCode(APFProtocol.SERVICE_REQUEST) + IntToStr(service.length) + service; socket.write(data); - Debug("APF: Send service request " + service); + //Debug("APF: Send service request " + service); if (service == 'auth@amt.intel.com') { obj.cirastate = CIRASTATE.AUTH_SERVICE_REQUEST_SENT; } else if (service == 'pfwd@amt.intel.com') { @@ -215,7 +213,7 @@ function CreateAPFClient(parent, args) { data += IntToStr(8) + 'password'; data += binzerostring(1) + IntToStr(pass.length) + pass; socket.write(data); - Debug("APF: Send username password authentication to MPS"); + //Debug("APF: Send username password authentication to MPS"); obj.cirastate = CIRASTATE.AUTH_REQUEST_SENT; } @@ -224,20 +222,18 @@ function CreateAPFClient(parent, args) { var data = String.fromCharCode(APFProtocol.GLOBAL_REQUEST) + IntToStr(tcpipfwd.length) + tcpipfwd + binzerostring(1, 1); data += IntToStr(amthostname.length) + amthostname + IntToStr(amtport); socket.write(data); - Debug("APF: Send tcpip-forward " + amthostname + ":" + amtport); + //Debug("APF: Send tcpip-forward " + amthostname + ":" + amtport); obj.cirastate = CIRASTATE.GLOBAL_REQUEST_SENT; } function SendKeepAliveRequest(socket) { - var data = String.fromCharCode(APFProtocol.KEEPALIVE_REQUEST) + IntToStr(255); - socket.write(data); - Debug("APF: Send keepalive request"); + socket.write(String.fromCharCode(APFProtocol.KEEPALIVE_REQUEST) + IntToStr(255)); + //Debug("APF: Send keepalive request"); } function SendKeepAliveReply(socket, cookie) { - var data = String.fromCharCode(APFProtocol.KEEPALIVE_REPLY) + IntToStr(cookie); - socket.write(data); - Debug("APF: Send keepalive reply"); + socket.write(String.fromCharCode(APFProtocol.KEEPALIVE_REPLY) + IntToStr(cookie)); + //Debug("APF: Send keepalive reply"); } function ProcessData(socket) { @@ -249,9 +245,8 @@ function CreateAPFClient(parent, args) { // Respond to MPS according to obj.cirastate switch (cmd) { case APFProtocol.SERVICE_ACCEPT: { - var slen = ReadInt(data, 1); - var service = data.substring(5, 6 + slen); - Debug("APF: Service request to " + service + " accepted."); + var slen = ReadInt(data, 1), service = data.substring(5, 6 + slen); + //Debug("APF: Service request to " + service + " accepted."); if (service == 'auth@amt.intel.com') { if (obj.cirastate >= CIRASTATE.AUTH_SERVICE_REQUEST_SENT) { SendUserAuthRequest(socket.ws, obj.args.mpsuser, obj.args.mpspass); @@ -266,47 +261,47 @@ function CreateAPFClient(parent, args) { case APFProtocol.REQUEST_SUCCESS: { if (len >= 5) { var port = ReadInt(data, 1); - Debug("APF: Request to port forward " + port + " successful."); + //Debug("APF: Request to port forward " + port + " successful."); // iterate to pending port forward request if (obj.pfwd_idx < pfwd_ports.length) { SendGlobalRequestPfwd(socket.ws, obj.args.clientname, pfwd_ports[obj.pfwd_idx++]); } else { // no more port forward, now setup timer to send keep alive - Debug("APF: Start keep alive for every " + obj.args.mpskeepalive + " ms."); + //Debug("APF: Start keep alive for every " + obj.args.mpskeepalive + " ms."); obj.timer = setInterval(function () { SendKeepAliveRequest(obj.forwardClient.ws); }, obj.args.mpskeepalive);// } return 5; } - Debug("APF: Request successful."); + //Debug("APF: Request successful."); return 1; } case APFProtocol.USERAUTH_SUCCESS: { - Debug("APF: User Authentication successful"); + //Debug("APF: User Authentication successful"); // Send Pfwd service request SendServiceRequest(socket.ws, 'pfwd@amt.intel.com'); return 1; } case APFProtocol.USERAUTH_FAILURE: { - Debug("APF: User Authentication failed"); + //Debug("APF: User Authentication failed"); obj.cirastate = CIRASTATE.FAILED; return 14; } case APFProtocol.KEEPALIVE_REQUEST: { - Debug("APF: Keep Alive Request with cookie: " + ReadInt(data, 1)); + //Debug("APF: Keep Alive Request with cookie: " + ReadInt(data, 1)); SendKeepAliveReply(socket.ws, ReadInt(data, 1)); return 5; } case APFProtocol.KEEPALIVE_REPLY: { - Debug("APF: Keep Alive Reply with cookie: " + ReadInt(data, 1)); + //Debug("APF: Keep Alive Reply with cookie: " + ReadInt(data, 1)); return 5; } // Channel management case APFProtocol.CHANNEL_OPEN: { // Parse CHANNEL OPEN request var p_res = parseChannelOpen(data); - Debug("APF: CHANNEL_OPEN request: " + JSON.stringify(p_res)); + //Debug("APF: CHANNEL_OPEN request: " + JSON.stringify(p_res)); // Check if target port is in pfwd_ports if (pfwd_ports.indexOf(p_res.target_port) >= 0) { // Connect socket to that port @@ -323,24 +318,24 @@ function CreateAPFClient(parent, args) { chan.on('data', function (ddata) { // Relay data to fordwardclient // TODO: Implement flow control - SendChannelData(socket.ws, p_res.sender_chan, ddata.length, ddata); + SendChannelData(socket.ws, p_res.sender_chan, ddata); }); chan.on('error', function (e) { - Debug("Downlink connection error: " + e); + //Debug("Downlink connection error: " + e); }); chan.on('end', function () { var chan = obj.downlinks[p_res.sender_chan]; if (chan != null) { try { - Debug("Socket ends."); + //Debug("Socket ends."); SendChannelClose(socket.ws, p_res.sender_chan); chan.xclosed = 1; // Add some delay before removing... otherwise race condition setTimeout(function () { delete obj.downlinks[p_res.sender_chan]; }, 100); } catch (e) { - Debug("Downlink connection exception: " + e); + //Debug("Downlink connection exception: " + e); } } }); @@ -353,12 +348,12 @@ function CreateAPFClient(parent, args) { return p_res.len; } case APFProtocol.CHANNEL_OPEN_CONFIRMATION: { - Debug("APF: CHANNEL_OPEN_CONFIRMATION"); + //Debug("APF: CHANNEL_OPEN_CONFIRMATION"); return 17; } case APFProtocol.CHANNEL_CLOSE: { var rcpt_chan = ReadInt(data, 1); - Debug("APF: CHANNEL_CLOSE: " + rcpt_chan); + //Debug("APF: CHANNEL_CLOSE: " + rcpt_chan); var chan = obj.downlinks[rcpt_chan]; if ((chan != null) && (chan.xclosed !== 1)) { SendChannelClose(socket.ws, rcpt_chan); @@ -368,7 +363,7 @@ function CreateAPFClient(parent, args) { return 5; } case APFProtocol.CHANNEL_DATA: { - Debug("APF: CHANNEL_DATA: " + JSON.stringify(rstr2hex(data))); + //Debug("APF: CHANNEL_DATA: " + JSON.stringify(rstr2hex(data))); var rcpt_chan = ReadInt(data, 1); var chan_data_len = ReadInt(data, 5); var chan_data = data.substring(9, 9 + chan_data_len); @@ -376,23 +371,23 @@ function CreateAPFClient(parent, args) { if (chan != null) { chan.curInWindow += chan_data_len; try { - chan.write(chan_data, 'binary', function () { - Debug("Write completed."); + chan.write(Buffer.from(chan_data, 'binary'), function () { + //Debug("Write completed."); // If the incoming window is over half used, send an adjust. if (this.curInWindow > (this.maxInWindow / 2)) { SendChannelWindowAdjust(socket.ws, rcpt_chan, this.curInWindow); this.curInWindow = 0; } }); } catch (e) { - Debug("Cannot forward data to downlink socket."); + //Debug("Cannot forward data to downlink socket."); } } return 9 + chan_data_len; } case APFProtocol.CHANNEL_WINDOW_ADJUST: { - Debug("APF: CHANNEL_WINDOW_ADJUST "); + //Debug("APF: CHANNEL_WINDOW_ADJUST "); return 9; } default: { - Debug("CMD: " + cmd + " is not implemented."); + //Debug("CMD: " + cmd + " is not implemented."); obj.cirastate = CIRASTATE.FAILED; return 0; } @@ -416,35 +411,28 @@ function CreateAPFClient(parent, args) { } function SendChannelOpenFailure(socket, chan_data) { - var data = String.fromCharCode(APFProtocol.CHANNEL_OPEN_FAILURE) + IntToStr(chan_data.sender_chan) - + IntToStr(2) + IntToStr(0) + IntToStr(0); - socket.write(data); - Debug("APF: Send ChannelOpenFailure"); + socket.write(String.fromCharCode(APFProtocol.CHANNEL_OPEN_FAILURE) + IntToStr(chan_data.sender_chan) + IntToStr(2) + IntToStr(0) + IntToStr(0)); + //Debug("APF: Send ChannelOpenFailure"); } function SendChannelOpenConfirm(socket, chan_data) { - var data = String.fromCharCode(APFProtocol.CHANNEL_OPEN_CONFIRMATION) + IntToStr(chan_data.sender_chan) - + IntToStr(chan_data.sender_chan) + IntToStr(chan_data.window_size) + IntToStr(0xFFFFFFFF); - socket.write(data); - Debug("APF: Send ChannelOpenConfirmation"); + socket.write(String.fromCharCode(APFProtocol.CHANNEL_OPEN_CONFIRMATION) + IntToStr(chan_data.sender_chan) + IntToStr(chan_data.sender_chan) + IntToStr(chan_data.window_size) + IntToStr(0xFFFFFFFF)); + //Debug("APF: Send ChannelOpenConfirmation"); } function SendChannelWindowAdjust(socket, chan, size) { - var data = String.fromCharCode(APFProtocol.CHANNEL_WINDOW_ADJUST) + IntToStr(chan) + IntToStr(size); - socket.write(data); - Debug("APF: Send ChannelWindowAdjust: " + rstr2hex(data)); + socket.write(String.fromCharCode(APFProtocol.CHANNEL_WINDOW_ADJUST) + IntToStr(chan) + IntToStr(size)); + //Debug("APF: Send ChannelWindowAdjust: " + rstr2hex(data)); } - function SendChannelData(socket, chan, len, data) { - var buf = String.fromCharCode(APFProtocol.CHANNEL_DATA) + IntToStr(chan) + IntToStr(len) + data; - socket.write(buf); - Debug("APF: Send ChannelData: " + rstr2hex(buf)); + function SendChannelData(socket, chan, data) { + socket.write(Buffer.concat([Buffer.from(String.fromCharCode(APFProtocol.CHANNEL_DATA) + IntToStr(chan) + IntToStr(data.length), 'binary'), data])); + //Debug("APF: Send ChannelData: " + rstr2hex(buf)); } function SendChannelClose(socket, chan) { - var buf = String.fromCharCode(APFProtocol.CHANNEL_CLOSE) + IntToStr(chan); - socket.write(buf); - Debug("APF: Send ChannelClose "); + socket.write(String.fromCharCode(APFProtocol.CHANNEL_CLOSE) + IntToStr(chan)); + //Debug("APF: Send ChannelClose "); } obj.connect = function () { diff --git a/amt/amt-wsman-comm.js b/amt/amt-wsman-comm.js index aec168d7..4342df4f 100644 --- a/amt/amt-wsman-comm.js +++ b/amt/amt-wsman-comm.js @@ -51,6 +51,16 @@ var CreateWsmanComm = function (host, port, user, pass, tls, tlsoptions, ciraCon // Private method obj.Debug = function (msg) { console.log(msg); } + // Used to add TLS to a steam + function SerialTunnel(options) { + var obj = new require('stream').Duplex(options); + obj.forwardwrite = null; + obj.updateBuffer = function (chunk) { this.push(chunk); }; + obj._write = function (chunk, encoding, callback) { if (obj.forwardwrite != null) { obj.forwardwrite(chunk); } else { console.err("Failed to fwd _write."); } if (callback) callback(); }; // Pass data written to forward + obj._read = function (size) { }; // Push nothing, anything to read should be pushed from updateBuffer() + return obj; + } + // Private method // pri = priority, if set to 1, the call is high priority and put on top of the stack. obj.PerformAjax = function (postdata, callback, tag, pri, url, action) { @@ -167,11 +177,12 @@ var CreateWsmanComm = function (host, port, user, pass, tls, tlsoptions, ciraCon obj.kerberosDone = 0; if (obj.ciraConnection != null) { - // Setup a new channel using the CIRA/Relay/LMS connection - obj.socket = obj.ciraConnection.SetupChannel(obj.port); - if (obj.socket == null) { - try { obj.xxOnSocketClosed(); } catch (e) { } - } else { + if (obj.xtls != 1) { + // Setup a new channel using the CIRA/Relay/LMS connection + obj.socket = obj.ciraConnection.SetupChannel(obj.port); + if (obj.socket == null) { obj.xxOnSocketClosed(); return; } + + // Connect without TLS obj.socket.onData = function (ccon, data) { obj.xxOnSocketData(data); } obj.socket.onStateChange = function (ccon, state) { if (state == 0) { @@ -181,12 +192,57 @@ var CreateWsmanComm = function (host, port, user, pass, tls, tlsoptions, ciraCon obj.socketHeader = null; obj.socketData = ''; obj.socketState = 0; - try { obj.xxOnSocketClosed(); } catch (e) { } + obj.xxOnSocketClosed(); } else if (state == 2) { // Channel open success obj.xxOnSocketConnected(); } } + } else { + // Setup a new channel using the CIRA/Relay/LMS connection + obj.cirasocket = obj.ciraConnection.SetupChannel(obj.port); + if (obj.cirasocket == null) { obj.xxOnSocketClosed(); return; } + + // Connect with TLS + var ser = new SerialTunnel(); + + // let's chain up the TLSSocket <-> SerialTunnel <-> CIRA APF (chnl) + // Anything that needs to be forwarded by SerialTunnel will be encapsulated by chnl write + ser.forwardwrite = function (msg) { obj.cirasocket.write(msg); }; // TLS ---> CIRA + + // When APF tunnel return something, update SerialTunnel buffer + obj.cirasocket.onData = function (ciraconn, data) { if (data.length > 0) { try { ser.updateBuffer(Buffer.from(data, 'binary')); } catch (e) { } } }; // CIRA ---> TLS + + // Handle CIRA tunnel state change + obj.cirasocket.onStateChange = function (ciraconn, state) { + if (state == 0) { obj.xxOnSocketClosed(); } + if (state == 2) { + // TLSSocket to encapsulate TLS communication, which then tunneled via SerialTunnel an then wrapped through CIRA APF + var options = { socket: ser, ciphers: 'RSA+AES:!aNULL:!MD5:!DSS', secureOptions: obj.constants.SSL_OP_NO_SSLv2 | obj.constants.SSL_OP_NO_SSLv3 | obj.constants.SSL_OP_NO_COMPRESSION | obj.constants.SSL_OP_CIPHER_SERVER_PREFERENCE, rejectUnauthorized: false }; + if (obj.tls1only == 1) { tlsoptions.secureProtocol = 'TLSv1_method'; } + if (obj.xtlsoptions) { + if (obj.xtlsoptions.ca) options.ca = obj.xtlsoptions.ca; + if (obj.xtlsoptions.cert) options.cert = obj.xtlsoptions.cert; + if (obj.xtlsoptions.key) options.key = obj.xtlsoptions.key; + } + + //obj.socket = new TLSSocket(ser, options); + obj.socket = obj.tls.connect(obj.port, obj.host, options, obj.xxOnSocketConnected); + obj.socket.setEncoding('binary'); + obj.socket.setTimeout(6000); // Set socket idle timeout + obj.socket.on('error', function (err) { console.log("CIRA TLS Connection Error ", err); obj.xxOnSocketClosed(); }); + //obj.socket.on('error', function (e) { if (e.message && e.message.indexOf('sslv3 alert bad record mac') >= 0) { obj.xtlsMethod = 1 - obj.xtlsMethod; } }); + obj.socket.on('close', obj.xxOnSocketClosed); + obj.socket.on('timeout', obj.xxOnSocketTimeout); + + // Decrypted tunnel from TLS communcation to be forwarded to websocket + obj.socket.on('data', function (data) { try { obj.xxOnSocketData(data.toString('binary')); } catch (e) { } }); // AMT/TLS ---> WS + + // If TLS is on, forward it through TLSSocket + obj.forwardclient = obj.socket; + obj.forwardclient.xtls = 1; + } + }; } } else { // Direct connection @@ -229,7 +285,7 @@ var CreateWsmanComm = function (host, port, user, pass, tls, tlsoptions, ciraCon obj.xxOnSocketConnected = function () { if (obj.socket == null) return; // check TLS certificate for webrelay and direct only - if ((obj.ciraConnection == null) && (obj.xtls == 1)) { + if (obj.xtls == 1) { obj.xtlsCertificate = obj.socket.getPeerCertificate(); // ###BEGIN###{Certificates} @@ -365,8 +421,15 @@ var CreateWsmanComm = function (host, port, user, pass, tls, tlsoptions, ciraCon //obj.Debug("xxOnSocketClosed"); obj.socketState = 0; if (obj.socket != null) { - if (obj.ciraConnection == null) { obj.socket.destroy(); } else { obj.socket.close(); } + try { + if (obj.ciraConnection == null) { + obj.socket.destroy(); + } else { + if (obj.cirasocket != null) { obj.cirasocket.close(); } else { obj.socket.close(); } + } + } catch (ex) { } obj.socket = null; + obj.cirasocket = null; } if (obj.pendingAjaxCall.length > 0) { var r = obj.pendingAjaxCall.shift(), retry = r[5]; @@ -376,14 +439,22 @@ var CreateWsmanComm = function (host, port, user, pass, tls, tlsoptions, ciraCon obj.xxOnSocketTimeout = function () { if (obj.socket != null) { - if (obj.ciraConnection == null) { obj.socket.destroy(); } else { obj.socket.close(); } + try { + if (obj.ciraConnection == null) { + obj.socket.destroy(); + } else { + if (obj.cirasocket != null) { obj.cirasocket.close(); } else { obj.socket.close(); } + } + } catch (ex) { } obj.socket = null; + obj.cirasocket = null; } } // NODE.js specific private method obj.xxSend = function (x) { - if (obj.socketState == 2) { obj.socket.write(Buffer.from(x, "binary")); } + //console.log('xxSend', x); + if (obj.socketState == 2) { obj.socket.write(Buffer.from(x, 'binary')); } } // Cancel all pending queries with given status diff --git a/amtmanager.js b/amtmanager.js index a9d2189f..6de55f5e 100644 --- a/amtmanager.js +++ b/amtmanager.js @@ -49,6 +49,9 @@ module.exports.CreateAmtManager = function(parent) { // If the connection type we are using is not longer valid, remove our managed device. if ((dev != null) && (dev.conntype != null) && ((dev.conntype & event.conn) == 0)) { removeDevice(event.nodeid); dev = null; } + // Debug line, to only manage CIRA/Relay connections + //if ((event.conn & 10) == 0) return; + // Create or update a managed device if ((event.conn & 14) != 0) { // connectType: Bitmask, 1 = MeshAgent, 2 = Intel AMT CIRA, 4 = Intel AMT local, 8 = Intel AMT Relay, 16 = MQTT // We have an OOB connection to Intel AMT, update our information @@ -224,7 +227,6 @@ module.exports.CreateAmtManager = function(parent) { // Connect now //console.log('CIRA-Connect', (dotls == 1)?"TLS":"NoTLS", dev.name, dev.host, user, pass); var comm; - dotls = 0; // TODO: We don't support TLS with CIRA/Relay/LMS connections yet. Remove this when we do. if (dotls == 1) { comm = CreateWsmanComm(dev.nodeid, 16993, user, pass, 1, null, ciraconn); // Perform TLS comm.xtlsFingerprint = 0; // Perform no certificate checking @@ -253,7 +255,6 @@ module.exports.CreateAmtManager = function(parent) { // Connect now var comm; - dev.tlsfail = true; // TODO: We don't support TLS with CIRA/Relay/LMS connections yet. Remove this when we do. if (dev.tlsfail !== true) { //console.log('Relay-Connect', "TLS", dev.name, dev.host, user, pass); comm = CreateWsmanComm(dev.nodeid, 16993, user, pass, 1, null, ciraconn); // Perform TLS diff --git a/mpsserver.js b/mpsserver.js index 25412c4b..a456bda4 100644 --- a/mpsserver.js +++ b/mpsserver.js @@ -854,7 +854,7 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) { var cirachannel = socket.tag.channels[RecipientChannel]; if (cirachannel == null) { 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.onData) { cirachannel.onData(cirachannel, Buffer.from(data.substring(9, 9 + LengthOfData), 'binary')); } if (cirachannel.amtpendingcredits > (cirachannel.ciraWindow / 2)) { SendChannelWindowAdjust(cirachannel.socket, cirachannel.amtchannelid, cirachannel.amtpendingcredits); // Adjust the buffer window cirachannel.amtpendingcredits = 0; @@ -960,8 +960,8 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) { } function SendChannelData(socket, channelid, data) { - parent.debug('mpscmddata', '<-- CHANNEL_DATA', channelid, data.length); - Write(socket, String.fromCharCode(APFProtocol.CHANNEL_DATA) + common.IntToStr(channelid) + common.IntToStr(data.length) + data); + parent.debug('mpscmddata', '<-- CHANNEL_DATA', channelid, data.length, Buffer.from(data, 'binary').toString('hex')); + Write(socket, String.fromCharCode(APFProtocol.CHANNEL_DATA) + common.IntToStr(channelid) + common.IntToStr(data.length) + ((typeof data == 'string') ? data : data.toString('binary'))); } function SendChannelWindowAdjust(socket, channelid, bytestoadd) { @@ -987,14 +987,16 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) { } function Write(socket, data) { - if (args.mpsdebug) { - // Print out sent bytes - var buf = Buffer.from(data, 'binary'); - console.log('MPS <-- (' + buf.length + '):' + buf.toString('hex')); - if (socket.websocket == 1) { socket.send(buf); } else { socket.write(buf); } - } else { - if (socket.websocket == 1) { socket.send(Buffer.from(data, 'binary')); } else { socket.write(Buffer.from(data, 'binary')); } - } + try { + if (args.mpsdebug) { + // Print out sent bytes + var buf = Buffer.from(data, 'binary'); + console.log('MPS <-- (' + buf.length + '):' + buf.toString('hex')); + if (socket.websocket == 1) { socket.send(buf); } else { socket.write(buf); } + } else { + if (socket.websocket == 1) { socket.send(Buffer.from(data, 'binary')); } else { socket.write(Buffer.from(data, 'binary')); } + } + } catch (ex) { } } // Returns a CIRA/Relay/LMS connection to a nodeid, use the best possible connection, CIRA first, Relay second, LMS third. diff --git a/public/scripts/amt-wsman-0.2.0-min.js b/public/scripts/amt-wsman-0.2.0-min.js index a8eb3bca..86d1ae50 100644 --- a/public/scripts/amt-wsman-0.2.0-min.js +++ b/public/scripts/amt-wsman-0.2.0-min.js @@ -1 +1 @@ -var WsmanStackCreateService=function(e,s,r,a,o,t){var p={};function l(e){if(!e)return"";var s=" ";for(var r in e)e.hasOwnProperty(r)&&0===r.indexOf("@")&&(s+=r.substring(1)+'="'+e[r]+'" ');return s}function w(e){if(!e)return"";if("string"==typeof e)return e;if(e.InstanceID)return''+e.InstanceID+"";var s="";for(var r in e)if(e.hasOwnProperty(r)){if(s+='',e[r].ReferenceParameters){s+="",s+=""+e[r].Address+""+e[r].ReferenceParameters.ResourceURI+"";var a=e[r].ReferenceParameters.SelectorSet.Selector;if(Array.isArray(a))for(var o=0;o"+a[o].Value+"";else s+=""+a.Value+"";s+=""}else s+=e[r];s+=""}return s+=""}return p.NextMessageId=1,p.Address="/wsman",p.comm=CreateWsmanComm(e,s,r,a,o,t),p.PerformAjax=function(e,o,s,r,a){null==a&&(a=""),p.comm.PerformAjax('
"+e,function(e,s,r){if(200==s){var a=p.ParseWsman(e);a&&null!=a?o(p,a.Header.ResourceURI,a,200,r):o(p,null,{Header:{HttpError:s}},601,r)}else o(p,null,{Header:{HttpError:s}},s,r)},s,r)},p.CancelAllQueries=function(e){p.comm.CancelAllQueries(e)},p.GetNameFromUrl=function(e){var s=e.lastIndexOf("/");return-1==s?e:e.substring(s+1)},p.ExecSubscribe=function(e,s,r,a,o,t,n,l,d,c){var m="",i="";null!=d&&null!=c&&(m="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#UsernameToken"+d+''+c+"",i=''),l=null!=l&&null!=l?""+l+"":"";var u="http://schemas.xmlsoap.org/ws/2004/08/eventing/Subscribe"+p.Address+""+e+""+p.NextMessageId+++"http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous"+w(n)+m+'
'+r+""+i+"PT0.000000S";p.PerformAjax(u+"
",a,o,t,'xmlns:e="http://schemas.xmlsoap.org/ws/2004/08/eventing" xmlns:t="http://schemas.xmlsoap.org/ws/2005/02/trust" xmlns:se="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:m="http://x.com"')},p.ExecUnSubscribe=function(e,s,r,a,o){var t="http://schemas.xmlsoap.org/ws/2004/08/eventing/Unsubscribe"+p.Address+""+e+""+p.NextMessageId+++"http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous"+w(o)+"";p.PerformAjax(t+"",s,r,a,'xmlns:e="http://schemas.xmlsoap.org/ws/2004/08/eventing"')},p.ExecPut=function(e,s,r,a,o,t){var n="http://schemas.xmlsoap.org/ws/2004/09/transfer/Put"+p.Address+""+e+""+p.NextMessageId+++"http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymousPT60.000S"+w(t)+""+function(e,s){if(!e||null==s)return"";var r=p.GetNameFromUrl(e),a="';for(var o in s)if(s.hasOwnProperty(o)&&0!==o.indexOf("__")&&0!==o.indexOf("@")&&void 0!==s[o]&&null!==s[o]&&"function"!=typeof s[o])if("object"==typeof s[o]&&s[o].ReferenceParameters){a+=""+s[o].Address+""+s[o].ReferenceParameters.ResourceURI+"";var t=s[o].ReferenceParameters.SelectorSet.Selector;if(Array.isArray(t))for(var n=0;n"+t[n].Value+"";else a+=""+t.Value+"";a+=""}else if(Array.isArray(s[o]))for(n=0;n"+s[o][n].toString()+"";else a+=""+s[o].toString()+"";return a+=""}(e,s);p.PerformAjax(n+"",r,a,o)},p.ExecCreate=function(e,s,r,a,o,t){var n=p.GetNameFromUrl(e),l="http://schemas.xmlsoap.org/ws/2004/09/transfer/Create"+p.Address+""+e+""+p.NextMessageId+++"http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymousPT60S"+w(t)+"';for(var d in s)l+=""+s[d]+"";p.PerformAjax(l+"",r,a,o)},p.ExecCreateXml=function(e,s,r,a,o){var t=p.GetNameFromUrl(e);p.PerformAjax("http://schemas.xmlsoap.org/ws/2004/09/transfer/Create"+p.Address+""+e+""+p.NextMessageId+++"http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymousPT60.000S'+s+"",r,a,o)},p.ExecDelete=function(e,s,r,a,o){var t="http://schemas.xmlsoap.org/ws/2004/09/transfer/Delete"+p.Address+""+e+""+p.NextMessageId+++"http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymousPT60S"+w(s)+"";p.PerformAjax(t,r,a,o)},p.ExecGet=function(e,s,r,a){p.PerformAjax("http://schemas.xmlsoap.org/ws/2004/09/transfer/Get"+p.Address+""+e+""+p.NextMessageId+++"http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymousPT60S",s,r,a)},p.ExecMethod=function(e,s,r,a,o,t,n){var l="";for(var d in r)if(null!=r[d])if(Array.isArray(r[d]))for(var c in r[d])l+=""+r[d][c]+"";else l+=""+r[d]+"";p.ExecMethodXml(e,s,l,a,o,t,n)},p.ExecMethodXml=function(e,s,r,a,o,t,n){p.PerformAjax(e+"/"+s+""+p.Address+""+e+""+p.NextMessageId+++"http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymousPT60S"+w(n)+"'+r+"",a,o,t)},p.ExecEnum=function(e,s,r,a){p.PerformAjax("http://schemas.xmlsoap.org/ws/2004/09/enumeration/Enumerate"+p.Address+""+e+""+p.NextMessageId+++'http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymousPT60S',s,r,a)},p.ExecPull=function(e,s,r,a,o){p.PerformAjax("http://schemas.xmlsoap.org/ws/2004/09/enumeration/Pull"+p.Address+""+e+""+p.NextMessageId+++'http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymousPT60S'+s+"99999999",r,a,o)},p.ParseWsman=function(s){try{s.childNodes||(s=function(e){{if(window.DOMParser)return(new DOMParser).parseFromString(e,"text/xml");var s=new ActiveXObject("Microsoft.XMLDOM");return s.async=!1,s.loadXML(e),s}}(s));var e,r={Header:{}},a=s.getElementsByTagName("Header")[0];if(!(a=a||s.getElementsByTagName("a:Header")[0]))return null;for(var o=0;o'+e.InstanceID+"";var s="";for(var r in e)if(e.hasOwnProperty(r)){if(s+='',e[r].ReferenceParameters){s+="",s+=""+e[r].Address+""+e[r].ReferenceParameters.ResourceURI+"";var a=e[r].ReferenceParameters.SelectorSet.Selector;if(Array.isArray(a))for(var o=0;o"+a[o].Value+"";else s+=""+a.Value+"";s+=""}else s+=e[r];s+=""}return s+=""}return p.NextMessageId=1,p.Address="/wsman",p.comm=CreateWsmanComm(e,s,r,a,o,t),p.PerformAjax=function(e,o,s,r,a){null==a&&(a=""),p.comm.PerformAjax('
"+e,function(e,s,r){if(200==s){var a=p.ParseWsman(e);a&&null!=a?o(p,a.Header.ResourceURI,a,200,r):o(p,null,{Header:{HttpError:s}},601,r)}else o(p,null,{Header:{HttpError:s}},s,r)},s,r)},p.CancelAllQueries=function(e){p.comm.CancelAllQueries(e)},p.GetNameFromUrl=function(e){var s=e.lastIndexOf("/");return-1==s?e:e.substring(s+1)},p.ExecSubscribe=function(e,s,r,a,o,t,n,l,c,d){var m="",i="";null!=c&&null!=d&&(m="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#UsernameToken"+c+''+d+"",i=''),l=null!=l&&null!=l?""+l+"":"";var u="http://schemas.xmlsoap.org/ws/2004/08/eventing/Subscribe"+p.Address+""+e+""+p.NextMessageId+++"http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous"+w(n)+m+'
'+r+""+i+"PT0.000000S";p.PerformAjax(u+"
",a,o,t,'xmlns:e="http://schemas.xmlsoap.org/ws/2004/08/eventing" xmlns:t="http://schemas.xmlsoap.org/ws/2005/02/trust" xmlns:se="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:m="http://x.com"')},p.ExecUnSubscribe=function(e,s,r,a,o){var t="http://schemas.xmlsoap.org/ws/2004/08/eventing/Unsubscribe"+p.Address+""+e+""+p.NextMessageId+++"http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous"+w(o)+"";p.PerformAjax(t+"",s,r,a,'xmlns:e="http://schemas.xmlsoap.org/ws/2004/08/eventing"')},p.ExecPut=function(e,s,r,a,o,t){var n="http://schemas.xmlsoap.org/ws/2004/09/transfer/Put"+p.Address+""+e+""+p.NextMessageId+++"http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymousPT60.000S"+w(t)+""+function(e,s){if(!e||null==s)return"";var r=p.GetNameFromUrl(e),a="';for(var o in s)if(s.hasOwnProperty(o)&&0!==o.indexOf("__")&&0!==o.indexOf("@")&&void 0!==s[o]&&null!==s[o]&&"function"!=typeof s[o])if("object"==typeof s[o]&&s[o].ReferenceParameters){a+=""+s[o].Address+""+s[o].ReferenceParameters.ResourceURI+"";var t=s[o].ReferenceParameters.SelectorSet.Selector;if(Array.isArray(t))for(var n=0;n"+t[n].Value+"";else a+=""+t.Value+"";a+=""}else if(Array.isArray(s[o]))for(n=0;n"+s[o][n].toString()+"";else a+=""+s[o].toString()+"";return a+=""}(e,s);p.PerformAjax(n+"",r,a,o)},p.ExecCreate=function(e,s,r,a,o,t){var n=p.GetNameFromUrl(e),l="http://schemas.xmlsoap.org/ws/2004/09/transfer/Create"+p.Address+""+e+""+p.NextMessageId+++"http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymousPT60S"+w(t)+"';for(var c in s)l+=""+s[c]+"";p.PerformAjax(l+"",r,a,o)},p.ExecCreateXml=function(e,s,r,a,o){var t=p.GetNameFromUrl(e);p.PerformAjax("http://schemas.xmlsoap.org/ws/2004/09/transfer/Create"+p.Address+""+e+""+p.NextMessageId+++"http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymousPT60.000S'+s+"",r,a,o)},p.ExecDelete=function(e,s,r,a,o){var t="http://schemas.xmlsoap.org/ws/2004/09/transfer/Delete"+p.Address+""+e+""+p.NextMessageId+++"http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymousPT60S"+w(s)+"";p.PerformAjax(t,r,a,o)},p.ExecGet=function(e,s,r,a){p.PerformAjax("http://schemas.xmlsoap.org/ws/2004/09/transfer/Get"+p.Address+""+e+""+p.NextMessageId+++"http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymousPT60S",s,r,a)},p.ExecMethod=function(e,s,r,a,o,t,n){var l="";for(var c in r)if(null!=r[c])if(Array.isArray(r[c]))for(var d in r[c])l+=""+r[c][d]+"";else l+=""+r[c]+"";p.ExecMethodXml(e,s,l,a,o,t,n)},p.ExecMethodXml=function(e,s,r,a,o,t,n){p.PerformAjax(e+"/"+s+""+p.Address+""+e+""+p.NextMessageId+++"http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymousPT60S"+w(n)+"'+r+"",a,o,t)},p.ExecEnum=function(e,s,r,a){p.PerformAjax("http://schemas.xmlsoap.org/ws/2004/09/enumeration/Enumerate"+p.Address+""+e+""+p.NextMessageId+++'http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymousPT60S',s,r,a)},p.ExecPull=function(e,s,r,a,o){p.PerformAjax("http://schemas.xmlsoap.org/ws/2004/09/enumeration/Pull"+p.Address+""+e+""+p.NextMessageId+++'http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymousPT60S'+s+"99999999",r,a,o)},p.ParseWsman=function(s){try{s.childNodes||(s=function(e){{if(window.DOMParser)return(new DOMParser).parseFromString(e,"text/xml");var s=new ActiveXObject("Microsoft.XMLDOM");return s.async=!1,s.loadXML(e),s}}(s));var e,r={Header:{}},a=s.getElementsByTagName("Header")[0];if(!(a=a||s.getElementsByTagName("a:Header")[0]))return null;for(var o=0;o