manageAllDeviceGroups - Added group support (members of) (#7310)
stephannn committed
Sep 30, 2025 at 10:27 UTC
bd3f582b6845cebdb24b7d56f087f028d39518b4
3 files changed
+25
-8
meshcentral-config-schema.json
+1
-1
@@ -686,7 +686,7 @@
686
"items": {
687
"type": "string"
688
},
689
- "description": "Users in this list are allowed to see and manage all device groups within their domain. For example ['user//billybob','user//fred'] would allow billybob and fred to manage all device groups from all users in their domain."
689
+ "description": "Users or groups that users are a member of in this list are allowed to see and manage all device groups within their domain. For example ['user//billybob','user//fred','ugrp//RA...'] would allow billybob, fred and members of ugrp//RA to manage all device groups from all users in their domain."
690
},
691
"manageCrossDomain": {
692
"type": "array",
meshuser.js
+2
-2
@@ -613,7 +613,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
613
serverinfo.logoutonidlesessiontimeout = true;
614
}
615
if (user.siteadmin === SITERIGHT_ADMIN) {
616
- if (parent.parent.config.settings.managealldevicegroups.indexOf(user._id) >= 0) { serverinfo.manageAllDeviceGroups = true; }
616
+ if (parent.parent.config.settings.managealldevicegroups.indexOf(user._id) >= 0 || (Object.keys(user.links).some(key => parent.parent.config.settings.managealldevicegroups.indexOf(key) >= 0))) { serverinfo.manageAllDeviceGroups = true; }
617
if (obj.crossDomain === true) { serverinfo.crossDomain = []; for (var i in parent.parent.config.domains) { serverinfo.crossDomain.push(i); } }
618
if (typeof parent.webCertificateExpire[domain.id] == 'number') { serverinfo.certExpire = parent.webCertificateExpire[domain.id]; }
619
}
@@ -6749,7 +6749,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
6749
if (common.validateInt(command.type, 1, 4) == false) return; // Validate type
6750
if (common.validateInt(command.groupBy, 1, 3) == false) return; // Validate groupBy: 1 = User, 2 = Device, 3 = Day
6751
if ((typeof command.start != 'number') || (typeof command.end != 'number') || (command.start >= command.end)) return; // Validate start and end time
6752
- const manageAllDeviceGroups = ((user.siteadmin == 0xFFFFFFFF) && (parent.parent.config.settings.managealldevicegroups.indexOf(user._id) >= 0));
6752
+ const manageAllDeviceGroups = ((user.siteadmin == 0xFFFFFFFF) && (parent.parent.config.settings.managealldevicegroups.indexOf(user._id) >= 0 || (Object.keys(user.links).some(key => parent.parent.config.settings.managealldevicegroups.indexOf(key) >= 0))));
6753
if ((command.devGroup != null) && (manageAllDeviceGroups == false) && ((user.links == null) || (user.links[command.devGroup] == null))) return; // Asking for a device group that is not allowed
6754
6755
const msgIdFilter = [5, 10, 11, 12, 122, 123, 124, 125, 126, 144];
webserver.js
+22
-5
@@ -288,6 +288,23 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
288
obj.userGroups[docs[i]._id] = docs[i]; // Get all user groups
289
}
290
291
+ // Mapping between users and groups
292
+ for (var ugrpId in obj.userGroups) {
293
+ const ugrp = obj.userGroups[ugrpId];
294
+ if (ugrp.links != null) {
295
+ for (var userId in ugrp.links) {
296
+ if (userId.startsWith('user/') && (obj.users[userId] != null)) {
297
+ const user = obj.users[userId];
298
+ if (user.links == null) { user.links = {}; }
299
+ if (user.links[ugrpId] == null) {
300
+ // Adding group link to user
301
+ user.links[ugrpId] = { rights: ugrp.links[userId].rights || 1 };
302
+ }
303
+ }
304
+ }
305
+ }
306
+ }
307
+
308
// Perform device group link cleanup
309
for (var i in obj.meshes) {
310
const mesh = obj.meshes[i];
@@ -8962,7 +8979,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
8979
if ((nodes == null) || (nodes.length != 1)) { func(null, 0, false); return; } // No such nodeid
8980
8981
// This is a super user that can see all device groups for a given domain
8965
- if ((user.siteadmin == 0xFFFFFFFF) && (parent.config.settings.managealldevicegroups.indexOf(user._id) >= 0) && (nodes[0].domain == user.domain)) {
8982
+ if ((user.siteadmin == 0xFFFFFFFF) && ((parent.config.settings.managealldevicegroups.indexOf(user._id) >= 0) || (Object.keys(user.links).some(key => parent.config.settings.managealldevicegroups.indexOf(key) >= 0))) && (nodes[0].domain == user.domain)) {
8983
func(nodes[0], removeUserRights(0xFFFFFFFF, user), true); return;
8984
}
8985
@@ -9020,7 +9037,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
9037
if (user == null) { return []; }
9038
9039
var r = [];
9023
- if ((user.siteadmin == 0xFFFFFFFF) && (parent.config.settings.managealldevicegroups.indexOf(user._id) >= 0)) {
9040
+ if ((user.siteadmin == 0xFFFFFFFF) && ((parent.config.settings.managealldevicegroups.indexOf(user._id) >= 0) || (Object.keys(user.links).some(key => parent.config.settings.managealldevicegroups.indexOf(key) >= 0))) ) {
9041
// This is a super user that can see all device groups for a given domain
9042
var meshStartStr = 'mesh/' + user.domain + '/';
9043
for (var i in obj.meshes) { if ((obj.meshes[i]._id.startsWith(meshStartStr)) && (obj.meshes[i].deleted == null)) { r.push(obj.meshes[i]); } }
@@ -9051,7 +9068,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
9068
if (typeof user == 'string') { user = obj.users[user]; }
9069
if (user == null) { return []; }
9070
var r = [];
9054
- if ((user.siteadmin == 0xFFFFFFFF) && (parent.config.settings.managealldevicegroups.indexOf(user._id) >= 0)) {
9071
+ if ((user.siteadmin == 0xFFFFFFFF) && ((parent.config.settings.managealldevicegroups.indexOf(user._id) >= 0) || (Object.keys(user.links).some(key => parent.config.settings.managealldevicegroups.indexOf(key) >= 0)))) {
9072
// This is a super user that can see all device groups for a given domain
9073
var meshStartStr = 'mesh/' + user.domain + '/';
9074
for (var i in obj.meshes) { if ((obj.meshes[i]._id.startsWith(meshStartStr)) && (obj.meshes[i].deleted == null)) { r.push(obj.meshes[i]._id); } }
@@ -9096,7 +9113,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
9113
} else return 0;
9114
9115
// Check if this is a super user that can see all device groups for a given domain
9099
- if ((user.siteadmin == 0xFFFFFFFF) && (parent.config.settings.managealldevicegroups.indexOf(user._id) >= 0) && (meshid.startsWith('mesh/' + user.domain + '/'))) { return removeUserRights(0xFFFFFFFF, user); }
9116
+ if ((user.siteadmin == 0xFFFFFFFF) && ((parent.config.settings.managealldevicegroups.indexOf(user._id) >= 0) || (Object.keys(user.links).some(key => parent.config.settings.managealldevicegroups.indexOf(key) >= 0))) && (meshid.startsWith('mesh/' + user.domain + '/'))) { return removeUserRights(0xFFFFFFFF, user); }
9117
9118
// Check direct user to device group permissions
9119
if (user.links == null) return 0;
@@ -9141,7 +9158,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
9158
} else return false;
9159
9160
// Check if this is a super user that can see all device groups for a given domain
9144
- if ((user.siteadmin == 0xFFFFFFFF) && (parent.config.settings.managealldevicegroups.indexOf(user._id) >= 0) && (meshid.startsWith('mesh/' + user.domain + '/'))) { return true; }
9161
+ if ((user.siteadmin == 0xFFFFFFFF) && ((parent.config.settings.managealldevicegroups.indexOf(user._id) >= 0) || (Object.keys(user.links).some(key => parent.config.settings.managealldevicegroups.indexOf(key) >= 0))) && (meshid.startsWith('mesh/' + user.domain + '/'))) { return true; }
9162
9163
// Check direct user to device group permissions
9164
if (user.links == null) { return false; }