AddLocalDevice and AddAmtDevice to meshctrl.js #6473

Signed-off-by: si458 <simonsmith5521@gmail.com>

si458 committed Oct 25, 2024 at 10:34 UTC 141bec559fb291a0f361826d3000851a118e08cb
2 files changed +170 -57
meshctrl.js
+93 -1
@@ -16,7 +16,7 @@ var settings = {};
16 const crypto = require('crypto');
17 const args = require('minimist')(process.argv.slice(2));
18 const path = require('path');
19 -const possibleCommands = ['edituser', 'listusers', 'listusersessions', 'listdevicegroups', 'listdevices', 'listusersofdevicegroup', 'listevents', 'logintokens', 'serverinfo', 'userinfo', 'adduser', 'removeuser', 'adddevicegroup', 'removedevicegroup', 'editdevicegroup', 'broadcast', 'showevents', 'addusertodevicegroup', 'removeuserfromdevicegroup', 'addusertodevice', 'removeuserfromdevice', 'sendinviteemail', 'generateinvitelink', 'config', 'movetodevicegroup', 'deviceinfo', 'removedevice', 'editdevice', 'addusergroup', 'listusergroups', 'removeusergroup', 'runcommand', 'shell', 'upload', 'download', 'deviceopenurl', 'devicemessage', 'devicetoast', 'addtousergroup', 'removefromusergroup', 'removeallusersfromusergroup', 'devicesharing', 'devicepower', 'indexagenterrorlog', 'agentdownload', 'report', 'grouptoast', 'groupmessage'];
19 +const possibleCommands = ['edituser', 'listusers', 'listusersessions', 'listdevicegroups', 'listdevices', 'listusersofdevicegroup', 'listevents', 'logintokens', 'serverinfo', 'userinfo', 'adduser', 'removeuser', 'adddevicegroup', 'removedevicegroup', 'editdevicegroup', 'broadcast', 'showevents', 'addusertodevicegroup', 'removeuserfromdevicegroup', 'addusertodevice', 'removeuserfromdevice', 'sendinviteemail', 'generateinvitelink', 'config', 'movetodevicegroup', 'deviceinfo', 'removedevice', 'editdevice', 'addlocaldevice', 'addamtdevice', 'addusergroup', 'listusergroups', 'removeusergroup', 'runcommand', 'shell', 'upload', 'download', 'deviceopenurl', 'devicemessage', 'devicetoast', 'addtousergroup', 'removefromusergroup', 'removeallusersfromusergroup', 'devicesharing', 'devicepower', 'indexagenterrorlog', 'agentdownload', 'report', 'grouptoast', 'groupmessage'];
20 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; } }
21
22 if (args['_'].length == 0) {
@@ -36,6 +36,8 @@ if (args['_'].length == 0) {
36 console.log(" ListEvents - List server events.");
37 console.log(" LoginTokens - List, create and remove login tokens.");
38 console.log(" DeviceInfo - Show information about a device.");
39 + console.log(" AddLocalDevice - Add a local device.");
40 + console.log(" AddAmtDevice - Add a AMT device.");
41 console.log(" EditDevice - Make changes to a device.");
42 console.log(" RemoveDevice - Delete a device.");
43 console.log(" Config - Perform operation on config.json file.");
@@ -109,6 +111,22 @@ if (args['_'].length == 0) {
111 else { ok = true; }
112 break;
113 }
114 + case 'addlocaldevice': {
115 + if (args.id == null) { console.log(winRemoveSingleQuotes("Missing device id, use --id '[deviceid]'")); }
116 + else if (args.devicename == null) { console.log(winRemoveSingleQuotes("Missing devicename, use --devicename [devicename]")); }
117 + else if (args.hostname == null) { console.log(winRemoveSingleQuotes("Missing hostname, use --hostname [hostname]")); }
118 + else { ok = true; }
119 + break;
120 + }
121 + case 'addamtdevice': {
122 + if (args.id == null) { console.log(winRemoveSingleQuotes("Missing device id, use --id '[deviceid]'")); }
123 + else if (args.devicename == null) { console.log(winRemoveSingleQuotes("Missing devicename, use --devicename [devicename]")); }
124 + else if (args.hostname == null) { console.log(winRemoveSingleQuotes("Missing hostname, use --hostname [hostname]")); }
125 + else if (args.user == null) { console.log(winRemoveSingleQuotes("Missing user, use --user [user]")); }
126 + else if (args.pass == null) { console.log(winRemoveSingleQuotes("Missing pass, use --pass [pass]")); }
127 + else { ok = true; }
128 + break;
129 + }
130 case 'addusertodevicegroup': {
131 if ((args.id == null) && (args.group == null)) { console.log(winRemoveSingleQuotes("Device group identifier missing, use --id '[groupid]' or --group [groupname]")); }
132 else if (args.userid == null) { console.log("Add user to group missing useid, use --userid [userid]"); }
@@ -788,6 +806,55 @@ if (args['_'].length == 0) {
806 }
807 break;
808 }
809 + case 'addlocaldevice': {
810 + console.log("Add a Local Device, Example usages:\r\n");
811 + console.log(winRemoveSingleQuotes(" MeshCtrl AddLocalDevice --id 'meshid' --devicename 'devicename' --hostname 'hostname'"));
812 + console.log(winRemoveSingleQuotes(" MeshCtrl AddLocalDevice --id 'meshid' --devicename 'devicename' --hostname 'hostname' --type 6"));
813 + console.log("\r\nRequired arguments:\r\n");
814 + if (process.platform == 'win32') {
815 + console.log(" --id [meshid] - The mesh identifier.");
816 + console.log(" --devicename [devicename] - The device name.");
817 + console.log(" --hostname [hostname] - The devices hostname or ip address.");
818 + } else {
819 + console.log(" --id '[meshid]' - The mesh identifier.");
820 + console.log(" --devicename '[devicename]' - The device name.");
821 + console.log(" --hostname '[hostname]' - The devices hostname or ip address.");
822 + }
823 +
824 + console.log("\r\nOptional arguments:\r\n");
825 + console.log(" --type [TypeNumber] - With the following choices:");
826 + console.log(" type 4 - Default, Windows (RDP)");
827 + console.log(" type 6 - Linux (SSH/SCP/VNC)");
828 + console.log(" type 29 - macOS (SSH/SCP/VNC)");
829 + break;
830 + }
831 + case 'addamtdevice': {
832 + console.log("Add an Intel AMT Device, Example usages:\r\n");
833 + console.log(winRemoveSingleQuotes(" MeshCtrl AddAmtDevice --id 'meshid' --devicename 'devicename' --hostname 'hostname --user 'admin' --pass 'admin'"));
834 + console.log(winRemoveSingleQuotes(" MeshCtrl AddAmtDevice --id 'meshid' --devicename 'devicename' --hostname 'hostname --user 'admin' --pass 'admin' --notls"));
835 + console.log("\r\nRequired arguments:\r\n");
836 + if (process.platform == 'win32') {
837 + console.log(" --id [meshid] - The mesh identifier.");
838 + console.log(" --devicename [devicename] - The device name.");
839 + console.log(" --hostname [hostname] - The devices hostname or ip address.");
840 + console.log(" --user [user] - The devices AMT username.");
841 + console.log(" --pass [pass] - The devices AMT password.");
842 + console.log("")
843 + } else {
844 + console.log(" --id '[meshid]' - The mesh identifier.");
845 + console.log(" --devicename '[devicename]' - The device name.");
846 + console.log(" --hostname '[hostname]' - The devices hostname or ip address.");
847 + console.log(" --user '[user]' - The devices AMT username.");
848 + console.log(" --pass '[pass]' - The devices AMT password.");
849 + }
850 + console.log("\r\nOptional arguments:\r\n");
851 + if (process.platform == 'win32') {
852 + console.log(" --notls - Use No TLS Security.");
853 + } else {
854 + console.log(" --notls - Use No TLS Security.");
855 + }
856 + break;
857 + }
858 case 'editdevice': {
859 console.log("Change information about a device, Example usages:\r\n");
860 console.log(winRemoveSingleQuotes(" MeshCtrl EditDevice --id 'deviceid' --name 'device1'"));
@@ -1490,6 +1557,29 @@ function serverConnect() {
1557 ws.send(JSON.stringify(op));
1558 break;
1559 }
1560 + case 'addamtdevice': {
1561 + var op = { action: 'addamtdevice', amttls: 1, responseid: 'meshctrl' };
1562 + if (args.id) { op.meshid = args.id; }
1563 + if ((typeof args.devicename == 'string') && (args.devicename != '')) { op.devicename = args.devicename; }
1564 + if ((typeof args.hostname == 'string') && (args.hostname != '')) { op.hostname = args.hostname; }
1565 + if ((typeof args.user == 'string') && (args.user != '')) { op.amtusername = args.user; }
1566 + if ((typeof args.pass == 'string') && (args.pass != '')) { op.amtpassword = args.pass; }
1567 + if (args.notls) { op.amttls = 0; }
1568 + ws.send(JSON.stringify(op));
1569 + break;
1570 + }
1571 + case 'addlocaldevice': {
1572 + var op = { action: 'addlocaldevice', type: 4, responseid: 'meshctrl' };
1573 + if (args.id) { op.meshid = args.id; }
1574 + if ((typeof args.devicename == 'string') && (args.devicename != '')) { op.devicename = args.devicename; }
1575 + if ((typeof args.hostname == 'string') && (args.hostname != '')) { op.hostname = args.hostname; }
1576 + if (args.type) {
1577 + if ((typeof parseInt(args.type) != 'number') || isNaN(parseInt(args.type))) { console.log("Invalid type."); process.exit(1); return; }
1578 + op.type = args.type;
1579 + }
1580 + ws.send(JSON.stringify(op));
1581 + break;
1582 + }
1583 case 'editdevicegroup': {
1584 var op = { action: 'editmesh', responseid: 'meshctrl' };
1585 if (args.id) { op.meshid = args.id; } else if (args.group) { op.meshidname = args.group; }
@@ -2084,6 +2174,8 @@ function serverConnect() {
2174 case 'toast': // TOAST
2175 case 'adduser': // ADDUSER
2176 case 'edituser': // EDITUSER
2177 + case 'addamtdevice': // ADDAMTDEVICE
2178 + case 'addlocaldevice': // ADDLOCALDEVICE
2179 case 'removedevices': // REMOVEDEVICE
2180 case 'changedevice': // EDITDEVICE
2181 case 'deleteuser': // REMOVEUSER
meshuser.js
+77 -56
@@ -2555,77 +2555,98 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
2555 }
2556 case 'addlocaldevice':
2557 {
2558 - if (common.validateString(command.meshid, 8, 134) == false) break; // Check meshid
2559 - if ((command.meshid.split('/').length != 3) || (command.meshid.split('/')[1] != domain.id)) return; // Invalid domain, operation only valid for current domain
2560 - if (common.validateString(command.devicename, 1, 256) == false) break; // Check device name
2561 - if (common.validateString(command.hostname, 1, 256) == false) break; // Check hostname
2562 - if (typeof command.type != 'number') break; // Type must be a number
2563 - if ((command.type != 4) && (command.type != 6) && (command.type != 29)) break; // Check device type
2564 -
2565 - // Get the mesh
2566 - mesh = parent.meshes[command.meshid];
2567 - if (mesh) {
2568 - if (mesh.mtype != 3) return; // This operation is only allowed for mesh type 3, local device agentless mesh.
2569 -
2570 - // Check if this user has rights to do this
2571 - if ((parent.GetMeshRights(user, mesh) & MESHRIGHT_MANAGECOMPUTERS) == 0) return;
2572 -
2573 - // Create a new nodeid
2574 - parent.crypto.randomBytes(48, function (err, buf) {
2575 - // Create the new node
2576 - nodeid = 'node/' + domain.id + '/' + buf.toString('base64').replace(/\+/g, '@').replace(/\//g, '$');
2577 - var device = { type: 'node', _id: nodeid, meshid: command.meshid, mtype: 3, icon: 1, name: command.devicename, host: command.hostname, domain: domain.id, agent: { id: command.type, caps: 0 } };
2578 - db.Set(device);
2579 -
2580 - // Event the new node
2581 - parent.parent.DispatchEvent(parent.CreateMeshDispatchTargets(command.meshid, [nodeid]), obj, { etype: 'node', userid: user._id, username: user.name, action: 'addnode', node: parent.CloneSafeNode(device), msgid: 84, msgArgs: [command.devicename, mesh.name], msg: 'Added device ' + command.devicename + ' to device group ' + mesh.name, domain: domain.id });
2582 - });
2558 + var err = null;
2559 + // Perform input validation
2560 + try {
2561 + if (common.validateString(command.meshid, 8, 134) == false) { err = "Invalid device group id"; } // Check meshid
2562 + if (common.validateString(command.devicename, 1, 256) == false) { err = "Invalid devicename"; } // Check device name
2563 + if (common.validateString(command.hostname, 1, 256) == false) { err = "Invalid hostname"; } // Check hostname
2564 + if (typeof command.type != 'number') { err = "Invalid type"; } // Type must be a number
2565 + if ((command.type != 4) && (command.type != 6) && (command.type != 29)) { err = "Invalid type"; } // Check device type
2566 + else {
2567 + if (command.meshid.indexOf('/') == -1) { command.meshid = 'mesh/' + domain.id + '/' + command.meshid; }
2568 + mesh = parent.meshes[command.meshid];
2569 + if (mesh == null) { err = "Unknown device group"; }
2570 + if (mesh.mtype != 3) { err = "Local device agentless mesh only allowed" } // This operation is only allowed for mesh type 3, local device agentless mesh.
2571 + else if ((parent.GetMeshRights(user, mesh) & MESHRIGHT_MANAGECOMPUTERS) == 0) { err = "Permission denied"; }
2572 + else if ((command.meshid.split('/').length != 3) || (command.meshid.split('/')[1] != domain.id)) { err = "Invalid domain"; } // Invalid domain, operation only valid for current domain
2573 + }
2574 + } catch (ex) { console.log(ex); err = "Validation exception: " + ex; }
2575 + // Handle any errors
2576 + if (err != null) {
2577 + if (command.responseid != null) { try { ws.send(JSON.stringify({ action: 'changeDeviceMesh', responseid: command.responseid, result: err })); } catch (ex) { } }
2578 + break;
2579 }
2580
2581 + // Create a new nodeid
2582 + parent.crypto.randomBytes(48, function (err, buf) {
2583 + // Create the new node
2584 + nodeid = 'node/' + domain.id + '/' + buf.toString('base64').replace(/\+/g, '@').replace(/\//g, '$');
2585 + var device = { type: 'node', _id: nodeid, meshid: command.meshid, mtype: 3, icon: 1, name: command.devicename, host: command.hostname, domain: domain.id, agent: { id: command.type, caps: 0 } };
2586 + db.Set(device);
2587 +
2588 + // Event the new node
2589 + parent.parent.DispatchEvent(parent.CreateMeshDispatchTargets(command.meshid, [nodeid]), obj, { etype: 'node', userid: user._id, username: user.name, action: 'addnode', node: parent.CloneSafeNode(device), msgid: 84, msgArgs: [command.devicename, mesh.name], msg: 'Added device ' + command.devicename + ' to device group ' + mesh.name, domain: domain.id });
2590 + // Send response if required
2591 + if (command.responseid != null) { try { ws.send(JSON.stringify({ action: 'addlocaldevice', responseid: command.responseid, result: 'ok' })); } catch (ex) { } }
2592 + });
2593 break;
2594 }
2595 case 'addamtdevice':
2596 {
2597 if (args.wanonly == true) return; // This is a WAN-only server, local Intel AMT computers can't be added
2590 - if (common.validateString(command.meshid, 8, 134) == false) break; // Check meshid
2591 - if ((command.meshid.split('/').length != 3) || (command.meshid.split('/')[1] != domain.id)) return; // Invalid domain, operation only valid for current domain
2592 - if (common.validateString(command.devicename, 1, 256) == false) break; // Check device name
2593 - if (common.validateString(command.hostname, 1, 256) == false) break; // Check hostname
2594 - if (common.validateString(command.amtusername, 0, 16) == false) break; // Check username
2595 - if (common.validateString(command.amtpassword, 0, 16) == false) break; // Check password
2596 - if (command.amttls == '0') { command.amttls = 0; } else if (command.amttls == '1') { command.amttls = 1; } // Check TLS flag
2597 - if ((command.amttls != 1) && (command.amttls != 0)) break;
2598 + var err = null;
2599 + // Perform input validation
2600 + try {
2601 + if (common.validateString(command.meshid, 8, 134) == false) { err = "Invalid device group id"; } // Check meshid
2602 + if (common.validateString(command.devicename, 1, 256) == false) { err = "Invalid devicename"; } // Check device name
2603 + if (common.validateString(command.hostname, 1, 256) == false) { err = "Invalid hostname"; } // Check hostname
2604 + if (common.validateString(command.amtusername, 0, 16) == false) { err = "Invalid amtusername"; } // Check username
2605 + if (common.validateString(command.amtpassword, 0, 16) == false) { err = "Invalid amtpassword"; } // Check password
2606 + if (command.amttls == '0') { command.amttls = 0; } else if (command.amttls == '1') { command.amttls = 1; } // Check TLS flag
2607 + if ((command.amttls != 1) && (command.amttls != 0)) { err = "Invalid amttls"; }
2608 + else {
2609 + if (command.meshid.indexOf('/') == -1) { command.meshid = 'mesh/' + domain.id + '/' + command.meshid; }
2610 + // Get the mesh
2611 + mesh = parent.meshes[command.meshid];
2612 + if (mesh == null) { err = "Unknown device group"; }
2613 + if (mesh.mtype != 1) { err = "Intel AMT agentless mesh only allowed"; } // This operation is only allowed for mesh type 1, Intel AMT agentless mesh.
2614 + // Check if this user has rights to do this
2615 + else if ((parent.GetMeshRights(user, mesh) & MESHRIGHT_MANAGECOMPUTERS) == 0) { err = "Permission denied"; }
2616 + else if ((command.meshid.split('/').length != 3) || (command.meshid.split('/')[1] != domain.id)) { err = "Invalid domain"; } // Invalid domain, operation only valid for current domain
2617 + }
2618 + } catch (ex) { console.log(ex); err = "Validation exception: " + ex; }
2619 +
2620 + // Handle any errors
2621 + if (err != null) {
2622 + if (command.responseid != null) { try { ws.send(JSON.stringify({ action: 'changeDeviceMesh', responseid: command.responseid, result: err })); } catch (ex) { } }
2623 + break;
2624 + }
2625
2626 // If we are in WAN-only mode, hostname is not used
2627 if ((args.wanonly == true) && (command.hostname)) { delete command.hostname; }
2628
2602 - // Get the mesh
2603 - mesh = parent.meshes[command.meshid];
2604 - if (mesh) {
2605 - if (mesh.mtype != 1) return; // This operation is only allowed for mesh type 1, Intel AMT agentless mesh.
2606 -
2607 - // Check if this user has rights to do this
2608 - if ((parent.GetMeshRights(user, mesh) & MESHRIGHT_MANAGECOMPUTERS) == 0) return;
2629 + // Create a new nodeid
2630 + parent.crypto.randomBytes(48, function (err, buf) {
2631 + // Create the new node
2632 + nodeid = 'node/' + domain.id + '/' + buf.toString('base64').replace(/\+/g, '@').replace(/\//g, '$');
2633 + var device = { type: 'node', _id: nodeid, meshid: command.meshid, mtype: 1, icon: 1, name: command.devicename, host: command.hostname, domain: domain.id, intelamt: { user: command.amtusername, pass: command.amtpassword, tls: command.amttls } };
2634
2610 - // Create a new nodeid
2611 - parent.crypto.randomBytes(48, function (err, buf) {
2612 - // Create the new node
2613 - nodeid = 'node/' + domain.id + '/' + buf.toString('base64').replace(/\+/g, '@').replace(/\//g, '$');
2614 - var device = { type: 'node', _id: nodeid, meshid: command.meshid, mtype: 1, icon: 1, name: command.devicename, host: command.hostname, domain: domain.id, intelamt: { user: command.amtusername, pass: command.amtpassword, tls: command.amttls } };
2635 + // Add optional feilds
2636 + if (common.validateInt(command.state, 0, 3)) { device.intelamt.state = command.state; }
2637 + if (common.validateString(command.ver, 1, 16)) { device.intelamt.ver = command.ver; }
2638 + if (common.validateString(command.hash, 1, 256)) { device.intelamt.hash = command.hash; }
2639 + if (common.validateString(command.realm, 1, 256)) { device.intelamt.realm = command.realm; }
2640
2616 - // Add optional feilds
2617 - if (common.validateInt(command.state, 0, 3)) { device.intelamt.state = command.state; }
2618 - if (common.validateString(command.ver, 1, 16)) { device.intelamt.ver = command.ver; }
2619 - if (common.validateString(command.hash, 1, 256)) { device.intelamt.hash = command.hash; }
2620 - if (common.validateString(command.realm, 1, 256)) { device.intelamt.realm = command.realm; }
2641 + // Save the device to the database
2642 + db.Set(device);
2643
2622 - // Save the device to the database
2623 - db.Set(device);
2644 + // Event the new node
2645 + parent.parent.DispatchEvent(parent.CreateMeshDispatchTargets(command.meshid, [nodeid]), obj, { etype: 'node', userid: user._id, username: user.name, action: 'addnode', node: parent.CloneSafeNode(device), msgid: 84, msgArgs: [command.devicename, mesh.name], msg: 'Added device ' + command.devicename + ' to device group ' + mesh.name, domain: domain.id });
2646 + // Send response if required
2647 + if (command.responseid != null) { try { ws.send(JSON.stringify({ action: 'addamtdevice', responseid: command.responseid, result: 'ok' })); } catch (ex) { } }
2648 + });
2649
2625 - // Event the new node
2626 - parent.parent.DispatchEvent(parent.CreateMeshDispatchTargets(command.meshid, [nodeid]), obj, { etype: 'node', userid: user._id, username: user.name, action: 'addnode', node: parent.CloneSafeNode(device), msgid: 84, msgArgs: [command.devicename, mesh.name], msg: 'Added device ' + command.devicename + ' to device group ' + mesh.name, domain: domain.id });
2627 - });
2628 - }
2650 break;
2651 }
2652 case 'scanamtdevice':