Added device power operations to meshctrl.js.

Ylian Saint-Hilaire committed Jan 5, 2021 at 18:29 UTC d919c23461d8bcff4fa7db0ff2ee5a3a2460aec3
4 files changed +81 -9
agents/meshcore.js
+1 -1
@@ -1014,7 +1014,7 @@ function createMeshCore(agent) {
1014 }
1015 case 'wakeonlan': {
1016 // Send wake-on-lan on all interfaces for all MAC addresses in data.macs array. The array is a list of HEX MAC addresses.
1017 - sendConsoleText("Server requesting wake-on-lan for: " + data.macs.join(', '));
1017 + //sendConsoleText("Server requesting wake-on-lan for: " + data.macs.join(', '));
1018 for (var i in data.macs) { sendWakeOnLan(data.macs[i]); }
1019 break;
1020 }
meshctrl.js
+51 -2
@@ -7,7 +7,7 @@ try { require('ws'); } catch (ex) { console.log('Missing module "ws", type "npm
7 var settings = {};
8 const crypto = require('crypto');
9 const args = require('minimist')(process.argv.slice(2));
10 -const possibleCommands = ['edituser', 'listusers', 'listusersessions', 'listdevicegroups', 'listdevices', 'listusersofdevicegroup', 'serverinfo', 'userinfo', 'adduser', 'removeuser', 'adddevicegroup', 'removedevicegroup', 'editdevicegroup', 'broadcast', 'showevents', 'addusertodevicegroup', 'removeuserfromdevicegroup', 'addusertodevice', 'removeuserfromdevice', 'sendinviteemail', 'generateinvitelink', 'config', 'movetodevicegroup', 'deviceinfo', 'addusergroup', 'listusergroups', 'removeusergroup', 'runcommand', 'shell', 'upload', 'download', 'deviceopenurl', 'devicemessage', 'devicetoast', 'addtousergroup', 'removefromusergroup', 'removeallusersfromusergroup', 'devicesharing'];
10 +const possibleCommands = ['edituser', 'listusers', 'listusersessions', 'listdevicegroups', 'listdevices', 'listusersofdevicegroup', 'serverinfo', 'userinfo', 'adduser', 'removeuser', 'adddevicegroup', 'removedevicegroup', 'editdevicegroup', 'broadcast', 'showevents', 'addusertodevicegroup', 'removeuserfromdevicegroup', 'addusertodevice', 'removeuserfromdevice', 'sendinviteemail', 'generateinvitelink', 'config', 'movetodevicegroup', 'deviceinfo', 'addusergroup', 'listusergroups', 'removeusergroup', 'runcommand', 'shell', 'upload', 'download', 'deviceopenurl', 'devicemessage', 'devicetoast', 'addtousergroup', 'removefromusergroup', 'removeallusersfromusergroup', 'devicesharing', 'devicepower'];
11 if (args.proxy != null) { try { require('https-proxy-agent'); } catch (ex) { console.log('Missing module "https-proxy-agent", type "npm install https-proxy-agent" to install it.'); return; } }
12
13 if (args['_'].length == 0) {
@@ -53,6 +53,7 @@ if (args['_'].length == 0) {
53 console.log(" DeviceOpenUrl - Open a URL on a remote device.");
54 console.log(" DeviceMessage - Open a message box on a remote device.");
55 console.log(" DeviceToast - Display a toast notification on a remote device.");
56 + console.log(" DevicePower - Perform wake/sleep/reset/off operations on remote devices.");
57 console.log(" DeviceSharing - View, add and remove sharing links for a given device.");
58 console.log("\r\nSupported login arguments:");
59 console.log(" --url [wss://server] - Server url, wss://localhost:443 is default.");
@@ -206,6 +207,11 @@ if (args['_'].length == 0) {
207 else { ok = true; }
208 break;
209 }
210 + case 'devicepower': {
211 + if (args.id == null) { console.log(winRemoveSingleQuotes("Missing device id, use --id '[deviceid]'")); }
212 + else { ok = true; }
213 + break;
214 + }
215 case 'devicesharing': {
216 if (args.id == null) { console.log(winRemoveSingleQuotes("Missing device id, use --id '[deviceid]'")); }
217 else { ok = true; }
@@ -715,6 +721,26 @@ if (args['_'].length == 0) {
721 console.log(" --powershell - Run a Windows PowerShell.");
722 break;
723 }
724 + case 'devicepower': {
725 + console.log("Perform power operations on remote devices, Example usages:\r\n");
726 + console.log(winRemoveSingleQuotes(" MeshCtrl DevicePower --wake --id 'deviceid'"));
727 + console.log(winRemoveSingleQuotes(" MeshCtrl DevicePower --sleep --id 'deviceid'"));
728 + console.log(winRemoveSingleQuotes(" MeshCtrl DevicePower --reset --id 'deviceid'"));
729 + console.log(winRemoveSingleQuotes(" MeshCtrl DevicePower --off --id 'deviceid1,deviceid2'"));
730 + console.log("\r\nNote that some power operations may take up to a minute to execute.\r\n");
731 + console.log("Required arguments:\r\n");
732 + if (process.platform == 'win32') {
733 + console.log(" --id [deviceid1,deviceid2] - Device identifiers.");
734 + } else {
735 + console.log(" --id '[deviceid1,deviceid2]' - Device identifiers.");
736 + }
737 + console.log("\r\nOptional arguments:\r\n");
738 + console.log(" --wake - Attempt to wake up the remote device.");
739 + console.log(" --reset - Attempt to remote the remote device.");
740 + console.log(" --sleep - Attempt to place the remote device in low power mode.");
741 + console.log(" --off - Attempt to power off the remote device.");
742 + break;
743 + }
744 case 'devicesharing': {
745 var tzoffset = (new Date()).getTimezoneOffset() * 60000; // Offset in milliseconds
746 var localISOTime = (new Date(Date.now() - tzoffset)).toISOString().slice(0, -5);
@@ -722,7 +748,7 @@ if (args['_'].length == 0) {
748 console.log(winRemoveSingleQuotes(" MeshCtrl DeviceSharing --id 'deviceid'"));
749 console.log(winRemoveSingleQuotes(" MeshCtrl DeviceSharing --id 'deviceid' --remote abcdef"));
750 console.log(winRemoveSingleQuotes(" MeshCtrl DeviceSharing --id 'deviceid' --add Guest --start " + localISOTime + " --duration 30"));
725 - console.log(winRemoveSingleQuotes(" MeshCtrl DeviceSharing --id 'deviceid' --add Guest --type terminal --consent prompt"));
751 + console.log(winRemoveSingleQuotes(" MeshCtrl DeviceSharing --id 'deviceid' --add Guest --type terminal --consent prompt"));
752 console.log("\r\nRequired arguments:\r\n");
753 if (process.platform == 'win32') {
754 console.log(" --id [deviceid] - The device identifier.");
@@ -1317,6 +1343,26 @@ function serverConnect() {
1343 ws.send("{\"action\":\"authcookie\"}");
1344 break;
1345 }
1346 + case 'devicepower': {
1347 + var nodes = args.id.split(',');
1348 + if (args.wake) {
1349 + // Wake operation
1350 + ws.send(JSON.stringify({ action: 'wakedevices', nodeids: nodes, responseid: 'meshctrl' }));
1351 + } else if (args.off) {
1352 + // Power off operation
1353 + ws.send(JSON.stringify({ action: 'poweraction', nodeids: nodes, actiontype: 2, responseid: 'meshctrl' }));
1354 + } else if (args.reset) {
1355 + // Reset operation
1356 + ws.send(JSON.stringify({ action: 'poweraction', nodeids: nodes, actiontype: 3, responseid: 'meshctrl' }));
1357 + } else if (args.sleep) {
1358 + // Sleep operation
1359 + ws.send(JSON.stringify({ action: 'poweraction', nodeids: nodes, actiontype: 4, responseid: 'meshctrl' }));
1360 + } else {
1361 + console.log('No power operation specified.');
1362 + process.exit(1);
1363 + }
1364 + break;
1365 + }
1366 case 'devicesharing': {
1367 if (args.add) {
1368 if (args.add.length == 0) { console.log("Invalid guest name."); process.exit(1); }
@@ -1544,14 +1590,17 @@ function serverConnect() {
1590 case 'createmesh': // ADDDEVICEGROUP
1591 case 'deletemesh': // REMOVEDEVICEGROUP
1592 case 'editmesh': // EDITDEVICEGROUP
1593 + case 'wakedevices':
1594 case 'changeDeviceMesh':
1595 case 'addmeshuser': //
1596 case 'removemeshuser': //
1597 + case 'wakedevices': //
1598 case 'inviteAgent': //
1599 case 'adddeviceuser': //
1600 case 'createusergroup': //
1601 case 'deleteusergroup': //
1602 case 'runcommands':
1603 + case 'poweraction':
1604 case 'addusertousergroup':
1605 case 'removeuserfromusergroup':
1606 case 'removeDeviceShare':
meshuser.js
+27 -4
@@ -3643,8 +3643,15 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
3643
3644 // Perform wake-on-lan
3645 for (i in command.nodeids) {
3646 + var nodeid = command.nodeids[i];
3647 +
3648 + // Argument validation
3649 + if (common.validateString(nodeid, 8, 128) == false) { continue; } // Check the nodeid
3650 + else if (nodeid.indexOf('/') == -1) { nodeid = 'node/' + domain.id + '/' + nodeid; }
3651 + else if ((nodeid.split('/').length != 3) || (nodeid.split('/')[1] != domain.id)) { continue; } // Invalid domain, operation only valid for current domain
3652 +
3653 // Get the node and the rights for this node
3647 - parent.GetNodeWithRights(domain, user, command.nodeids[i], function (node, rights, visible) {
3654 + parent.GetNodeWithRights(domain, user, nodeid, function (node, rights, visible) {
3655 // Check we have the rights to delete this device
3656 if ((rights & MESHRIGHT_WAKEDEVICE) == 0) return;
3657
@@ -3681,8 +3688,13 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
3688 }
3689 });
3690 });
3691 +
3692 // Confirm we may be doing something (TODO)
3685 - try { ws.send(JSON.stringify({ action: 'wakedevices' })); } catch (ex) { }
3693 + if (command.responseid != null) {
3694 + try { ws.send(JSON.stringify({ action: 'wakedevices', responseid: command.responseid, result: 'ok' })); } catch (ex) { }
3695 + } else {
3696 + try { ws.send(JSON.stringify({ action: 'wakedevices' })); } catch (ex) { }
3697 + }
3698 }
3699 break;
3700 }
@@ -3782,8 +3794,15 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
3794 if (common.validateArray(command.nodeids, 1) == false) break; // Check nodeid's
3795 if (common.validateInt(command.actiontype, 2, 4) == false) break; // Check actiontype
3796 for (i in command.nodeids) {
3797 + var nodeid = command.nodeids[i];
3798 +
3799 + // Argument validation
3800 + if (common.validateString(nodeid, 8, 128) == false) { continue; } // Check the nodeid
3801 + else if (nodeid.indexOf('/') == -1) { nodeid = 'node/' + domain.id + '/' + nodeid; }
3802 + else if ((nodeid.split('/').length != 3) || (nodeid.split('/')[1] != domain.id)) { continue; } // Invalid domain, operation only valid for current domain
3803 +
3804 // Get the node and the rights for this node
3786 - parent.GetNodeWithRights(domain, user, command.nodeids[i], function (node, rights, visible) {
3805 + parent.GetNodeWithRights(domain, user, nodeid, function (node, rights, visible) {
3806 // Check we have the rights to delete this device
3807 if ((rights & MESHRIGHT_RESETOFF) == 0) return;
3808
@@ -3798,7 +3817,11 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
3817 });
3818
3819 // Confirm we may be doing something (TODO)
3801 - try { ws.send(JSON.stringify({ action: 'poweraction' })); } catch (ex) { }
3820 + if (command.responseid != null) {
3821 + try { ws.send(JSON.stringify({ action: 'poweraction', responseid: command.responseid, result: 'ok' })); } catch (ex) { }
3822 + } else {
3823 + try { ws.send(JSON.stringify({ action: 'poweraction' })); } catch (ex) { }
3824 + }
3825 }
3826 break;
3827 }
readme.md
+2 -2
@@ -12,9 +12,9 @@
12
13 MeshCentral is a full computer management web site. With MeshCentral, you can run your own web server to remotely manage and control computers on a local network or anywhere on the internet. Once you get the server started, create device group and download and install an agent on each computer you want to manage. A minute later, the new computer will show up on the web site and you can take control of it. MeshCentral includes full web-based remote desktop, terminal and file management capability.
14
15 -To try out this software, please go to [MeshCentral.com](http://meshcentral.com). Be mindful that the public MeshCentral server comes with no guaranties, most should setup their own server
15 +To try out this software on the public server, please visit [MeshCentral.com/login](https://meshcentral.com/login). Be mindful that the public MeshCentral server comes with no guaranties, most should setup their own server.
16
17 -For more information, [visit MeshCommander.com/MeshCentral2](https://www.meshcommander.com/meshcentral2).
17 +For more information, [visit MeshCentral.com](https://www.meshcentral.com).
18
19 ## Social Media
20 [Reddit](https://www.reddit.com/r/MeshCentral/)