MeshRouter now supports new icon, fixed server crash when running on single CPU, Removed Let's Encrypt wildcard altname being added by GreenLock.
Ylian Saint-Hilaire committed
Mar 2, 2020 at 12:36 UTC
607cdf888fbcbd13ddd3f637dec6aa39a20b37cf
8 files changed
+55
-24
agents/MeshCentralRouter.exe
Binary files a/agents/MeshCentralRouter.exe and b/agents/MeshCentralRouter.exe differ
certoperations.js
+1
-1
@@ -854,7 +854,7 @@ module.exports.CertificateOperations = function (parent) {
854
obj.acceleratorPerformOperation = function (operation, data, tag, func) {
855
if (acceleratorTotalCount <= 1) {
856
// No accelerators available
857
- program.processMessage({ action: operation, data: data, tag: tag, func: func });
857
+ require(program).processMessage({ action: operation, data: data, tag: tag, func: func });
858
} else {
859
var acc = obj.getAccelerator();
860
if (acc == null) {
letsEncrypt.js
+18
-1
@@ -261,13 +261,28 @@ module.exports.CreateLetsEncrypt = function (parent) {
261
262
// GreenLock v3 Manager
263
module.exports.create = function (options) {
264
+ //console.log('xxx-create', options);
265
var manager = { parent: globalLetsEncrypt };
266
manager.find = async function (options) {
266
- //console.log('LE-FIND', options);
267
+ try {
268
+ // GreenLock sometimes has the bad behavior of adding a wildcard cert request, remove it here if needed.
269
+ if ((options.wildname != null) && (options.wildname != '')) { options.wildname = ''; }
270
+ if (options.altnames) {
271
+ var altnames2 = [];
272
+ for (var i in options.altnames) { if (options.altnames[i].indexOf('*') == -1) { altnames2.push(options.altnames[i]); } }
273
+ options.altnames = altnames2;
274
+ }
275
+ if (options.servernames) {
276
+ var servernames2 = [];
277
+ for (var i in options.servernames) { if (options.servernames[i].indexOf('*') == -1) { servernames2.push(options.servernames[i]); } }
278
+ options.servernames = servernames2;
279
+ }
280
+ } catch (ex) { console.log(ex); }
281
return Promise.resolve([{ subject: options.servername, altnames: options.altnames }]);
282
};
283
284
manager.set = function (options) {
285
+ //console.log('xxx-set', options);
286
manager.parent.parent.debug('cert', "Certificate has been set: " + JSON.stringify(options));
287
if (manager.parent.parent.config.letsencrypt.production == manager.parent.runAsProduction) { manager.parent.performRestart = true; }
288
else if ((manager.parent.parent.config.letsencrypt.production === true) && (manager.parent.runAsProduction === false)) { manager.parent.performMoveToProduction = true; }
@@ -275,6 +290,7 @@ module.exports.create = function (options) {
290
};
291
292
manager.remove = function (options) {
293
+ //console.log('xxx-remove', options);
294
manager.parent.parent.debug('cert', "Certificate has been removed: " + JSON.stringify(options));
295
if (manager.parent.parent.config.letsencrypt.production == manager.parent.runAsProduction) { manager.parent.performRestart = true; }
296
else if ((manager.parent.parent.config.letsencrypt.production === true) && (manager.parent.runAsProduction === false)) { manager.parent.performMoveToProduction = true; }
@@ -283,6 +299,7 @@ module.exports.create = function (options) {
299
300
// set the global config
301
manager.defaults = async function (options) {
302
+ //console.log('xxx-defaults', options);
303
var r;
304
if (manager.parent.runAsProduction === true) {
305
// Production
meshcentral.js
+1
@@ -1079,6 +1079,7 @@ function CreateMeshCentralServer(config, args) {
1079
var leok = true;
1080
if (typeof obj.config.letsencrypt.email != 'string') { leok = false; addServerWarning("Missing Let's Encrypt email address."); }
1081
else if (typeof obj.config.letsencrypt.names != 'string') { leok = false; addServerWarning("Invalid Let's Encrypt host names."); }
1082
+ else if (obj.config.letsencrypt.names.indexOf('*') >= 0) { leok = false; addServerWarning("Invalid Let's Encrypt names, can't contain a *."); }
1083
else if (obj.config.letsencrypt.email.split('@').length != 2) { leok = false; addServerWarning("Invalid Let's Encrypt email address."); }
1084
else if (obj.config.letsencrypt.email.trim() !== obj.config.letsencrypt.email) { leok = false; addServerWarning("Invalid Let's Encrypt email address."); }
1085
else {
package.json
+1
-1
@@ -1,6 +1,6 @@
1
{
2
"name": "meshcentral",
3
- "version": "0.4.9-o",
3
+ "version": "0.4.9-q",
4
"keywords": [
5
"Remote Management",
6
"Intel AMT",
public/scripts/amt-0.2.0.js
+2
-1
@@ -760,7 +760,7 @@ function AmtStackCreateService(wsmanStack) {
760
// ###BEGIN###{Certificates}
761
762
// Forge MD5
763
-function hex_md5(str) { return forge.md.md5.create().update(str).digest().toHex(); }
763
+function hex_md5(str) { if (str == null) { str = ''; } return forge.md.md5.create().update(str).digest().toHex(); }
764
765
// ###END###{Certificates}
766
@@ -774,6 +774,7 @@ for (var i = 0; i < 64;) { md5_k[i] = 0 | (Math.abs(Math.sin(++i)) * 4294967296)
774
775
// Perform MD5 on raw string and return hex
776
function hex_md5(str) {
777
+ if (str == null) { str = ''; }
778
var b, c, d, j,
779
x = [],
780
str2 = unescape(encodeURI(str)),
public/scripts/amt-wsman-ws-0.2.0.js
+23
-19
@@ -80,12 +80,12 @@ var CreateWsmanComm = function (host, port, user, pass, tls) {
80
81
// Websocket relay specific private method (Content Length Encoding)
82
obj.sendRequest = function (postdata, url, action) {
83
- url = url ? url : "/wsman";
84
- action = action ? action : "POST";
85
- var h = action + " " + url + " HTTP/1.1\r\n";
83
+ url = url ? url : '/wsman';
84
+ action = action ? action : 'POST';
85
+ var h = action + ' ' + url + ' HTTP/1.1\r\n';
86
if (obj.challengeParams != null) {
87
- var response = hex_md5(hex_md5(obj.user + ':' + obj.challengeParams["realm"] + ':' + obj.pass) + ':' + obj.challengeParams["nonce"] + ':' + obj.noncecounter + ':' + obj.cnonce + ':' + obj.challengeParams["qop"] + ':' + hex_md5(action + ':' + url));
88
- h += 'Authorization: ' + obj.renderDigest({ "username": obj.user, "realm": obj.challengeParams["realm"], "nonce": obj.challengeParams["nonce"], "uri": url, "qop": obj.challengeParams["qop"], "response": response, "nc": obj.noncecounter++, "cnonce": obj.cnonce }) + '\r\n';
87
+ var response = hex_md5(hex_md5(obj.user + ':' + obj.challengeParams['realm'] + ':' + obj.pass) + ':' + obj.challengeParams['nonce'] + ':' + obj.noncecounter + ':' + obj.cnonce + ':' + obj.challengeParams['qop'] + ':' + hex_md5(action + ':' + url + ((obj.challengeParams['qop'] == 'auth-int') ? (':' + hex_md5(postdata)) : '')));
88
+ h += 'Authorization: ' + obj.renderDigest({ 'username': obj.user, 'realm': obj.challengeParams['realm'], 'nonce': obj.challengeParams['nonce'], 'uri': url, 'qop': obj.challengeParams['qop'], 'response': response, 'nc': obj.noncecounter++, 'cnonce': obj.cnonce }) + '\r\n';
89
}
90
//h += 'Host: ' + obj.host + ':' + obj.port + '\r\nContent-Length: ' + postdata.length + '\r\n\r\n' + postdata; // Use Content-Length
91
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
@@ -93,12 +93,11 @@ var CreateWsmanComm = function (host, port, user, pass, tls) {
93
//obj.Debug("SEND: " + h); // Display send packet
94
}
95
96
- // Websocket relay specific private method
97
- obj.parseDigest = function (header) {
98
- var t = header.substring(7).split(',');
99
- for (i in t) t[i] = t[i].trim();
100
- return t.reduce(function (obj, s) { var parts = s.split('='); obj[parts[0]] = parts[1].replace(/"/g, ''); return obj; }, {})
101
- }
96
+ // Parse the HTTP digest header and return a list of key & values.
97
+ 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; }, {}) }
98
+
99
+ // Split a string on quotes but do not do it when in quotes
100
+ 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 }
101
102
// Websocket relay specific private method
103
obj.renderDigest = function (params) {
@@ -117,7 +116,7 @@ var CreateWsmanComm = function (host, port, user, pass, tls) {
116
obj.socketState = 1;
117
118
console.log(obj.tlsv1only);
120
- obj.socket = new WebSocket(window.location.protocol.replace("http", "ws") + "//" + window.location.host + window.location.pathname.substring(0, window.location.pathname.lastIndexOf('/')) + "/webrelay.ashx?p=1&host=" + obj.host + "&port=" + obj.port + "&tls=" + obj.tls + "&tlsv1only=" + obj.tlsv1only + ((user == '*') ? "&serverauth=1" : "") + ((typeof pass === "undefined") ? ("&serverauth=1&user=" + user) : "")); // The "p=1" indicates to the relay that this is a WSMAN session
119
+ obj.socket = new WebSocket(window.location.protocol.replace('http', 'ws') + '//' + window.location.host + window.location.pathname.substring(0, window.location.pathname.lastIndexOf('/')) + '/webrelay.ashx?p=1&host=' + obj.host + '&port=' + obj.port + '&tls=' + obj.tls + '&tlsv1only=' + obj.tlsv1only + ((user == '*') ? '&serverauth=1' : '') + ((typeof pass === 'undefined') ? ('&serverauth=1&user=' + user) : '')); // The "p=1" indicates to the relay that this is a WSMAN session
120
obj.socket.onopen = _OnSocketConnected;
121
obj.socket.onmessage = _OnMessage;
122
obj.socket.onclose = _OnSocketClosed;
@@ -154,7 +153,7 @@ var CreateWsmanComm = function (host, port, user, pass, tls) {
153
fileReader.readAsArrayBuffer(e.data);
154
} else {
155
// IE10, readAsBinaryString does not exist, use an alternative.
157
- var binary = "", bytes = new Uint8Array(e.data), length = bytes.byteLength;
156
+ var binary = '', bytes = new Uint8Array(e.data), length = bytes.byteLength;
157
for (var i = 0; i < length; i++) { binary += String.fromCharCode(bytes[i]); }
158
_OnSocketData(binary);
159
}
@@ -169,7 +168,7 @@ var CreateWsmanComm = function (host, port, user, pass, tls) {
168
169
if (typeof data === 'object') {
170
// This is an ArrayBuffer, convert it to a string array (used in IE)
172
- var binary = "", bytes = new Uint8Array(data), length = bytes.byteLength;
171
+ var binary = '', bytes = new Uint8Array(data), length = bytes.byteLength;
172
for (var i = 0; i < length; i++) { binary += String.fromCharCode(bytes[i]); }
173
data = binary;
174
}
@@ -180,10 +179,10 @@ var CreateWsmanComm = function (host, port, user, pass, tls) {
179
obj.socketAccumulator += data;
180
while (true) {
181
if (obj.socketParseState == 0) {
183
- var headersize = obj.socketAccumulator.indexOf("\r\n\r\n");
182
+ var headersize = obj.socketAccumulator.indexOf('\r\n\r\n');
183
if (headersize < 0) return;
184
//obj.Debug(obj.socketAccumulator.substring(0, headersize)); // Display received HTTP header
186
- obj.socketHeader = obj.socketAccumulator.substring(0, headersize).split("\r\n");
185
+ obj.socketHeader = obj.socketAccumulator.substring(0, headersize).split('\r\n');
186
obj.socketAccumulator = obj.socketAccumulator.substring(headersize + 4);
187
obj.socketParseState = 1;
188
obj.socketData = '';
@@ -197,12 +196,12 @@ var CreateWsmanComm = function (host, port, user, pass, tls) {
196
}
197
if (obj.socketParseState == 1) {
198
var csize = -1;
200
- if ((obj.socketXHeader["connection"] != undefined) && (obj.socketXHeader["connection"].toLowerCase() == 'close') && ((obj.socketXHeader["transfer-encoding"] == undefined) || (obj.socketXHeader["transfer-encoding"].toLowerCase() != 'chunked'))) {
199
+ if ((obj.socketXHeader['connection'] != undefined) && (obj.socketXHeader['connection'].toLowerCase() == 'close') && ((obj.socketXHeader["transfer-encoding"] == undefined) || (obj.socketXHeader["transfer-encoding"].toLowerCase() != 'chunked'))) {
200
// The body ends with a close, in this case, we will only process the header
201
csize = 0;
203
- } else if (obj.socketXHeader["content-length"] != undefined) {
202
+ } else if (obj.socketXHeader['content-length'] != undefined) {
203
// The body length is specified by the content-length
205
- csize = parseInt(obj.socketXHeader["content-length"]);
204
+ csize = parseInt(obj.socketXHeader['content-length']);
205
if (obj.socketAccumulator.length < csize) return;
206
var data = obj.socketAccumulator.substring(0, csize);
207
obj.socketAccumulator = obj.socketAccumulator.substring(csize);
@@ -239,6 +238,11 @@ var CreateWsmanComm = function (host, port, user, pass, tls) {
238
if (isNaN(s)) s = 602;
239
if (s == 401 && ++(obj.authcounter) < 3) {
240
obj.challengeParams = obj.parseDigest(header['www-authenticate']); // Set the digest parameters, after this, the socket will close and we will auto-retry
241
+ if (obj.challengeParams['qop'] != null) {
242
+ var qopList = obj.challengeParams['qop'].split(',');
243
+ for (var i in qopList) { qopList[i] = qopList[i].trim(); }
244
+ if (qopList.indexOf('auth-int') >= 0) { obj.challengeParams['qop'] = 'auth-int'; } else { obj.challengeParams['qop'] = 'auth'; }
245
+ }
246
} else {
247
var r = obj.pendingAjaxCall.shift();
248
// 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.
redirserver.js
+9
-1
@@ -75,7 +75,15 @@ module.exports.CreateRedirServer = function (parent, db, args, func) {
75
parent.letsencrypt.challenge(req.url.slice(leChallengePrefix.length), getCleanHostname(req), function (response) { if (response == null) { res.sendStatus(404); } else { res.send(response); } });
76
} else {
77
// Everything else
78
- res.set({ 'strict-transport-security': "max-age=60000; includeSubDomains", "Referrer-Policy": "no-referrer", "x-frame-options": "SAMEORIGIN", "X-XSS-Protection": "1; mode=block", "X-Content-Type-Options": "nosniff", "Content-Security-Policy": "default-src http: ws: \"self\" \"unsafe-inline\"" });
78
+ var selfurl = ((args.notls !== true) ? (' wss://' + req.headers.host) : (' ws://' + req.headers.host));
79
+ res.set({
80
+ 'strict-transport-security': 'max-age=60000; includeSubDomains',
81
+ 'Referrer-Policy': 'no-referrer',
82
+ 'x-frame-options': 'SAMEORIGIN',
83
+ 'X-XSS-Protection': '1; mode=block',
84
+ 'X-Content-Type-Options': 'nosniff',
85
+ 'Content-Security-Policy': "default-src 'none'; style-src 'self' 'unsafe-inline';"
86
+ });
87
return next();
88
}
89
});