Fixed meshcore agent update when used with AgentPort.

Ylian Saint-Hilaire committed Jan 28, 2021 at 15:49 UTC 6f6040d74255cc96217794968fc686f1f162a3ed
4 files changed +53 -71
agents/meshcore.js
+11 -8
@@ -3993,6 +3993,10 @@ function agentUpdate_Start(updateurl, updateoptions) {
3993 // If this value is null
3994 var sessionid = (updateoptions != null) ? updateoptions.sessionid : null; // If this is null, messages will be broadcast. Otherwise they will be unicasted
3995
3996 + // If the url starts with *, switch it to use the same protoco, host and port as the control channel.
3997 + updateurl = getServerTargetUrlEx(updateurl);
3998 + if (updateurl.startsWith("wss://")) { updateurl = "https://" + updateurl.substring(6); }
3999 +
4000 if (agentUpdate_Start._selfupdate != null) {
4001 // We were already called, so we will ignore this duplicate request
4002 if (sessionid != null) { sendConsoleText('Self update already in progress...', sessionid); }
@@ -4006,7 +4010,7 @@ function agentUpdate_Start(updateurl, updateoptions) {
4010 else {
4011 var agentfilename = process.execPath.split(process.platform == 'win32' ? '\\' : '/').pop(); // Local File Name, ie: MeshAgent.exe
4012 var name = require('MeshAgent').serviceName;
4009 - if (name == null) { name = process.platform == 'win32' ? 'Mesh Agent' : 'meshagent'; } // This is an older agent that doesn't expose the service name, so use the default
4013 + if (name == null) { name = (process.platform == 'win32' ? 'Mesh Agent' : 'meshagent'); } // This is an older agent that doesn't expose the service name, so use the default
4014 try {
4015 var s = require('service-manager').manager.getService(name);
4016 if (!s.isMe()) {
@@ -4035,9 +4039,8 @@ function agentUpdate_Start(updateurl, updateoptions) {
4039 // Check that the certificate is the one expected by the server, fail if not.
4040 if (checkServerIdentity.servertlshash == null) {
4041 if (require('MeshAgent').ServerInfo == null || require('MeshAgent').ServerInfo.ControlChannelCertificate == null) { return; }
4038 -
4039 - sendConsoleText('Self Update failed, because the url cannot be verified', sessionid);
4040 - sendAgentMessage('Self Update failed, because the url cannot be verified', 3);
4042 + sendConsoleText('Self Update failed, because the url cannot be verified: ' + updateurl, sessionid);
4043 + sendAgentMessage('Self Update failed, because the url cannot be verified: ' + updateurl, 3);
4044 throw new Error('BadCert');
4045 }
4046 if (certs[0].digest == null) { return; }
@@ -4050,8 +4053,8 @@ function agentUpdate_Start(updateurl, updateoptions) {
4053 options.checkServerIdentity.servertlshash = (updateoptions != null ? updateoptions.tlshash : null);
4054 agentUpdate_Start._selfupdate = require('https').get(options);
4055 agentUpdate_Start._selfupdate.on('error', function (e) {
4053 - sendConsoleText('Self Update failed, because there was a problem trying to download the update', sessionid);
4054 - sendAgentMessage('Self Update failed, because there was a problem trying to download the update', 3);
4056 + sendConsoleText('Self Update failed, because there was a problem trying to download the update from ' + updateurl, sessionid);
4057 + sendAgentMessage('Self Update failed, because there was a problem trying to download the update from ' + updateurl, 3);
4058 agentUpdate_Start._selfupdate = null;
4059 });
4060 agentUpdate_Start._selfupdate.on('response', function (img) {
@@ -4064,8 +4067,8 @@ function agentUpdate_Start(updateurl, updateoptions) {
4067 }
4068 else {
4069 agentUpdate_Start._retryCount++;
4067 - sendConsoleText('Self Update FAILED because the downloaded agent FAILED hash check (' + agentUpdate_Start._retryCount + ')', sessionid);
4068 - sendAgentMessage('Self Update FAILED because the downloaded agent FAILED hash check (' + agentUpdate_Start._retryCount + ')', 3);
4070 + sendConsoleText('Self Update FAILED because the downloaded agent FAILED hash check (' + agentUpdate_Start._retryCount + '), URL: ' + updateurl, sessionid);
4071 + sendAgentMessage('Self Update FAILED because the downloaded agent FAILED hash check (' + agentUpdate_Start._retryCount + '), URL: ' + updateurl, 3);
4072 agentUpdate_Start._selfupdate = null;
4073
4074 if (agentUpdate_Start._retryCount < 4) {
agents/recoverycore.js
+37 -59
@@ -324,70 +324,62 @@ function windows_execve(name, agentfilename, sessionid) {
324 }
325
326 // Start a JavaScript based Agent Self-Update
327 -function agentUpdate_Start(updateurl, updateoptions)
328 -{
327 +function agentUpdate_Start(updateurl, updateoptions) {
328 // If this value is null
329 var sessionid = (updateoptions != null) ? updateoptions.sessionid : null; // If this is null, messages will be broadcast. Otherwise they will be unicasted
330
332 - if (agentUpdate_Start._selfupdate != null)
333 - {
331 + // If the url starts with *, switch it to use the same protoco, host and port as the control channel.
332 + updateurl = getServerTargetUrlEx(updateurl);
333 + if (updateurl.startsWith("wss://")) { updateurl = "https://" + updateurl.substring(6); }
334 +
335 + if (agentUpdate_Start._selfupdate != null) {
336 // We were already called, so we will ignore this duplicate request
337 if (sessionid != null) { sendConsoleText('Self update already in progress...', sessionid); }
338 }
337 - else
338 - {
339 + else {
340 if (agentUpdate_Start._retryCount == null) { agentUpdate_Start._retryCount = 0; }
340 - if (require('MeshAgent').ARCHID == null && updateurl == null)
341 - {
341 + if (require('MeshAgent').ARCHID == null && updateurl == null) {
342 // This agent doesn't have the ability to tell us which ARCHID it is, so we don't know which agent to pull
343 sendConsoleText('Unable to initiate update, agent ARCHID is not defined', sessionid);
344 }
345 - else
346 - {
345 + else {
346 var agentfilename = process.execPath.split(process.platform == 'win32' ? '\\' : '/').pop(); // Local File Name, ie: MeshAgent.exe
347 var name = require('MeshAgent').serviceName;
349 - if (name == null) { name = process.platform == 'win32' ? 'Mesh Agent' : 'meshagent'; } // This is an older agent that doesn't expose the service name, so use the default
350 - try
351 - {
348 + if (name == null) { name = (process.platform == 'win32' ? 'Mesh Agent' : 'meshagent'); } // This is an older agent that doesn't expose the service name, so use the default
349 + try {
350 var s = require('service-manager').manager.getService(name);
353 - if (!s.isMe())
354 - {
351 + if (!s.isMe()) {
352 if (process.platform == 'win32') { s.close(); }
353 sendConsoleText('Self Update cannot continue, this agent is not an instance of (' + name + ')', sessionid);
354 return;
355 }
356 if (process.platform == 'win32') { s.close(); }
357 }
361 - catch (zz)
362 - {
358 + catch (zz) {
359 sendConsoleText('Self Update Failed because this agent is not an instance of (' + name + ')', sessionid);
360 sendAgentMessage('Self Update Failed because this agent is not an instance of (' + name + ')', 3);
361 return;
362 }
363
368 - if (sessionid != null) { sendConsoleText('Downloading update...', sessionid); }
364 + if (sessionid != null) { sendConsoleText('Downloading update from: ' + updateurl, sessionid); }
365 var options = require('http').parseUri(updateurl != null ? updateurl : require('MeshAgent').ServerUrl);
366 options.protocol = 'https:';
367 if (updateurl == null) { options.path = ('/meshagents?id=' + require('MeshAgent').ARCHID); }
368 options.rejectUnauthorized = false;
373 - options.checkServerIdentity = function checkServerIdentity(certs)
374 - {
369 + options.checkServerIdentity = function checkServerIdentity(certs) {
370 // If the tunnel certificate matches the control channel certificate, accept the connection
371 try { if (require('MeshAgent').ServerInfo.ControlChannelCertificate.digest == certs[0].digest) return; } catch (ex) { }
372 try { if (require('MeshAgent').ServerInfo.ControlChannelCertificate.fingerprint == certs[0].fingerprint) return; } catch (ex) { }
373
374 // Check that the certificate is the one expected by the server, fail if not.
380 - if (checkServerIdentity.servertlshash == null)
381 - {
375 + if (checkServerIdentity.servertlshash == null) {
376 if (require('MeshAgent').ServerInfo == null || require('MeshAgent').ServerInfo.ControlChannelCertificate == null) { return; }
383 -
384 - sendConsoleText('Self Update failed, because the url cannot be verified', sessionid);
385 - sendAgentMessage('Self Update failed, because the url cannot be verified', 3);
377 + sendConsoleText('Self Update failed, because the url cannot be verified: ' + updateurl, sessionid);
378 + sendAgentMessage('Self Update failed, because the url cannot be verified: ' + updateurl, 3);
379 throw new Error('BadCert');
380 }
381 if (certs[0].digest == null) { return; }
389 - if ((checkServerIdentity.servertlshash != null) && (checkServerIdentity.servertlshash.toLowerCase() != certs[0].digest.split(':').join('').toLowerCase()))
390 - {
382 + if ((checkServerIdentity.servertlshash != null) && (checkServerIdentity.servertlshash.toLowerCase() != certs[0].digest.split(':').join('').toLowerCase())) {
383 sendConsoleText('Self Update failed, because the supplied certificate does not match', sessionid);
384 sendAgentMessage('Self Update failed, because the supplied certificate does not match', 3);
385 throw new Error('BadCert')
@@ -395,47 +387,38 @@ function agentUpdate_Start(updateurl, updateoptions)
387 }
388 options.checkServerIdentity.servertlshash = (updateoptions != null ? updateoptions.tlshash : null);
389 agentUpdate_Start._selfupdate = require('https').get(options);
398 - agentUpdate_Start._selfupdate.on('error', function (e)
399 - {
400 - sendConsoleText('Self Update failed, because there was a problem trying to download the update', sessionid);
401 - sendAgentMessage('Self Update failed, because there was a problem trying to download the update', 3);
390 + agentUpdate_Start._selfupdate.on('error', function (e) {
391 + sendConsoleText('Self Update failed, because there was a problem trying to download the update from ' + updateurl, sessionid);
392 + sendAgentMessage('Self Update failed, because there was a problem trying to download the update from ' + updateurl, 3);
393 agentUpdate_Start._selfupdate = null;
394 });
404 - agentUpdate_Start._selfupdate.on('response', function (img)
405 - {
395 + agentUpdate_Start._selfupdate.on('response', function (img) {
396 this._file = require('fs').createWriteStream(agentfilename + '.update', { flags: 'wb' });
397 this._filehash = require('SHA384Stream').create();
408 - this._filehash.on('hash', function (h)
409 - {
410 - if (updateoptions != null && updateoptions.hash != null)
411 - {
412 - if (updateoptions.hash.toLowerCase() == h.toString('hex').toLowerCase())
413 - {
398 + this._filehash.on('hash', function (h) {
399 + if (updateoptions != null && updateoptions.hash != null) {
400 + if (updateoptions.hash.toLowerCase() == h.toString('hex').toLowerCase()) {
401 if (sessionid != null) { sendConsoleText('Download complete. HASH verified.', sessionid); }
402 }
416 - else
417 - {
403 + else {
404 agentUpdate_Start._retryCount++;
419 - sendConsoleText('Self Update FAILED because the downloaded agent FAILED hash check (' + agentUpdate_Start._retryCount + ')', sessionid);
420 - sendAgentMessage('Self Update FAILED because the downloaded agent FAILED hash check (' + agentUpdate_Start._retryCount + ')', 3);
405 + sendConsoleText('Self Update FAILED because the downloaded agent FAILED hash check (' + agentUpdate_Start._retryCount + '), URL: ' + updateurl, sessionid);
406 + sendAgentMessage('Self Update FAILED because the downloaded agent FAILED hash check (' + agentUpdate_Start._retryCount + '), URL: ' + updateurl, 3);
407 agentUpdate_Start._selfupdate = null;
408
423 - if (agentUpdate_Start._retryCount < 4)
424 - {
409 + if (agentUpdate_Start._retryCount < 4) {
410 // Retry the download again
411 sendConsoleText('Self Update will try again in 60 seconds...', sessionid);
412 agentUpdate_Start._timeout = setTimeout(agentUpdate_Start, 60000, updateurl, updateoptions);
413 }
429 - else
430 - {
414 + else {
415 sendConsoleText('Self Update giving up, too many failures...', sessionid);
416 sendAgentMessage('Self Update giving up, too many failures...', 3);
417 }
418 return;
419 }
420 }
437 - else
438 - {
421 + else {
422 sendConsoleText('Download complete. HASH=' + h.toString('hex'), sessionid);
423 }
424
@@ -443,13 +426,11 @@ function agentUpdate_Start(updateurl, updateoptions)
426 try { require('MeshAgent').SendCommand({ action: 'agentupdatedownloaded' }); } catch (e) { }
427
428 if (sessionid != null) { sendConsoleText('Updating and restarting agent...', sessionid); }
446 - if (process.platform == 'win32')
447 - {
429 + if (process.platform == 'win32') {
430 // Use _wexecve() equivalent to perform the update
431 windows_execve(name, agentfilename, sessionid);
432 }
451 - else
452 - {
433 + else {
434 var m = require('fs').statSync(process.execPath).mode;
435 require('fs').chmodSync(process.cwd() + agentfilename + '.update', m);
436
@@ -463,8 +444,7 @@ function agentUpdate_Start(updateurl, updateoptions)
444 // erase update
445 require('fs').unlinkSync(process.cwd() + agentfilename + '.update');
446
466 - switch (process.platform)
467 - {
447 + switch (process.platform) {
448 case 'freebsd':
449 bsd_execv(name, agentfilename, sessionid);
450 break;
@@ -472,14 +452,12 @@ function agentUpdate_Start(updateurl, updateoptions)
452 linux_execv(name, agentfilename, sessionid);
453 break;
454 default:
475 - try
476 - {
455 + try {
456 // restart service
457 var s = require('service-manager').manager.getService(name);
458 s.restart();
459 }
481 - catch (zz)
482 - {
460 + catch (zz) {
461 sendConsoleText('Self Update encountered an error trying to restart service', sessionid);
462 sendAgentMessage('Self Update encountered an error trying to restart service', 3);
463 }
meshagent.js
+2 -4
@@ -1171,8 +1171,7 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
1171
1172 // Agent update. The recovery core was loaded in the agent, send a command to update the agent
1173 obj.agentCoreUpdateTaskId = taskid;
1174 - var url = obj.agentExeInfo.url;
1175 - if (url.startsWith('http://')) { url = url.replace('http://', 'https://') }
1174 + const url = '*' + require('url').parse(obj.agentExeInfo.url).path;
1175 var cmd = { action: 'agentupdate', url: url, hash: obj.agentExeInfo.hashhex };
1176
1177 // Add the hash
@@ -1483,8 +1482,7 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
1482
1483 // Agent is requesting an agent update
1484 obj.agentCoreUpdateTaskId = taskid;
1486 - var url = obj.agentExeInfo.url;
1487 - if (url.startsWith('http://')) { url = url.replace('http://', 'https://') }
1485 + const url = '*' + require('url').parse(obj.agentExeInfo.url).path;
1486 var cmd = { action: 'agentupdate', url: url, hash: obj.agentExeInfo.hashhex, sessionid: agentUpdateFunc.sessionid };
1487
1488 // Add the hash
webserver.js
+3
@@ -5513,6 +5513,9 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
5513
5514 // Setup agent to/from server file transfer handler
5515 obj.agentapp.ws(url + 'agenttransfer.ashx', handleAgentFileTransfer); // Setup agent to/from server file transfer handler
5516 +
5517 + // Setup agent downloads for meshcore updates
5518 + obj.agentapp.get(url + 'meshagents', obj.handleMeshAgentRequest);
5519 }
5520
5521 // Indicates to ExpressJS that the override public folder should be used to serve static files.