From 1aa0e80f53e8e48e0081b6d39e7a0c54fa6539aa Mon Sep 17 00:00:00 2001 From: Ylian Saint-Hilaire Date: Fri, 15 Dec 2017 13:43:04 -0800 Subject: [PATCH] Improved MeshCmd support --- agents/meshcmd.js | 30 +++++++++++++++++------------- agents/meshcore.js | 2 +- package.json | 2 +- views/default.handlebars | 32 +++++++++++++++++++++++++------- webserver.js | 39 ++++++++++++++++++++++++++++----------- 5 files changed, 72 insertions(+), 33 deletions(-) diff --git a/agents/meshcmd.js b/agents/meshcmd.js index 8c72e314..5ed0ca3e 100644 --- a/agents/meshcmd.js +++ b/agents/meshcmd.js @@ -68,14 +68,17 @@ function run(argv) { //console.log('addedModules = ' + JSON.stringify(addedModules)); var actionpath = 'meshaction.txt'; if (args.actionfile != null) { actionpath = args.actionfile; } + var actions = ['ROUTE', 'AMTLMS', 'AMTLOADWEBAPP', 'AMTLOADSMALLWEBAPP', 'AMTLOADLARGEWEBAPP', 'AMTCLEARWEBAPP', 'AMTSTORAGESTATE', 'MEINFO', 'MEVERSIONS', 'MEHASHES']; // Load the action file var actionfile = null; try { actionfile = fs.readFileSync(actionpath); } catch (e) { } if ((actionpath != 'meshaction.txt') && (actionfile == null)) { console.log('Unable to load \"' + actionpath + '\". Create this file or specify the location using --actionfile [filename].'); exit(1); return; } if (actionfile != null) { try { settings = JSON.parse(actionfile); } catch (e) { console.log(actionpath, e); exit(1); return; } } else { if (argv.length >= 2) { settings = { action: argv[1] } } } + if (settings == null) { settings = {}; } // Set the arguments + if ((typeof args.action) == 'string') { settings.action = args.action; } if ((typeof args.localport) == 'string') { settings.localport = parseInt(args.localport); } if ((typeof args.remotenodeid) == 'string') { settings.remoteNodeId = args.remotenodeid; } if ((typeof args.username) == 'string') { settings.username = args.username; } @@ -88,9 +91,10 @@ function run(argv) { if ((typeof args.serverhttpshash) == 'string') { settings.serverHttpsHash = args.serverhttpshash; } if ((typeof args.remoteport) == 'string') { settings.remotePort = parseInt(args.remoteport); } if ((typeof args.debug) == 'string') { settings.debugLevel = parseInt(args.debug); } + if ((argv.length > 1) && (actions.indexOf(argv[1].toUpperCase()) >= 0)) { settings.action = argv[1]; } // Validate meshaction.txt - if ((settings == null) || (settings.action == null)) { console.log('No action specified, valid actions are ROUTE, LOADWEBAPP, CLEARWEBAPP, STORAGESTATE, MEINFO, MEVERSIONS, MEHASHES, LMS.'); exit(1); return; } + if (settings.action == null) { console.log('No action specified, valid actions are ' + actions.join(', ') + '.'); exit(1); return; } settings.action = settings.action.toLowerCase(); debug(1, "Settings: " + JSON.stringify(settings)); if (settings.action == 'route') { // MeshCentral Router @@ -103,7 +107,7 @@ function run(argv) { if ((settings.remotePort == null) || (typeof settings.remotePort != 'number') || (settings.remotePort < 0) || (settings.remotePort > 65535)) { console.log('No or invalid \"remotePort\" specified, use --remoteport [remoteport].'); exit(1); return; } if (settings.serverUrl != null) { startRouter(); } else { discoverMeshServer(); } // Start MeshCentral Router } - else if ((settings.action == 'loadwebapp') || (settings.action == 'loadsmallwebapp') || (settings.action == 'loadlargewebapp') || (settings.action == 'clearwebapp') || (settings.action == 'storagestate')) { // Intel AMT Web Application Actions + else if ((settings.action == 'amtloadwebapp') || (settings.action == 'amtloadsmallwebapp') || (settings.action == 'amtloadlargewebapp') || (settings.action == 'amtclearwebapp') || (settings.action == 'amtstoragestate')) { // Intel AMT Web Application Actions if ((settings.password == null) || (typeof settings.password != 'string') || (settings.password == '')) { console.log('No or invalid \"password\" specified, use --password [password].'); exit(1); return; } if ((settings.hostname == null) || (typeof settings.hostname != 'string') || (settings.hostname == '')) { settings.hostname = '127.0.0.1'; } if ((settings.username == null) || (typeof settings.username != 'string') || (settings.username == '')) { settings.username = 'admin'; } @@ -112,13 +116,13 @@ function run(argv) { debug(1, "Settings: " + JSON.stringify(settings)); digest = require('http-digest').create(settings.username, settings.password); digest.http = require('http'); - if (settings.action == 'storagestate') { + if (settings.action == 'amtstoragestate') { getAmtStorage(function (statusCode, data) { if (statusCode == 200) { console.log("Storage State: " + JSON.stringify(data, null, 2)); exit(); return; } else { console.log("Unable to read storage state."); exit(); return; } }); } else { - if (settings.action == 'loadwebapp') { settings.webapp = Medium_IntelAmtWebApp; } - else if (settings.action == 'loadsmallwebapp') { settings.webapp = Small_IntelAmtWebApp; } - else if (settings.action == 'loadlargewebapp') { settings.webapp = Large_IntelAmtWebApp; } - else if (settings.action == 'clearwebapp') { settings.webapp = null; } + if (settings.action == 'amtloadwebapp') { settings.webapp = Medium_IntelAmtWebApp; } + else if (settings.action == 'amtloadsmallwebapp') { settings.webapp = Small_IntelAmtWebApp; } + else if (settings.action == 'amtloadlargewebapp') { settings.webapp = Large_IntelAmtWebApp; } + else if (settings.action == 'amtclearwebapp') { settings.webapp = null; } nextStepStorageUpload(); } } else if ((settings.action == 'meversion') || (settings.action == 'meversions') || (settings.action == 'mever')) { @@ -141,7 +145,7 @@ function run(argv) { exitOnCount = handles.length; for (var i = 0; i < handles.length; ++i) { this.getCertHashEntry(handles[i], function (result) { - console.log('----------\r\n' + result.name + ', (' + (result.isDefault ? 'Default' : '') + (result.isActive ? ', Active' : ', Disabled') + ')\r\n' + result.hashAlgorithm + ': ' + result.certificateHash); + console.log('----------\r\n' + result.name + ', (' + (result.isDefault ? 'Default' : '') + (result.isActive ? ', Active' : ', Disabled') + ')\r\n' + result.hashAlgorithmStr + ': ' + result.certificateHash); if (--exitOnCount == 0) { console.log('----------'); exit(1); } }); } @@ -162,15 +166,15 @@ function run(argv) { this.getDnsSuffix(function (result) { mestate.dns = result; var str = 'Intel AMT v' + mestate.ver; - if (mestate.ProvisioningState == 'PRE') { str += ', pre-provisioning state'; } - else if (mestate.ProvisioningState == 'IN') { str += ', in-provisioning state'; } - else if (mestate.ProvisioningState == 'POST') { if (mestate.ProvisioningMode == 'ENTERPRISE') { str += ', activated in ' + mestate.controlmode.consoleMode; } else { str += ', activated in ' + mestate.ProvisioningMode; } } - if (mestate.ehbc == true) { str += ', EHBC enabled'; } + if (mestate.ProvisioningState.stateStr == 'PRE') { str += ', pre-provisioning state'; } + else if (mestate.ProvisioningState.stateStr == 'IN') { str += ', in-provisioning state'; } + else if (mestate.ProvisioningState.stateStr == 'POST') { if (mestate.ProvisioningMode.modeStr == 'ENTERPRISE') { str += ', activated in ' + ["none", "client control mode", "admin control mode", "remote assistance mode"][mestate.controlmode.controlMode]; } else { str += ', activated in ' + mestate.ProvisioningMode.modeStr; } } + if (mestate.ehbc.EHBC == true) { str += ', EHBC enabled'; } console.log(str + '.'); exit(1); }); }); - } else if (settings.action == 'lms') { + } else if (settings.action == 'amtlms') { startLms(); } else { console.log('Invalid \"action\" specified.'); exit(1); return; diff --git a/agents/meshcore.js b/agents/meshcore.js index 6c612ca1..59a8d7b3 100644 --- a/agents/meshcore.js +++ b/agents/meshcore.js @@ -684,7 +684,7 @@ function createMeshCore(agent) { var response = null; switch (cmd) { case 'help': { // Displays available commands - response = 'xxxxxxAvailable commands: help, info, args, print, type, dbget, dbset, dbcompact, parseuri, httpget, wslist, wsconnect, wssend, wsclose, notify, ls, amt, netinfo, location, power, wakeonlan, scanwifi.'; + response = 'Available commands: help, info, args, print, type, dbget, dbset, dbcompact, parseuri, httpget, wslist, wsconnect, wssend, wsclose, notify, ls, amt, netinfo, location, power, wakeonlan, scanwifi.'; break; } case 'notify': { // Send a notification message to the mesh diff --git a/package.json b/package.json index aa62f1b4..9c109ef0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "meshcentral", - "version": "0.1.1-c", + "version": "0.1.1-f", "keywords": [ "Remote Management", "Intel AMT", diff --git a/views/default.handlebars b/views/default.handlebars index 74e18503..61bb4da7 100644 --- a/views/default.handlebars +++ b/views/default.handlebars @@ -754,6 +754,7 @@ hideContextMenu(); // Hide the context menu if present QV('verifyEmailId2', false); QV('logoutControl', false); + serverPoll(); } else if (state == 2) { // Fetch list of meshes, nodes, files meshserver.Send({ action: 'meshes' }); @@ -762,6 +763,18 @@ } } + // Poll the server, if it responds, refresh the page. + function serverPoll() { + xdr = null; + try { xdr = new XDomainRequest(); } catch (e) { } + if (!xdr) xdr = new XMLHttpRequest(); + xdr.open("HEAD", window.location.href); + xdr.timeout = 15000; + xdr.onload = function () { reload(); }; + xdr.onerror = xdr.ontimeout = function () { console.log('error'); setTimeout(serverPoll, 10000); }; + xdr.send(); + } + // Return true if this browser supports clickonce function detectClickOnce() { for (var i in window.navigator.mimeTypes) { if (window.navigator.mimeTypes[i].type == "application/x-ms-application") { return true; } } @@ -1390,7 +1403,10 @@ r += '
'; // This height of 1 div fixes a problem in Linux firefox browsers // Add a "Add Mesh" option - if ((view < 3) && (sort == 0) && (meshcount > 0)) { r += '
Add Mesh
'; } + r += '
'; + if ((view < 3) && (sort == 0) && (meshcount > 0)) { r += 'Add Mesh '; } + r += 'MeshCmd
'; + r += ''; QH('xdevices', r); deviceHeaderSet(); @@ -2481,7 +2497,7 @@ if (mesh.mtype == 2) x += 'Interfaces '; if (xxmap != null) x += 'Location '; - if (mesh.mtype == 2) x += 'Router '; + if (mesh.mtype == 2) x += 'Router '; // RDP link, show this link only of the remote machine is Windows. if (((connectivity & 1) != 0) && (clickOnce == true) && (mesh.mtype == 2) && ((meshrights & 8) != 0)) { @@ -2758,7 +2774,7 @@ } // Show router dialog - function p10showRouterDialog() { + function p10showMeshCmdDialog(mode, nodeid) { if (xxdialogMode) return; var y = ""; var x = ""; - x += "
Download \"meshcmd\" with an action file to route traffic thru this server to this device. Make sure to edit meshaction.txt and add your account password or make any changes needed.

"; + if (mode == 0) { x += '
MeshCmd is a command line tool that performs lots of different operations. The action file can optionally be downloaded and edited to provide server information and credentials.

'; } + if (mode == 1) { x += '
Download "meshcmd" with an action file to route traffic thru this server to this device. Make sure to edit meshaction.txt and add your account password or make any changes needed.

'; } x += addHtmlValue('Operating System', y); - x += addHtmlValue('Mesh Command', ''); - x += addHtmlValue('Action File', 'MeshAction (.txt)'); + x += addHtmlValue('MeshCmd', ''); + if (mode == 0) { x += addHtmlValue('Action File', 'MeshAction (.txt)'); } + if (mode == 1) { x += addHtmlValue('Action File', 'MeshAction (.txt)'); } x += "
"; - setDialogMode(2, "Network Router", 1, null, x, currentNode._id); + setDialogMode(2, ["Download MeshCmd","Network Router"][mode], 9, null, x); meshCmdOsClick(); } diff --git a/webserver.js b/webserver.js index 5505d7d0..e5486933 100644 --- a/webserver.js +++ b/webserver.js @@ -1354,18 +1354,33 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate }); } else if (req.query.meshaction != null) { var domain = checkUserIpAddress(req, res); + if (domain == null) { res.sendStatus(404); return; } var user = obj.users[req.session.userid]; - if (domain == null || req.query.nodeid == null) { res.sendStatus(404); return; } - obj.db.Get(req.query.nodeid, function (err, nodes) { - if (nodes.length != 1) { res.sendStatus(401); return; } - var node = nodes[0]; - // Create the meshaction.txt file for meshcmd.exe + if ((req.query.meshaction == 'route') && (req.query.nodeid != null)) { + obj.db.Get(req.query.nodeid, function (err, nodes) { + if (nodes.length != 1) { res.sendStatus(401); return; } + var node = nodes[0]; + // Create the meshaction.txt file for meshcmd.exe + var meshaction = { + action: req.query.meshaction, + localPort: 1234, + remoteName: node.name, + remoteNodeId: node._id, + remotePort: 3389, + username: '', + password: '', + serverId: obj.agentCertificateHashHex.toUpperCase(), // SHA384 of server HTTPS public key + serverHttpsHash: new Buffer(obj.webCertificateHash, 'binary').toString('hex').toUpperCase(), // SHA384 of server HTTPS certificate + debugLevel: 0 + } + if (user != null) { meshaction.username = user.name; } + if (obj.args.lanonly != true) { meshaction.serverUrl = ((obj.args.notls == true) ? 'ws://' : 'wss://') + obj.certificates.CommonName + ':' + obj.args.port + '/' + ((domain.id == '') ? '' : ('/' + domain.id)) + 'meshrelay.ashx'; } + res.set({ 'Cache-Control': 'no-cache, no-store, must-revalidate', 'Pragma': 'no-cache', 'Expires': '0', 'Content-Type': 'text/plain', 'Content-Disposition': 'attachment; filename=meshaction.txt' }); + res.send(JSON.stringify(meshaction, null, ' ')); + }); + } + else if (req.query.meshaction == 'generic') { var meshaction = { - action: req.query.meshaction, - localPort: 1234, - remoteName: node.name, - remoteNodeId: node._id, - remotePort: 3389, username: '', password: '', serverId: obj.agentCertificateHashHex.toUpperCase(), // SHA384 of server HTTPS public key @@ -1376,7 +1391,9 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate if (obj.args.lanonly != true) { meshaction.serverUrl = ((obj.args.notls == true) ? 'ws://' : 'wss://') + obj.certificates.CommonName + ':' + obj.args.port + '/' + ((domain.id == '') ? '' : ('/' + domain.id)) + 'meshrelay.ashx'; } res.set({ 'Cache-Control': 'no-cache, no-store, must-revalidate', 'Pragma': 'no-cache', 'Expires': '0', 'Content-Type': 'text/plain', 'Content-Disposition': 'attachment; filename=meshaction.txt' }); res.send(JSON.stringify(meshaction, null, ' ')); - }); + } else { + res.sendStatus(401); + } } else { // Send a list of available mesh agents var response = 'Mesh Agents';