From 9c09a3ebc01c75820a382c29cf05b5d7a12f2b93 Mon Sep 17 00:00:00 2001 From: jsastriawan Date: Fri, 20 Sep 2019 17:21:58 -0700 Subject: [PATCH] A working serverside AMT API via 3 different modes, namely mode 1 (AMT Direct), mode 2 (CIRA) and mode 3 (APF bridge) --- agents/modules_meshcore/apfclient.js | 12 ++-- agents/modules_meshcore_min/apfclient.min.js | 2 +- amt/amt-wsman-comm.js | 39 +++++------- amt/amt-wsman.js | 6 +- meshuser.js | 66 ++++++++++++++++++++ mpsserver.js | 4 +- 6 files changed, 94 insertions(+), 35 deletions(-) diff --git a/agents/modules_meshcore/apfclient.js b/agents/modules_meshcore/apfclient.js index 3f26c01a..4dcb900c 100644 --- a/agents/modules_meshcore/apfclient.js +++ b/agents/modules_meshcore/apfclient.js @@ -332,7 +332,7 @@ function CreateAPFClient(parent, args) { if (pfwd_ports.indexOf(p_res.target_port) >= 0) { // connect socket to that port obj.downlinks[p_res.sender_chan] = obj.net.createConnection({ host: obj.args.clientaddress, port: p_res.target_port }, function () { - obj.downlinks[p_res.sender_chan].setEncoding('binary');//assume everything is binary, not interpreting + //obj.downlinks[p_res.sender_chan].setEncoding('binary');//assume everything is binary, not interpreting SendChannelOpenConfirm(socket.ws, p_res); }); @@ -348,8 +348,10 @@ function CreateAPFClient(parent, args) { obj.downlinks[p_res.sender_chan].on('end', function () { if (obj.downlinks[p_res.sender_chan]) { try { + Debug("Socket ends."); SendChannelClose(socket.ws, p_res.sender_chan); - delete obj.downlinks[p_res.sender_chan]; + // 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); } @@ -449,14 +451,14 @@ function CreateAPFClient(parent, args) { function SendChannelData(socket, chan, len, data) { var buf = String.fromCharCode(APFProtocol.CHANNEL_DATA) + IntToStr(chan) + IntToStr(len) + data; - socket.write(Buffer.from(buf, 'binary')); + socket.write(buf); Debug("APF: Send ChannelData: " + rstr2hex(buf)); } function SendChannelClose(socket, chan) { var buf = String.fromCharCode(APFProtocol.CHANNEL_CLOSE) + IntToStr(chan); - socket.write(Buffer.from(buf, 'binary')); - Debug("APF: Send ChannelClose: " + rstr2hex(buf)); + socket.write(buf); + Debug("APF: Send ChannelClose "); } obj.connect = function () { diff --git a/agents/modules_meshcore_min/apfclient.min.js b/agents/modules_meshcore_min/apfclient.min.js index 5e4eca9e..f917dcba 100644 --- a/agents/modules_meshcore_min/apfclient.min.js +++ b/agents/modules_meshcore_min/apfclient.min.js @@ -1 +1 @@ -function CreateAPFClient(q,e){var o={};o.parent=q;o.args=e;o.http=require("http");o.net=require("net");o.forwardClient=null;o.downlinks={};o.pfwd_idx=0;o.timer=null;function u(K,J){return(K.charCodeAt(J)*16777216)+(K.charCodeAt(J+1)<<16)+(K.charCodeAt(J+2)<<8)+K.charCodeAt(J+3)}function n(J){return String.fromCharCode((J>>24)&255,(J>>16)&255,(J>>8)&255,J&255)}function m(J){var L="",K=(""+J).match(/../g),M;while(M=K.shift()){L+=String.fromCharCode("0x"+M)}return L}function h(J){return(J+256).toString(16).substr(-2).toUpperCase()}function w(K){var L="",J;for(J=0;J0){o.forwardClient.tag.accumulator=o.forwardClient.tag.accumulator.slice(O)}if(o.cirastate==i.FAILED){k("APF: in a failed state, destroying socket.");o.forwardClient.ws.end()}}while(O>0)}catch(N){k(N)}});o.forwardClient.ws.on("error",function(M){k("APF: Connection error, ending connecting.");if(o.timer!=null){clearInterval(o.timer);o.timer=null}});o.state=i.INITIAL;F(o.forwardClient.ws,o.args.clientuuid);G(o.forwardClient.ws,"auth@amt.intel.com")};function l(J){return J.substring(6,8)+J.substring(4,6)+J.substring(2,4)+J.substring(0,2)+"-"+J.substring(10,12)+J.substring(8,10)+"-"+J.substring(14,16)+J.substring(12,14)+"-"+J.substring(16,20)+"-"+J.substring(20)}function I(K){K=K.replace(/-/g,"");var J=K.substring(6,8)+K.substring(4,6)+K.substring(2,4)+K.substring(0,2);J+=K.substring(10,12)+K.substring(8,10)+K.substring(14,16)+K.substring(12,14)+K.substring(16,20)+K.substring(20);return J}function f(K){var L="";for(var J=0;J=i.AUTH_SERVICE_REQUEST_SENT){H(U.ws,o.args.mpsuser,o.args.mpspass)}}else{if(S=="pfwd@amt.intel.com"){if(o.cirastate>=i.PFWD_SERVICE_REQUEST_SENT){C(U.ws,o.args.clientname,s[o.pfwd_idx++])}}}return 5+T;case d.REQUEST_SUCCESS:if(O>=5){var Q=u(M,1);k("APF: Request to port forward "+Q+" successful.");if(o.pfwd_idx=0){o.downlinks[P.sender_chan]=o.net.createConnection({host:o.args.clientaddress,port:P.target_port},function(){o.downlinks[P.sender_chan].setEncoding("binary");z(U.ws,P)});o.downlinks[P.sender_chan].on("data",function(V){y(U.ws,P.sender_chan,V.length,V)});o.downlinks[P.sender_chan].on("error",function(V){k("Downlink connection error: "+V)});o.downlinks[P.sender_chan].on("end",function(){if(o.downlinks[P.sender_chan]){try{x(U.ws,P.sender_chan);delete o.downlinks[P.sender_chan]}catch(V){k("Downlink connection exception: "+V)}}})}else{A(U.ws,P)}return P.len;case d.CHANNEL_OPEN_CONFIRMATION:k("APF: CHANNEL_OPEN_CONFIRMATION");return 17;case d.CHANNEL_CLOSE:var R=u(M,1);k("APF: CHANNEL_CLOSE: "+R);x(U.ws,R);try{o.downlinks[R].end();delete o.downlinks[R]}catch(N){}return 5;case d.CHANNEL_DATA:k("APF: CHANNEL_DATA: "+JSON.stringify(w(M)));var R=u(M,1);var K=u(M,5);var J=M.substring(9,9+K);if(o.downlinks[R]){try{o.downlinks[R].write(J,"binary",function(){k("Write completed.");B(U.ws,R,K)})}catch(N){k("Cannot forward data to downlink socket.")}}return 9+K;case d.CHANNEL_WINDOW_ADJUST:k("APF: CHANNEL_WINDOW_ADJUST ");return 9;default:k("CMD: "+L+" is not implemented.");o.cirastate=i.FAILED;return 0}}function r(L){var N={len:0,cmd:d.CHANNEL_OPEN,chan_type:"",sender_chan:0,window_size:0,target_address:"",target_port:0,origin_address:"",origin_port:0,};var K=u(L,1);N.chan_type=L.substring(5,5+K);N.sender_chan=u(L,5+K);N.window_size=u(L,9+K);var J=u(L,17+K);N.target_address=L.substring(21+K,21+K+J);N.target_port=u(L,21+K+J);var M=u(L,25+K+J);N.origin_address=L.substring(29+K+J,29+K+J+M);N.origin_port=u(L,29+K+J+M);N.len=33+K+J+M;return N}function A(L,J){var K=String.fromCharCode(d.CHANNEL_OPEN_FAILURE)+n(J.sender_chan)+n(2)+n(0)+n(0);L.write(K);k("APF: Send ChannelOpenFailure")}function z(L,J){var K=String.fromCharCode(d.CHANNEL_OPEN_CONFIRMATION)+n(J.sender_chan)+n(J.sender_chan)+n(J.window_size)+n(4294967295);L.write(K);k("APF: Send ChannelOpenConfirmation")}function B(M,J,L){var K=String.fromCharCode(d.CHANNEL_WINDOW_ADJUST)+n(J)+n(L);M.write(K);k("APF: Send ChannelWindowAdjust: "+w(K))}function y(N,K,M,L){var J=String.fromCharCode(d.CHANNEL_DATA)+n(K)+n(M)+L;N.write(Buffer.from(J,"binary"));k("APF: Send ChannelData: "+w(J))}function x(L,K){var J=String.fromCharCode(d.CHANNEL_CLOSE)+n(K);L.write(Buffer.from(J,"binary"));k("APF: Send ChannelClose: "+w(J))}o.connect=function(){if(o.forwardClient!=null){try{o.forwardClient.ws.end()}catch(J){k(J)}}o.cirastate=i.INITIAL;o.pfwd_idx=0;var K=o.http.parseUri(o.args.mpsurl);K.rejectUnauthorized=0;o.forwardClient=o.http.request(K);o.forwardClient.upgrade=o.onSecureConnect;o.forwardClient.end()};o.disconnect=function(){try{o.forwardClient.ws.end()}catch(J){k(J)}};return o}module.exports=CreateAPFClient; \ No newline at end of file +function CreateAPFClient(q,e){var o={};o.parent=q;o.args=e;o.http=require("http");o.net=require("net");o.forwardClient=null;o.downlinks={};o.pfwd_idx=0;o.timer=null;function u(K,J){return(K.charCodeAt(J)*16777216)+(K.charCodeAt(J+1)<<16)+(K.charCodeAt(J+2)<<8)+K.charCodeAt(J+3)}function n(J){return String.fromCharCode((J>>24)&255,(J>>16)&255,(J>>8)&255,J&255)}function m(J){var L="",K=(""+J).match(/../g),M;while(M=K.shift()){L+=String.fromCharCode("0x"+M)}return L}function h(J){return(J+256).toString(16).substr(-2).toUpperCase()}function w(K){var L="",J;for(J=0;J0){o.forwardClient.tag.accumulator=o.forwardClient.tag.accumulator.slice(O)}if(o.cirastate==i.FAILED){k("APF: in a failed state, destroying socket.");o.forwardClient.ws.end()}}while(O>0)}catch(N){k(N)}});o.forwardClient.ws.on("error",function(M){k("APF: Connection error, ending connecting.");if(o.timer!=null){clearInterval(o.timer);o.timer=null}});o.state=i.INITIAL;F(o.forwardClient.ws,o.args.clientuuid);G(o.forwardClient.ws,"auth@amt.intel.com")};function l(J){return J.substring(6,8)+J.substring(4,6)+J.substring(2,4)+J.substring(0,2)+"-"+J.substring(10,12)+J.substring(8,10)+"-"+J.substring(14,16)+J.substring(12,14)+"-"+J.substring(16,20)+"-"+J.substring(20)}function I(K){K=K.replace(/-/g,"");var J=K.substring(6,8)+K.substring(4,6)+K.substring(2,4)+K.substring(0,2);J+=K.substring(10,12)+K.substring(8,10)+K.substring(14,16)+K.substring(12,14)+K.substring(16,20)+K.substring(20);return J}function f(K){var L="";for(var J=0;J=i.AUTH_SERVICE_REQUEST_SENT){H(U.ws,o.args.mpsuser,o.args.mpspass)}}else{if(S=="pfwd@amt.intel.com"){if(o.cirastate>=i.PFWD_SERVICE_REQUEST_SENT){C(U.ws,o.args.clientname,s[o.pfwd_idx++])}}}return 5+T;case d.REQUEST_SUCCESS:if(O>=5){var Q=u(M,1);k("APF: Request to port forward "+Q+" successful.");if(o.pfwd_idx=0){o.downlinks[P.sender_chan]=o.net.createConnection({host:o.args.clientaddress,port:P.target_port},function(){z(U.ws,P)});o.downlinks[P.sender_chan].on("data",function(V){y(U.ws,P.sender_chan,V.length,V)});o.downlinks[P.sender_chan].on("error",function(V){k("Downlink connection error: "+V)});o.downlinks[P.sender_chan].on("end",function(){if(o.downlinks[P.sender_chan]){try{k("Socket ends.");x(U.ws,P.sender_chan);setTimeout(function(){delete o.downlinks[P.sender_chan]},100)}catch(V){k("Downlink connection exception: "+V)}}})}else{A(U.ws,P)}return P.len;case d.CHANNEL_OPEN_CONFIRMATION:k("APF: CHANNEL_OPEN_CONFIRMATION");return 17;case d.CHANNEL_CLOSE:var R=u(M,1);k("APF: CHANNEL_CLOSE: "+R);x(U.ws,R);try{o.downlinks[R].end();delete o.downlinks[R]}catch(N){}return 5;case d.CHANNEL_DATA:k("APF: CHANNEL_DATA: "+JSON.stringify(w(M)));var R=u(M,1);var K=u(M,5);var J=M.substring(9,9+K);if(o.downlinks[R]){try{o.downlinks[R].write(J,"binary",function(){k("Write completed.");B(U.ws,R,K)})}catch(N){k("Cannot forward data to downlink socket.")}}return 9+K;case d.CHANNEL_WINDOW_ADJUST:k("APF: CHANNEL_WINDOW_ADJUST ");return 9;default:k("CMD: "+L+" is not implemented.");o.cirastate=i.FAILED;return 0}}function r(L){var N={len:0,cmd:d.CHANNEL_OPEN,chan_type:"",sender_chan:0,window_size:0,target_address:"",target_port:0,origin_address:"",origin_port:0,};var K=u(L,1);N.chan_type=L.substring(5,5+K);N.sender_chan=u(L,5+K);N.window_size=u(L,9+K);var J=u(L,17+K);N.target_address=L.substring(21+K,21+K+J);N.target_port=u(L,21+K+J);var M=u(L,25+K+J);N.origin_address=L.substring(29+K+J,29+K+J+M);N.origin_port=u(L,29+K+J+M);N.len=33+K+J+M;return N}function A(L,J){var K=String.fromCharCode(d.CHANNEL_OPEN_FAILURE)+n(J.sender_chan)+n(2)+n(0)+n(0);L.write(K);k("APF: Send ChannelOpenFailure")}function z(L,J){var K=String.fromCharCode(d.CHANNEL_OPEN_CONFIRMATION)+n(J.sender_chan)+n(J.sender_chan)+n(J.window_size)+n(4294967295);L.write(K);k("APF: Send ChannelOpenConfirmation")}function B(M,J,L){var K=String.fromCharCode(d.CHANNEL_WINDOW_ADJUST)+n(J)+n(L);M.write(K);k("APF: Send ChannelWindowAdjust: "+w(K))}function y(N,K,M,L){var J=String.fromCharCode(d.CHANNEL_DATA)+n(K)+n(M)+L;N.write(J);k("APF: Send ChannelData: "+w(J))}function x(L,K){var J=String.fromCharCode(d.CHANNEL_CLOSE)+n(K);L.write(J);k("APF: Send ChannelClose ")}o.connect=function(){if(o.forwardClient!=null){try{o.forwardClient.ws.end()}catch(J){k(J)}}o.cirastate=i.INITIAL;o.pfwd_idx=0;var K=o.http.parseUri(o.args.mpsurl);K.rejectUnauthorized=0;o.forwardClient=o.http.request(K);o.forwardClient.upgrade=o.onSecureConnect;o.forwardClient.end()};o.disconnect=function(){try{o.forwardClient.ws.end()}catch(J){k(J)}};return o}module.exports=CreateAPFClient; \ No newline at end of file diff --git a/amt/amt-wsman-comm.js b/amt/amt-wsman-comm.js index 49d32b89..9c804e5f 100644 --- a/amt/amt-wsman-comm.js +++ b/amt/amt-wsman-comm.js @@ -1,6 +1,6 @@ /** * @description Intel(r) AMT WSMAN communication using Node.js TLS -* @author Ylian Saint-Hilaire +* @author Ylian Saint-Hilaire/Joko Sastriawan * @version v0.2.0b */ @@ -39,7 +39,7 @@ var CreateWsmanComm = function (host, port, user, pass, tls, tlsoptions, parent, obj.xtls = tls; obj.xtlsoptions = tlsoptions; obj.parent = parent; - obj.mode = mode;//0: webrelay; 1: direct, 2: CIRA, 3: APF relay + obj.mode = mode;//1: direct, 2: CIRA, 3: APF relay obj.xtlsFingerprint; obj.xtlsCertificate = null; obj.xtlsCheck = 0; // 0 = No TLS, 1 = CA Checked, 2 = Pinned, 3 = Untrusted @@ -167,17 +167,7 @@ var CreateWsmanComm = function (host, port, user, pass, tls, tlsoptions, parent, obj.socketState = 1; obj.kerberosDone = 0; - if (obj.mode==0 && obj.xtlsoptions && obj.xtlsoptions.meshServerConnect) { //Webrelay - // Use the websocket wrapper to connect to MeshServer server - obj.socket = CreateWebSocketWrapper(obj.xtlsoptions.host, obj.xtlsoptions.port, '/webrelay.ashx?user=' + encodeURIComponent(obj.xtlsoptions.username) + '&pass=' + encodeURIComponent(obj.xtlsoptions.password) + '&host=' + encodeURIComponent(obj.host) + '&p=1&tls1only=' + obj.xtlsMethod, obj.xtlsoptions.xtlsFingerprint); - obj.socket.setEncoding('binary'); - obj.socket.setTimeout(6000); // Set socket idle timeout - obj.socket.ondata = obj.xxOnSocketData; - obj.socket.onclose = function () { if (obj.xtlsDataReceived == false) { obj.xtlsMethod = 1 - obj.xtlsMethod; } obj.xxOnSocketClosed(); } - obj.socket.ontimeout = function () { if (obj.xtlsDataReceived == false) { obj.xtlsMethod = 1 - obj.xtlsMethod; } obj.xxOnSocketClosed(); } - obj.socket.connect(obj.xxOnSocketConnected); - obj.socket.setNoDelay(true); // Disable nagle. We will encode each WSMAN request as a single send block and want to send it at once. This may help Intel AMT handle pipelining? - } else if (obj.mode==1 ) { //Direct + if (obj.mode==1 ) { //Direct if (obj.xtls != 1) { // Connect without TLS obj.socket = new obj.net.Socket(); @@ -214,7 +204,7 @@ var CreateWsmanComm = function (host, port, user, pass, tls, tlsoptions, parent, obj.socket = obj.parent.apfserver.SetupCiraChannel(apfconn, obj.port); } obj.socket.onData = function (ccon, data) { - _OnSocketData(data); + obj.xxOnSocketData(data); } obj.socket.onStateChange = function (ccon, state) { @@ -225,11 +215,11 @@ var CreateWsmanComm = function (host, port, user, pass, tls, tlsoptions, parent, obj.socketHeader = null; obj.socketData = ''; obj.socketState = 0; - _OnSocketClosed(); + obj.xxOnSocketClosed(); } catch (e) { } } else if (state == 2) { // channel open success - _OnSocketConnected(); + obj.xxOnSocketConnected(); } } } @@ -289,8 +279,8 @@ var CreateWsmanComm = function (host, port, user, pass, tls, tlsoptions, parent, // NODE.js specific private method obj.xxOnSocketData = function (data) { - obj.xtlsDataReceived = true; - if (urlvars && urlvars['wsmantrace']) { console.log("WSMAN-RECV(" + data.length + "): " + data); } + //console.log("RECV:"+data); + obj.xtlsDataReceived = true; if (typeof data === 'object') { // This is an ArrayBuffer, convert it to a string array (used in IE) var binary = "", bytes = new Uint8Array(data), length = bytes.byteLength; @@ -305,7 +295,7 @@ var CreateWsmanComm = function (host, port, user, pass, tls, tlsoptions, parent, if (obj.socketParseState == 0) { var headersize = obj.socketAccumulator.indexOf("\r\n\r\n"); if (headersize < 0) return; - //obj.Debug(obj.socketAccumulator.substring(0, headersize)); // Display received HTTP header + //obj.Debug("Header: "+obj.socketAccumulator.substring(0, headersize)); // Display received HTTP header obj.socketHeader = obj.socketAccumulator.substring(0, headersize).split("\r\n"); if (obj.amtVersion == null) { for (var i in obj.socketHeader) { if (obj.socketHeader[i].indexOf('Server: Intel(R) Active Management Technology ') == 0) { obj.amtVersion = obj.socketHeader[i].substring(46); } } } obj.socketAccumulator = obj.socketAccumulator.substring(headersize + 4); @@ -361,8 +351,10 @@ var CreateWsmanComm = function (host, port, user, pass, tls, tlsoptions, parent, var s = parseInt(header.Directive[1]); if (isNaN(s)) s = 500; if (s == 401 && ++(obj.authcounter) < 3) { - obj.challengeParams = obj.parseDigest(header['www-authenticate']); // Set the digest parameters, after this, the socket will close and we will auto-retry - obj.socket.end(); + obj.challengeParams = obj.parseDigest(header['www-authenticate']); // Set the digest parameters, after this, the socket will close and we will auto-retry + if (obj.mode==1) { + obj.socket.end(); + } } else { var r = obj.pendingAjaxCall.shift(); if (r == null || r.length < 1) { console.log("pendingAjaxCall error, " + r); return; } @@ -378,7 +370,7 @@ var CreateWsmanComm = function (host, port, user, pass, tls, tlsoptions, parent, obj.xxOnSocketClosed = function (data) { //obj.Debug("xxOnSocketClosed"); obj.socketState = 0; - if (obj.socket != null) { obj.socket.destroy(); obj.socket = null; } + if (obj.mode ==1 && obj.socket != null) { obj.socket.destroy(); obj.socket = null; } if (obj.pendingAjaxCall.length > 0) { var r = obj.pendingAjaxCall.shift(); var retry = r[5]; @@ -389,8 +381,7 @@ var CreateWsmanComm = function (host, port, user, pass, tls, tlsoptions, parent, // NODE.js specific private method obj.xxSend = function (x) { if (obj.socketState == 2) { - if (urlvars && urlvars['wsmantrace']) { console.log("WSMAN-SEND(" + x.length + "): " + x); } - obj.socket.write(new Buffer(x, "binary")); + obj.socket.write(Buffer.from(x, "binary")); } } diff --git a/amt/amt-wsman.js b/amt/amt-wsman.js index 88f71bde..4dc38aa5 100644 --- a/amt/amt-wsman.js +++ b/amt/amt-wsman.js @@ -16,12 +16,12 @@ limitations under the License. /** * @description Intel(r) AMT WSMAN Stack -* @author Ylian Saint-Hilaire +* @author Ylian Saint-Hilaire/Joko Sastriawan * @version v0.2.0 */ // Construct a MeshServer object -function WsmanStackCreateService(CreateWsmanComm, host, port, user, pass, tls, extra) +function WsmanStackCreateService(CreateWsmanComm, host, port, user, pass, tls, extra, parent, mode) { var obj = {_ObjectID: 'WSMAN'}; //obj.onDebugMessage = null; // Set to a function if you want to get debug messages. @@ -38,7 +38,7 @@ function WsmanStackCreateService(CreateWsmanComm, host, port, user, pass, tls, e { var CreateWsmanComm = arguments[0]; if (CreateWsmanComm) { - obj.comm = new CreateWsmanComm(host, port, user, pass, tls, extra); + obj.comm = new CreateWsmanComm(host, port, user, pass, tls, extra, parent, mode); } } diff --git a/meshuser.js b/meshuser.js index 52a1ad68..629b316d 100644 --- a/meshuser.js +++ b/meshuser.js @@ -48,6 +48,11 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use obj.user = user; obj.domain = domain; + // Server side amt stack + var WsmanComm = require('./amt/amt-wsman-comm.js'); + var Wsman = require('./amt/amt-wsman.js'); + var Amt = require('./amt/amt.js'); + // Send a message to the user //obj.send = function (data) { try { if (typeof data == 'string') { ws.send(Buffer.from(data, 'binary')); } else { ws.send(data); } } catch (e) { } } @@ -2784,6 +2789,39 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use } break; } + case 'amt': { + if (common.validateString(command.nodeid, 1, 1024) == false) break; // Check nodeid + if (common.validateInt(command.mode, 0, 3) == false) break; // Check connection mode + // validate if communication mode is possible + if (command.mode == null || command.mode==0) { + break;//unsupported + } else if (command.mode == 1) { + var state = parent.parent.GetConnectivityState(command.nodeid); + if ( (state == null) || (state.connectivity & 4)==0 ) break; + } else if (command.mode == 2) { + if (parent.parent.mpsserver.ciraConnections[command.nodeid] == null) break; + } else if (command.mode == 3) { + if (parent.parent.apfserver.apfConnections[command.nodeid] == null) break; + } + var nodeid = command.nodeid; + if ((nodeid.split('/').length == 3) && (nodeid.split('/')[1] == domain.id)) { // Validate the domain, operation only valid for current domain + // Get the device + db.Get(nodeid, function (err, nodes) { + if ((nodes == null) || (nodes.length != 1)) return; + var node = nodes[0]; + + // Get the mesh for this device + mesh = parent.meshes[node.meshid]; + if (mesh) { + // Check if this user has rights to do this + if (mesh.links[user._id] != null && ((mesh.links[user._id].rights & 8) != 0)) { // "Remote Control permission" + handleAmtCommand(command, node); + } + } + }); + } + break; + } default: { // Unknown user action console.log('Unknown action from user ' + user.name + ': ' + command.action + '.'); @@ -2912,5 +2950,33 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use function getRandomPassword() { return Buffer.from(parent.crypto.randomBytes(9), 'binary').toString('base64').split('/').join('@'); } + function handleAmtCommand(cmd, node) { + if (cmd==null) return; + var host = cmd.nodeid; + if (cmd.mode==1) { + host = node.host; + } + var tlsoptions = null; + var wsman = new Wsman(WsmanComm, host, node.intelamt.tls? 16993: 16992, node.intelamt.user, node.intelamt.pass, + node.intelamt.tls,tlsoptions, parent.parent, cmd.mode); + var amt = new Amt(wsman); + switch (cmd.command) { + case "Get-GeneralSettings": { + amt.Get("AMT_GeneralSettings", function(obj, name, response, status) { + if (status==200) { + var resp = { action: 'amt', nodeid: cmd.nodeid, command: 'Get-GeneralSettings', value: response.Body} + ws.send(JSON.stringify(resp)); + } else { + ws.send(JSON.stringify({"error": error})); + } + }); + break; + } + default: { + // do nothing + } + } + } + return obj; }; \ No newline at end of file diff --git a/mpsserver.js b/mpsserver.js index 8be3c95c..764fd28e 100644 --- a/mpsserver.js +++ b/mpsserver.js @@ -791,8 +791,8 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) { return true; } // Send a part of the message - cirachannel.sendBuffer = data.substring(cirachannel.sendcredits); - SendChannelData(cirachannel.socket, cirachannel.amtchannelid, data.substring(0, cirachannel.sendcredits)); + cirachannel.sendBuffer = data.toString('binary').substring(cirachannel.sendcredits); + SendChannelData(cirachannel.socket, cirachannel.amtchannelid, data.toString('binary').substring(0, cirachannel.sendcredits)); cirachannel.sendcredits = 0; return false; };