diff --git a/agents/meshcore_diagnostic.js b/agents/meshcore_diagnostic.js
index 81d6cb0b09..2c8ec3eea7 100644
--- a/agents/meshcore_diagnostic.js
+++ b/agents/meshcore_diagnostic.js
@@ -85,9 +85,9 @@ function DownloadAgentBinary(path, ID)
{
var options = require('http').parseUri(require('MeshAgent').ServerInfo.ServerUri);
var downloadUri = 'https://' + options.host + ':' + options.port + '/meshagents?id=' + (ID != null ? ID : getARCHID());
- sendServerLog('Diagnostic: Attempting to downlod agent from: ' + downloadUri);
+ sendServerLog('Diagnostic: Attempting to download agent from: ' + downloadUri);
- return (wget(downloadUri, path, { rejectUnauthorized: false }));
+ return (wget(downloadUri, path));
}
function giveup()
@@ -204,3 +204,4 @@ function start()
}
}
};
+
diff --git a/agents/modules_meshcmd/amt-wsman.js b/agents/modules_meshcmd/amt-wsman.js
index 280c617d72..41e67d906b 100644
--- a/agents/modules_meshcmd/amt-wsman.js
+++ b/agents/modules_meshcmd/amt-wsman.js
@@ -63,7 +63,7 @@ function WsmanStackCreateService(/*CreateWsmanComm, host, port, user, pass, tls,
// Perform a WSMAN Subscribe operation
obj.ExecSubscribe = function ExecSubscribe(resuri, delivery, url, callback, tag, pri, selectors, opaque, user, pass) {
- var digest = "", digest2 = "", opaque = "";
+ var digest = "", digest2 = "";
if (user != null && pass != null) { digest = 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#UsernameToken' + user + '' + pass + ''; digest2 = ''; }
if (opaque != null) { opaque = '' + opaque + ''; }
if (delivery == 'PushWithAck') { delivery = 'dmtf.org/wbem/wsman/1/wsman/PushWithAck'; } else if (delivery == 'Push') { delivery = 'xmlsoap.org/ws/2004/08/eventing/DeliveryModes/Push'; }
diff --git a/agents/modules_meshcore/sysinfo.js b/agents/modules_meshcore/sysinfo.js
index cc13574dde..23d33824d5 100644
--- a/agents/modules_meshcore/sysinfo.js
+++ b/agents/modules_meshcore/sysinfo.js
@@ -218,12 +218,13 @@ function macos_memUtilization()
mem.MemTotal = (mem.MemFree + mem.MemUsed);
mem.percentFree = ((mem.MemFree / mem.MemTotal) * 100);//.toFixed(2);
mem.percentConsumed = (((mem.MemTotal - mem.MemFree) / mem.MemTotal) * 100);//.toFixed(2);
- return (mem);
+ ret._res(mem);
}
else
{
- throw ('Parse Error');
+ ret._rej('Parse Error');
}
+ return (ret);
}
function windows_thermals()
@@ -243,7 +244,7 @@ function windows_thermals()
function linux_thermals()
{
var ret = [];
- child = require('child_process').execFile('/bin/sh', ['sh']);
+ var child = require('child_process').execFile('/bin/sh', ['sh']);
child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); });
child.stderr.str = ''; child.stderr.on('data', function (c) { this.str += c.toString(); });
child.stdin.write("for folder in /sys/class/thermal/thermal_zone*/; do [ -e \"$folder/temp\" ] && echo \"$(cat \"$folder/temp\"),$(cat \"$folder/type\")\"; done\nexit\n");
diff --git a/agents/modules_meshcore/wifi-scanner.js b/agents/modules_meshcore/wifi-scanner.js
index fa3681d9cf..c805c7918b 100644
--- a/agents/modules_meshcore/wifi-scanner.js
+++ b/agents/modules_meshcore/wifi-scanner.js
@@ -81,7 +81,7 @@ function WiFiScanner()
this.child.ms.on('end', function ()
{
var str = this.buffer.toString();
- tokens = str.split(' - Address: ');
+ var tokens = str.split(' - Address: ');
for (var block in tokens)
{
if (block == 0) continue;
diff --git a/agents/modules_meshcore/win-deskutils.js b/agents/modules_meshcore/win-deskutils.js
index 70531a5e11..ad92c6b00c 100644
--- a/agents/modules_meshcore/win-deskutils.js
+++ b/agents/modules_meshcore/win-deskutils.js
@@ -104,7 +104,7 @@ function sessionDispatch(tsid, parent, method, args)
//
function background_get(tsid)
{
- if (tsid != null || tsid === null) // TSID is not undefined or is explicitly null
+ if (tsid !== undefined) // TSID is not undefined
{
// Need to disatch to different session first
return (sessionDispatch(tsid, 'background', 'get', []));
@@ -123,7 +123,7 @@ function background_get(tsid)
//
function background_set(path, tsid)
{
- if (tsid != null || tsid === null) // TSID is not undefined or is explicitly null
+ if (tsid !== undefined) // TSID is not undefined
{
// Need to disatch to different session first
return (sessionDispatch(tsid, 'background', 'set', [path]));
@@ -160,7 +160,7 @@ function dispatch(parent, method, args)
//
function mousetrails_set(value, tsid)
{
- if (tsid != null || tsid === null) // TSID is not undefined or is explicitly null
+ if (tsid !== undefined) // TSID is not undefined
{
// Need to disatch to different session first
return (sessionDispatch(tsid, 'mouse', 'setTrails', [value]));
@@ -178,7 +178,7 @@ function mousetrails_set(value, tsid)
//
function mousetrails_get(tsid)
{
- if (tsid != null || tsid === null) // TSID is not undefined or is explicitly null
+ if (tsid !== undefined) // TSID is not undefined
{
// Need to disatch to different session first
return (sessionDispatch(tsid, 'mouse', 'getTrails', []));
@@ -205,7 +205,7 @@ function mousetrails_get(tsid)
//
function idle_getSeconds(tsid)
{
- if (tsid != null || tsid === null) // TSID is not undefined or is explicitly null
+ if (tsid !== undefined) // TSID is not undefined
{
// Need to dispatch to different session first
return (sessionDispatch(tsid, 'idle', 'getSeconds', []));
@@ -296,4 +296,4 @@ function idle_getSecondsAllSessions()
module.exports = { background: { get: background_get, set: background_set } };
module.exports.mouse = { getTrails: mousetrails_get, setTrails: mousetrails_set };
module.exports.idle = { getSeconds: idle_getSeconds, getSecondsAllSessions: idle_getSecondsAllSessions };
-module.exports.dispatch = dispatch;
\ No newline at end of file
+module.exports.dispatch = dispatch;
diff --git a/agents/modules_meshcore/win-volumes.js b/agents/modules_meshcore/win-volumes.js
index 59e87c1a2e..85b15ee54d 100644
--- a/agents/modules_meshcore/win-volumes.js
+++ b/agents/modules_meshcore/win-volumes.js
@@ -102,6 +102,7 @@ function windows_volumes()
var germanpass = (abc !== '' && abc.includes('Kennwort:') && !abc.includes('Numerisches Kennwort:')); // German Password
var frenchpass = (abc !== '' && abc.includes('Mot de passe :') && !abc.includes('Mot de passe num')); // French Password
if (englishidpass || germanidpass || frenchidpass|| englishpass || germanpass || frenchpass) {
+ if (x + 1 >= lines.length) { continue; }
var nextline = lines[x + 1].trim();
if (x + 1 < lines.length && (nextline !== '' && (nextline.startsWith('ID:') || nextline.startsWith('ID :')) )) {
identifier = nextline.replace('ID:','').replace('ID :', '').trim();
@@ -125,4 +126,4 @@ function windows_volumes()
module.exports = {
getVolumes: function () { try { return (getVolumes()); } catch (x) { return ({}); } },
volumes_promise: windows_volumes
-};
\ No newline at end of file
+};
diff --git a/amt/amt-wsman-comm.js b/amt/amt-wsman-comm.js
index 25acdba012..661be456aa 100644
--- a/amt/amt-wsman-comm.js
+++ b/amt/amt-wsman-comm.js
@@ -1,537 +1,537 @@
-/*
-Copyright 2020-2021 Intel Corporation
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-
-@description Intel AMT WSMAN communication module for NodeJS
-@author Ylian Saint-Hilaire
-@version v0.3.0
-*/
-
-/*jslint node: true */
-/*jshint node: true */
-/*jshint strict:false */
-/*jshint -W097 */
-/*jshint esversion: 6 */
-"use strict";
-
-// Construct a WSMAN stack communication object
-var CreateWsmanComm = function (host, port, user, pass, tls, tlsoptions, mpsConnection) {
- //console.log('CreateWsmanComm', host, port, user, pass, tls, tlsoptions);
-
- var obj = {};
- obj.PendingAjax = []; // List of pending AJAX calls. When one frees up, another will start.
- obj.ActiveAjaxCount = 0; // Number of currently active AJAX calls
- obj.MaxActiveAjaxCount = 1; // Maximum number of activate AJAX calls at the same time.
- obj.FailAllError = 0; // Set this to non-zero to fail all AJAX calls with that error status, 999 causes responses to be silent.
- obj.challengeParams = null;
- obj.noncecounter = 1;
- obj.authcounter = 0;
-
- obj.net = require('net');
- obj.tls = require('tls');
- obj.crypto = require('crypto');
- obj.constants = require('constants');
- obj.socket = null;
- obj.socketState = 0;
- obj.kerberosDone = 0;
- obj.amtVersion = null;
-
- obj.Address = '/wsman';
- obj.cnonce = obj.crypto.randomBytes(16).toString('hex'); // Generate a random client nonce
-
- obj.host = host;
- obj.port = port;
- obj.user = user;
- obj.pass = pass;
- obj.xtls = tls;
- obj.xtlsoptions = tlsoptions;
- obj.mpsConnection = mpsConnection; // Link to a MPS connection, this can be CIRA, Relay or LMS. If null, local sockets are used as transport.
- obj.xtlsFingerprint;
- obj.xtlsCertificate = null;
- obj.xtlsCheck = 0; // 0 = No TLS, 1 = CA Checked, 2 = Pinned, 3 = Untrusted
- obj.xtlsSkipHostCheck = 0;
- obj.xtlsMethod = 0;
- obj.xtlsDataReceived = false;
- obj.digestRealmMatch = null;
- obj.digestRealm = null;
-
- // 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) { try { this.push(chunk); } catch (ex) { } };
- 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) {
- if ((obj.ActiveAjaxCount == 0 || ((obj.ActiveAjaxCount < obj.MaxActiveAjaxCount) && (obj.challengeParams != null))) && obj.PendingAjax.length == 0) {
- // There are no pending AJAX calls, perform the call now.
- obj.PerformAjaxEx(postdata, callback, tag, url, action);
- } else {
- // If this is a high priority call, put this call in front of the array, otherwise put it in the back.
- if (pri == 1) { obj.PendingAjax.unshift([postdata, callback, tag, url, action]); } else { obj.PendingAjax.push([postdata, callback, tag, url, action]); }
- }
- }
-
- // Private method
- obj.PerformNextAjax = function () {
- if (obj.ActiveAjaxCount >= obj.MaxActiveAjaxCount || obj.PendingAjax.length == 0) return;
- var x = obj.PendingAjax.shift();
- obj.PerformAjaxEx(x[0], x[1], x[2], x[3], x[4]);
- obj.PerformNextAjax();
- }
-
- // Private method
- obj.PerformAjaxEx = function (postdata, callback, tag, url, action) {
- if (obj.FailAllError != 0) { obj.gotNextMessagesError({ status: obj.FailAllError }, 'error', null, [postdata, callback, tag, url, action]); return; }
- if (!postdata) postdata = '';
- //obj.Debug('SEND: ' + postdata); // DEBUG
-
- obj.ActiveAjaxCount++;
- return obj.PerformAjaxExNodeJS(postdata, callback, tag, url, action);
- }
-
- // NODE.js specific private method
- obj.pendingAjaxCall = [];
-
- // NODE.js specific private method
- obj.PerformAjaxExNodeJS = function (postdata, callback, tag, url, action) { obj.PerformAjaxExNodeJS2(postdata, callback, tag, url, action, 5); }
-
- // NODE.js specific private method
- obj.PerformAjaxExNodeJS2 = function (postdata, callback, tag, url, action, retry) {
- if ((retry <= 0) || (obj.FailAllError != 0)) {
- // Too many retry, fail here.
- obj.ActiveAjaxCount--;
- if (obj.FailAllError != 999) obj.gotNextMessages(null, 'error', { status: ((obj.FailAllError == 0) ? 408 : obj.FailAllError) }, [postdata, callback, tag, url, action]); // 408 is timeout error
- obj.PerformNextAjax();
- return;
- }
- obj.pendingAjaxCall.push([postdata, callback, tag, url, action, retry]);
- if (obj.socketState == 0) { obj.xxConnectHttpSocket(); }
- else if (obj.socketState == 2) { obj.sendRequest(postdata, url, action); }
- }
-
- // NODE.js specific private method
- obj.sendRequest = function (postdata, url, action) {
- url = url ? url : '/wsman';
- action = action ? action : 'POST';
- var h = action + ' ' + url + ' HTTP/1.1\r\n';
- if (obj.challengeParams != null) {
- obj.digestRealm = obj.challengeParams['realm'];
- if (obj.digestRealmMatch && (obj.digestRealm != obj.digestRealmMatch)) {
- obj.FailAllError = 997; // Cause all new responses to be silent. 997 = Digest Realm check error
- obj.CancelAllQueries(997);
- return;
- }
- }
- if ((obj.user == '*') && (kerberos != null)) {
- // Kerberos Auth
- if (obj.kerberosDone == 0) {
- var ticketName = 'HTTP' + ((obj.tls == 1) ? 'S' : '') + '/' + ((obj.pass == '') ? (obj.host + ':' + obj.port) : obj.pass);
- // Ask for the new Kerberos ticket
- //console.log('kerberos.getTicket', ticketName);
- var ticketReturn = kerberos.getTicket(ticketName);
- if (ticketReturn.returnCode == 0 || ticketReturn.returnCode == 0x90312) {
- h += 'Authorization: Negotiate ' + ticketReturn.ticket + '\r\n';
- if (process.platform.indexOf('win') >= 0) {
- // Clear kerberos tickets on both 32 and 64bit Windows platforms
- try { require('child_process').exec('%windir%\\system32\\klist purge', function (error, stdout, stderr) { if (error) { require('child_process').exec('%windir%\\sysnative\\klist purge', function (error, stdout, stderr) { if (error) { console.error('Unable to purge kerberos tickets'); } }); } }); } catch (e) { console.log(e); }
- }
- } else {
- console.log('Unexpected Kerberos error code: ' + ticketReturn.returnCode);
- }
- obj.kerberosDone = 1;
- }
- } else if (obj.challengeParams != null) {
- var response = hex_md5(hex_md5(obj.user + ':' + obj.challengeParams['realm'] + ':' + obj.pass) + ':' + obj.challengeParams['nonce'] + ':' + nonceHex(obj.noncecounter) + ':' + obj.cnonce + ':' + obj.challengeParams['qop'] + ':' + hex_md5(action + ':' + url + ((obj.challengeParams['qop'] == 'auth-int') ? (':' + hex_md5(postdata)) : '')));
- h += 'Authorization: ' + obj.renderDigest({ 'username': obj.user, 'realm': obj.challengeParams['realm'], 'nonce': obj.challengeParams['nonce'], 'uri': url, 'qop': obj.challengeParams['qop'], 'response': response, 'nc': nonceHex(obj.noncecounter++), 'cnonce': obj.cnonce }) + '\r\n';
- }
- h += 'Host: ' + obj.host + ':' + obj.port + '\r\nContent-Length: ' + postdata.length + '\r\n\r\n' + postdata; // Use Content-Length
- //h += 'Host: ' + obj.host + ':' + obj.port + '\r\nTransfer-Encoding: chunked\r\n\r\n' + postdata.length.toString(16).toUpperCase() + '\r\n' + postdata + '\r\n0\r\n\r\n'; // Use Chunked-Encoding
- obj.xxSend(h);
- //console.log('SEND: ' + h); // Display send packet
- }
-
- // Parse the HTTP digest header and return a list of key & values.
- obj.parseDigest = function (header) { return correctedQuoteSplit(header.substring(7)).reduce(function (obj, s) { var parts = s.trim().split('='); obj[parts[0]] = parts[1].replace(new RegExp('\"', 'g'), ''); return obj; }, {}) }
-
- // Split a string on quotes but do not do it when in quotes
- function correctedQuoteSplit(str) { return str.split(',').reduce(function (a, c) { if (a.ic) { a.st[a.st.length - 1] += ',' + c } else { a.st.push(c) } if (c.split('"').length % 2 == 0) { a.ic = !a.ic } return a; }, { st: [], ic: false }).st }
- function nonceHex(v) { var s = ('00000000' + v.toString(16)); return s.substring(s.length - 8); }
-
- // NODE.js specific private method
- obj.renderDigest = function (params) {
- var paramsnames = [];
- for (var i in params) { paramsnames.push(i); }
- return 'Digest ' + paramsnames.reduce(function (s1, ii) { return s1 + ',' + (((ii == 'nc') || (ii == 'qop')) ? (ii + '=' + params[ii]) : (ii + '="' + params[ii] + '"')); }, '').substring(1);
- }
-
- // NODE.js specific private method
- obj.xxConnectHttpSocket = function () {
- //obj.Debug("xxConnectHttpSocket");
- obj.socketParseState = 0;
- obj.socketAccumulator = '';
- obj.socketHeader = null;
- obj.socketData = '';
- obj.socketState = 1;
- obj.kerberosDone = 0;
-
- if (obj.mpsConnection != null) {
- if (obj.xtls != 1) {
- // Setup a new channel using the CIRA/Relay/LMS connection
- obj.socket = obj.mpsConnection.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) {
- // Channel closed
- obj.socketParseState = 0;
- obj.socketAccumulator = '';
- obj.socketHeader = null;
- obj.socketData = '';
- obj.socketState = 0;
- 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.mpsConnection.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) { try { obj.cirasocket.write(msg); } catch (ex) { } }; // 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 | obj.constants.SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION, rejectUnauthorized: false };
- if (obj.xtlsMethod == 1) {
- options.secureProtocol = 'TLSv1_method';
- } else {
- options.minVersion = 'TLSv1';
- }
- 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 = obj.tls.connect(obj.port, obj.host, options, obj.xxOnSocketConnected);
- obj.socket.setEncoding('binary');
- obj.socket.setTimeout(60000); // Set socket idle timeout
- obj.socket.on('error', function (ex) { obj.xtlsMethod = 1 - obj.xtlsMethod; });
- obj.socket.on('close', obj.xxOnSocketClosed);
- obj.socket.on('timeout', obj.destroy);
-
- // 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
- if (obj.xtls != 1) {
- // Direct connect without TLS
- obj.socket = new obj.net.Socket();
- obj.socket.setEncoding('binary');
- obj.socket.setTimeout(60000); // Set socket idle timeout
- obj.socket.on('data', obj.xxOnSocketData);
- obj.socket.on('close', obj.xxOnSocketClosed);
- obj.socket.on('timeout', obj.destroy);
- obj.socket.on('error', obj.xxOnSocketClosed);
- obj.socket.connect(obj.port, obj.host, obj.xxOnSocketConnected);
- } else {
- // Direct connect with TLS
- var options = { 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 | obj.constants.SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION, rejectUnauthorized: false };
- if (obj.xtlsMethod == 1) {
- options.secureProtocol = 'TLSv1_method';
- } else {
- options.minVersion = 'TLSv1';
- }
- 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 = obj.tls.connect(obj.port, obj.host, options, obj.xxOnSocketConnected);
- obj.socket.setEncoding('binary');
- obj.socket.setTimeout(28000); // Set socket idle timeout of 28 seconds
- obj.socket.on('data', obj.xxOnSocketData);
- obj.socket.on('close', obj.xxOnSocketClosed);
- obj.socket.on('timeout', obj.destroy);
- obj.socket.on('error', function (ex) { if (ex.message && ex.message.indexOf('sslv3 alert bad record mac') >= 0) { obj.xtlsMethod = 1 - obj.xtlsMethod; } });
- }
- 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?
- }
- }
-
- // Get the certificate of Intel AMT
- obj.getPeerCertificate = function () { if (obj.xtls == 1) { return obj.socket.getPeerCertificate(); } return null; }
- obj.getPeerCertificateFingerprint = function () { if (obj.xtls == 1) { return obj.socket.getPeerCertificate().fingerprint.split(':').join('').toLowerCase(); } return null; }
-
- // Check if the certificate matched the certificate hash.
- function checkCertHash(cert, hash) {
- // Check not required
- if (hash == 0) return true;
-
- // SHA1 compare
- if (cert.fingerprint.split(':').join('').toLowerCase() == hash) return true;
-
- // SHA256 compare
- if ((hash.length == 64) && (obj.crypto.createHash('sha256').update(cert.raw).digest('hex') == hash)) { return true; }
-
- // SHA384 compare
- if ((hash.length == 96) && (obj.crypto.createHash('sha384').update(cert.raw).digest('hex') == hash)) { return true; }
-
- return false;
- }
-
- // NODE.js specific private method
- obj.xxOnSocketConnected = function () {
- if (obj.socket == null) return;
- // check TLS certificate for webrelay and direct only
- if (obj.xtls == 1) {
- obj.xtlsCertificate = obj.socket.getPeerCertificate();
-
- // Setup the forge certificate check
- var camatch = 0;
- if ((obj.xtlsoptions != null) && (obj.xtlsoptions.ca != null)) {
- var forgeCert = forge.pki.certificateFromAsn1(forge.asn1.fromDer(atob(obj.xtlsCertificate.raw.toString('base64'))));
- var caStore = forge.pki.createCaStore(obj.xtlsoptions.ca);
- // Got thru all certificates in the store and look for a match.
- for (var i in caStore.certs) {
- if (camatch == 0) {
- var c = caStore.certs[i], verified = false;
- try { verified = c.verify(forgeCert); } catch (e) { }
- if (verified == true) { camatch = c; }
- }
- }
- // We found a match, check that the CommonName matches the hostname
- if ((obj.xtlsSkipHostCheck == 0) && (camatch != 0)) {
- amtcertname = forgeCert.subject.getField('CN').value;
- if (amtcertname.toLowerCase() != obj.host.toLowerCase()) { camatch = 0; }
- }
- }
- if ((camatch == 0) && (checkCertHash(obj.xtlsCertificate, obj.xtlsFingerprint) == false)) {
- obj.FailAllError = 998; // Cause all new responses to be silent. 998 = TLS Certificate check error
- obj.CancelAllQueries(998);
- return;
- }
- if ((obj.xtlsFingerprint == 0) && (camatch == 0)) { obj.xtlsCheck = 3; } else { obj.xtlsCheck = (camatch == 0) ? 2 : 1; }
- } else { obj.xtlsCheck = 0; }
- obj.socketState = 2;
- obj.socketParseState = 0;
- for (i in obj.pendingAjaxCall) { obj.sendRequest(obj.pendingAjaxCall[i][0], obj.pendingAjaxCall[i][3], obj.pendingAjaxCall[i][4]); }
- }
-
- // NODE.js specific private method
- obj.xxOnSocketData = function (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;
- for (var i = 0; i < length; i++) { binary += String.fromCharCode(bytes[i]); }
- data = binary;
- }
- else if (typeof data !== 'string') return;
-
- obj.socketAccumulator += data;
- while (true) {
- //console.log('ACC(' + obj.socketAccumulator + '): ' + obj.socketAccumulator);
- if (obj.socketParseState == 0) {
- var headersize = obj.socketAccumulator.indexOf('\r\n\r\n');
- if (headersize < 0) return;
- //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);
- obj.socketParseState = 1;
- obj.socketData = '';
- obj.socketXHeader = { Directive: obj.socketHeader[0].split(' ') };
- for (i in obj.socketHeader) {
- if (i != 0) {
- var x2 = obj.socketHeader[i].indexOf(':');
- obj.socketXHeader[obj.socketHeader[i].substring(0, x2).toLowerCase()] = obj.socketHeader[i].substring(x2 + 2);
- }
- }
- }
- if (obj.socketParseState == 1) {
- var csize = -1;
- if ((obj.socketXHeader['connection'] != undefined) && (obj.socketXHeader['connection'].toLowerCase() == 'close') && ((obj.socketXHeader["transfer-encoding"] == undefined) || (obj.socketXHeader["transfer-encoding"].toLowerCase() != 'chunked'))) {
- // The body ends with a close, in this case, we will only process the header
- csize = 0;
- } else if (obj.socketXHeader['content-length'] != undefined) {
- // The body length is specified by the content-length
- csize = parseInt(obj.socketXHeader['content-length']);
- if (obj.socketAccumulator.length < csize) return;
- var data = obj.socketAccumulator.substring(0, csize);
- obj.socketAccumulator = obj.socketAccumulator.substring(csize);
- obj.socketData = data;
- csize = 0;
- } else {
- // The body is chunked
- var clen = obj.socketAccumulator.indexOf('\r\n');
- if (clen < 0) return; // Chunk length not found, exit now and get more data.
- // Chunk length if found, lets see if we can get the data.
- csize = parseInt(obj.socketAccumulator.substring(0, clen), 16);
- if (obj.socketAccumulator.length < clen + 2 + csize + 2) return;
- // We got a chunk with all of the data, handle the chunck now.
- var data = obj.socketAccumulator.substring(clen + 2, clen + 2 + csize);
- obj.socketAccumulator = obj.socketAccumulator.substring(clen + 2 + csize + 2);
- try { obj.socketData += data; } catch (ex) { console.log(ex, typeof data, data.length); }
- }
- if (csize == 0) {
- //obj.Debug("xxOnSocketData DONE: (" + obj.socketData.length + "): " + obj.socketData);
- obj.xxProcessHttpResponse(obj.socketXHeader, obj.socketData);
- obj.socketParseState = 0;
- obj.socketHeader = null;
- }
- }
- }
- }
-
- // NODE.js specific private method
- obj.xxProcessHttpResponse = function (header, data) {
- //obj.Debug("xxProcessHttpResponse: " + header.Directive[1]);
-
- 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
- if (obj.challengeParams['qop'] != null) {
- var qopList = obj.challengeParams['qop'].split(',');
- for (var i in qopList) { qopList[i] = qopList[i].trim(); }
- if (qopList.indexOf('auth-int') >= 0) { obj.challengeParams['qop'] = 'auth-int'; } else { obj.challengeParams['qop'] = 'auth'; }
- }
- if (obj.mpsConnection == null) { obj.socket.end(); } else { obj.socket.close(); }
- } else {
- var r = obj.pendingAjaxCall.shift();
- if ((r == null) || (r.length < 1)) { /*console.log("pendingAjaxCall error, " + r);*/ return; } // Get a response without any pending requests.
- //if (s != 200) { obj.Debug("Error, status=" + s + "\r\n\r\nreq=" + r[0] + "\r\n\r\nresp=" + data); } // Debug: Display the request & response if something did not work.
- obj.authcounter = 0;
- obj.ActiveAjaxCount--;
- obj.gotNextMessages(data, 'success', { status: s }, r);
- obj.PerformNextAjax();
- }
- }
-
- // NODE.js specific private method
- obj.xxOnSocketClosed = function () {
- //obj.Debug("xxOnSocketClosed");
- obj.socketState = 0;
- if (obj.socket != null) {
- if (obj.socket.removeAllListeners) {
- // Do not remove the error handler since it may still get triggered.
- obj.socket.removeAllListeners('data');
- obj.socket.removeAllListeners('close');
- obj.socket.removeAllListeners('timeout');
- }
- try {
- if (obj.mpsConnection == 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];
- setTimeout(function () { obj.PerformAjaxExNodeJS2(r[0], r[1], r[2], r[3], r[4], --retry) }, 500); // Wait half a second and try again
- }
- }
-
- obj.destroy = function () {
- if (obj.socket != null) {
- if (obj.socket.removeAllListeners) {
- // Do not remove the error handler since it may still get triggered.
- obj.socket.removeAllListeners('data');
- obj.socket.removeAllListeners('close');
- obj.socket.removeAllListeners('timeout');
- }
- try {
- if (obj.mpsConnection == null) {
- obj.socket.destroy();
- } else {
- if (obj.cirasocket != null) { obj.cirasocket.close(); } else { obj.socket.close(); }
- }
- } catch (ex) { }
- delete obj.socket;
- delete obj.cirasocket;
- obj.socketState = 0;
- }
- }
-
- // NODE.js specific private method
- obj.xxSend = function (x) {
- //console.log('xxSend', x);
- if (obj.socketState == 2) { obj.socket.write(Buffer.from(x, 'binary')); }
- }
-
- // Cancel all pending queries with given status
- obj.CancelAllQueries = function (s) {
- obj.FailAllError = s;
- while (obj.PendingAjax.length > 0) { var x = obj.PendingAjax.shift(); x[1](null, s, x[2]); }
- obj.destroy();
- }
-
- // Private method
- obj.gotNextMessages = function (data, status, request, callArgs) {
- if (obj.FailAllError == 999) return;
- if (obj.FailAllError != 0) { try { callArgs[1](null, obj.FailAllError, callArgs[2]); } catch (ex) { console.error(ex); } return; }
- if (request.status != 200) { try { callArgs[1](null, request.status, callArgs[2]); } catch (ex) { console.error(ex); } return; }
- try { callArgs[1](data, 200, callArgs[2]); } catch (ex) { console.error(ex); }
- }
-
- // Private method
- obj.gotNextMessagesError = function (request, status, errorThrown, callArgs) {
- if (obj.FailAllError == 999) return;
- if (obj.FailAllError != 0) { try { callArgs[1](null, obj.FailAllError, callArgs[2]); } catch (ex) { console.error(ex); } return; }
- try { callArgs[1](obj, null, { Header: { HttpError: request.status } }, request.status, callArgs[2]); } catch (ex) { console.error(ex); }
- }
-
- // MD5 digest hash
- function hex_md5(str) { return obj.crypto.createHash('md5').update(str).digest('hex'); }
-
- return obj;
-}
-
-module.exports = CreateWsmanComm;
\ No newline at end of file
+/*
+Copyright 2020-2021 Intel Corporation
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+@description Intel AMT WSMAN communication module for NodeJS
+@author Ylian Saint-Hilaire
+@version v0.3.0
+*/
+
+/*jslint node: true */
+/*jshint node: true */
+/*jshint strict:false */
+/*jshint -W097 */
+/*jshint esversion: 6 */
+"use strict";
+
+// Construct a WSMAN stack communication object
+var CreateWsmanComm = function (host, port, user, pass, tls, tlsoptions, mpsConnection) {
+ //console.log('CreateWsmanComm', host, port, user, pass, tls, tlsoptions);
+
+ var obj = {};
+ obj.PendingAjax = []; // List of pending AJAX calls. When one frees up, another will start.
+ obj.ActiveAjaxCount = 0; // Number of currently active AJAX calls
+ obj.MaxActiveAjaxCount = 1; // Maximum number of activate AJAX calls at the same time.
+ obj.FailAllError = 0; // Set this to non-zero to fail all AJAX calls with that error status, 999 causes responses to be silent.
+ obj.challengeParams = null;
+ obj.noncecounter = 1;
+ obj.authcounter = 0;
+
+ obj.net = require('net');
+ obj.tls = require('tls');
+ obj.crypto = require('crypto');
+ obj.constants = require('constants');
+ obj.socket = null;
+ obj.socketState = 0;
+ obj.kerberosDone = 0;
+ obj.amtVersion = null;
+
+ obj.Address = '/wsman';
+ obj.cnonce = obj.crypto.randomBytes(16).toString('hex'); // Generate a random client nonce
+
+ obj.host = host;
+ obj.port = port;
+ obj.user = user;
+ obj.pass = pass;
+ obj.xtls = tls;
+ obj.xtlsoptions = tlsoptions;
+ obj.mpsConnection = mpsConnection; // Link to a MPS connection, this can be CIRA, Relay or LMS. If null, local sockets are used as transport.
+ obj.xtlsFingerprint;
+ obj.xtlsCertificate = null;
+ obj.xtlsCheck = 0; // 0 = No TLS, 1 = CA Checked, 2 = Pinned, 3 = Untrusted
+ obj.xtlsSkipHostCheck = 0;
+ obj.xtlsMethod = 0;
+ obj.xtlsDataReceived = false;
+ obj.digestRealmMatch = null;
+ obj.digestRealm = null;
+
+ // 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) { try { this.push(chunk); } catch (ex) { } };
+ obj._write = function (chunk, encoding, callback) { if (obj.forwardwrite != null) { obj.forwardwrite(chunk); } else { console.error("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) {
+ if ((obj.ActiveAjaxCount == 0 || ((obj.ActiveAjaxCount < obj.MaxActiveAjaxCount) && (obj.challengeParams != null))) && obj.PendingAjax.length == 0) {
+ // There are no pending AJAX calls, perform the call now.
+ obj.PerformAjaxEx(postdata, callback, tag, url, action);
+ } else {
+ // If this is a high priority call, put this call in front of the array, otherwise put it in the back.
+ if (pri == 1) { obj.PendingAjax.unshift([postdata, callback, tag, url, action]); } else { obj.PendingAjax.push([postdata, callback, tag, url, action]); }
+ }
+ }
+
+ // Private method
+ obj.PerformNextAjax = function () {
+ if (obj.ActiveAjaxCount >= obj.MaxActiveAjaxCount || obj.PendingAjax.length == 0) return;
+ var x = obj.PendingAjax.shift();
+ obj.PerformAjaxEx(x[0], x[1], x[2], x[3], x[4]);
+ obj.PerformNextAjax();
+ }
+
+ // Private method
+ obj.PerformAjaxEx = function (postdata, callback, tag, url, action) {
+ if (obj.FailAllError != 0) { obj.gotNextMessagesError({ status: obj.FailAllError }, 'error', null, [postdata, callback, tag, url, action]); return; }
+ if (!postdata) postdata = '';
+ //obj.Debug('SEND: ' + postdata); // DEBUG
+
+ obj.ActiveAjaxCount++;
+ return obj.PerformAjaxExNodeJS(postdata, callback, tag, url, action);
+ }
+
+ // NODE.js specific private method
+ obj.pendingAjaxCall = [];
+
+ // NODE.js specific private method
+ obj.PerformAjaxExNodeJS = function (postdata, callback, tag, url, action) { obj.PerformAjaxExNodeJS2(postdata, callback, tag, url, action, 5); }
+
+ // NODE.js specific private method
+ obj.PerformAjaxExNodeJS2 = function (postdata, callback, tag, url, action, retry) {
+ if ((retry <= 0) || (obj.FailAllError != 0)) {
+ // Too many retry, fail here.
+ obj.ActiveAjaxCount--;
+ if (obj.FailAllError != 999) obj.gotNextMessages(null, 'error', { status: ((obj.FailAllError == 0) ? 408 : obj.FailAllError) }, [postdata, callback, tag, url, action]); // 408 is timeout error
+ obj.PerformNextAjax();
+ return;
+ }
+ obj.pendingAjaxCall.push([postdata, callback, tag, url, action, retry]);
+ if (obj.socketState == 0) { obj.xxConnectHttpSocket(); }
+ else if (obj.socketState == 2) { obj.sendRequest(postdata, url, action); }
+ }
+
+ // NODE.js specific private method
+ obj.sendRequest = function (postdata, url, action) {
+ url = url ? url : '/wsman';
+ action = action ? action : 'POST';
+ var h = action + ' ' + url + ' HTTP/1.1\r\n';
+ if (obj.challengeParams != null) {
+ obj.digestRealm = obj.challengeParams['realm'];
+ if (obj.digestRealmMatch && (obj.digestRealm != obj.digestRealmMatch)) {
+ obj.FailAllError = 997; // Cause all new responses to be silent. 997 = Digest Realm check error
+ obj.CancelAllQueries(997);
+ return;
+ }
+ }
+ if ((obj.user == '*') && (kerberos != null)) {
+ // Kerberos Auth
+ if (obj.kerberosDone == 0) {
+ var ticketName = 'HTTP' + ((obj.tls == 1) ? 'S' : '') + '/' + ((obj.pass == '') ? (obj.host + ':' + obj.port) : obj.pass);
+ // Ask for the new Kerberos ticket
+ //console.log('kerberos.getTicket', ticketName);
+ var ticketReturn = kerberos.getTicket(ticketName);
+ if (ticketReturn.returnCode == 0 || ticketReturn.returnCode == 0x90312) {
+ h += 'Authorization: Negotiate ' + ticketReturn.ticket + '\r\n';
+ if (process.platform.indexOf('win') >= 0) {
+ // Clear kerberos tickets on both 32 and 64bit Windows platforms
+ try { require('child_process').exec('%windir%\\system32\\klist purge', function (error, stdout, stderr) { if (error) { require('child_process').exec('%windir%\\sysnative\\klist purge', function (error, stdout, stderr) { if (error) { console.error('Unable to purge kerberos tickets'); } }); } }); } catch (e) { console.log(e); }
+ }
+ } else {
+ console.log('Unexpected Kerberos error code: ' + ticketReturn.returnCode);
+ }
+ obj.kerberosDone = 1;
+ }
+ } else if (obj.challengeParams != null) {
+ var response = hex_md5(hex_md5(obj.user + ':' + obj.challengeParams['realm'] + ':' + obj.pass) + ':' + obj.challengeParams['nonce'] + ':' + nonceHex(obj.noncecounter) + ':' + obj.cnonce + ':' + obj.challengeParams['qop'] + ':' + hex_md5(action + ':' + url + ((obj.challengeParams['qop'] == 'auth-int') ? (':' + hex_md5(postdata)) : '')));
+ h += 'Authorization: ' + obj.renderDigest({ 'username': obj.user, 'realm': obj.challengeParams['realm'], 'nonce': obj.challengeParams['nonce'], 'uri': url, 'qop': obj.challengeParams['qop'], 'response': response, 'nc': nonceHex(obj.noncecounter++), 'cnonce': obj.cnonce }) + '\r\n';
+ }
+ h += 'Host: ' + obj.host + ':' + obj.port + '\r\nContent-Length: ' + postdata.length + '\r\n\r\n' + postdata; // Use Content-Length
+ //h += 'Host: ' + obj.host + ':' + obj.port + '\r\nTransfer-Encoding: chunked\r\n\r\n' + postdata.length.toString(16).toUpperCase() + '\r\n' + postdata + '\r\n0\r\n\r\n'; // Use Chunked-Encoding
+ obj.xxSend(h);
+ //console.log('SEND: ' + h); // Display send packet
+ }
+
+ // Parse the HTTP digest header and return a list of key & values.
+ obj.parseDigest = function (header) { return correctedQuoteSplit(header.substring(7)).reduce(function (obj, s) { var parts = s.trim().split('='); obj[parts[0]] = parts[1].replace(new RegExp('\"', 'g'), ''); return obj; }, {}) }
+
+ // Split a string on quotes but do not do it when in quotes
+ function correctedQuoteSplit(str) { return str.split(',').reduce(function (a, c) { if (a.ic) { a.st[a.st.length - 1] += ',' + c } else { a.st.push(c) } if (c.split('"').length % 2 == 0) { a.ic = !a.ic } return a; }, { st: [], ic: false }).st }
+ function nonceHex(v) { var s = ('00000000' + v.toString(16)); return s.substring(s.length - 8); }
+
+ // NODE.js specific private method
+ obj.renderDigest = function (params) {
+ var paramsnames = [];
+ for (var i in params) { paramsnames.push(i); }
+ return 'Digest ' + paramsnames.reduce(function (s1, ii) { return s1 + ',' + (((ii == 'nc') || (ii == 'qop')) ? (ii + '=' + params[ii]) : (ii + '="' + params[ii] + '"')); }, '').substring(1);
+ }
+
+ // NODE.js specific private method
+ obj.xxConnectHttpSocket = function () {
+ //obj.Debug("xxConnectHttpSocket");
+ obj.socketParseState = 0;
+ obj.socketAccumulator = '';
+ obj.socketHeader = null;
+ obj.socketData = '';
+ obj.socketState = 1;
+ obj.kerberosDone = 0;
+
+ if (obj.mpsConnection != null) {
+ if (obj.xtls != 1) {
+ // Setup a new channel using the CIRA/Relay/LMS connection
+ obj.socket = obj.mpsConnection.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) {
+ // Channel closed
+ obj.socketParseState = 0;
+ obj.socketAccumulator = '';
+ obj.socketHeader = null;
+ obj.socketData = '';
+ obj.socketState = 0;
+ 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.mpsConnection.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) { try { obj.cirasocket.write(msg); } catch (ex) { } }; // 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 | obj.constants.SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION, rejectUnauthorized: false };
+ if (obj.xtlsMethod == 1) {
+ options.secureProtocol = 'TLSv1_method';
+ } else {
+ options.minVersion = 'TLSv1';
+ }
+ 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 = obj.tls.connect(obj.port, obj.host, options, obj.xxOnSocketConnected);
+ obj.socket.setEncoding('binary');
+ obj.socket.setTimeout(60000); // Set socket idle timeout
+ obj.socket.on('error', function (ex) { obj.xtlsMethod = 1 - obj.xtlsMethod; });
+ obj.socket.on('close', obj.xxOnSocketClosed);
+ obj.socket.on('timeout', obj.destroy);
+
+ // 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
+ if (obj.xtls != 1) {
+ // Direct connect without TLS
+ obj.socket = new obj.net.Socket();
+ obj.socket.setEncoding('binary');
+ obj.socket.setTimeout(60000); // Set socket idle timeout
+ obj.socket.on('data', obj.xxOnSocketData);
+ obj.socket.on('close', obj.xxOnSocketClosed);
+ obj.socket.on('timeout', obj.destroy);
+ obj.socket.on('error', obj.xxOnSocketClosed);
+ obj.socket.connect(obj.port, obj.host, obj.xxOnSocketConnected);
+ } else {
+ // Direct connect with TLS
+ var options = { 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 | obj.constants.SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION, rejectUnauthorized: false };
+ if (obj.xtlsMethod == 1) {
+ options.secureProtocol = 'TLSv1_method';
+ } else {
+ options.minVersion = 'TLSv1';
+ }
+ 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 = obj.tls.connect(obj.port, obj.host, options, obj.xxOnSocketConnected);
+ obj.socket.setEncoding('binary');
+ obj.socket.setTimeout(28000); // Set socket idle timeout of 28 seconds
+ obj.socket.on('data', obj.xxOnSocketData);
+ obj.socket.on('close', obj.xxOnSocketClosed);
+ obj.socket.on('timeout', obj.destroy);
+ obj.socket.on('error', function (ex) { if (ex.message && ex.message.indexOf('sslv3 alert bad record mac') >= 0) { obj.xtlsMethod = 1 - obj.xtlsMethod; } });
+ }
+ 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?
+ }
+ }
+
+ // Get the certificate of Intel AMT
+ obj.getPeerCertificate = function () { if (obj.xtls == 1) { return obj.socket.getPeerCertificate(); } return null; }
+ obj.getPeerCertificateFingerprint = function () { if (obj.xtls == 1) { return obj.socket.getPeerCertificate().fingerprint.split(':').join('').toLowerCase(); } return null; }
+
+ // Check if the certificate matched the certificate hash.
+ function checkCertHash(cert, hash) {
+ // Check not required
+ if (hash == 0) return true;
+
+ // SHA1 compare
+ if (cert.fingerprint.split(':').join('').toLowerCase() == hash) return true;
+
+ // SHA256 compare
+ if ((hash.length == 64) && (obj.crypto.createHash('sha256').update(cert.raw).digest('hex') == hash)) { return true; }
+
+ // SHA384 compare
+ if ((hash.length == 96) && (obj.crypto.createHash('sha384').update(cert.raw).digest('hex') == hash)) { return true; }
+
+ return false;
+ }
+
+ // NODE.js specific private method
+ obj.xxOnSocketConnected = function () {
+ if (obj.socket == null) return;
+ // check TLS certificate for webrelay and direct only
+ if (obj.xtls == 1) {
+ obj.xtlsCertificate = obj.socket.getPeerCertificate();
+
+ // Setup the forge certificate check
+ var camatch = 0;
+ if ((obj.xtlsoptions != null) && (obj.xtlsoptions.ca != null)) {
+ var forgeCert = forge.pki.certificateFromAsn1(forge.asn1.fromDer(atob(obj.xtlsCertificate.raw.toString('base64'))));
+ var caStore = forge.pki.createCaStore(obj.xtlsoptions.ca);
+ // Got thru all certificates in the store and look for a match.
+ for (var i in caStore.certs) {
+ if (camatch == 0) {
+ var c = caStore.certs[i], verified = false;
+ try { verified = c.verify(forgeCert); } catch (e) { }
+ if (verified == true) { camatch = c; }
+ }
+ }
+ // We found a match, check that the CommonName matches the hostname
+ if ((obj.xtlsSkipHostCheck == 0) && (camatch != 0)) {
+ amtcertname = forgeCert.subject.getField('CN').value;
+ if (amtcertname.toLowerCase() != obj.host.toLowerCase()) { camatch = 0; }
+ }
+ }
+ if ((camatch == 0) && (checkCertHash(obj.xtlsCertificate, obj.xtlsFingerprint) == false)) {
+ obj.FailAllError = 998; // Cause all new responses to be silent. 998 = TLS Certificate check error
+ obj.CancelAllQueries(998);
+ return;
+ }
+ if ((obj.xtlsFingerprint == 0) && (camatch == 0)) { obj.xtlsCheck = 3; } else { obj.xtlsCheck = (camatch == 0) ? 2 : 1; }
+ } else { obj.xtlsCheck = 0; }
+ obj.socketState = 2;
+ obj.socketParseState = 0;
+ for (i in obj.pendingAjaxCall) { obj.sendRequest(obj.pendingAjaxCall[i][0], obj.pendingAjaxCall[i][3], obj.pendingAjaxCall[i][4]); }
+ }
+
+ // NODE.js specific private method
+ obj.xxOnSocketData = function (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;
+ for (var i = 0; i < length; i++) { binary += String.fromCharCode(bytes[i]); }
+ data = binary;
+ }
+ else if (typeof data !== 'string') return;
+
+ obj.socketAccumulator += data;
+ while (true) {
+ //console.log('ACC(' + obj.socketAccumulator + '): ' + obj.socketAccumulator);
+ if (obj.socketParseState == 0) {
+ var headersize = obj.socketAccumulator.indexOf('\r\n\r\n');
+ if (headersize < 0) return;
+ //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);
+ obj.socketParseState = 1;
+ obj.socketData = '';
+ obj.socketXHeader = { Directive: obj.socketHeader[0].split(' ') };
+ for (i in obj.socketHeader) {
+ if (i != 0) {
+ var x2 = obj.socketHeader[i].indexOf(':');
+ obj.socketXHeader[obj.socketHeader[i].substring(0, x2).toLowerCase()] = obj.socketHeader[i].substring(x2 + 2);
+ }
+ }
+ }
+ if (obj.socketParseState == 1) {
+ var csize = -1;
+ if ((obj.socketXHeader['connection'] != undefined) && (obj.socketXHeader['connection'].toLowerCase() == 'close') && ((obj.socketXHeader["transfer-encoding"] == undefined) || (obj.socketXHeader["transfer-encoding"].toLowerCase() != 'chunked'))) {
+ // The body ends with a close, in this case, we will only process the header
+ csize = 0;
+ } else if (obj.socketXHeader['content-length'] != undefined) {
+ // The body length is specified by the content-length
+ csize = parseInt(obj.socketXHeader['content-length']);
+ if (obj.socketAccumulator.length < csize) return;
+ var data = obj.socketAccumulator.substring(0, csize);
+ obj.socketAccumulator = obj.socketAccumulator.substring(csize);
+ obj.socketData = data;
+ csize = 0;
+ } else {
+ // The body is chunked
+ var clen = obj.socketAccumulator.indexOf('\r\n');
+ if (clen < 0) return; // Chunk length not found, exit now and get more data.
+ // Chunk length if found, lets see if we can get the data.
+ csize = parseInt(obj.socketAccumulator.substring(0, clen), 16);
+ if (obj.socketAccumulator.length < clen + 2 + csize + 2) return;
+ // We got a chunk with all of the data, handle the chunck now.
+ var data = obj.socketAccumulator.substring(clen + 2, clen + 2 + csize);
+ obj.socketAccumulator = obj.socketAccumulator.substring(clen + 2 + csize + 2);
+ try { obj.socketData += data; } catch (ex) { console.log(ex, typeof data, data.length); }
+ }
+ if (csize == 0) {
+ //obj.Debug("xxOnSocketData DONE: (" + obj.socketData.length + "): " + obj.socketData);
+ obj.xxProcessHttpResponse(obj.socketXHeader, obj.socketData);
+ obj.socketParseState = 0;
+ obj.socketHeader = null;
+ }
+ }
+ }
+ }
+
+ // NODE.js specific private method
+ obj.xxProcessHttpResponse = function (header, data) {
+ //obj.Debug("xxProcessHttpResponse: " + header.Directive[1]);
+
+ 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
+ if (obj.challengeParams['qop'] != null) {
+ var qopList = obj.challengeParams['qop'].split(',');
+ for (var i in qopList) { qopList[i] = qopList[i].trim(); }
+ if (qopList.indexOf('auth-int') >= 0) { obj.challengeParams['qop'] = 'auth-int'; } else { obj.challengeParams['qop'] = 'auth'; }
+ }
+ if (obj.mpsConnection == null) { obj.socket.end(); } else { obj.socket.close(); }
+ } else {
+ var r = obj.pendingAjaxCall.shift();
+ if ((r == null) || (r.length < 1)) { /*console.log("pendingAjaxCall error, " + r);*/ return; } // Get a response without any pending requests.
+ //if (s != 200) { obj.Debug("Error, status=" + s + "\r\n\r\nreq=" + r[0] + "\r\n\r\nresp=" + data); } // Debug: Display the request & response if something did not work.
+ obj.authcounter = 0;
+ obj.ActiveAjaxCount--;
+ obj.gotNextMessages(data, 'success', { status: s }, r);
+ obj.PerformNextAjax();
+ }
+ }
+
+ // NODE.js specific private method
+ obj.xxOnSocketClosed = function () {
+ //obj.Debug("xxOnSocketClosed");
+ obj.socketState = 0;
+ if (obj.socket != null) {
+ if (obj.socket.removeAllListeners) {
+ // Do not remove the error handler since it may still get triggered.
+ obj.socket.removeAllListeners('data');
+ obj.socket.removeAllListeners('close');
+ obj.socket.removeAllListeners('timeout');
+ }
+ try {
+ if (obj.mpsConnection == 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];
+ setTimeout(function () { obj.PerformAjaxExNodeJS2(r[0], r[1], r[2], r[3], r[4], --retry) }, 500); // Wait half a second and try again
+ }
+ }
+
+ obj.destroy = function () {
+ if (obj.socket != null) {
+ if (obj.socket.removeAllListeners) {
+ // Do not remove the error handler since it may still get triggered.
+ obj.socket.removeAllListeners('data');
+ obj.socket.removeAllListeners('close');
+ obj.socket.removeAllListeners('timeout');
+ }
+ try {
+ if (obj.mpsConnection == null) {
+ obj.socket.destroy();
+ } else {
+ if (obj.cirasocket != null) { obj.cirasocket.close(); } else { obj.socket.close(); }
+ }
+ } catch (ex) { }
+ delete obj.socket;
+ delete obj.cirasocket;
+ obj.socketState = 0;
+ }
+ }
+
+ // NODE.js specific private method
+ obj.xxSend = function (x) {
+ //console.log('xxSend', x);
+ if (obj.socketState == 2) { obj.socket.write(Buffer.from(x, 'binary')); }
+ }
+
+ // Cancel all pending queries with given status
+ obj.CancelAllQueries = function (s) {
+ obj.FailAllError = s;
+ while (obj.PendingAjax.length > 0) { var x = obj.PendingAjax.shift(); x[1](null, s, x[2]); }
+ obj.destroy();
+ }
+
+ // Private method
+ obj.gotNextMessages = function (data, status, request, callArgs) {
+ if (obj.FailAllError == 999) return;
+ if (obj.FailAllError != 0) { try { callArgs[1](null, obj.FailAllError, callArgs[2]); } catch (ex) { console.error(ex); } return; }
+ if (request.status != 200) { try { callArgs[1](null, request.status, callArgs[2]); } catch (ex) { console.error(ex); } return; }
+ try { callArgs[1](data, 200, callArgs[2]); } catch (ex) { console.error(ex); }
+ }
+
+ // Private method
+ obj.gotNextMessagesError = function (request, status, errorThrown, callArgs) {
+ if (obj.FailAllError == 999) return;
+ if (obj.FailAllError != 0) { try { callArgs[1](null, obj.FailAllError, callArgs[2]); } catch (ex) { console.error(ex); } return; }
+ try { callArgs[1](obj, null, { Header: { HttpError: request.status } }, request.status, callArgs[2]); } catch (ex) { console.error(ex); }
+ }
+
+ // MD5 digest hash
+ function hex_md5(str) { return obj.crypto.createHash('md5').update(str).digest('hex'); }
+
+ return obj;
+}
+
+module.exports = CreateWsmanComm;
diff --git a/amtprovisioningserver.js b/amtprovisioningserver.js
index d31b7b8387..47da4e3f35 100644
--- a/amtprovisioningserver.js
+++ b/amtprovisioningserver.js
@@ -39,7 +39,7 @@ module.exports.CreateAmtProvisioningServer = function (parent, config) {
socket.on('error', function (err) { })
socket.on('close', function () { if (this.data != null) { processHelloData(this.data, this.ra); } delete this.ra; this.removeAllListeners(); })
socket.on('data', function (data) {
- if (this.data == null) { this.data = data; } else { Buffer.concat([this.data, data]); }
+ if (this.data == null) { this.data = data; } else { this.data = Buffer.concat([this.data, data]); }
var str = this.data.toString();
if (str.startsWith('GET ') && (str.indexOf('\r\n\r\n') >= 0)) {
this.data = null;
@@ -696,3 +696,4 @@ module.exports.CreateAmtProvisioningServer = function (parent, config) {
return obj;
};
+
diff --git a/interceptor.js b/interceptor.js
index c6e4a87820..dafe85eb25 100644
--- a/interceptor.js
+++ b/interceptor.js
@@ -86,7 +86,7 @@ module.exports.CreateHttpInterceptor = function (args) {
} else if (obj.amt.mode == 1) { // Length Body Mode
// Send the body of content-length size
var rl = obj.amt.count;
- if (rl < obj.amt.acc.length) rl = obj.amt.acc.length;
+ if (rl > obj.amt.acc.length) rl = obj.amt.acc.length;
r = obj.amt.acc.substring(0, rl);
obj.amt.acc = obj.amt.acc.substring(rl);
obj.amt.count -= rl;
@@ -197,38 +197,38 @@ module.exports.CreateHttpInterceptor = function (args) {
} else if (obj.ws.mode == 1) { // Length Body Mode
// Send the body of content-length size
var rl = obj.ws.count;
- if (rl < obj.ws.acc.length) rl = obj.ws.acc.length;
+ if (rl > obj.ws.acc.length) rl = obj.ws.acc.length;
r = obj.ws.acc.substring(0, rl);
obj.ws.acc = obj.ws.acc.substring(rl);
obj.ws.count -= rl;
if (obj.ws.count == 0) { obj.ws.mode = 0; }
return r;
- } else if (obj.amt.mode == 2) { // Chunked Body Mode
+ } else if (obj.ws.mode == 2) { // Chunked Body Mode
// Send data one chunk at a time
- headerend = obj.amt.acc.indexOf('\r\n');
+ headerend = obj.ws.acc.indexOf('\r\n');
if (headerend < 0) return '';
- var chunksize = parseInt(obj.amt.acc.substring(0, headerend), 16);
+ var chunksize = parseInt(obj.ws.acc.substring(0, headerend), 16);
if (isNaN(chunksize)) { // TODO: Check this path
// Chunk is not in this batch, move one
- r = obj.amt.acc.substring(0, headerend + 2);
- obj.amt.acc = obj.amt.acc.substring(headerend + 2);
+ r = obj.ws.acc.substring(0, headerend + 2);
+ obj.ws.acc = obj.ws.acc.substring(headerend + 2);
// Peek if we next is the end of chunked transfer
- headerend = obj.amt.acc.indexOf('\r\n');
+ headerend = obj.ws.acc.indexOf('\r\n');
if (headerend > 0) {
- chunksize = parseInt(obj.amt.acc.substring(0, headerend), 16);
- if (chunksize == 0) { obj.amt.mode = 0; }
+ chunksize = parseInt(obj.ws.acc.substring(0, headerend), 16);
+ if (chunksize == 0) { obj.ws.mode = 0; }
}
return r;
- } else if (chunksize == 0 && obj.amt.acc.length >= headerend + 4) {
+ } else if (chunksize == 0 && obj.ws.acc.length >= headerend + 4) {
// Send the ending chunk (NOTE: We do not support trailing headers)
- r = obj.amt.acc.substring(0, headerend + 4);
- obj.amt.acc = obj.amt.acc.substring(headerend + 4);
- obj.amt.mode = 0;
+ r = obj.ws.acc.substring(0, headerend + 4);
+ obj.ws.acc = obj.ws.acc.substring(headerend + 4);
+ obj.ws.mode = 0;
return r;
- } else if (chunksize > 0 && obj.amt.acc.length >= headerend + 4) {
+ } else if (chunksize > 0 && obj.ws.acc.length >= headerend + 4) {
// Send a chunk
- r = obj.amt.acc.substring(0, headerend + chunksize + 4);
- obj.amt.acc = obj.amt.acc.substring(headerend + chunksize + 4);
+ r = obj.ws.acc.substring(0, headerend + chunksize + 4);
+ obj.ws.acc = obj.ws.acc.substring(headerend + chunksize + 4);
return r;
}
} else if (obj.ws.mode == 3) { // Until Close Mode
@@ -457,4 +457,4 @@ module.exports.CreateRedirInterceptor = function (args) {
};
return obj;
-};
\ No newline at end of file
+};
diff --git a/mcrec.js b/mcrec.js
index 6761227807..be632218e4 100644
--- a/mcrec.js
+++ b/mcrec.js
@@ -233,7 +233,7 @@ function readLastBlock(state, func) {
var xtype = buf2.readUInt16BE(0); // Type (1 = Header, 2 = Network Data, 3 = End, 4 = Extra Metadata)
var xflags = buf2.readUInt16BE(2); // Flags (1 = Binary, 2 = User)
var xsize = buf2.readUInt32BE(4); // Size
- var xtime = buf.readUIntBE(10, 6); // Time
+ var xtime = buf2.readUIntBE(10, 6); // Time
var buf3 = Buffer.alloc(xsize);
fs.read(state.recFile, buf3, 0, xsize, time + 16, function (err, bytesRead, buf3) {
func(state, true, xtime, JSON.parse(buf3.toString()));
@@ -331,4 +331,4 @@ if (directRun) { setup(); }
// Export table
module.exports.startEx = startEx;
-module.exports.indexFile = indexFile;
\ No newline at end of file
+module.exports.indexFile = indexFile;
diff --git a/monitoring.js b/monitoring.js
index c73e688b9a..84c8b9d72a 100644
--- a/monitoring.js
+++ b/monitoring.js
@@ -40,7 +40,7 @@ module.exports.CreateMonitoring = function (parent, args) {
ConnectedUsers: { description: "Connected Users" }, // Object.keys(parent.webserver.wssessions).length
UsersSessions: { description: "Users Sessions" }, // Object.keys(parent.webserver.wssessions2).length
RelaySessions: { description: "Relay Sessions" }, // parent.webserver.relaySessionCount
- RelayCount: { description: "Relay Count" } // Object.keys(parent.webserver.wsrelays).length30bb4fb74dfb758d36be52a7
+ RelayCount: { description: "Relay Count" } // Object.keys(parent.webserver.wsrelays).length
}
obj.collectors = [];
if (parent.config.settings.prometheus != null) { // Create Prometheus Monitoring Endpoint
@@ -119,4 +119,4 @@ module.exports.CreateMonitoring = function (parent, args) {
}
}
return obj;
-}
\ No newline at end of file
+}
diff --git a/pkcs7-modified.js b/pkcs7-modified.js
index 661904a6bb..5f36b2248d 100644
--- a/pkcs7-modified.js
+++ b/pkcs7-modified.js
@@ -27,7 +27,7 @@ try {
require('../node-forge/lib/pkcs7asn1');
require('../node-forge/lib/random');
require('../node-forge/lib/util');
- require('../node-forge/lib/x509'); f
+ require('../node-forge/lib/x509');
} catch (ex) { }
if (forge == null) {
@@ -1277,3 +1277,4 @@ function _decryptContent(msg) {
msg.content = ciph.output;
}
}
+
diff --git a/public/js/ui-components.js b/public/js/ui-components.js
index 7bc6c88fc7..8645704aa0 100644
--- a/public/js/ui-components.js
+++ b/public/js/ui-components.js
@@ -32,24 +32,6 @@ class ModernModal {
const sizeClass = this.options.size === 'large' ? 'modal-lg' :
this.options.size === 'extra-large' ? 'modal-xl' : '';
- let modalContent = `
-
- `;
-
setModalContent(this.modalId, title, content, this.options.size);
if (okCallback) {
@@ -393,3 +375,4 @@ if (typeof module !== 'undefined' && module.exports) {
createIconUploadComponent
};
}
+
diff --git a/public/novnc/core/ra2.js b/public/novnc/core/ra2.js
index d330b848d2..cf6523e825 100644
--- a/public/novnc/core/ra2.js
+++ b/public/novnc/core/ra2.js
@@ -10,7 +10,7 @@ class RA2Cipher {
async setKey(key) {
this._cipher = await legacyCrypto.importKey(
- "raw", key, { name: "AES-EAX" }, false, ["encrypt, decrypt"]);
+ "raw", key, { name: "AES-EAX" }, false, ["encrypt", "decrypt"]);
}
async makeMessage(message) {
diff --git a/public/scripts/agent-redir-rtc-0.1.0-min.js b/public/scripts/agent-redir-rtc-0.1.0-min.js
index e08bad4f13..bdca523441 100644
--- a/public/scripts/agent-redir-rtc-0.1.0-min.js
+++ b/public/scripts/agent-redir-rtc-0.1.0-min.js
@@ -1 +1 @@
-var CreateKvmDataChannel=function(e,t,n){var a={};a.m=t,t.parent=a,a.webchannel=e,a.State=0,a.protocol=t.protocol,a.onStateChanged=null,a.onControlMsg=null,a.debugmode=0,a.keepalive=n,a.rtcKeepAlive=null,a.Start=function(){1==a.debugmode&&console.log("start"),a.xxStateChange(3),a.webchannel.onmessage=a.xxOnMessage,a.rtcKeepAlive=setInterval(a.xxSendRtcKeepAlive,3e4)};var r=new FileReader,o=!1,l=[];return r.readAsBinaryString?r.onload=function(e){a.xxOnSocketData(e.target.result),0==l.length?o=!1:r.readAsBinaryString(new Blob([l.shift()]))}:r.readAsArrayBuffer&&(r.onloadend=function(e){a.xxOnSocketData(e.target.result),0==l.length?o=!1:r.readAsArrayBuffer(l.shift())}),a.xxOnMessage=function(e){if("string"!=typeof e.data)if("object"==typeof e.data){if(1==o)return void l.push(e.data);if(r.readAsBinaryString)o=!0,r.readAsBinaryString(new Blob([e.data]));else if(f.readAsArrayBuffer)o=!0,r.readAsArrayBuffer(e.data);else{for(var t="",n=new Uint8Array(e.data),i=n.byteLength,s=0;s 30) {
nextTagNumber = new type.UInt8().read(s).value;
}
@@ -109,3 +110,4 @@ module.exports = {
decode : decode,
encode : encode
};
+
diff --git a/rdp/core/log.js b/rdp/core/log.js
index c2eb6a8e88..b1e826c2b4 100644
--- a/rdp/core/log.js
+++ b/rdp/core/log.js
@@ -67,19 +67,15 @@ module.exports = {
level: Levels.INFO, // Levels.INFO,
Levels: Levels,
debug: function (message) {
- //console.log(message);
- //logger.debug(message);
+ log('DEBUG', message);
},
info: function (message) {
- //console.log(message);
- //logger.info(message);
+ log('INFO', message);
},
warn: function (message) {
- //console.log(message);
- //logger.warn(message);
+ log('WARN', message);
},
error: function (message) {
- //console.log(message);
- //logger.error(message);
+ log('ERROR', message);
}
};
diff --git a/rdp/protocol/cert.js b/rdp/protocol/cert.js
index 9f9ecc6331..0c80a80f05 100644
--- a/rdp/protocol/cert.js
+++ b/rdp/protocol/cert.js
@@ -24,7 +24,7 @@ var rsa = require('../security').rsa;
var asn1 = require('../asn1');
/**
- * @see http://msdn.microsoft.com/en-us/library/cc240521.aspx
+ * @see http://msdn.microsoft.com/en-us/library/cc240521.aspx
*/
var CertificateType = {
CERT_CHAIN_VERSION_1 : 0x00000001,
@@ -158,7 +158,7 @@ function certificate() {
self.certData = x509CertificateChain().read(s);
break;
default:
- log.error('unknown cert type ' + self.dwVersion.value & 0x7fffffff);
+ log.error('unknown cert type ' + (self.dwVersion.value & 0x7fffffff));
}
})
};
@@ -172,4 +172,4 @@ function certificate() {
module.exports = {
CertificateType : CertificateType,
certificate : certificate
-};
\ No newline at end of file
+};
diff --git a/rdp/protocol/pdu/data.js b/rdp/protocol/pdu/data.js
index dec3ffd8f2..66957e286f 100644
--- a/rdp/protocol/pdu/data.js
+++ b/rdp/protocol/pdu/data.js
@@ -128,16 +128,6 @@ var UpdateType = {
UPDATETYPE_SYNCHRONIZE : 0x0003
};
-/**
- * @see http://msdn.microsoft.com/en-us/library/cc240608.aspx
- */
-var UpdateType = {
- UPDATETYPE_ORDERS : 0x0000,
- UPDATETYPE_BITMAP : 0x0001,
- UPDATETYPE_PALETTE : 0x0002,
- UPDATETYPE_SYNCHRONIZE : 0x0003
-};
-
/**
* @see http://msdn.microsoft.com/en-us/library/cc240583.aspx
*/
@@ -704,7 +694,7 @@ function clientInputEventPDU(inputs, opt) {
return self.slowPathInputEvents.obj.length;
}),
pad2Octets : new type.UInt16Le(),
- slowPathInputEvents : inputs || new type.Factory(function(s) {
+ slowPathInputEvents : inputs || new type.Factory(function(s) {
self.slowPathInputEvents = new type.Component([]);
for(var i = 0; i < self.numEvents.value; i++) {
self.slowPathInputEvents.obj.push(slowPathInputEvent().read(s));
@@ -871,7 +861,7 @@ function bitmapUpdateDataPDU(data, opt) {
numberRectangles : new type.UInt16Le(function() {
return self.rectangles.obj.length;
}),
- rectangles : data || new type.Factory(function(s) {
+ rectangles : data || new type.Factory(function(s) {
self.rectangles = new type.Component([]);
for(var i = 0; i < self.numberRectangles.value; i++) {
self.rectangles.obj.push(bitmapData().read(s));
@@ -943,7 +933,7 @@ function dataPDU(pduData, shareId, opt) {
}), function() {
return self.pduData.obj.__PDUTYPE2__;
}, shareId),
- pduData : pduData || new type.Factory(function(s) {
+ pduData : pduData || new type.Factory(function(s) {
//compute local readLength
var options = { readLength : new type.CallableValue(function() {
@@ -1164,7 +1154,7 @@ function fastPathUpdatePDU(updateData, opt) {
size : new type.UInt16Le( function () {
return self.updateData.size();
}),
- updateData : updateData || new type.Factory( function (s) {
+ updateData : updateData || new type.Factory( function (s) {
var options = { readLength : new type.CallableValue( function () {
return self.size.value;
}) };
@@ -1249,4 +1239,4 @@ module.exports = {
fastPathUpdatePDU: fastPathUpdatePDU,
clipPDU: clipPDU,
ClipPDUMsgType: ClipPDUMsgType
-};
\ No newline at end of file
+};
diff --git a/rdp/protocol/pdu/global.js b/rdp/protocol/pdu/global.js
index e6a978334a..274bfe18ba 100644
--- a/rdp/protocol/pdu/global.js
+++ b/rdp/protocol/pdu/global.js
@@ -99,7 +99,7 @@ function Client(transport, fastPathTransport) {
this.clientCapabilities[caps.CapsType.CAPSTYPE_OFFSCREENCACHE] = caps.offscreenBitmapCacheCapability();
this.clientCapabilities[caps.CapsType.CAPSTYPE_VIRTUALCHANNEL] = caps.virtualChannelCapability();
this.clientCapabilities[caps.CapsType.CAPSTYPE_SOUND] = caps.soundCapability();
- this.clientCapabilities[caps.CapsType.CAPSETTYPE_MULTIFRAGMENTUPDATE] = caps.multiFragmentUpdate();
+ this.clientCapabilities[caps.CapsETTYPE_MULTIFRAGMENTUPDATE] = caps.multiFragmentUpdate();
}
// inherit from Layer
@@ -205,6 +205,7 @@ Client.prototype.recvServerControlCooperatePDU = function(s) {
this.transport.once('data', function(s) {
self.recvServerControlCooperatePDU(s);
});
+ return;
}
var self = this;
@@ -229,6 +230,7 @@ Client.prototype.recvServerControlGrantedPDU = function(s) {
this.transport.once('data', function(s) {
self.recvServerControlGrantedPDU(s);
});
+ return;
}
var self = this;
@@ -252,6 +254,7 @@ Client.prototype.recvServerFontMapPDU = function(s) {
this.transport.once('data', function(s) {
self.recvServerFontMapPDU(s);
});
+ return;
}
this.emit('connect');
@@ -404,4 +407,4 @@ Client.prototype.sendInputEvents = function (inputEvents) {
*/
module.exports = {
Client : Client
-};
\ No newline at end of file
+};
diff --git a/rdp/protocol/t125/gcc.js b/rdp/protocol/t125/gcc.js
index 42a17a1c8d..adb258a911 100644
--- a/rdp/protocol/t125/gcc.js
+++ b/rdp/protocol/t125/gcc.js
@@ -444,8 +444,8 @@ function readConferenceCreateResponse(s) {
throw new error.ProtocolError('NODE_RDP_PROTOCOL_T125_GCC_BAD_H221_SC_KEY');
}
- length = per.readLength(s);
- serverSettings = settings(null, { readLength : new type.CallableValue(length) });
+ var length = per.readLength(s);
+ var serverSettings = settings(null, { readLength : new type.CallableValue(length) });
// Object magic
return serverSettings.read(s).obj.blocks.obj.map(function(e) {
@@ -479,7 +479,7 @@ function readConferenceCreateRequest (s) {
per.readOctetStream(s, h221_cs_key, 4);
- length = per.readLength(s);
+ var length = per.readLength(s);
var clientSettings = settings(null, { readLength : new type.CallableValue(length) });
// Object magic
@@ -537,4 +537,4 @@ module.exports = {
readConferenceCreateRequest : readConferenceCreateRequest,
writeConferenceCreateRequest : writeConferenceCreateRequest,
writeConferenceCreateResponse : writeConferenceCreateResponse
-};
\ No newline at end of file
+};
diff --git a/rdp/protocol/t125/per.js b/rdp/protocol/t125/per.js
index 17cbf46639..3507757483 100644
--- a/rdp/protocol/t125/per.js
+++ b/rdp/protocol/t125/per.js
@@ -204,7 +204,7 @@ function readObjectIdentifier(s, oid) {
* @returns {type.Component} per encoded object identifier
*/
function writeObjectIdentifier(oid) {
- return new type.Component([new type.UInt8(5), new type.UInt8((oid[0] << 4) & (oid[1] & 0x0f)), new type.UInt8(oid[2]), new type.UInt8(oid[3]), new type.UInt8(oid[4]), new type.UInt8(oid[5])]);
+ return new type.Component([new type.UInt8(5), new type.UInt8((oid[0] << 4) | (oid[1] & 0x0f)), new type.UInt8(oid[2]), new type.UInt8(oid[3]), new type.UInt8(oid[4]), new type.UInt8(oid[5])]);
}
/**
@@ -335,4 +335,4 @@ module.exports = {
writePadding : writePadding,
readOctetStream : readOctetStream,
writeOctetStream : writeOctetStream
-};
\ No newline at end of file
+};
diff --git a/rdp/protocol/x224.js b/rdp/protocol/x224.js
index c323b7dbab..fcd373983c 100644
--- a/rdp/protocol/x224.js
+++ b/rdp/protocol/x224.js
@@ -43,6 +43,19 @@ var NegotiationType = {
TYPE_RDP_NEG_FAILURE : 0x03
};
+/**
+ * Failure codes used in negotiation failure packet
+ * @see http://msdn.microsoft.com/en-us/library/cc240507.aspx
+ */
+var NegotiationFailureCode = {
+ SSL_REQUIRED_BY_SERVER : 0x00000001,
+ SSL_NOT_ALLOWED_BY_SERVER : 0x00000002,
+ SSL_CERT_NOT_ON_SERVER : 0x00000003,
+ INCONSISTENT_FLAGS : 0x00000004,
+ HYBRID_REQUIRED_BY_SERVER : 0x00000005,
+ SSL_WITH_USER_AUTH_REQUIRED_BY_SERVER : 0x00000006
+};
+
/**
* Protocols available for x224 layer
*/
@@ -308,7 +321,7 @@ Server.prototype.recvConnectionRequest = function (s) {
if (!(this.selectedProtocol & Protocols.PROTOCOL_SSL)) {
var confirm = serverConnectionConfirm();
- confirm.obj.protocolNeg.obj.type.value = NegociationType.TYPE_RDP_NEG_FAILURE;
+ confirm.obj.protocolNeg.obj.type.value = NegotiationType.TYPE_RDP_NEG_FAILURE;
confirm.obj.protocolNeg.obj.result.value = NegotiationFailureCode.SSL_REQUIRED_BY_SERVER;
this.transport.send(confirm);
this.close();
@@ -347,3 +360,4 @@ module.exports = {
Client : Client,
Server : Server
};
+
diff --git a/rdp/security/rc4.js b/rdp/security/rc4.js
index 3b116fe185..5d445e01cf 100644
--- a/rdp/security/rc4.js
+++ b/rdp/security/rc4.js
@@ -63,8 +63,8 @@ RC4.prototype.encrypt = function (input) {
RC4.prototype.decrypt = function (input) {
var outputText = '';
input = input.match(/[a-z0-9]{2}/gi);
- for (var i = 0, ii = input.length; i < ii; i++) { outputText += String.fromCharCode((parseInt(input[i], 16) ^ byteStream.next().value)); }
+ for (var i = 0, ii = input.length; i < ii; i++) { outputText += String.fromCharCode((parseInt(input[i], 16) ^ this.byteStream.next().value)); }
return outputText;
}
-module.exports = RC4;
\ No newline at end of file
+module.exports = RC4;