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
'+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'+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