From 8da5c11b42d473f4022c7ed55f2ad6c1c7ef3284 Mon Sep 17 00:00:00 2001 From: Ylian Saint-Hilaire Date: Thu, 16 Apr 2020 08:46:53 -0700 Subject: [PATCH] Added device group move to MeshCtrl. --- meshctrl.js | 25 +++++++++++++++++- meshuser.js | 55 +++++++++++++++++++++++++++++++++++----- translate/translate.json | 4 +-- 3 files changed, 75 insertions(+), 9 deletions(-) diff --git a/meshctrl.js b/meshctrl.js index b8941f7f..3363903a 100644 --- a/meshctrl.js +++ b/meshctrl.js @@ -7,7 +7,7 @@ try { require('ws'); } catch (ex) { console.log('Missing module "ws", type "npm var settings = {}; const crypto = require('crypto'); const args = require('minimist')(process.argv.slice(2)); -const possibleCommands = ['listusers', 'listdevicegroups', 'listdevices', 'listusersofdevicegroup', 'serverinfo', 'userinfo', 'adduser', 'removeuser', 'adddevicegroup', 'removedevicegroup', 'broadcast', 'showevents', 'addusertodevicegroup', 'removeuserfromdevicegroup', 'addusertodevice', 'removeuserfromdevice', 'sendinviteemail', 'generateinvitelink', 'config']; +const possibleCommands = ['listusers', 'listdevicegroups', 'listdevices', 'listusersofdevicegroup', 'serverinfo', 'userinfo', 'adduser', 'removeuser', 'adddevicegroup', 'removedevicegroup', 'broadcast', 'showevents', 'addusertodevicegroup', 'removeuserfromdevicegroup', 'addusertodevice', 'removeuserfromdevice', 'sendinviteemail', 'generateinvitelink', 'config', 'movetodevicegroup']; 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; } } if (args['_'].length == 0) { @@ -27,6 +27,7 @@ if (args['_'].length == 0) { console.log(" RemoveUser - Delete a user account."); console.log(" AddDeviceGroup - Create a new device group."); console.log(" RemoveDeviceGroup - Delete a device group."); + console.log(" MoveToDeviceGroup - Move a device to a different device group."); console.log(" AddUserToDeviceGroup - Add a user to a device group."); console.log(" RemoveUserFromDeviceGroup - Remove a user from a device group."); console.log(" AddUserToDevice - Add a user to a device."); @@ -97,6 +98,12 @@ if (args['_'].length == 0) { else { ok = true; } break; } + case 'movetodevicegroup': { + if ((args.id == null) && (args.group == null)) { console.log("Device group identifier missing, use --id [groupid] or --group [groupname]"); } + else if (args.devid == null) { console.log("Device identifier missing, use --devid [deviceid]"); } + else { ok = true; } + break; + } case 'broadcast': { if (args.msg == null) { console.log("Message missing, use --msg [message]"); } else { ok = true; } @@ -266,6 +273,15 @@ if (args['_'].length == 0) { console.log(" --group [groupname] - Device group name (or --id)."); break; } + case 'movetodevicegroup': { + console.log("Move a device to a new device group, Example usages:\r\n"); + console.log(" MeshCtrl MoveToDeviceGroup --devid deviceid --id groupid"); + console.log("\r\nRequired arguments:\r\n"); + console.log(" --id [groupid] - Device group identifier (or --group)."); + console.log(" --group [groupname] - Device group name (or --id)."); + console.log(" --devid [deviceid] - Device identifier."); + break; + } case 'addusertodevicegroup': { console.log("Add a user to a device group, Example usages:\r\n"); console.log(" MeshCtrl AddUserToDeviceGroup --id groupid --userid userid --fullrights"); @@ -591,6 +607,12 @@ function serverConnect() { ws.send(JSON.stringify(op)); break; } + case 'movetodevicegroup': { + var op = { action: 'changeDeviceMesh', responseid: 'meshctrl', nodeids: [ args.devid ] }; + if (args.id) { op.meshid = args.id; } else if (args.group) { op.meshname = args.group; } + ws.send(JSON.stringify(op)); + break; + } case 'addusertodevicegroup': { var meshrights = 0; if (args.fullrights) { meshrights = 0xFFFFFFFF; } @@ -716,6 +738,7 @@ function serverConnect() { case 'deleteuser': // REMOVEUSER case 'createmesh': // ADDDEVICEGROUP case 'deletemesh': // REMOVEDEVICEGROUP + case 'changeDeviceMesh': case 'addmeshuser': // case 'removemeshuser': // case 'inviteAgent': // diff --git a/meshuser.js b/meshuser.js index 83e5e615..53200b2a 100644 --- a/meshuser.js +++ b/meshuser.js @@ -2817,22 +2817,62 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use } case 'changeDeviceMesh': { - if (common.validateStrArray(command.nodeids, 1, 256) == false) break; // Check nodeid strings - if (common.validateString(command.meshid, 1, 256) == false) break; // Check target meshid string + var err = null; + + // Resolve the device group name if needed + if ((typeof command.meshname == 'string') && (command.meshid == null)) { + for (var i in parent.meshes) { + var m = parent.meshes[i]; + if ((m.mtype == 2) && (m.name == command.meshname) && parent.IsMeshViewable(user, m)) { + if (command.meshid == null) { command.meshid = m._id; } else { err = 'Duplicate device groups found'; } + } + } + } + + // Perform input validation + try { + if (common.validateStrArray(command.nodeids, 1, 256) == false) { err = "Invalid nodeids"; } // Check nodeids + if (common.validateString(command.meshid, 1, 1024) == false) { err = "Invalid groupid"; } // Check meshid + else { + if (command.meshid.indexOf('/') == -1) { command.meshid = 'mesh/' + domain.id + '/' + command.meshid; } + mesh = parent.meshes[command.meshid]; + if (mesh == null) { err = "Unknown device group"; } + else if ((parent.GetMeshRights(user, mesh) & MESHRIGHT_MANAGECOMPUTERS) == 0) { err = "Permission denied"; } + else if ((command.meshid.split('/').length != 3) || (command.meshid.split('/')[1] != domain.id)) { err = "Invalid domain"; } // Invalid domain, operation only valid for current domain + } + } catch (ex) { console.log(ex); err = "Validation exception: " + ex; } + + // Handle any errors + if (err != null) { + if (command.responseid != null) { try { ws.send(JSON.stringify({ action: 'addmeshuser', responseid: command.responseid, result: err })); } catch (ex) { } } + break; + } // For each nodeid, change the group for (var i = 0; i < command.nodeids.length; i++) { + var xnodeid = command.nodeids[i]; + if (xnodeid.indexOf('/') == -1) { xnodeid = 'node/' + domain.id + '/' + xnodeid; } + // Get the node and the rights for this node - parent.GetNodeWithRights(domain, user, command.nodeids[i], function (node, rights, visible) { + parent.GetNodeWithRights(domain, user, xnodeid, function (node, rights, visible) { + // Check if we found this device + if (node == null) { if (command.responseid != null) { try { ws.send(JSON.stringify({ action: 'changeDeviceMesh', responseid: command.responseid, result: 'Device not found' })); } catch (ex) { } } return; } + // Check if already in the right mesh - if ((node == null) || (node.meshid == command.meshid)) return; + if (node.meshid == command.meshid) { if (command.responseid != null) { try { ws.send(JSON.stringify({ action: 'changeDeviceMesh', responseid: command.responseid, result: 'Device already in correct group' })); } catch (ex) { } } return; } // Make sure both source and target mesh are the same type - try { if (parent.meshes[node.meshid].mtype != parent.meshes[command.meshid].mtype) return; } catch (e) { return; }; + try { if (parent.meshes[node.meshid].mtype != parent.meshes[command.meshid].mtype) return; } catch (e) { + if (command.responseid != null) { try { ws.send(JSON.stringify({ action: 'changeDeviceMesh', responseid: command.responseid, result: 'Device groups are of different types' })); } catch (ex) { } } + return; + }; // Make sure that we have rights on both source and destination mesh const targetMeshRights = parent.GetMeshRights(user, command.meshid); - if (((rights & MESHRIGHT_MANAGECOMPUTERS) == 0) || ((targetMeshRights & MESHRIGHT_MANAGECOMPUTERS) == 0)) return; + if (((rights & MESHRIGHT_MANAGECOMPUTERS) == 0) || ((targetMeshRights & MESHRIGHT_MANAGECOMPUTERS) == 0)) { + if (command.responseid != null) { try { ws.send(JSON.stringify({ action: 'changeDeviceMesh', responseid: command.responseid, result: 'Permission denied' })); } catch (ex) { } } + return; + } // Perform the switch, start by saving the node with the new meshid. const oldMeshId = node.meshid; @@ -2867,6 +2907,9 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use var event = { etype: 'node', userid: user._id, username: user.name, action: 'nodemeshchange', nodeid: node._id, node: node, oldMeshId: oldMeshId, newMeshId: command.meshid, msg: 'Moved device ' + node.name + ' to group ' + newMesh.name, domain: domain.id }; if (db.changeStream) { event.noact = 1; } // If DB change stream is active, don't use this event to change the mesh. Another event will come. parent.parent.DispatchEvent(parent.CreateMeshDispatchTargets(command.meshid, [oldMeshId, node._id]), obj, event); + + // Send response if required + if (command.responseid != null) { try { ws.send(JSON.stringify({ action: 'changeDeviceMesh', responseid: command.responseid, result: 'ok' })); } catch (ex) { } } }); } break; diff --git a/translate/translate.json b/translate/translate.json index 79c460e9..2966cdd3 100644 --- a/translate/translate.json +++ b/translate/translate.json @@ -20442,7 +20442,7 @@ }, { "en": "Remove User Group Permissions", - "nl": "Gebruikersgroepmachtigingen verwijderen" + "nl": "Gebruikersgroepmachtigingen verwijderen", "xloc": [ "default.handlebars->29->1272", "default.handlebars->29->1593" @@ -29541,4 +29541,4 @@ ] } ] -} +} \ No newline at end of file