Added MeshCentral Assistant download from agent.
Ylian Saint-Hilaire committed
Apr 27, 2021 at 00:53 UTC
b4a42b03d59d2185ab0e642f42c3d4da71333610
2 files changed
+55
-2
agents/meshcore.js
+51
@@ -1273,6 +1273,17 @@ function handleServerCommand(data) {
1273
break;
1274
case 'meshToolInfo':
1275
if (data.pipe == true) { delete data.pipe; delete data.action; data.cmd = 'meshToolInfo'; broadcastToRegisteredApps(data); }
1276
+ if (data.tag == 'info') { sendConsoleText(JSON.stringify(data, null, 2)); }
1277
+ if (data.tag == 'install') {
1278
+ data.func = function (options, success) {
1279
+ sendConsoleText('Download of MeshCentral Assistant ' + (success?'succeed':'failed'));
1280
+ if (success) {
1281
+ // TODO: Install & Run
1282
+ }
1283
+ }
1284
+ data.filename = 'MeshAssistant.exe';
1285
+ downloadFile(data);
1286
+ }
1287
break;
1288
case 'wget': // Server uses this command to tell the agent to download a file using HTTPS/GET and place it in a given path. This is used for one-to-many file uploads.
1289
agentFileHttpPendingRequests.push(data);
@@ -1288,6 +1299,34 @@ function handleServerCommand(data) {
1299
}
1300
}
1301
1302
+// Download a file from the server and check the hash.
1303
+// This download is similar to the one used for meshcore self-update.
1304
+var trustedDownloads = {};
1305
+function downloadFile(downloadoptions) {
1306
+ var options = require('http').parseUri(downloadoptions.url);
1307
+ options.rejectUnauthorized = false;
1308
+ options.checkServerIdentity = function checkServerIdentity(certs) {
1309
+ // If the tunnel certificate matches the control channel certificate, accept the connection
1310
+ try { if (require('MeshAgent').ServerInfo.ControlChannelCertificate.digest == certs[0].digest) return; } catch (ex) { }
1311
+ try { if (require('MeshAgent').ServerInfo.ControlChannelCertificate.fingerprint == certs[0].fingerprint) return; } catch (ex) { }
1312
+ // Check that the certificate is the one expected by the server, fail if not.
1313
+ if (checkServerIdentity.servertlshash == null) { if (require('MeshAgent').ServerInfo == null || require('MeshAgent').ServerInfo.ControlChannelCertificate == null) return; throw new Error('BadCert'); }
1314
+ if (certs[0].digest == null) return;
1315
+ if ((checkServerIdentity.servertlshash != null) && (checkServerIdentity.servertlshash.toLowerCase() != certs[0].digest.split(':').join('').toLowerCase())) { throw new Error('BadCert') }
1316
+ }
1317
+ //options.checkServerIdentity.servertlshash = downloadoptions.serverhash;
1318
+ trustedDownloads[downloadoptions.name] = downloadoptions;
1319
+ trustedDownloads[downloadoptions.name].dl = require('https').get(options);
1320
+ trustedDownloads[downloadoptions.name].dl.on('error', function (e) { downloadoptions.func(downloadoptions, false); delete trustedDownloads[downloadoptions.name]; });
1321
+ trustedDownloads[downloadoptions.name].dl.on('response', function (img) {
1322
+ this._file = require('fs').createWriteStream(trustedDownloads[downloadoptions.name].filename, { flags: 'wb' });
1323
+ this._filehash = require('SHA384Stream').create();
1324
+ this._filehash.on('hash', function (h) { if ((downloadoptions.hash != null) && (downloadoptions.hash.toLowerCase() != h.toString('hex').toLowerCase())) { downloadoptions.func(downloadoptions, false); delete trustedDownloads[downloadoptions.name]; return; } downloadoptions.func(downloadoptions, true); });
1325
+ img.pipe(this._file);
1326
+ img.pipe(this._filehash);
1327
+ });
1328
+}
1329
+
1330
// Handle APF JSON control commands
1331
function handleApfJsonControl(data) {
1332
if (data.action == 'console') { addAmtEvent(data.msg); } // Add console message to AMT event log
@@ -2818,6 +2857,18 @@ function processConsoleCommand(cmd, args, rights, sessionid) {
2857
break;
2858
}
2859
break;
2860
+ case 'assistant':
2861
+ if (process.platform == 'win32') {
2862
+ // Install MeshCentral Assistant on this device
2863
+ response = "Usage: Assistant [info|install|uninstall]";
2864
+ if (args['_'].length == 1) {
2865
+ if ((args['_'][0] == 'install') || (args['_'][0] == 'info')) { response = ''; require('MeshAgent').SendCommand({ action: 'meshToolInfo', sessionid: sessionid, name: 'MeshCentralAssistant', cookie: true, tag: args['_'][0] }); }
2866
+ // TODO: Uninstall
2867
+ }
2868
+ } else {
2869
+ response = "MeshCentral Assistant is not supported on this platform.";
2870
+ }
2871
+ break;
2872
case 'agentupdate':
2873
require('MeshAgent').SendCommand({ action: 'agentupdate', sessionid: sessionid });
2874
break;
meshagent.js
+4
-2
@@ -1479,13 +1479,15 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
1479
break;
1480
}
1481
case 'meshToolInfo': {
1482
+ // Return information about a MeshCentral tool. Current tools are 'MeshCentralRouter' and 'MeshCentralAssistant'
1483
+ // Information includes file hash and download location URL
1484
if (typeof command.name != 'string') break;
1485
var info = parent.parent.meshToolsBinaries[command.name];
1486
if ((command.hash != null) && (info.hash == command.hash)) return;
1485
- const responseCmd = { action: 'meshToolInfo', name: command.name, hash: info.hash, size: info.size, url: info.url };
1487
+ const responseCmd = { action: 'meshToolInfo', name: command.name, tag: command.tag, sessionid: command.sessionid, hash: info.hash, size: info.size, url: info.url };
1488
if (command.cookie === true) { responseCmd.url += ('&auth=' + parent.parent.encodeCookie({ download: info.dlname }, parent.parent.loginCookieEncryptionKey)); }
1489
if (command.pipe === true) { responseCmd.pipe = true; }
1488
- if (parent.webCertificateHashs[domain.id] != null) { responseCmd.serverhash = Buffer.from(parent.webCertificateHashs[domain.id], 'binary').toString('hex'); }
1490
+ if (parent.webCertificateHashs[domain.id] != null) { responseCmd.serverhash = Buffer.from(parent.webCertificateHashs[domain.id],'binary').toString('hex'); }
1491
try { ws.send(JSON.stringify(responseCmd)); } catch (ex) { }
1492
break;
1493
}