Fixed user account delete with user manager.

Ylian Saint-Hilaire committed Mar 17, 2020 at 17:17 UTC b72f43c119611122dc85410ef19cd0ae5f5bab89
7 files changed +217 -156
meshagent.js
+18 -18
@@ -72,7 +72,7 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
72 db.removeAllPowerEventsForNode(obj.dbNodeKey); // Remove all power events for this node
73
74 // Event node deletion
75 - parent.parent.DispatchEvent(parent.CreateMeshDispatchTargets(obj.dbMeshKey), obj, { etype: 'node', action: 'removenode', nodeid: obj.dbNodeKey, domain: domain.id, nolog: 1 });
75 + parent.parent.DispatchEvent(parent.CreateMeshDispatchTargets(obj.dbMeshKey, [obj.dbNodeKey]), obj, { etype: 'node', action: 'removenode', nodeid: obj.dbNodeKey, domain: domain.id, nolog: 1 });
76
77 // Disconnect all connections if needed
78 const state = parent.parent.GetConnectivityState(obj.dbNodeKey);
@@ -555,12 +555,12 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
555 if (adminUser.links == null) adminUser.links = {};
556 adminUser.links[obj.dbMeshKey] = { rights: 0xFFFFFFFF };
557 db.SetUser(adminUser);
558 - parent.parent.DispatchEvent(parent.CreateMeshDispatchTargets(obj.dbMeshKey, [adminUser._id]), obj, { etype: 'mesh', username: adminUser.name, meshid: obj.dbMeshKey, name: meshname, mtype: 2, desc: '', action: 'createmesh', links: links, msg: 'Mesh created: ' + obj.meshid, domain: domain.id });
558 + parent.parent.DispatchEvent(parent.CreateMeshDispatchTargets(obj.dbMeshKey, [adminUser._id, obj.dbNodeKey]), obj, { etype: 'mesh', username: adminUser.name, meshid: obj.dbMeshKey, name: meshname, mtype: 2, desc: '', action: 'createmesh', links: links, msg: 'Mesh created: ' + obj.meshid, domain: domain.id });
559 }
560 } else {
561 if ((mesh != null) && (mesh.deleted != null) && (mesh.links)) {
562 // Must un-delete this mesh
563 - var ids = parent.CreateMeshDispatchTargets(mesh._id);
563 + var ids = parent.CreateMeshDispatchTargets(mesh._id, [obj.dbNodeKey]);
564
565 // See if users still exists, if so, add links to the mesh
566 for (var userid in mesh.links) {
@@ -640,13 +640,13 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
640 mesh = { type: 'mesh', _id: obj.dbMeshKey, name: obj.meshid, mtype: 2, desc: '', domain: domain.id, links: links };
641 db.Set(common.escapeLinksFieldName(mesh));
642 parent.meshes[obj.meshid] = mesh;
643 - parent.parent.AddEventDispatch(parent.CreateMeshDispatchTargets(obj.meshid), ws);
643 + parent.parent.AddEventDispatch(parent.CreateMeshDispatchTargets(obj.meshid, [obj.dbNodeKey]), ws);
644
645 if (adminUser.links == null) user.links = {};
646 adminUser.links[obj.meshid] = { rights: 0xFFFFFFFF };
647 //adminUser.subscriptions = parent.subscribe(adminUser._id, ws);
648 db.SetUser(user);
649 - parent.parent.DispatchEvent(parent.CreateMeshDispatchTargets(meshid, [user._id]), obj, { etype: 'mesh', username: user.name, meshid: obj.meshid, name: obj.meshid, mtype: 2, desc: '', action: 'createmesh', links: links, msg: 'Mesh created: ' + obj.meshid, domain: domain.id });
649 + parent.parent.DispatchEvent(parent.CreateMeshDispatchTargets(meshid, [user._id, obj.dbNodeKey]), obj, { etype: 'mesh', username: user.name, meshid: obj.meshid, name: obj.meshid, mtype: 2, desc: '', action: 'createmesh', links: links, msg: 'Mesh created: ' + obj.meshid, domain: domain.id });
650 }
651 }
652
@@ -741,7 +741,7 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
741 var event = { etype: 'node', action: 'changenode', nodeid: obj.dbNodeKey, domain: domain.id, node: parent.CloneSafeNode(device) };
742 if (log == 0) { event.nolog = 1; } else { event.msg = 'Changed device ' + device.name + ' from group ' + mesh.name + ': ' + changes.join(', '); }
743 if (db.changeStream) { event.noact = 1; } // If DB change stream is active, don't use this event to change the node. Another event will come.
744 - parent.parent.DispatchEvent(parent.CreateMeshDispatchTargets(device.meshid), obj, event);
744 + parent.parent.DispatchEvent(parent.CreateMeshDispatchTargets(device.meshid, [obj.dbNodeKey]), obj, event);
745 }
746 }
747
@@ -781,9 +781,9 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
781 // Event the new node
782 if (obj.agentInfo.capabilities & 0x20) {
783 // This is a temporary agent, don't log.
784 - parent.parent.DispatchEvent(parent.CreateMeshDispatchTargets(obj.dbMeshKey), obj, { etype: 'node', action: 'addnode', node: device, domain: domain.id, nolog: 1 });
784 + parent.parent.DispatchEvent(parent.CreateMeshDispatchTargets(obj.dbMeshKey, [obj.dbNodeKey]), obj, { etype: 'node', action: 'addnode', node: device, domain: domain.id, nolog: 1 });
785 } else {
786 - parent.parent.DispatchEvent(parent.CreateMeshDispatchTargets(obj.dbMeshKey), obj, { etype: 'node', action: 'addnode', node: device, msg: ('Added device ' + obj.agentInfo.computerName + ' to mesh ' + mesh.name), domain: domain.id });
786 + parent.parent.DispatchEvent(parent.CreateMeshDispatchTargets(obj.dbMeshKey, [obj.dbNodeKey]), obj, { etype: 'node', action: 'addnode', node: device, msg: ('Added device ' + obj.agentInfo.computerName + ' to mesh ' + mesh.name), domain: domain.id });
787 }
788
789 completeAgentConnection3(device, mesh);
@@ -1114,7 +1114,7 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
1114 } catch (ex) { }
1115
1116 // Event the node interface information change (This is a lot of traffic, probably don't need this).
1117 - //parent.parent.DispatchEvent(parent.CreateMeshDispatchTargets(obj.meshid), obj, { action: 'smBiosChange', nodeid: obj.dbNodeKey, domain: domain.id, smbios: command.value, nolog: 1 });
1117 + //parent.parent.DispatchEvent(parent.CreateMeshDispatchTargets(obj.meshid, [obj.dbNodeKey]), obj, { action: 'smBiosChange', nodeid: obj.dbNodeKey, domain: domain.id, smbios: command.value, nolog: 1 });
1118
1119 break;
1120 }
@@ -1128,7 +1128,7 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
1128 db.Set(command);
1129
1130 // Event the node interface information change
1131 - parent.parent.DispatchEvent(parent.CreateMeshDispatchTargets(obj.meshid), obj, { action: 'ifchange', nodeid: obj.dbNodeKey, domain: domain.id, nolog: 1 });
1131 + parent.parent.DispatchEvent(parent.CreateMeshDispatchTargets(obj.meshid, [obj.dbNodeKey]), obj, { action: 'ifchange', nodeid: obj.dbNodeKey, domain: domain.id, nolog: 1 });
1132
1133 break;
1134 }
@@ -1167,7 +1167,7 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
1167
1168 // Event node deletion
1169 const change = 'Migrated device ' + node.name;
1170 - parent.parent.DispatchEvent(parent.CreateMeshDispatchTargets(node.meshid), obj, { etype: 'node', action: 'removenode', nodeid: node._id, msg: change, domain: node.domain });
1170 + parent.parent.DispatchEvent(parent.CreateMeshDispatchTargets(node.meshid, [obj.dbNodeKey]), obj, { etype: 'node', action: 'removenode', nodeid: node._id, msg: change, domain: node.domain });
1171 }
1172 });
1173 break;
@@ -1183,7 +1183,7 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
1183 // Log a value in the event log
1184 if ((typeof command.msg == 'string') && (command.msg.length < 4096)) {
1185 var event = { etype: 'node', action: 'agentlog', nodeid: obj.dbNodeKey, domain: domain.id, msg: command.msg };
1186 - var targets = parent.CreateMeshDispatchTargets(obj.dbMeshKey);
1186 + var targets = parent.CreateMeshDispatchTargets(obj.dbMeshKey, [obj.dbNodeKey]);
1187 if (typeof command.userid == 'string') {
1188 var loguser = parent.users[command.userid];
1189 if (loguser) { event.userid = command.userid; event.username = loguser.name; targets.push(command.userid); }
@@ -1227,7 +1227,7 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
1227 // Log this activation event
1228 var event = { etype: 'node', action: 'amtactivate', nodeid: obj.dbNodeKey, domain: domain.id, msg: 'Device requested Intel AMT ACM activation, FQDN: ' + command.fqdn, ip: obj.remoteaddrport };
1229 if (db.changeStream) { event.noact = 1; } // If DB change stream is active, don't use this event to change the node. Another event will come.
1230 - parent.parent.DispatchEvent(parent.CreateMeshDispatchTargets(obj.dbMeshKey), obj, event);
1230 + parent.parent.DispatchEvent(parent.CreateMeshDispatchTargets(obj.dbMeshKey, [obj.dbNodeKey]), obj, event);
1231
1232 // Update the device Intel AMT information
1233 ChangeAgentCoreInfo({ "intelamt": { user: 'admin', pass: amtpassword, uuid: command.uuid, realm: command.realm } });
@@ -1277,7 +1277,7 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
1277 if (((obj.agentInfo.capabilities & 0x40) != 0) && (typeof command.value.value == 'string') && (command.value.value.length < 256)) {
1278 // If this is a diagnostic agent, log the event in the log of the main agent
1279 var event = { etype: 'node', action: 'diagnostic', nodeid: obj.realNodeKey, domain: domain.id, msg: command.value.value };
1280 - parent.parent.DispatchEvent(parent.CreateMeshDispatchTargets(obj.dbMeshKey), obj, event);
1280 + parent.parent.DispatchEvent(parent.CreateMeshDispatchTargets(obj.dbMeshKey, [obj.dbNodeKey]), obj, event);
1281 }
1282 break;
1283 }
@@ -1295,7 +1295,7 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
1295
1296 // Event the new sysinfo hash, this will notify everyone that the sysinfo document was changed
1297 var event = { etype: 'node', action: 'sysinfohash', nodeid: obj.dbNodeKey, domain: domain.id, hash: command.data.hash, nolog: 1 };
1298 - parent.parent.DispatchEvent(parent.CreateMeshDispatchTargets(obj.dbMeshKey), obj, event);
1298 + parent.parent.DispatchEvent(parent.CreateMeshDispatchTargets(obj.dbMeshKey, [obj.dbNodeKey]), obj, event);
1299 }
1300 break;
1301 }
@@ -1394,7 +1394,7 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
1394 if (changes.length > 0) { event.msg = 'Changed device ' + device.name + ' from group ' + mesh.name + ': ' + changes.join(', '); }
1395 if ((log == 0) || ((obj.agentInfo) && (obj.agentInfo.capabilities) && (obj.agentInfo.capabilities & 0x20)) || (changes.length == 0)) { event.nolog = 1; } // If this is a temporary device, don't log changes
1396 if (db.changeStream) { event.noact = 1; } // If DB change stream is active, don't use this event to change the node. Another event will come.
1397 - parent.parent.DispatchEvent(parent.CreateMeshDispatchTargets(device.meshid), obj, event);
1397 + parent.parent.DispatchEvent(parent.CreateMeshDispatchTargets(device.meshid, [obj.dbNodeKey]), obj, event);
1398 }
1399 }
1400 });
@@ -1435,7 +1435,7 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
1435 var event = { etype: 'node', action: 'changenode', nodeid: obj.dbNodeKey, domain: domain.id, node: parent.CloneSafeNode(device), msg: 'Changed device ' + device.name + ' from group ' + mesh.name + ': ' + changes.join(', ') };
1436 if (obj.agentInfo.capabilities & 0x20) { event.nolog = 1; } // If this is a temporary device, don't log changes
1437 if (db.changeStream) { event.noact = 1; } // If DB change stream is active, don't use this event to change the node. Another event will come.
1438 - parent.parent.DispatchEvent(parent.CreateMeshDispatchTargets(device.meshid), obj, event);
1438 + parent.parent.DispatchEvent(parent.CreateMeshDispatchTargets(device.meshid, [obj.dbNodeKey]), obj, event);
1439 }
1440 }
1441 });
@@ -1464,7 +1464,7 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
1464 // Event the node change
1465 var event = { etype: 'node', action: 'changenode', nodeid: obj.dbNodeKey, domain: domain.id, node: parent.CloneSafeNode(device), nolog: 1 };
1466 if (db.changeStream) { event.noact = 1; } // If DB change stream is active, don't use this event to change the node. Another event will come.
1467 - parent.parent.DispatchEvent(parent.CreateMeshDispatchTargets(device.meshid), obj, event);
1467 + parent.parent.DispatchEvent(parent.CreateMeshDispatchTargets(device.meshid, [obj.dbNodeKey]), obj, event);
1468 }
1469 }
1470 });
meshuser.js
+6 -6
@@ -1250,7 +1250,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
1250 deluser = parent.users[deluserid];
1251 if (deluser == null) { err = 'User does not exists'; }
1252 else if ((delusersplit.length != 3) || (delusersplit[1] != domain.id)) { err = 'Invalid domain'; } // Invalid domain, operation only valid for current domain
1253 - else if ((deluser.siteadmin != null) && (deluser.siteadmin > 0) && (user.siteadmin != 0xFFFFFFFF)) { err = 'Permission denied'; } // Need full admin to remote another administrator
1253 + else if ((deluser.siteadmin == 0xFFFFFFFF) && (user.siteadmin != 0xFFFFFFFF)) { err = 'Permission denied'; } // Need full admin to remote another administrator
1254 else if ((user.groups != null) && (user.groups.length > 0) && ((deluser.groups == null) || (findOne(deluser.groups, user.groups) == false))) { err = 'Invalid user group'; } // Can only perform this operation on other users of our group.
1255 }
1256 } catch (ex) { err = 'Validation exception: ' + ex; }
@@ -2547,7 +2547,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
2547 db.Set(device);
2548
2549 // Event the new node
2550 - parent.parent.DispatchEvent(['*', command.meshid], obj, { etype: 'node', userid: user._id, username: user.name, action: 'addnode', node: parent.CloneSafeNode(device), msg: 'Added device ' + command.devicename + ' to mesh ' + mesh.name, domain: domain.id });
2550 + parent.parent.DispatchEvent(['*', command.meshid, nodeid], obj, { etype: 'node', userid: user._id, username: user.name, action: 'addnode', node: parent.CloneSafeNode(device), msg: 'Added device ' + command.devicename + ' to mesh ' + mesh.name, domain: domain.id });
2551 });
2552 }
2553 break;
@@ -2616,7 +2616,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
2616 var newMesh = parent.meshes[command.meshid];
2617 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 };
2618 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.
2619 - parent.parent.DispatchEvent(['*', oldMeshId, command.meshid], obj, event);
2619 + parent.parent.DispatchEvent(['*', oldMeshId, command.meshid, node._id], obj, event);
2620 });
2621 }
2622 break;
@@ -2648,7 +2648,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
2648 var event = { etype: 'node', userid: user._id, username: user.name, action: 'removenode', nodeid: node._id, msg: 'Removed device ' + node.name + ' from group ' + parent.meshes[node.meshid].name, domain: domain.id };
2649 // TODO: We can't use the changeStream for node delete because we will not know the meshid the device was in.
2650 //if (db.changeStream) { event.noact = 1; } // If DB change stream is active, don't use this event to remove the node. Another event will come.
2651 - parent.parent.DispatchEvent(['*', node.meshid], obj, event);
2651 + parent.parent.DispatchEvent(['*', node.meshid, node._id], obj, event);
2652
2653 // Disconnect all connections if needed
2654 var state = parent.parent.GetConnectivityState(nodeid);
@@ -2849,7 +2849,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
2849 event.msg = 'Changed device ' + node.name + ' from group ' + mesh.name + ': ' + changes.join(', ');
2850 event.node = parent.CloneSafeNode(node);
2851 if (db.changeStream) { event.noact = 1; } // If DB change stream is active, don't use this event to change the node. Another event will come.
2852 - parent.parent.DispatchEvent(['*', node.meshid, user._id], obj, event);
2852 + parent.parent.DispatchEvent(['*', node.meshid, user._id, node._id], obj, event);
2853 }
2854 });
2855 break;
@@ -2970,7 +2970,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
2970 if (rights == 0) return;
2971
2972 // Add an event for this device
2973 - var targets = ['*', 'server-users', user._id, node.meshid];
2973 + var targets = ['*', 'server-users', user._id, node.meshid, node._id];
2974 var event = { etype: 'node', userid: user._id, username: user.name, nodeid: node._id, action: 'manual', msg: decodeURIComponent(command.msg), domain: domain.id };
2975 parent.parent.DispatchEvent(targets, obj, event);
2976 });
package.json
+1 -1
@@ -1,6 +1,6 @@
1 {
2 "name": "meshcentral",
3 - "version": "0.5.0-i",
3 + "version": "0.5.0-j",
4 "keywords": [
5 "Remote Management",
6 "Intel AMT",
translate/translate.json
+107 -101
@@ -542,7 +542,7 @@
542 "default-mobile.handlebars->9->246",
543 "default-mobile.handlebars->9->70",
544 "default.handlebars->27->1233",
545 - "default.handlebars->27->1469",
545 + "default.handlebars->27->1470",
546 "default.handlebars->27->653"
547 ]
548 },
@@ -1851,7 +1851,7 @@
1851 "default.handlebars->27->1169",
1852 "default.handlebars->27->1171",
1853 "default.handlebars->27->1369",
1854 - "default.handlebars->27->1446",
1854 + "default.handlebars->27->1447",
1855 "default.handlebars->27->187"
1856 ]
1857 },
@@ -1918,7 +1918,7 @@
1918 "nl": "Lidmaatschap toevoegen",
1919 "ru": "Добавить участие",
1920 "xloc": [
1921 - "default.handlebars->27->1465"
1921 + "default.handlebars->27->1466"
1922 ]
1923 },
1924 {
@@ -1964,7 +1964,7 @@
1964 "xloc": [
1965 "default.handlebars->27->1075",
1966 "default.handlebars->27->1170",
1967 - "default.handlebars->27->1455"
1967 + "default.handlebars->27->1456"
1968 ]
1969 },
1970 {
@@ -2304,7 +2304,7 @@
2304 "nl": "Agent fout tellers",
2305 "ru": "Счетчик ошибок агента",
2306 "xloc": [
2307 - "default.handlebars->27->1477"
2307 + "default.handlebars->27->1478"
2308 ]
2309 },
2310 {
@@ -2350,7 +2350,7 @@
2350 "nl": "Agent Sessies",
2351 "ru": "Сессии агентов",
2352 "xloc": [
2353 - "default.handlebars->27->1493"
2353 + "default.handlebars->27->1494"
2354 ]
2355 },
2356 {
@@ -2447,7 +2447,7 @@
2447 "pt": "Agentes",
2448 "ru": "Агенты",
2449 "xloc": [
2450 - "default.handlebars->27->1506"
2450 + "default.handlebars->27->1507"
2451 ]
2452 },
2453 {
@@ -3038,7 +3038,7 @@
3038 "nl": "Weet u zeker dat u de plug-in {0} wilt gebruiken: {1}",
3039 "ru": "Вы уверенны, что {0} плагин: {1}",
3040 "xloc": [
3041 - "default.handlebars->27->1542"
3041 + "default.handlebars->27->1543"
3042 ]
3043 },
3044 {
@@ -3359,7 +3359,7 @@
3359 "nl": "Ongeldige handtening",
3360 "ru": "Плохой ключ",
3361 "xloc": [
3362 - "default.handlebars->27->1484"
3362 + "default.handlebars->27->1485"
3363 ]
3364 },
3365 {
@@ -3370,7 +3370,7 @@
3370 "nl": "Onjuist webcertificaat",
3371 "ru": "Плохой веб-сертификат",
3372 "xloc": [
3373 - "default.handlebars->27->1483"
3373 + "default.handlebars->27->1484"
3374 ]
3375 },
3376 {
@@ -3563,7 +3563,7 @@
3563 "pt": "Servidor CIRA",
3564 "ru": "CIRA Сервер",
3565 "xloc": [
3566 - "default.handlebars->27->1533"
3566 + "default.handlebars->27->1534"
3567 ]
3568 },
3569 {
@@ -3577,7 +3577,7 @@
3577 "pt": "Comandos do servidor CIRA",
3578 "ru": "CIRA Сервер команды",
3579 "xloc": [
3580 - "default.handlebars->27->1534"
3580 + "default.handlebars->27->1535"
3581 ]
3582 },
3583 {
@@ -3588,7 +3588,7 @@
3588 "nl": "CPU gebruik",
3589 "ru": "Загрузка CPU",
3590 "xloc": [
3591 - "default.handlebars->27->1498"
3591 + "default.handlebars->27->1499"
3592 ]
3593 },
3594 {
@@ -3602,7 +3602,7 @@
3602 "pt": "Carga da CPU nos últimos 15 minutos",
3603 "ru": "Загрузка CPU за последние 15 минут",
3604 "xloc": [
3605 - "default.handlebars->27->1501"
3605 + "default.handlebars->27->1502"
3606 ]
3607 },
3608 {
@@ -3616,7 +3616,7 @@
3616 "pt": "Carga da CPU nos últimos 5 minutos",
3617 "ru": "Загрузка CPU за последние 5 минут",
3618 "xloc": [
3619 - "default.handlebars->27->1500"
3619 + "default.handlebars->27->1501"
3620 ]
3621 },
3622 {
@@ -3630,7 +3630,7 @@
3630 "pt": "Carga da CPU no último minuto",
3631 "ru": "Загрузка CPU за последнюю минуту",
3632 "xloc": [
3633 - "default.handlebars->27->1499"
3633 + "default.handlebars->27->1500"
3634 ]
3635 },
3636 {
@@ -3676,7 +3676,7 @@
3676 "pt": "Erro de chamada",
3677 "ru": "Ошибка вызова",
3678 "xloc": [
3679 - "default.handlebars->27->1543"
3679 + "default.handlebars->27->1544"
3680 ]
3681 },
3682 {
@@ -4018,7 +4018,7 @@
4018 "pt": "Verificando ...",
4019 "ru": "Проверка...",
4020 "xloc": [
4021 - "default.handlebars->27->1539",
4021 + "default.handlebars->27->1540",
4022 "default.handlebars->27->778"
4023 ]
4024 },
@@ -4322,7 +4322,7 @@
4322 "ru": "Общие группы устройств",
4323 "xloc": [
4324 "default.handlebars->27->1370",
4325 - "default.handlebars->27->1447"
4325 + "default.handlebars->27->1448"
4326 ]
4327 },
4328 {
@@ -4401,6 +4401,12 @@
4401 "default.handlebars->27->380"
4402 ]
4403 },
4404 + {
4405 + "en": "Confirm deletion of user {0}?",
4406 + "xloc": [
4407 + "default.handlebars->27->1446"
4408 + ]
4409 + },
4410 {
4411 "cs": "Potvrdit přesun jednoho záznamu do tohoto umístění?",
4412 "de": "Bestätigen Sie das Verschieben von 1 Eintrag an diesen Ort?",
@@ -4466,7 +4472,7 @@
4472 "ru": "Подтвердить удаление группы устройств {0}?",
4473 "xloc": [
4474 "default.handlebars->27->1380",
4469 - "default.handlebars->27->1467"
4475 + "default.handlebars->27->1468"
4476 ]
4477 },
4478 {
@@ -4477,7 +4483,7 @@
4483 "nl": "Bevestig het verwijderen van de groep {0}?",
4484 "ru": "Подтвердить удаление группы {0}?",
4485 "xloc": [
4480 - "default.handlebars->27->1463"
4486 + "default.handlebars->27->1464"
4487 ]
4488 },
4489 {
@@ -4599,7 +4605,7 @@
4605 "nl": "Verbonden Intel&reg; AMT",
4606 "ru": "Подключено Intel&reg; AMT",
4607 "xloc": [
4602 - "default.handlebars->27->1489"
4608 + "default.handlebars->27->1490"
4609 ]
4610 },
4611 {
@@ -4610,7 +4616,7 @@
4616 "nl": "Verbonden gebruikers",
4617 "ru": "Подключенные пользователи",
4618 "xloc": [
4613 - "default.handlebars->27->1494"
4619 + "default.handlebars->27->1495"
4620 ]
4621 },
4622 {
@@ -4667,7 +4673,7 @@
4673 "pt": "Contagem de conexões",
4674 "ru": "Подключений ",
4675 "xloc": [
4670 - "default.handlebars->27->1505"
4676 + "default.handlebars->27->1506"
4677 ]
4678 },
4679 {
@@ -4681,7 +4687,7 @@
4687 "pt": "Encaminhador de conexão",
4688 "ru": "Ретранслятор подключения",
4689 "xloc": [
4684 - "default.handlebars->27->1532"
4690 + "default.handlebars->27->1533"
4691 ]
4692 },
4693 {
@@ -4768,7 +4774,7 @@
4774 "pt": "Codificador de cookies",
4775 "ru": "Cookie-кодировщик",
4776 "xloc": [
4771 - "default.handlebars->27->1519"
4777 + "default.handlebars->27->1520"
4778 ]
4779 },
4780 {
@@ -4977,7 +4983,7 @@
4983 "pt": "Servidor Core",
4984 "ru": "Основной сервер",
4985 "xloc": [
4980 - "default.handlebars->27->1518"
4986 + "default.handlebars->27->1519"
4987 ]
4988 },
4989 {
@@ -5844,8 +5850,8 @@
5850 "default.handlebars->27->1145",
5851 "default.handlebars->27->1147",
5852 "default.handlebars->27->1376",
5847 - "default.handlebars->27->1453",
5848 - "default.handlebars->27->1459"
5853 + "default.handlebars->27->1454",
5854 + "default.handlebars->27->1460"
5855 ]
5856 },
5857 {
@@ -5878,7 +5884,7 @@
5884 "default.handlebars->27->1348",
5885 "default.handlebars->27->1361",
5886 "default.handlebars->27->1416",
5881 - "default.handlebars->27->1492",
5887 + "default.handlebars->27->1493",
5888 "default.handlebars->container->column_l->p2->9"
5889 ]
5890 },
@@ -6681,7 +6687,7 @@
6687 "nl": "Duplicaat Agent",
6688 "ru": "Скопировать агент",
6689 "xloc": [
6684 - "default.handlebars->27->1488"
6690 + "default.handlebars->27->1489"
6691 ]
6692 },
6693 {
@@ -7578,7 +7584,7 @@
7584 "nl": "Extern",
7585 "ru": "Внешний",
7586 "xloc": [
7581 - "default.handlebars->27->1512"
7587 + "default.handlebars->27->1513"
7588 ]
7589 },
7590 {
@@ -7934,8 +7940,8 @@
7940 "pt": "Livre",
7941 "ru": "Свободно",
7942 "xloc": [
7937 - "default.handlebars->27->1473",
7938 - "default.handlebars->27->1475"
7943 + "default.handlebars->27->1474",
7944 + "default.handlebars->27->1476"
7945 ]
7946 },
7947 {
@@ -8114,7 +8120,7 @@
8120 "xloc": [
8121 "default.handlebars->27->1090",
8122 "default.handlebars->27->1373",
8117 - "default.handlebars->27->1450"
8123 + "default.handlebars->27->1451"
8124 ]
8125 },
8126 {
@@ -8610,7 +8616,7 @@
8616 "es": "Heap Total",
8617 "nl": "Heap Totaal",
8618 "xloc": [
8613 - "default.handlebars->27->1514"
8619 + "default.handlebars->27->1515"
8620 ]
8621 },
8622 {
@@ -8620,7 +8626,7 @@
8626 "es": "Heap Used",
8627 "nl": "Heap gebruikt",
8628 "xloc": [
8623 - "default.handlebars->27->1513"
8629 + "default.handlebars->27->1514"
8630 ]
8631 },
8632 {
@@ -9142,8 +9148,8 @@
9148 "xloc": [
9149 "default.handlebars->27->1222",
9150 "default.handlebars->27->1228",
9145 - "default.handlebars->27->1510",
9146 - "default.handlebars->27->1531"
9151 + "default.handlebars->27->1511",
9152 + "default.handlebars->27->1532"
9153 ]
9154 },
9155 {
@@ -9705,7 +9711,7 @@
9711 "nl": "Ongeldige apparaatgroep type",
9712 "ru": "Некорректный тип группы устройств",
9713 "xloc": [
9708 - "default.handlebars->27->1487"
9714 + "default.handlebars->27->1488"
9715 ]
9716 },
9717 {
@@ -9716,7 +9722,7 @@
9722 "nl": "Onjuiste JSON",
9723 "ru": "Некорректный JSON",
9724 "xloc": [
9719 - "default.handlebars->27->1481"
9725 + "default.handlebars->27->1482"
9726 ]
9727 },
9728 {
@@ -9756,7 +9762,7 @@
9762 "nl": "Onjuiste PKCS handtekening",
9763 "ru": "Некорректная сигнатура PKCS",
9764 "xloc": [
9759 - "default.handlebars->27->1479"
9765 + "default.handlebars->27->1480"
9766 ]
9767 },
9768 {
@@ -9767,7 +9773,7 @@
9773 "nl": "Ongeldige RSA handtekening",
9774 "ru": "Некорректная сигнатура RSA",
9775 "xloc": [
9770 - "default.handlebars->27->1480"
9776 + "default.handlebars->27->1481"
9777 ]
9778 },
9779 {
@@ -10589,7 +10595,7 @@
10595 "pt": "Menos",
10596 "ru": "Меньше",
10597 "xloc": [
10592 - "default.handlebars->27->1545"
10598 + "default.handlebars->27->1546"
10599 ]
10600 },
10601 {
@@ -11418,7 +11424,7 @@
11424 "pt": "Mensagens do servidor principal",
11425 "ru": "Сообщения главного сервера",
11426 "xloc": [
11421 - "default.handlebars->27->1521"
11427 + "default.handlebars->27->1522"
11428 ]
11429 },
11430 {
@@ -11715,7 +11721,7 @@
11721 "nl": "Max Sessies bereikt",
11722 "ru": "Достигнуто максимальное число сессий",
11723 "xloc": [
11718 - "default.handlebars->27->1485"
11724 + "default.handlebars->27->1486"
11725 ]
11726 },
11727 {
@@ -11760,7 +11766,7 @@
11766 "pt": "Megabytes",
11767 "ru": "Мегабайт",
11768 "xloc": [
11763 - "default.handlebars->27->1511"
11769 + "default.handlebars->27->1512"
11770 ]
11771 },
11772 {
@@ -11774,7 +11780,7 @@
11780 "pt": "Memória",
11781 "ru": "ОЗУ",
11782 "xloc": [
11777 - "default.handlebars->27->1502",
11783 + "default.handlebars->27->1503",
11784 "default.handlebars->27->743",
11785 "default.handlebars->container->column_l->p40->3->1->p40type->3"
11786 ]
@@ -11884,7 +11890,7 @@
11890 "nl": "MeshAgent verkeer",
11891 "ru": "Трафик MeshAgent",
11892 "xloc": [
11887 - "default.handlebars->27->1523"
11893 + "default.handlebars->27->1524"
11894 ]
11895 },
11896 {
@@ -11897,7 +11903,7 @@
11903 "nl": "MeshAgent update",
11904 "ru": "Обновление MeshAgent",
11905 "xloc": [
11900 - "default.handlebars->27->1524"
11906 + "default.handlebars->27->1525"
11907 ]
11908 },
11909 {
@@ -11977,7 +11983,7 @@
11983 "pt": "Peering do servidor MeshCentral",
11984 "ru": "Соединения сервера MeshCentral",
11985 "xloc": [
11980 - "default.handlebars->27->1522"
11986 + "default.handlebars->27->1523"
11987 ]
11988 },
11989 {
@@ -12169,7 +12175,7 @@
12175 "pt": "Despachante de mensagens",
12176 "ru": "Диспетчер сообщения",
12177 "xloc": [
12172 - "default.handlebars->27->1520"
12178 + "default.handlebars->27->1521"
12179 ]
12180 },
12181 {
@@ -12251,7 +12257,7 @@
12257 "pt": "Mais",
12258 "ru": "Еще",
12259 "xloc": [
12254 - "default.handlebars->27->1544"
12260 + "default.handlebars->27->1545"
12261 ]
12262 },
12263 {
@@ -12804,7 +12810,7 @@
12810 "ru": "События не найдены",
12811 "xloc": [
12812 "default.handlebars->27->1269",
12807 - "default.handlebars->27->1468",
12813 + "default.handlebars->27->1469",
12814 "default.handlebars->27->691"
12815 ]
12816 },
@@ -12951,7 +12957,7 @@
12957 "default.handlebars->27->1091",
12958 "default.handlebars->27->1192",
12959 "default.handlebars->27->1374",
12954 - "default.handlebars->27->1451"
12960 + "default.handlebars->27->1452"
12961 ]
12962 },
12963 {
@@ -13020,7 +13026,7 @@
13026 "ru": "Нет общих групп устройств",
13027 "xloc": [
13028 "default.handlebars->27->1377",
13023 - "default.handlebars->27->1454"
13029 + "default.handlebars->27->1455"
13030 ]
13031 },
13032 {
@@ -13229,7 +13235,7 @@
13235 "nl": "Geen gebruikersgroep lidmaatschap",
13236 "ru": "Нет членства в группах пользователей",
13237 "xloc": [
13232 - "default.handlebars->27->1460"
13238 + "default.handlebars->27->1461"
13239 ]
13240 },
13241 {
@@ -13622,7 +13628,7 @@
13628 "pt": "Ocorreu em {0}",
13629 "ru": "Произошло в {0}",
13630 "xloc": [
13625 - "default.handlebars->27->1471"
13631 + "default.handlebars->27->1472"
13632 ]
13633 },
13634 {
@@ -13943,7 +13949,7 @@
13949 "xloc": [
13950 "default.handlebars->27->1089",
13951 "default.handlebars->27->1371",
13946 - "default.handlebars->27->1448"
13952 + "default.handlebars->27->1449"
13953 ]
13954 },
13955 {
@@ -14435,7 +14441,7 @@
14441 "nl": "Plugin Actie",
14442 "ru": "Действие плагина",
14443 "xloc": [
14438 - "default.handlebars->27->1541",
14444 + "default.handlebars->27->1542",
14445 "default.handlebars->27->159"
14446 ]
14447 },
@@ -14978,7 +14984,7 @@
14984 "pt": "RSS",
14985 "ru": "RSS",
14986 "xloc": [
14981 - "default.handlebars->27->1515"
14987 + "default.handlebars->27->1516"
14988 ]
14989 },
14990 {
@@ -15121,7 +15127,7 @@
15127 "nl": "Relay geteld",
15128 "ru": "Число ретрансляций",
15129 "xloc": [
15124 - "default.handlebars->27->1497"
15130 + "default.handlebars->27->1498"
15131 ]
15132 },
15133 {
@@ -15132,7 +15138,7 @@
15138 "nl": "Relay fouten",
15139 "ru": "Ошибки ретранслятора",
15140 "xloc": [
15135 - "default.handlebars->27->1490"
15141 + "default.handlebars->27->1491"
15142 ]
15143 },
15144 {
@@ -15145,8 +15151,8 @@
15151 "pt": "Retransmissão de sessão ",
15152 "ru": "Сессии ретранслятора",
15153 "xloc": [
15148 - "default.handlebars->27->1496",
15149 - "default.handlebars->27->1509"
15154 + "default.handlebars->27->1497",
15155 + "default.handlebars->27->1510"
15156 ]
15157 },
15158 {
@@ -15358,7 +15364,7 @@
15364 "ru": "Удалить группу устройств.",
15365 "xloc": [
15366 "default.handlebars->27->1379",
15361 - "default.handlebars->27->1466"
15367 + "default.handlebars->27->1467"
15368 ]
15369 },
15370 {
@@ -15369,7 +15375,7 @@
15375 "nl": "Verwijder gebruiker",
15376 "ru": "Удалить пользователя",
15377 "xloc": [
15372 - "default.handlebars->27->1462"
15378 + "default.handlebars->27->1463"
15379 ]
15380 },
15381 {
@@ -15442,7 +15448,7 @@
15448 "nl": "Verwijder de groepslidmaatschap",
15449 "ru": "Удалить членство пользователя в группе",
15450 "xloc": [
15445 - "default.handlebars->27->1458"
15451 + "default.handlebars->27->1459"
15452 ]
15453 },
15454 {
@@ -15469,7 +15475,7 @@
15475 "xloc": [
15476 "default.handlebars->27->1092",
15477 "default.handlebars->27->1366",
15472 - "default.handlebars->27->1452"
15478 + "default.handlebars->27->1453"
15479 ]
15480 },
15481 {
@@ -16479,14 +16485,14 @@
16485 "nl": "Server Certificaat",
16486 "ru": "Сертификат сервера",
16487 "xloc": [
16482 - "default.handlebars->27->1525"
16488 + "default.handlebars->27->1526"
16489 ]
16490 },
16491 {
16492 "en": "Server Database",
16493 "nl": "Server Database",
16494 "xloc": [
16489 - "default.handlebars->27->1526"
16495 + "default.handlebars->27->1527"
16496 ]
16497 },
16498 {
@@ -16571,7 +16577,7 @@
16577 "nl": "Server Status",
16578 "ru": "Состояние сервера",
16579 "xloc": [
16574 - "default.handlebars->27->1476"
16580 + "default.handlebars->27->1477"
16581 ]
16582 },
16583 {
@@ -16599,7 +16605,7 @@
16605 "pt": "Rastreamento de servidor",
16606 "ru": "Трассировка сервера",
16607 "xloc": [
16602 - "default.handlebars->27->1535"
16608 + "default.handlebars->27->1536"
16609 ]
16610 },
16611 {
@@ -16707,7 +16713,7 @@
16713 "pt": "ServerStats.csv",
16714 "ru": "ServerStats.csv",
16715 "xloc": [
16710 - "default.handlebars->27->1517"
16716 + "default.handlebars->27->1518"
16717 ]
16718 },
16719 {
@@ -18291,7 +18297,7 @@
18297 "pt": "Atualmente não há notificações",
18298 "ru": "На данный момент уведомлений нет",
18299 "xloc": [
18294 - "default.handlebars->27->1470"
18300 + "default.handlebars->27->1471"
18301 ]
18302 },
18303 {
@@ -19176,7 +19182,7 @@
19182 "default-mobile.handlebars->9->174",
19183 "default-mobile.handlebars->9->175",
19184 "default.handlebars->27->13",
19179 - "default.handlebars->27->1461",
19185 + "default.handlebars->27->1462",
19186 "default.handlebars->27->364",
19187 "default.handlebars->27->41",
19188 "default.handlebars->27->42",
@@ -19209,7 +19215,7 @@
19215 "nl": "Onbekende actie",
19216 "ru": "Неизвестное действие",
19217 "xloc": [
19212 - "default.handlebars->27->1482"
19218 + "default.handlebars->27->1483"
19219 ]
19220 },
19221 {
@@ -19221,8 +19227,8 @@
19227 "ru": "Неизвестная группа устройств",
19228 "xloc": [
19229 "default.handlebars->27->1372",
19224 - "default.handlebars->27->1449",
19225 - "default.handlebars->27->1486"
19230 + "default.handlebars->27->1450",
19231 + "default.handlebars->27->1487"
19232 ]
19233 },
19234 {
@@ -19233,7 +19239,7 @@
19239 "nl": "Onbekende groep",
19240 "ru": "Неизвестная группа",
19241 "xloc": [
19236 - "default.handlebars->27->1478"
19242 + "default.handlebars->27->1479"
19243 ]
19244 },
19245 {
@@ -19259,7 +19265,7 @@
19265 "nl": "Onbekende gebruikersgroep",
19266 "ru": "Неизвестная группа пользователей",
19267 "xloc": [
19262 - "default.handlebars->27->1457"
19268 + "default.handlebars->27->1458"
19269 ]
19270 },
19271 {
@@ -19320,7 +19326,7 @@
19326 "nl": "Bijgewerkt",
19327 "ru": "Актуально",
19328 "xloc": [
19323 - "default.handlebars->27->1540"
19329 + "default.handlebars->27->1541"
19330 ]
19331 },
19332 {
@@ -19509,8 +19515,8 @@
19515 "pt": "Usava",
19516 "ru": "Использовано",
19517 "xloc": [
19512 - "default.handlebars->27->1472",
19513 - "default.handlebars->27->1474"
19518 + "default.handlebars->27->1473",
19519 + "default.handlebars->27->1475"
19520 ]
19521 },
19522 {
@@ -19568,7 +19574,7 @@
19574 "nl": "Gebruikersaccounts",
19575 "ru": "Учетные записи пользователей",
19576 "xloc": [
19571 - "default.handlebars->27->1491"
19577 + "default.handlebars->27->1492"
19578 ]
19579 },
19580 {
@@ -19609,7 +19615,7 @@
19615 "xloc": [
19616 "default.handlebars->27->1146",
19617 "default.handlebars->27->1350",
19612 - "default.handlebars->27->1464"
19618 + "default.handlebars->27->1465"
19619 ]
19620 },
19621 {
@@ -19631,7 +19637,7 @@
19637 "nl": "Gebruikersgroeps lidmaatschap",
19638 "ru": "Членство в группах пользователей",
19639 "xloc": [
19634 - "default.handlebars->27->1456"
19640 + "default.handlebars->27->1457"
19641 ]
19642 },
19643 {
@@ -19713,7 +19719,7 @@
19719 "pt": "Sessões de Usuário",
19720 "ru": "Сессии пользователя",
19721 "xloc": [
19716 - "default.handlebars->27->1508"
19722 + "default.handlebars->27->1509"
19723 ]
19724 },
19725 {
@@ -19841,7 +19847,7 @@
19847 "xloc": [
19848 "default.handlebars->27->1349",
19849 "default.handlebars->27->1360",
19844 - "default.handlebars->27->1507",
19850 + "default.handlebars->27->1508",
19851 "default.handlebars->container->topbar->1->1->UsersSubMenuSpan->UsersSubMenu->1->0->UsersGeneral"
19852 ]
19853 },
@@ -19853,7 +19859,7 @@
19859 "nl": "gebruikers Sessies",
19860 "ru": "Сессии пользователей",
19861 "xloc": [
19856 - "default.handlebars->27->1495"
19862 + "default.handlebars->27->1496"
19863 ]
19864 },
19865 {
@@ -20167,8 +20173,8 @@
20173 "pt": "Servidor web",
20174 "ru": "Веб-сервер",
20175 "xloc": [
20170 - "default.handlebars->27->1527",
20171 - "default.handlebars->27->1528"
20176 + "default.handlebars->27->1528",
20177 + "default.handlebars->27->1529"
20178 ]
20179 },
20180 {
@@ -20182,7 +20188,7 @@
20188 "pt": "Solicitações de servidor Web",
20189 "ru": "Запросы веб-сервера",
20190 "xloc": [
20185 - "default.handlebars->27->1529"
20191 + "default.handlebars->27->1530"
20192 ]
20193 },
20194 {
@@ -20196,7 +20202,7 @@
20202 "pt": "Encaminhador de soquete da Web",
20203 "ru": "Ретранслятор Web Socket",
20204 "xloc": [
20199 - "default.handlebars->27->1530"
20205 + "default.handlebars->27->1531"
20206 ]
20207 },
20208 {
@@ -20862,7 +20868,7 @@
20868 "pt": "\\\\'",
20869 "ru": "\\\\'",
20870 "xloc": [
20865 - "default.handlebars->27->1538"
20871 + "default.handlebars->27->1539"
20872 ]
20873 },
20874 {
@@ -21053,7 +21059,7 @@
21059 "pt": "livre",
21060 "ru": "свободно",
21061 "xloc": [
21056 - "default.handlebars->27->1503"
21062 + "default.handlebars->27->1504"
21063 ]
21064 },
21065 {
@@ -21287,7 +21293,7 @@
21293 "pt": "servertrace.csv",
21294 "ru": "servertrace.csv",
21295 "xloc": [
21290 - "default.handlebars->27->1537"
21296 + "default.handlebars->27->1538"
21297 ]
21298 },
21299 {
@@ -21324,7 +21330,7 @@
21330 "pt": "tempo, conn.agente, conn.usuários.usersessions, conn.relaysession, conn.intelamt, mem.externo mem.amontoado, mem.heaptotal, mem.rss",
21331 "ru": "time, conn.agent, conn.users, conn.usersessions, conn.relaysession, conn.intelamt, mem.external, mem.heapused, mem.heaptotal, mem.rss",
21332 "xloc": [
21327 - "default.handlebars->27->1516"
21333 + "default.handlebars->27->1517"
21334 ]
21335 },
21336 {
@@ -21336,7 +21342,7 @@
21342 "pt": "hora, fonte, mensagem",
21343 "ru": "time, source, message",
21344 "xloc": [
21339 - "default.handlebars->27->1536"
21345 + "default.handlebars->27->1537"
21346 ]
21347 },
21348 {
@@ -21359,7 +21365,7 @@
21365 "pt": "total",
21366 "ru": "всего",
21367 "xloc": [
21362 - "default.handlebars->27->1504"
21368 + "default.handlebars->27->1505"
21369 ]
21370 },
21371 {
@@ -22063,4 +22069,4 @@
22069 ]
22070 }
22071 ]
22066 -}
22072 +}
\ No newline at end of file
views/default-mobile.handlebars
+17 -5
@@ -3458,14 +3458,14 @@
3458 if (typeof mesh == 'string') { mesh = meshes[mesh] }
3459 if ((mesh == null) || (mesh.links == null)) { return 0; }
3460
3461 - // Check if user user
3461 + // Check if super user
3462 if (userinfo.manageAllDeviceGroups) return 0xFFFFFFFF;
3463
3464 - // Check direct link permission
3464 + // Check device group link permission
3465 var rights = 0, r = mesh.links[userid];
3466 if (r != null) {
3467 + if (rights == 0xFFFFFFFF) { return 0xFFFFFFFF; } // User has full rights thru a device group link, stop here.
3468 rights = r.rights;
3468 - if (rights == 0xFFFFFFFF) { return rights; } // User has full rights thru a direct link, stop here.
3469 }
3470
3471 // Check permissions thru user groups
@@ -3476,7 +3476,7 @@
3476 if (i.startsWith('ugrp/')) {
3477 r = mesh.links[i];
3478 if (r != null) {
3479 - if (r.rights == 0xFFFFFFFF) { return r.rights; } // User has full rights thru a user group, stop here.
3479 + if (r.rights == 0xFFFFFFFF) { return 0xFFFFFFFF; } // User has full rights thru a user group, stop here.
3480 rights |= r.rights; // TODO: Deal with reverse permissions
3481 }
3482 }
@@ -3514,7 +3514,19 @@
3514 if (node == null) { return 0; }
3515 if (userid == null) { userid = userinfo._id; }
3516 if (typeof node == 'string') { node = getNodeFromId(node); if (node == null) { return 0; } }
3517 - return GetMeshRights(node.meshid, userid);
3517 + var r = GetMeshRights(node.meshid, userid);
3518 + if (r != 0xFFFFFFFF) {
3519 + var user = null;
3520 + if (userid == userinfo._id) { user = userinfo; } else { if (users != null) { user = users[userid]; } }
3521 + if ((user != null) && (user.links != null)) {
3522 + var r2 = user.links[node._id];
3523 + if (r2 != null) {
3524 + if (r2.rights == 0xFFFFFFFF) { return 0xFFFFFFFF; } // User has full rights thru a device link, stop here.
3525 + r |= r2; // TODO: Deal with reverse permissions
3526 + }
3527 + }
3528 + }
3529 + return r;
3530 }
3531
3532 //
views/default.handlebars
+54 -19
@@ -2721,7 +2721,7 @@
2721 go(parseInt('{{viewmode}}'));
2722 goBackStack.push(2);
2723 } else if (args.gotouser != null) {
2724 - if (users['user/' + domain + '/' + args.gotouser] == null) return; // This user is not loaded yet
2724 + if ((users == null) || (users['user/' + domain + '/' + args.gotouser] == null)) return; // This user is not loaded yet
2725 gotoUser('user/' + domain + '/' + args.gotouser);
2726 go(parseInt('{{viewmode}}'));
2727 goBackStack.push(4);
@@ -3123,9 +3123,11 @@
3123
3124 // Display all empty device groups, we need to do this because users can add devices to these at any time.
3125 if ((sort == 0) && (Q('SearchInput').value == '') && (view < 3)) {
3126 - var deviceHeaderId2 = deviceHeaderId;
3127 - for (var i in meshes) {
3128 - var mesh = meshes[i], meshrights = GetMeshRights(mesh);
3126 + var deviceHeaderId2 = deviceHeaderId, sortedMeshes = [];
3127 + for (var i in meshes) { sortedMeshes.push(meshes[i]); }
3128 + sortedMeshes.sort(nameSort);
3129 + for (var i in sortedMeshes) {
3130 + var mesh = sortedMeshes[i], meshrights = GetMeshRights(mesh);
3131 if (displayedMeshes[mesh._id] == null) {
3132 if ((current != '') && (r != '')) { r += '</tr></table>'; }
3133 r += '<table style=width:100%;padding-top:4px cellpadding=0 cellspacing=0><tr><td colspan=3 class=DevSt>';
@@ -3141,8 +3143,7 @@
3143 if (mesh.mtype == 1) {
3144 r += '<td><div style=padding:10px><i>' + "No Intel&reg; AMT devices in this mesh";
3145 if ((meshrights & 4) != 0) { r += ', <a href=# style=cursor:pointer onclick=\'return addDeviceToMesh(\"' + mesh._id + '\")\'>' + "add one" + '</a>'; }
3144 - }
3145 - if (mesh.mtype == 2) {
3146 + } else if (mesh.mtype == 2) {
3147 r += '<td>';
3148 r += '<div id=DevxCol' + deviceHeaderId2 + ((collapsed === true)?' style=display:none':'') + '>'; // Open collapse div
3149 r += '<div style=padding:10px><i>' + "No devices in this group";
@@ -10055,16 +10056,14 @@
10056 // Draw the user timeline
10057 drawUserPermissions();
10058
10058 - // Check if we can delete this user
10059 - var deletePossible = true;
10060 - if (user._id == userinfo._id) deletePossible = false;
10061 - if (user.siteadmin && user.siteadmin > 0 && userinfo.siteadmin != 0xFFFFFFFF) deletePossible = false;
10059 + // Check if we can change password / delete this user
10060 + var userAdminRights = (((userinfo.siteadmin != null) && (userinfo.siteadmin & 2) && (user.siteadmin != 0xFFFFFFFF)) || (userinfo.siteadmin == 0xFFFFFFFF));
10061
10062 // Show bottom buttons
10063 x = '<div style=float:right;font-size:x-small>';
10065 - if (deletePossible) x += '<a href=# style=cursor:pointer onclick=\'return p30showDeleteUserDialog()\' title="Remove this user">' + "Delete User" + '</a>';
10064 + if (userAdminRights) { x += '<a href=# style=cursor:pointer onclick=\'return p30showDeleteUserDialog()\' title="Remove this user">' + "Delete User" + '</a>'; }
10065 x += '</div><div style=font-size:x-small>';
10067 - if (((userinfo.siteadmin & 2) && (user.siteadmin != 0xFFFFFFFF)) || (userinfo.siteadmin == 0xFFFFFFFF)) x += '<a href=# style=cursor:pointer onclick=\'return p30showUserChangePassDialog(' + multiFactor + ')\' title="' + "Change the password for this user" + '">' + "Change Password" + '</a>';
10066 + if (userAdminRights) { x += '<a href=# style=cursor:pointer onclick=\'return p30showUserChangePassDialog(' + multiFactor + ')\' title="' + "Change the password for this user" + '">' + "Change Password" + '</a>'; }
10067 x += '</div><br>'
10068 QH('p30html3', x);
10069
@@ -10160,7 +10159,7 @@
10159
10160 function p30showDeleteUserDialog() {
10161 if (xxdialogMode) return;
10163 - setDialogMode(2, format("Delete User {0}", EscapeHtml(currentUser.name)), 3, p30showDeleteUserDialogEx, format('Confirm deletion of user {0}?', EscapeHtml(currentUser.name)));
10162 + setDialogMode(2, format("Delete User {0}", EscapeHtml(currentUser.name)), 3, p30showDeleteUserDialogEx, format("Confirm deletion of user {0}?", EscapeHtml(currentUser.name)));
10163 }
10164
10165 function p30showDeleteUserDialogEx() {
@@ -10170,6 +10169,29 @@
10169 // Draw device power bars. The bars are 766px wide.
10170 function drawUserPermissions() {
10171 var count = 1, x = '';
10172 +
10173 + if (urlargs.dp == 1) { // For testing only
10174 + // Display common devices
10175 + x += '<a href=# onclick="return p20showAddMeshUserDialog(1)" style=cursor:pointer;margin-right:10px><img src=images/icon-addnew.png border=0 height=12 width=12> ' + "Add Device" + '</a>';
10176 + x += '<table style="color:black;background-color:#EEE;border-color:#AAA;border-width:1px;border-style:solid;border-collapse:collapse" border=0 cellpadding=2 cellspacing=0 width=100%><tbody><tr style=background-color:#AAAAAA;font-weight:bold><th scope=col style=text-align:left;width:430px>' + "Common Devices" + '</th><th scope=col style=text-align:left></th></tr>';
10177 + if (currentUser.links) {
10178 + for (var i in currentUser.links) {
10179 + if (i.startsWith('node/')) {
10180 + var cr = 0, r = currentUser.links[i].rights, node = getNodeFromId(i), trash = '', rights = "Partial Device Rights";
10181 + if (node == null) { continue; }
10182 + if ((userinfo.links) && (userinfo.links[i] != null) && (userinfo.links[i].rights != null)) { cr = userinfo.links[i].rights; }
10183 + var nodename = node?EscapeHtml(node.name):('<i>' + "Unknown Device" + '</i>');
10184 + if (r == 0xFFFFFFFF) rights = "Full Device Rights"; else if (r == 0) rights = "No Rights";
10185 + if ((currentUser._id != userinfo._id) && ((cr & 2) != 0)) { trash = '<a href=# onclick=\'return p30removeNodeFromUser(event,"' + encodeURIComponent(node._id) + '")\' title=\"' + "Remove user rights to this device group" + '\" style=cursor:pointer><img src=images/trash.png border=0 height=10 width=10></a>'; }
10186 + x += '<tr ' + (((++count % 2) == 0) ? 'style=background-color:#DDD' : '') + '><td><div title=\"' + "Device Group" + '\" class=m99></div><div>&nbsp;' + nodename + '<div></div></div></td><td><div style=float:right>' + trash + '</div><div>' + rights + '</div></td></tr>';
10187 + }
10188 + }
10189 + }
10190 + if (count == 1) { x += '<tr><td><div style=padding:6px>&nbsp;<i>' + "No devices in common" + '</i><div></div></div></td><td></td></tr>'; }
10191 + x += '</tbody></table><br />';
10192 + }
10193 +
10194 + // Display common device groups
10195 var deviceGroupCount = 0, newDeviceGroup = false;
10196 for (var i in meshes) { deviceGroupCount++; if ((currentUser.links == null) || (currentUser.links[i] == null)) { newDeviceGroup = true; } }
10197 if ((deviceGroupCount > 0) && (newDeviceGroup)) { x += '<a href=# onclick="return p20showAddMeshUserDialog(1)" style=cursor:pointer;margin-right:10px><img src=images/icon-addnew.png border=0 height=12 width=12> ' + "Add Device Group" + '</a>'; }
@@ -10190,6 +10212,7 @@
10212 if (count == 1) { x += '<tr><td><div style=padding:6px>&nbsp;<i>' + "No device groups in common" + '</i><div></div></div></td><td></td></tr>'; }
10213 x += '</tbody></table>';
10214
10215 + // Display user groups
10216 if (usergroups != null) {
10217 count = 1;
10218 x += '<br />';
@@ -11169,14 +11192,14 @@
11192 if (typeof mesh == 'string') { mesh = meshes[mesh] }
11193 if ((mesh == null) || (mesh.links == null)) { return 0; }
11194
11172 - // Check if user user
11195 + // Check if super user
11196 if (userinfo.manageAllDeviceGroups) return 0xFFFFFFFF;
11197
11175 - // Check direct link permission
11198 + // Check device group link permission
11199 var rights = 0, r = mesh.links[userid];
11200 if (r != null) {
11201 + if (rights == 0xFFFFFFFF) { return 0xFFFFFFFF; } // User has full rights thru a device group link, stop here.
11202 rights = r.rights;
11179 - if (rights == 0xFFFFFFFF) { return rights; } // User has full rights thru a direct link, stop here.
11203 }
11204
11205 // Check permissions thru user groups
@@ -11187,7 +11210,7 @@
11210 if (i.startsWith('ugrp/')) {
11211 r = mesh.links[i];
11212 if (r != null) {
11190 - if (r.rights == 0xFFFFFFFF) { return r.rights; } // User has full rights thru a user group, stop here.
11213 + if (r.rights == 0xFFFFFFFF) { return 0xFFFFFFFF; } // User has full rights thru a user group, stop here.
11214 rights |= r.rights; // TODO: Deal with reverse permissions
11215 }
11216 }
@@ -11219,13 +11242,25 @@
11242
11243 return false;
11244 }
11222 -
11245 +
11246 // Return the user rights for a given node
11247 function GetNodeRights(node, userid) {
11248 if (node == null) { return 0; }
11249 if (userid == null) { userid = userinfo._id; }
11250 if (typeof node == 'string') { node = getNodeFromId(node); if (node == null) { return 0; } }
11228 - return GetMeshRights(node.meshid, userid);
11251 + var r = GetMeshRights(node.meshid, userid);
11252 + if (r != 0xFFFFFFFF) {
11253 + var user = null;
11254 + if (userid == userinfo._id) { user = userinfo; } else { if (users != null) { user = users[userid]; } }
11255 + if ((user != null) && (user.links != null)) {
11256 + var r2 = user.links[node._id];
11257 + if (r2 != null) {
11258 + if (r2.rights == 0xFFFFFFFF) { return 0xFFFFFFFF; } // User has full rights thru a device link, stop here.
11259 + r |= r2; // TODO: Deal with reverse permissions
11260 + }
11261 + }
11262 + }
11263 + return r;
11264 }
11265
11266 //
webserver.js
+14 -6
@@ -4101,12 +4101,20 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
4101 db.Get(nodeid, function (err, nodes) {
4102 if ((nodes == null) || (nodes.length != 1)) { func(null, 0, false); return; } // No such nodeid
4103
4104 - // Check direct link
4105 - var rights = 0, visible = false, r = user.links[nodes[0].meshid];
4104 + // Check device link
4105 + var rights = 0, visible = false, r = user.links[nodeid];
4106 if (r != null) {
4107 - rights = r.rights;
4107 + if (r.rights == 0xFFFFFFFF) { func(nodes[0], 0xFFFFFFFF, true); return; } // User has full rights thru a device link, stop here.
4108 + rights |= r.rights;
4109 + visible = true;
4110 + }
4111 +
4112 + // Check device group link
4113 + r = user.links[nodes[0].meshid];
4114 + if (r != null) {
4115 + if (r.rights == 0xFFFFFFFF) { func(nodes[0], 0xFFFFFFFF, true); return; } // User has full rights thru a device group link, stop here.
4116 + rights |= r.rights;
4117 visible = true;
4109 - if (rights == 0xFFFFFFFF) { func(nodes[0], rights, true); return; } // User has full rights thru a direct link, stop here.
4118 }
4119
4120 // Check user group links
@@ -4116,7 +4124,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
4124 if (g && (g.links != null)) {
4125 r = g.links[nodes[0].meshid];
4126 if (r != null) {
4119 - if (r.rights == 0xFFFFFFFF) { func(nodes[0], r.rights, true); return; } // User has full rights thru a user group link, stop here.
4127 + if (r.rights == 0xFFFFFFFF) { func(nodes[0], 0xFFFFFFFF, true); return; } // User has full rights thru a user group link, stop here.
4128 rights |= r.rights; // TODO: Deal with reverse rights
4129 visible = true;
4130 }
@@ -4202,7 +4210,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
4210 return r;
4211 }
4212
4205 - // Get the right of a user on a given device group
4213 + // Get the rights of a user on a given device group
4214 obj.GetMeshRights = function (user, mesh) {
4215 if ((user == null) || (mesh == null)) { return 0; }
4216 if (typeof user == 'string') { user = obj.users[user]; }