More work done on per-device permissions.

Ylian Saint-Hilaire committed Mar 26, 2020 at 19:33 UTC 2314a58cd22f75ebac0805e01699aa69ead2aa75
9 files changed +595 -129
common.js
+1
@@ -147,6 +147,7 @@ module.exports.escapeFieldName = function (name) { if ((name.indexOf('%') == -1)
147 module.exports.unEscapeFieldName = function (name) { if (name.indexOf('%') == -1) return name; return name.split('%2E').join('.').split('%24').join('$').split('%25').join('%'); };
148
149 // Escape all links
150 +module.exports.escapeLinksFieldNameEx = function (docx) { if (docx.links == null) { return docx; } var doc = Object.assign({}, docx); doc.links = Object.assign({}, doc.links); for (var i in doc.links) { var ue = module.exports.escapeFieldName(i); if (ue !== i) { doc.links[ue] = doc.links[i]; delete doc.links[i]; } } return doc; };
151 module.exports.escapeLinksFieldName = function (docx) { var doc = Object.assign({}, docx); if (doc.links != null) { doc.links = Object.assign({}, doc.links); for (var i in doc.links) { var ue = module.exports.escapeFieldName(i); if (ue !== i) { doc.links[ue] = doc.links[i]; delete doc.links[i]; } } } return doc; };
152 module.exports.unEscapeLinksFieldName = function (doc) { if (doc.links != null) { for (var j in doc.links) { var ue = module.exports.unEscapeFieldName(j); if (ue !== j) { doc.links[ue] = doc.links[j]; delete doc.links[j]; } } } return doc; };
153 //module.exports.escapeAllLinksFieldName = function (docs) { for (var i in docs) { module.exports.escapeLinksFieldName(docs[i]); } return docs; };
db.js
+26 -7
@@ -789,11 +789,17 @@ module.exports.CreateDB = function (parent, func) {
789 // Database actions on the main collection (MariaDB or MySQL)
790 obj.Set = function (value, func) {
791 var extra = null, extraex = null;
792 + value = common.escapeLinksFieldNameEx(value);
793 if (value.meshid) { extra = value.meshid; } else if (value.email) { extra = 'email/' + value.email; }
794 if ((value.type == 'node') && (value.intelamt != null) && (value.intelamt.uuid != null)) { extraex = 'uuid/' + value.intelamt.uuid; }
795 sqlDbQuery('REPLACE INTO meshcentral.main VALUE (?, ?, ?, ?, ?, ?)', [value._id, (value.type ? value.type : null), ((value.domain != null) ? value.domain : null), extra, extraex, JSON.stringify(performTypedRecordEncrypt(value))], func);
796 }
796 - obj.Get = function (_id, func) { sqlDbQuery('SELECT doc FROM meshcentral.main WHERE id = ?', [_id], func); }
797 + obj.Get = function (_id, func) {
798 + sqlDbQuery('SELECT doc FROM meshcentral.main WHERE id = ?', [_id], function (err, docs) {
799 + if ((docs != null) && (docs.length > 0) && (docs[0].links != null)) { docs[0] = common.unEscapeLinksFieldName(docs[0]); }
800 + func(_id, func);
801 + });
802 + }
803 obj.GetAll = function (func) { sqlDbQuery('SELECT domain, doc FROM meshcentral.main', null, func); }
804 obj.GetHash = function (id, func) { sqlDbQuery('SELECT doc FROM meshcentral.main WHERE id = ?', [id], func); }
805 obj.GetAllTypeNoTypeField = function (type, domain, func) { sqlDbQuery('SELECT doc FROM meshcentral.main WHERE type = ? AND domain = ?', [type, domain], function (err, docs) { if (err == null) { for (var i in docs) { delete docs[i].type } } func(err, docs); }); };
@@ -920,7 +926,7 @@ module.exports.CreateDB = function (parent, func) {
926 }
927 } else if (obj.databaseType == 3) {
928 // Database actions on the main collection (MongoDB)
923 - obj.Set = function (data, func) { obj.file.replaceOne({ _id: data._id }, performTypedRecordEncrypt(data), { upsert: true }, func); };
929 + obj.Set = function (data, func) { data = common.escapeLinksFieldNameEx(data); obj.file.replaceOne({ _id: data._id }, performTypedRecordEncrypt(data), { upsert: true }, func); };
930 obj.Get = function (id, func) {
931 if (arguments.length > 2) {
932 var parms = [func];
@@ -932,9 +938,15 @@ module.exports.CreateDB = function (parent, func) {
938 userCallback.apply(obj, _func2.userArgs);
939 };
940 func2.userArgs = parms;
935 - obj.file.find({ _id: id }).toArray(function (err, docs) { func2(err, performTypedRecordDecrypt(docs)); });
941 + obj.file.find({ _id: id }).toArray(function (err, docs) {
942 + if ((docs != null) && (docs.length > 0) && (docs[0].links != null)) { docs[0] = common.unEscapeLinksFieldName(docs[0]); }
943 + func2(err, performTypedRecordDecrypt(docs));
944 + });
945 } else {
937 - obj.file.find({ _id: id }).toArray(function (err, docs) { func(err, performTypedRecordDecrypt(docs)); });
946 + obj.file.find({ _id: id }).toArray(function (err, docs) {
947 + if ((docs != null) && (docs.length > 0) && (docs[0].links != null)) { docs[0] = common.unEscapeLinksFieldName(docs[0]); }
948 + func(err, performTypedRecordDecrypt(docs));
949 + });
950 }
951 };
952 obj.GetAll = function (func) { obj.file.find({}).toArray(function (err, docs) { func(err, performTypedRecordDecrypt(docs)); }); };
@@ -1052,7 +1064,7 @@ module.exports.CreateDB = function (parent, func) {
1064
1065 } else {
1066 // Database actions on the main collection (NeDB and MongoJS)
1055 - obj.Set = function (data, func) { var xdata = performTypedRecordEncrypt(data); obj.file.update({ _id: xdata._id }, xdata, { upsert: true }, func); };
1067 + obj.Set = function (data, func) { data = common.escapeLinksFieldNameEx(data); var xdata = performTypedRecordEncrypt(data); obj.file.update({ _id: xdata._id }, xdata, { upsert: true }, func); };
1068 obj.Get = function (id, func) {
1069 if (arguments.length > 2) {
1070 var parms = [func];
@@ -1064,9 +1076,15 @@ module.exports.CreateDB = function (parent, func) {
1076 userCallback.apply(obj, _func2.userArgs);
1077 };
1078 func2.userArgs = parms;
1067 - obj.file.find({ _id: id }, function (err, docs) { func2(err, performTypedRecordDecrypt(docs)); });
1079 + obj.file.find({ _id: id }, function (err, docs) {
1080 + if ((docs != null) && (docs.length > 0) && (docs[0].links != null)) { docs[0] = common.unEscapeLinksFieldName(docs[0]); }
1081 + func2(err, performTypedRecordDecrypt(docs));
1082 + });
1083 } else {
1069 - obj.file.find({ _id: id }, function (err, docs) { func(err, performTypedRecordDecrypt(docs)); });
1084 + obj.file.find({ _id: id }, function (err, docs) {
1085 + if ((docs != null) && (docs.length > 0) && (docs[0].links != null)) { docs[0] = common.unEscapeLinksFieldName(docs[0]); }
1086 + func(err, performTypedRecordDecrypt(docs));
1087 + });
1088 }
1089 };
1090 obj.GetAll = function (func) { obj.file.find({}, function (err, docs) { func(err, performTypedRecordDecrypt(docs)); }); };
@@ -1323,6 +1341,7 @@ module.exports.CreateDB = function (parent, func) {
1341
1342 // Called when a node has changed
1343 function dbNodeChange(nodeChange, added) {
1344 + common.unEscapeLinksFieldName(nodeChange.fullDocument);
1345 const node = nodeChange.fullDocument;
1346 if (node.intelamt && node.intelamt.pass) { delete node.intelamt.pass; } // Remove the Intel AMT password before eventing this.
1347 parent.DispatchEvent(['*', node.meshid], obj, { etype: 'node', action: (added ? 'addnode' : 'changenode'), node: node, nodeid: node._id, domain: node.domain, nolog: 1 });
meshagent.js
+3 -3
@@ -549,7 +549,7 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
549 const links = {};
550 links[adminUser._id] = { name: adminUser.name, rights: 0xFFFFFFFF };
551 mesh = { type: 'mesh', _id: obj.dbMeshKey, name: meshname, mtype: 2, desc: '', domain: domain.id, links: links };
552 - db.Set(common.escapeLinksFieldName(mesh));
552 + db.Set(mesh);
553 parent.meshes[obj.dbMeshKey] = mesh;
554
555 if (adminUser.links == null) adminUser.links = {};
@@ -580,7 +580,7 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
580
581 // Mark the mesh as active
582 delete mesh.deleted;
583 - db.Set(common.escapeLinksFieldName(mesh));
583 + db.Set(mesh);
584 }
585 }
586 return mesh;
@@ -638,7 +638,7 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
638 var links = {};
639 links[user._id] = { name: adminUser.name, rights: 0xFFFFFFFF };
640 mesh = { type: 'mesh', _id: obj.dbMeshKey, name: obj.meshid, mtype: 2, desc: '', domain: domain.id, links: links };
641 - db.Set(common.escapeLinksFieldName(mesh));
641 + db.Set(mesh);
642 parent.meshes[obj.meshid] = mesh;
643 parent.parent.AddEventDispatch(parent.CreateMeshDispatchTargets(obj.meshid, [obj.dbNodeKey]), ws);
644
meshcentral.js
+2 -2
@@ -815,8 +815,8 @@ function CreateMeshCentralServer(config, args) {
815 objectToAdd.push(newobj); // Add this user
816 }
817 } else if (newobj.type == 'mesh') {
818 - // Add this object after escaping
819 - objectToAdd.push(obj.common.escapeLinksFieldName(newobj));
818 + // Add this object
819 + objectToAdd.push(newobj);
820 } // Don't add nodes.
821 }
822 console.log('Importing ' + objectToAdd.length + ' object(s)...');
meshuser.js
+82 -19
@@ -1268,7 +1268,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
1268 mesh = parent.meshes[meshid];
1269 if (mesh) {
1270 // Remove user from the mesh
1271 - if (mesh.links[deluser._id] != null) { delete mesh.links[deluser._id]; parent.db.Set(common.escapeLinksFieldName(mesh)); }
1271 + if (mesh.links[deluser._id] != null) { delete mesh.links[deluser._id]; parent.db.Set(mesh); }
1272 // Notify mesh change
1273 change = 'Removed user ' + deluser.name + ' from group ' + mesh.name;
1274 var event = { etype: 'mesh', userid: user._id, username: user.name, meshid: mesh._id, name: mesh.name, mtype: mesh.mtype, desc: mesh.desc, action: 'meshchange', links: mesh.links, msg: change, domain: domain.id, invite: mesh.invite };
@@ -1664,7 +1664,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
1664 if (xmesh && xmesh.links) {
1665 ugrp.links[i] = { rights: cgroup.links[i].rights };
1666 xmesh.links[ugrpid] = { rights: cgroup.links[i].rights };
1667 - db.Set(common.escapeLinksFieldName(xmesh));
1667 + db.Set(xmesh);
1668
1669 // Notify mesh change
1670 var event = { etype: 'mesh', userid: user._id, username: user.name, meshid: xmesh._id, name: xmesh.name, mtype: xmesh.mtype, desc: xmesh.desc, action: 'meshchange', links: xmesh.links, msg: 'Added group ' + ugrp.name + ' to mesh ' + xmesh.name, domain: domain.id, invite: mesh.invite };
@@ -1678,7 +1678,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
1678 }
1679
1680 // Save the new group
1681 - db.Set(common.escapeLinksFieldName(ugrp));
1681 + db.Set(ugrp);
1682 if (db.changeStream == false) { parent.userGroups[ugrpid] = ugrp; }
1683
1684 // Event the device group creation
@@ -1703,7 +1703,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
1703
1704 db.Get(command.ugrpid, function (err, groups) {
1705 if ((err != null) || (groups.length != 1)) return;
1706 - var group = common.unEscapeLinksFieldName(groups[0]);
1706 + var group = groups[0];
1707
1708 // Unlink any user and meshes that have a link to this group
1709 if (group.links) {
@@ -1725,7 +1725,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
1725 var xmesh = parent.meshes[i];
1726 if (xmesh && xmesh.links) {
1727 delete xmesh.links[group._id];
1728 - db.Set(common.escapeLinksFieldName(xmesh));
1728 + db.Set(xmesh);
1729
1730 // Notify mesh change
1731 var event = { etype: 'mesh', userid: user._id, username: user.name, meshid: xmesh._id, name: xmesh.name, mtype: xmesh.mtype, desc: xmesh.desc, action: 'meshchange', links: xmesh.links, msg: 'Removed group ' + group.name + ' from mesh ' + xmesh.name, domain: domain.id, invite: mesh.invite };
@@ -1762,7 +1762,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
1762 if ((common.validateString(command.name, 1, 64) == true) && (command.name != group.name) && (command.name.indexOf(' ') == -1)) { change = 'User group name changed from "' + group.name + '" to "' + command.name + '"'; group.name = command.name; }
1763 if ((common.validateString(command.desc, 0, 1024) == true) && (command.desc != group.desc)) { if (change != '') change += ' and description changed'; else change += 'User group "' + group.name + '" description changed'; group.desc = command.desc; }
1764 if (change != '') {
1765 - db.Set(common.escapeLinksFieldName(group));
1765 + db.Set(group);
1766 var event = { etype: 'ugrp', userid: user._id, username: user.name, ugrpid: group._id, name: group.name, desc: group.desc, action: 'usergroupchange', links: group.links, msg: change, domain: domain.id };
1767 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.
1768 parent.parent.DispatchEvent(['*', group._id, user._id], obj, event);
@@ -1822,7 +1822,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
1822
1823 if (addedCount > 0) {
1824 // Save the new group to the database
1825 - db.Set(common.escapeLinksFieldName(group));
1825 + db.Set(group);
1826
1827 // Notify user group change
1828 var event = { etype: 'ugrp', userid: user._id, username: user.name, ugrpid: group._id, name: group.name, desc: group.desc, action: 'usergroupchange', links: group.links, msg: 'Added user ' + chguser.name + ' to user group ' + group.name, domain: domain.id };
@@ -1884,7 +1884,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
1884 if ((group.links != null) && (group.links[command.userid] != null)) {
1885 change = true;
1886 delete group.links[command.userid];
1887 - db.Set(common.escapeLinksFieldName(group));
1887 + db.Set(group);
1888
1889 // Notify user group change
1890 if (change) {
@@ -2158,7 +2158,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
2158 var links = {};
2159 links[user._id] = { name: user.name, rights: 4294967295 };
2160 mesh = { type: 'mesh', _id: meshid, name: command.meshname, mtype: command.meshtype, desc: command.desc, domain: domain.id, links: links };
2161 - db.Set(common.escapeLinksFieldName(mesh));
2161 + db.Set(mesh);
2162 parent.meshes[meshid] = mesh;
2163 parent.parent.AddEventDispatch([meshid], ws);
2164
@@ -2230,7 +2230,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
2230 var xgroup = parent.userGroups[j];
2231 if (xgroup && xgroup.links) {
2232 delete xgroup.links[mesh._id];
2233 - db.Set(common.escapeLinksFieldName(xgroup));
2233 + db.Set(xgroup);
2234
2235 // Notify user group change
2236 var targets = ['*', 'server-ugroups', user._id, xgroup._id];
@@ -2251,7 +2251,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
2251
2252 // Mark the mesh as deleted
2253 mesh.deleted = new Date(); // Mark the time this mesh was deleted, we can expire it at some point.
2254 - db.Set(common.escapeLinksFieldName(mesh)); // We don't really delete meshes because if a device connects to is again, we will un-delete it.
2254 + db.Set(mesh); // We don't really delete meshes because if a device connects to is again, we will un-delete it.
2255
2256 // Delete all devices attached to this mesh in the database
2257 db.RemoveMeshDocuments(command.meshid);
@@ -2304,7 +2304,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
2304 }
2305
2306 if (change != '') {
2307 - db.Set(common.escapeLinksFieldName(mesh));
2307 + db.Set(mesh);
2308 var event = { etype: 'mesh', userid: user._id, username: user.name, meshid: mesh._id, name: mesh.name, mtype: mesh.mtype, desc: mesh.desc, flags: mesh.flags, consent: mesh.consent, action: 'meshchange', links: mesh.links, msg: change, domain: domain.id, invite: mesh.invite };
2309 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.
2310 parent.parent.DispatchEvent(['*', mesh._id, user._id], obj, event);
@@ -2356,7 +2356,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
2356 if (newuser.links == null) { newuser.links = {}; }
2357 if (newuser.links[command.meshid]) { newuser.links[command.meshid].rights = command.meshadmin; } else { newuser.links[command.meshid] = { rights: command.meshadmin }; }
2358 if (newuserid.startsWith('user/')) { db.SetUser(newuser); }
2359 - else if (newuserid.startsWith('ugrp/')) { db.Set(common.escapeLinksFieldName(newuser)); }
2359 + else if (newuserid.startsWith('ugrp/')) { db.Set(newuser); }
2360 parent.parent.DispatchEvent([newuser._id], obj, 'resubscribe');
2361
2362 if (newuserid.startsWith('user/')) {
@@ -2375,7 +2375,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
2375
2376 // Add userid to the mesh
2377 mesh.links[newuserid] = { name: newuser.name, rights: command.meshadmin };
2378 - db.Set(common.escapeLinksFieldName(mesh));
2378 + db.Set(mesh);
2379
2380 // Notify mesh change
2381 var event = { etype: 'mesh', username: newuser.name, userid: user._id, meshid: mesh._id, name: mesh.name, mtype: mesh.mtype, desc: mesh.desc, action: 'meshchange', links: mesh.links, msg: 'Added user ' + newuser.name + ' to mesh ' + mesh.name, domain: domain.id, invite: mesh.invite };
@@ -2402,6 +2402,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
2402 try {
2403 if (common.validateString(command.nodeid, 1, 1024) == false) { err = 'Invalid nodeid'; } // Check the nodeid
2404 else if (common.validateInt(command.rights) == false) { err = 'Invalid rights'; } // Device rights must be an integer
2405 + else if ((command.rights & 7) != 0) { err = 'Invalid rights'; } // EDITMESH, MANAGEUSERS or MANAGECOMPUTERS rights can't be assigned to a user to device link
2406 else if ((common.validateStrArray(command.usernames, 1, 64) == false) && (common.validateStrArray(command.userids, 1, 128) == false)) { err = 'Invalid usernames'; } // Username is between 1 and 64 characters
2407 else {
2408 if (command.nodeid.indexOf('/') == -1) { command.nodeid = 'node/' + domain.id + '/' + command.meshid; }
@@ -2421,8 +2422,70 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
2422 for (var i in command.usernames) { command.userids.push('user/' + domain.id + '/' + command.usernames[i].toLowerCase()); }
2423 }
2424
2424 - // TODO
2425 - //console.log(command);
2425 + // Get the node and the rights for this node
2426 + parent.GetNodeWithRights(domain, user, command.nodeid, function (node, rights, visible) {
2427 + // Check if already in the right mesh
2428 + if ((node == null) || (node.meshid == command.meshid)) return;
2429 + var dispatchTargets = ['*', node.meshid, node._id];
2430 +
2431 + // Check that we have rights to manage users on this device
2432 + if ((rights & MESHRIGHT_MANAGEUSERS) == 0) return;
2433 +
2434 + // Add the new link to the users
2435 + var nodeChanged = false;
2436 + for (var i in command.userids) {
2437 + var newuserid = command.userids[i];
2438 + var newuser = parent.users[newuserid];
2439 + if (newuser != null) {
2440 + // Add this user to the dispatch target list
2441 + dispatchTargets.push(newuser._id);
2442 +
2443 + if (command.rights == 0) {
2444 + // Remove link to this user
2445 + if (newuser.links != null) {
2446 + delete newuser.links[command.nodeid];
2447 + if (Object.keys(newuser.links).length == 0) { delete newuser.links; }
2448 + }
2449 +
2450 + // Remove link to this device
2451 + if (node.links != null) {
2452 + delete node.links[newuserid];
2453 + nodeChanged = true;
2454 + if (Object.keys(node.links).length == 0) { delete node.links; }
2455 + }
2456 + } else {
2457 + // Add the new link to this user
2458 + if (newuser.links == null) { newuser.links = {}; }
2459 + newuser.links[command.nodeid] = { rights: command.rights };
2460 +
2461 + // Add the new link to the device
2462 + if (node.links == null) { node.links = {}; }
2463 + node.links[newuserid] = { rights: command.rights }
2464 + nodeChanged = true;
2465 + }
2466 +
2467 + // Save the user to the database
2468 + db.SetUser(newuser);
2469 +
2470 + // Notify user change
2471 + var targets = ['*', 'server-users', newuserid._id];
2472 + var event = { etype: 'user', userid: newuserid._id, username: newuserid.name, action: 'accountchange', msg: (command.rights == 0) ? ('Removed user device rights for ' + user.name) : ('Changed user device rights for ' + user.name), domain: domain.id, account: parent.CloneSafeUser(newuser) };
2473 + if (db.changeStream) { event.noact = 1; } // If DB change stream is active, don't use this event to change the user. Another event will come.
2474 + parent.parent.DispatchEvent(targets, obj, event);
2475 + }
2476 + }
2477 +
2478 + // Save the device
2479 + if (nodeChanged == true) {
2480 + // Save the node to the database
2481 + db.Set(node);
2482 +
2483 + // Event the node change
2484 + var event = { etype: 'node', userid: user._id, username: user.name, action: 'changenode', nodeid: node._id, domain: domain.id, msg: (command.rights == 0) ? ('Removed user device rights for ' + node.name) : ('Changed user device rights for ' + node.name), node: parent.CloneSafeNode(node) }
2485 + 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.
2486 + parent.parent.DispatchEvent(dispatchTargets, obj, event);
2487 + }
2488 + });
2489
2490 break;
2491 }
@@ -2461,7 +2524,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
2524 if ((delmeshrights == 0xFFFFFFFF) && (mesh.links[deluserid].rights != 0xFFFFFFFF)) return; // A non-admin can't kick out an admin
2525 delete deluser.links[command.meshid];
2526 if (deluserid.startsWith('user/')) { db.SetUser(deluser); }
2464 - else if (deluserid.startsWith('ugrp/')) { db.Set(common.escapeLinksFieldName(deluser)); }
2527 + else if (deluserid.startsWith('ugrp/')) { db.Set(deluser); }
2528 parent.parent.DispatchEvent([deluser._id], obj, 'resubscribe');
2529
2530 if (deluserid.startsWith('user/')) {
@@ -2483,7 +2546,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
2546 // Remove user from the mesh
2547 if (mesh.links[command.userid] != null) {
2548 delete mesh.links[command.userid];
2486 - db.Set(common.escapeLinksFieldName(mesh));
2549 + db.Set(mesh);
2550
2551 // Notify mesh change
2552 var event;
@@ -2528,7 +2591,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
2591 if (command.amtpolicy.type === 2) { amtpolicy = { type: command.amtpolicy.type, password: command.amtpolicy.password, badpass: command.amtpolicy.badpass, cirasetup: command.amtpolicy.cirasetup }; }
2592 else if (command.amtpolicy.type === 3) { amtpolicy = { type: command.amtpolicy.type, password: command.amtpolicy.password, cirasetup: command.amtpolicy.cirasetup }; }
2593 mesh.amt = amtpolicy;
2531 - db.Set(common.escapeLinksFieldName(mesh));
2594 + db.Set(mesh);
2595 var amtpolicy2 = Object.assign({}, amtpolicy); // Shallow clone
2596 delete amtpolicy2.password;
2597 var event = { etype: 'mesh', userid: user._id, username: user.name, meshid: mesh._id, amt: amtpolicy2, action: 'meshchange', links: mesh.links, msg: change, domain: domain.id, invite: mesh.invite };
translate/translate.json
+95 -88
@@ -653,7 +653,7 @@
653 "default-mobile.handlebars->9->246",
654 "default-mobile.handlebars->9->70",
655 "default.handlebars->27->1237",
656 - "default.handlebars->27->1483",
656 + "default.handlebars->27->1485",
657 "default.handlebars->27->653"
658 ]
659 },
@@ -2361,7 +2361,7 @@
2361 "ru": "Добавить участие",
2362 "zh-chs": "添加會員",
2363 "xloc": [
2364 - "default.handlebars->27->1479"
2364 + "default.handlebars->27->1481"
2365 ]
2366 },
2367 {
@@ -2847,7 +2847,7 @@
2847 "ru": "Счетчик ошибок агента",
2848 "zh-chs": "座席錯誤計數器",
2849 "xloc": [
2850 - "default.handlebars->27->1492"
2850 + "default.handlebars->27->1494"
2851 ]
2852 },
2853 {
@@ -2913,7 +2913,7 @@
2913 "ru": "Сессии агентов",
2914 "zh-chs": "座席會議",
2915 "xloc": [
2916 - "default.handlebars->27->1508"
2916 + "default.handlebars->27->1510"
2917 ]
2918 },
2919 {
@@ -3035,7 +3035,7 @@
3035 "ru": "Агенты",
3036 "zh-chs": "代理商",
3037 "xloc": [
3038 - "default.handlebars->27->1521"
3038 + "default.handlebars->27->1523"
3039 ]
3040 },
3041 {
@@ -3766,7 +3766,7 @@
3766 "ru": "Вы уверенны, что {0} плагин: {1}",
3767 "zh-chs": "您確定要{0}插件嗎:{1}",
3768 "xloc": [
3769 - "default.handlebars->27->1558"
3769 + "default.handlebars->27->1560"
3770 ]
3771 },
3772 {
@@ -4158,7 +4158,7 @@
4158 "ru": "Плохой ключ",
4159 "zh-chs": "錯誤的簽名",
4160 "xloc": [
4161 - "default.handlebars->27->1499"
4161 + "default.handlebars->27->1501"
4162 ]
4163 },
4164 {
@@ -4175,7 +4175,7 @@
4175 "ru": "Плохой веб-сертификат",
4176 "zh-chs": "錯誤的網絡證書",
4177 "xloc": [
4178 - "default.handlebars->27->1498"
4178 + "default.handlebars->27->1500"
4179 ]
4180 },
4181 {
@@ -4410,7 +4410,7 @@
4410 "ru": "CIRA Сервер",
4411 "zh-chs": "CIRA服務器",
4412 "xloc": [
4413 - "default.handlebars->27->1549"
4413 + "default.handlebars->27->1551"
4414 ]
4415 },
4416 {
@@ -4427,7 +4427,7 @@
4427 "ru": "CIRA Сервер команды",
4428 "zh-chs": "CIRA服務器命令",
4429 "xloc": [
4430 - "default.handlebars->27->1550"
4430 + "default.handlebars->27->1552"
4431 ]
4432 },
4433 {
@@ -4444,7 +4444,7 @@
4444 "ru": "Загрузка CPU",
4445 "zh-chs": "CPU負載",
4446 "xloc": [
4447 - "default.handlebars->27->1513"
4447 + "default.handlebars->27->1515"
4448 ]
4449 },
4450 {
@@ -4461,7 +4461,7 @@
4461 "ru": "Загрузка CPU за последние 15 минут",
4462 "zh-chs": "最近15分鐘的CPU負載",
4463 "xloc": [
4464 - "default.handlebars->27->1516"
4464 + "default.handlebars->27->1518"
4465 ]
4466 },
4467 {
@@ -4478,7 +4478,7 @@
4478 "ru": "Загрузка CPU за последние 5 минут",
4479 "zh-chs": "最近5分鐘的CPU負載",
4480 "xloc": [
4481 - "default.handlebars->27->1515"
4481 + "default.handlebars->27->1517"
4482 ]
4483 },
4484 {
@@ -4495,7 +4495,7 @@
4495 "ru": "Загрузка CPU за последнюю минуту",
4496 "zh-chs": "最後一分鐘的CPU負載",
4497 "xloc": [
4498 - "default.handlebars->27->1514"
4498 + "default.handlebars->27->1516"
4499 ]
4500 },
4501 {
@@ -4550,7 +4550,7 @@
4550 "ru": "Ошибка вызова",
4551 "zh-chs": "通話錯誤",
4552 "xloc": [
4553 - "default.handlebars->27->1559"
4553 + "default.handlebars->27->1561"
4554 ]
4555 },
4556 {
@@ -4968,7 +4968,7 @@
4968 "ru": "Проверка...",
4969 "zh-chs": "檢查...",
4970 "xloc": [
4971 - "default.handlebars->27->1555",
4971 + "default.handlebars->27->1557",
4972 "default.handlebars->27->778"
4973 ]
4974 },
@@ -5197,7 +5197,7 @@
5197 "en": "Clear this notification",
5198 "nl": "Wis deze melding",
5199 "xloc": [
5200 - "default.handlebars->27->1486"
5200 + "default.handlebars->27->1488"
5201 ]
5202 },
5203 {
@@ -5560,7 +5560,13 @@
5560 "zh-chs": "確認刪除設備組{0}?",
5561 "xloc": [
5562 "default.handlebars->27->1384",
5563 - "default.handlebars->27->1481"
5563 + "default.handlebars->27->1483"
5564 + ]
5565 + },
5566 + {
5567 + "en": "Confirm removal of device {0}?",
5568 + "xloc": [
5569 + "default.handlebars->27->1476"
5570 ]
5571 },
5572 {
@@ -5577,7 +5583,7 @@
5583 "ru": "Подтвердить удаление группы {0}?",
5584 "zh-chs": "確認刪除組{0}?",
5585 "xloc": [
5580 - "default.handlebars->27->1477"
5586 + "default.handlebars->27->1479"
5587 ]
5588 },
5589 {
@@ -5728,7 +5734,7 @@
5734 "ru": "Подключено Intel® AMT",
5735 "zh-chs": "連接的英特爾®AMT",
5736 "xloc": [
5731 - "default.handlebars->27->1504"
5737 + "default.handlebars->27->1506"
5738 ]
5739 },
5740 {
@@ -5745,7 +5751,7 @@
5751 "ru": "Подключенные пользователи",
5752 "zh-chs": "關聯用戶",
5753 "xloc": [
5748 - "default.handlebars->27->1509"
5754 + "default.handlebars->27->1511"
5755 ]
5756 },
5757 {
@@ -5817,7 +5823,7 @@
5823 "ru": "Подключений ",
5824 "zh-chs": "連接數",
5825 "xloc": [
5820 - "default.handlebars->27->1520"
5826 + "default.handlebars->27->1522"
5827 ]
5828 },
5829 {
@@ -5834,7 +5840,7 @@
5840 "ru": "Ретранслятор подключения",
5841 "zh-chs": "連接繼電器",
5842 "xloc": [
5837 - "default.handlebars->27->1548"
5843 + "default.handlebars->27->1550"
5844 ]
5845 },
5846 {
@@ -5941,7 +5947,7 @@
5947 "ru": "Cookie-кодировщик",
5948 "zh-chs": "Cookie編碼器",
5949 "xloc": [
5944 - "default.handlebars->27->1534"
5950 + "default.handlebars->27->1536"
5951 ]
5952 },
5953 {
@@ -6201,7 +6207,7 @@
6207 "ru": "Основной сервер",
6208 "zh-chs": "核心服務器",
6209 "xloc": [
6204 - "default.handlebars->27->1533"
6210 + "default.handlebars->27->1535"
6211 ]
6212 },
6213 {
@@ -7235,6 +7241,7 @@
7241 "zh-chs": "設備",
7242 "xloc": [
7243 "default.handlebars->27->1150",
7244 + "default.handlebars->27->1458",
7245 "default.handlebars->container->column_l->p1->devListToolbarSpan->1->0->9->devListToolbarSort->sortselect->5"
7246 ]
7247 },
@@ -7273,7 +7280,6 @@
7280 "default.handlebars->27->1148",
7281 "default.handlebars->27->1149",
7282 "default.handlebars->27->1380",
7276 - "default.handlebars->27->1458",
7283 "default.handlebars->27->1467",
7284 "default.handlebars->27->1473"
7285 ]
@@ -7314,7 +7320,7 @@
7320 "default.handlebars->27->1352",
7321 "default.handlebars->27->1365",
7322 "default.handlebars->27->1420",
7317 - "default.handlebars->27->1507",
7323 + "default.handlebars->27->1509",
7324 "default.handlebars->container->column_l->p2->9"
7325 ]
7326 },
@@ -8309,7 +8315,7 @@
8315 "ru": "Скопировать агент",
8316 "zh-chs": "代理重複",
8317 "xloc": [
8312 - "default.handlebars->27->1503"
8318 + "default.handlebars->27->1505"
8319 ]
8320 },
8321 {
@@ -8738,7 +8744,7 @@
8744 "en": "Email Traffic",
8745 "nl": "E-mailverkeer",
8746 "xloc": [
8741 - "default.handlebars->27->1542"
8747 + "default.handlebars->27->1544"
8748 ]
8749 },
8750 {
@@ -9450,7 +9456,7 @@
9456 "ru": "Внешний",
9457 "zh-chs": "外部",
9458 "xloc": [
9453 - "default.handlebars->27->1527"
9459 + "default.handlebars->27->1529"
9460 ]
9461 },
9462 {
@@ -9882,8 +9888,8 @@
9888 "ru": "Свободно",
9889 "zh-chs": "自由",
9890 "xloc": [
9885 - "default.handlebars->27->1488",
9886 - "default.handlebars->27->1490"
9891 + "default.handlebars->27->1490",
9892 + "default.handlebars->27->1492"
9893 ]
9894 },
9895 {
@@ -10731,7 +10737,7 @@
10737 "pt": "Total da pilha",
10738 "zh-chs": "堆總數",
10739 "xloc": [
10734 - "default.handlebars->27->1529"
10740 + "default.handlebars->27->1531"
10741 ]
10742 },
10743 {
@@ -10746,7 +10752,7 @@
10752 "pt": "Pilha usada",
10753 "zh-chs": "堆使用",
10754 "xloc": [
10749 - "default.handlebars->27->1528"
10755 + "default.handlebars->27->1530"
10756 ]
10757 },
10758 {
@@ -11404,8 +11410,8 @@
11410 "xloc": [
11411 "default.handlebars->27->1226",
11412 "default.handlebars->27->1232",
11407 - "default.handlebars->27->1525",
11408 - "default.handlebars->27->1547"
11413 + "default.handlebars->27->1527",
11414 + "default.handlebars->27->1549"
11415 ]
11416 },
11417 {
@@ -12098,7 +12104,7 @@
12104 "ru": "Некорректный тип группы устройств",
12105 "zh-chs": "無效的設備組類型",
12106 "xloc": [
12101 - "default.handlebars->27->1502"
12107 + "default.handlebars->27->1504"
12108 ]
12109 },
12110 {
@@ -12115,7 +12121,7 @@
12121 "ru": "Некорректный JSON",
12122 "zh-chs": "無效的JSON",
12123 "xloc": [
12118 - "default.handlebars->27->1496"
12124 + "default.handlebars->27->1498"
12125 ]
12126 },
12127 {
@@ -12167,7 +12173,7 @@
12173 "ru": "Некорректная сигнатура PKCS",
12174 "zh-chs": "無效的PKCS簽名",
12175 "xloc": [
12170 - "default.handlebars->27->1494"
12176 + "default.handlebars->27->1496"
12177 ]
12178 },
12179 {
@@ -12184,7 +12190,7 @@
12190 "ru": "Некорректная сигнатура RSA",
12191 "zh-chs": "無效的RSA密碼",
12192 "xloc": [
12187 - "default.handlebars->27->1495"
12193 + "default.handlebars->27->1497"
12194 ]
12195 },
12196 {
@@ -13205,7 +13211,7 @@
13211 "ru": "Меньше",
13212 "zh-chs": "減",
13213 "xloc": [
13208 - "default.handlebars->27->1561"
13214 + "default.handlebars->27->1563"
13215 ]
13216 },
13217 {
@@ -14222,7 +14228,7 @@
14228 "ru": "Сообщения главного сервера",
14229 "zh-chs": "主服務器消息",
14230 "xloc": [
14225 - "default.handlebars->27->1536"
14231 + "default.handlebars->27->1538"
14232 ]
14233 },
14234 {
@@ -14596,7 +14602,7 @@
14602 "ru": "Достигнуто максимальное число сессий",
14603 "zh-chs": "達到的會話數上限",
14604 "xloc": [
14599 - "default.handlebars->27->1500"
14605 + "default.handlebars->27->1502"
14606 ]
14607 },
14608 {
@@ -14650,7 +14656,7 @@
14656 "ru": "Мегабайт",
14657 "zh-chs": "兆字節",
14658 "xloc": [
14653 - "default.handlebars->27->1526"
14659 + "default.handlebars->27->1528"
14660 ]
14661 },
14662 {
@@ -14667,7 +14673,7 @@
14673 "ru": "ОЗУ",
14674 "zh-chs": "記憶",
14675 "xloc": [
14670 - "default.handlebars->27->1517",
14676 + "default.handlebars->27->1519",
14677 "default.handlebars->27->743",
14678 "default.handlebars->container->column_l->p40->3->1->p40type->3"
14679 ]
@@ -14800,7 +14806,7 @@
14806 "ru": "Трафик MeshAgent",
14807 "zh-chs": "MeshAgent流量",
14808 "xloc": [
14803 - "default.handlebars->27->1538"
14809 + "default.handlebars->27->1540"
14810 ]
14811 },
14812 {
@@ -14817,7 +14823,7 @@
14823 "ru": "Обновление MeshAgent",
14824 "zh-chs": "MeshAgent更新",
14825 "xloc": [
14820 - "default.handlebars->27->1539"
14826 + "default.handlebars->27->1541"
14827 ]
14828 },
14829 {
@@ -14916,7 +14922,7 @@
14922 "ru": "Соединения сервера MeshCentral",
14923 "zh-chs": "MeshCentral服務器對等",
14924 "xloc": [
14919 - "default.handlebars->27->1537"
14925 + "default.handlebars->27->1539"
14926 ]
14927 },
14928 {
@@ -15170,7 +15176,7 @@
15176 "ru": "Диспетчер сообщения",
15177 "zh-chs": "郵件調度程序",
15178 "xloc": [
15173 - "default.handlebars->27->1535"
15179 + "default.handlebars->27->1537"
15180 ]
15181 },
15182 {
@@ -15271,7 +15277,7 @@
15277 "ru": "Еще",
15278 "zh-chs": "更多",
15279 "xloc": [
15274 - "default.handlebars->27->1560"
15280 + "default.handlebars->27->1562"
15281 ]
15282 },
15283 {
@@ -15956,7 +15962,7 @@
15962 "zh-chs": "找不到活動",
15963 "xloc": [
15964 "default.handlebars->27->1273",
15959 - "default.handlebars->27->1482",
15965 + "default.handlebars->27->1484",
15966 "default.handlebars->27->691"
15967 ]
15968 },
@@ -17000,7 +17006,7 @@
17006 "ru": "Произошло в {0}",
17007 "zh-chs": "發生在{0}",
17008 "xloc": [
17003 - "default.handlebars->27->1485"
17009 + "default.handlebars->27->1487"
17010 ]
17011 },
17012 {
@@ -18015,7 +18021,7 @@
18021 "ru": "Действие плагина",
18022 "zh-chs": "插件動作",
18023 "xloc": [
18018 - "default.handlebars->27->1557",
18024 + "default.handlebars->27->1559",
18025 "default.handlebars->27->159"
18026 ]
18027 },
@@ -18707,7 +18713,7 @@
18713 "ru": "RSS",
18714 "zh-chs": "的RSS",
18715 "xloc": [
18710 - "default.handlebars->27->1530"
18716 + "default.handlebars->27->1532"
18717 ]
18718 },
18719 {
@@ -18886,7 +18892,7 @@
18892 "ru": "Число ретрансляций",
18893 "zh-chs": "中繼計數",
18894 "xloc": [
18889 - "default.handlebars->27->1512"
18895 + "default.handlebars->27->1514"
18896 ]
18897 },
18898 {
@@ -18902,7 +18908,7 @@
18908 "ru": "Ошибки ретранслятора",
18909 "zh-chs": "中繼錯誤",
18910 "xloc": [
18905 - "default.handlebars->27->1505"
18911 + "default.handlebars->27->1507"
18912 ]
18913 },
18914 {
@@ -18918,8 +18924,8 @@
18924 "ru": "Сессии ретранслятора",
18925 "zh-chs": "接力會議",
18926 "xloc": [
18921 - "default.handlebars->27->1511",
18922 - "default.handlebars->27->1524"
18927 + "default.handlebars->27->1513",
18928 + "default.handlebars->27->1526"
18929 ]
18930 },
18931 {
@@ -19193,7 +19199,7 @@
19199 "zh-chs": "刪除設備組",
19200 "xloc": [
19201 "default.handlebars->27->1383",
19196 - "default.handlebars->27->1480"
19202 + "default.handlebars->27->1482"
19203 ]
19204 },
19205 {
@@ -19210,7 +19216,8 @@
19216 "ru": "Удалить пользователя",
19217 "zh-chs": "刪除用戶",
19218 "xloc": [
19213 - "default.handlebars->27->1476"
19219 + "default.handlebars->27->1475",
19220 + "default.handlebars->27->1478"
19221 ]
19222 },
19223 {
@@ -20603,7 +20610,7 @@
20610 "ru": "Сертификат сервера",
20611 "zh-chs": "服務器證書",
20612 "xloc": [
20606 - "default.handlebars->27->1540"
20613 + "default.handlebars->27->1542"
20614 ]
20615 },
20616 {
@@ -20616,7 +20623,7 @@
20623 "pt": "Banco de Dados do Servidor",
20624 "zh-chs": "服務器數據庫",
20625 "xloc": [
20619 - "default.handlebars->27->1541"
20626 + "default.handlebars->27->1543"
20627 ]
20628 },
20629 {
@@ -20723,7 +20730,7 @@
20730 "ru": "Состояние сервера",
20731 "zh-chs": "服務器狀態",
20732 "xloc": [
20726 - "default.handlebars->27->1491"
20733 + "default.handlebars->27->1493"
20734 ]
20735 },
20736 {
@@ -20757,7 +20764,7 @@
20764 "ru": "Трассировка сервера",
20765 "zh-chs": "服務器跟踪",
20766 "xloc": [
20760 - "default.handlebars->27->1551"
20767 + "default.handlebars->27->1553"
20768 ]
20769 },
20770 {
@@ -20893,7 +20900,7 @@
20900 "ru": "ServerStats.csv",
20901 "zh-chs": "ServerStats.csv",
20902 "xloc": [
20896 - "default.handlebars->27->1532"
20903 + "default.handlebars->27->1534"
20904 ]
20905 },
20906 {
@@ -22869,7 +22876,7 @@
22876 "ru": "На данный момент уведомлений нет",
22877 "zh-chs": "目前沒有任何通知",
22878 "xloc": [
22872 - "default.handlebars->27->1484"
22879 + "default.handlebars->27->1486"
22880 ]
22881 },
22882 {
@@ -23995,7 +24002,7 @@
24002 "default-mobile.handlebars->9->174",
24003 "default-mobile.handlebars->9->175",
24004 "default.handlebars->27->13",
23998 - "default.handlebars->27->1475",
24005 + "default.handlebars->27->1477",
24006 "default.handlebars->27->364",
24007 "default.handlebars->27->41",
24008 "default.handlebars->27->42",
@@ -24037,7 +24044,7 @@
24044 "ru": "Неизвестное действие",
24045 "zh-chs": "未知動作",
24046 "xloc": [
24040 - "default.handlebars->27->1497"
24047 + "default.handlebars->27->1499"
24048 ]
24049 },
24050 {
@@ -24069,7 +24076,7 @@
24076 "xloc": [
24077 "default.handlebars->27->1376",
24078 "default.handlebars->27->1463",
24072 - "default.handlebars->27->1501"
24079 + "default.handlebars->27->1503"
24080 ]
24081 },
24082 {
@@ -24086,7 +24093,7 @@
24093 "ru": "Неизвестная группа",
24094 "zh-chs": "未知群組",
24095 "xloc": [
24089 - "default.handlebars->27->1493"
24096 + "default.handlebars->27->1495"
24097 ]
24098 },
24099 {
@@ -24196,7 +24203,7 @@
24203 "ru": "Актуально",
24204 "zh-chs": "最新",
24205 "xloc": [
24199 - "default.handlebars->27->1556"
24206 + "default.handlebars->27->1558"
24207 ]
24208 },
24209 {
@@ -24436,8 +24443,8 @@
24443 "ru": "Использовано",
24444 "zh-chs": "用過的",
24445 "xloc": [
24439 - "default.handlebars->27->1487",
24440 - "default.handlebars->27->1489"
24446 + "default.handlebars->27->1489",
24447 + "default.handlebars->27->1491"
24448 ]
24449 },
24450 {
@@ -24511,7 +24518,7 @@
24518 "ru": "Учетные записи пользователей",
24519 "zh-chs": "用戶帳號",
24520 "xloc": [
24514 - "default.handlebars->27->1506"
24521 + "default.handlebars->27->1508"
24522 ]
24523 },
24524 {
@@ -24565,7 +24572,7 @@
24572 "xloc": [
24573 "default.handlebars->27->1147",
24574 "default.handlebars->27->1354",
24568 - "default.handlebars->27->1478"
24575 + "default.handlebars->27->1480"
24576 ]
24577 },
24578 {
@@ -24703,7 +24710,7 @@
24710 "ru": "Сессии пользователя",
24711 "zh-chs": "用戶會話",
24712 "xloc": [
24706 - "default.handlebars->27->1523"
24713 + "default.handlebars->27->1525"
24714 ]
24715 },
24716 {
@@ -24858,7 +24865,7 @@
24865 "xloc": [
24866 "default.handlebars->27->1353",
24867 "default.handlebars->27->1364",
24861 - "default.handlebars->27->1522",
24868 + "default.handlebars->27->1524",
24869 "default.handlebars->container->topbar->1->1->UsersSubMenuSpan->UsersSubMenu->1->0->UsersGeneral"
24870 ]
24871 },
@@ -24876,7 +24883,7 @@
24883 "ru": "Сессии пользователей",
24884 "zh-chs": "用戶會話",
24885 "xloc": [
24879 - "default.handlebars->27->1510"
24886 + "default.handlebars->27->1512"
24887 ]
24888 },
24889 {
@@ -25270,8 +25277,8 @@
25277 "ru": "Веб-сервер",
25278 "zh-chs": "網絡服務器",
25279 "xloc": [
25273 - "default.handlebars->27->1543",
25274 - "default.handlebars->27->1544"
25280 + "default.handlebars->27->1545",
25281 + "default.handlebars->27->1546"
25282 ]
25283 },
25284 {
@@ -25288,7 +25295,7 @@
25295 "ru": "Запросы веб-сервера",
25296 "zh-chs": "Web服務器請求",
25297 "xloc": [
25291 - "default.handlebars->27->1545"
25298 + "default.handlebars->27->1547"
25299 ]
25300 },
25301 {
@@ -25305,7 +25312,7 @@
25312 "ru": "Ретранслятор Web Socket",
25313 "zh-chs": "Web套接字中繼",
25314 "xloc": [
25308 - "default.handlebars->27->1546"
25315 + "default.handlebars->27->1548"
25316 ]
25317 },
25318 {
@@ -26142,7 +26149,7 @@
26149 "ru": "\\\\'",
26150 "zh-chs": "\\\\'",
26151 "xloc": [
26145 - "default.handlebars->27->1554"
26152 + "default.handlebars->27->1556"
26153 ]
26154 },
26155 {
@@ -26381,7 +26388,7 @@
26388 "ru": "свободно",
26389 "zh-chs": "自由",
26390 "xloc": [
26384 - "default.handlebars->27->1518"
26391 + "default.handlebars->27->1520"
26392 ]
26393 },
26394 {
@@ -26675,7 +26682,7 @@
26682 "ru": "servertrace.csv",
26683 "zh-chs": "servertrace.csv",
26684 "xloc": [
26678 - "default.handlebars->27->1553"
26685 + "default.handlebars->27->1555"
26686 ]
26687 },
26688 {
@@ -26725,7 +26732,7 @@
26732 "ru": "time, conn.agent, conn.users, conn.usersessions, conn.relaysession, conn.intelamt, mem.external, mem.heapused, mem.heaptotal, mem.rss",
26733 "zh-chs": "時間,conn.agent,conn.users,conn.usersessions,conn.relaysession,conn.intelamt,mem.external,mem.heapused,mem.heaptotal,mem.rss",
26734 "xloc": [
26728 - "default.handlebars->27->1531"
26735 + "default.handlebars->27->1533"
26736 ]
26737 },
26738 {
@@ -26741,7 +26748,7 @@
26748 "ru": "time, source, message",
26749 "zh-chs": "時間,來源,訊息",
26750 "xloc": [
26744 - "default.handlebars->27->1552"
26751 + "default.handlebars->27->1554"
26752 ]
26753 },
26754 {
@@ -26771,7 +26778,7 @@
26778 "ru": "всего",
26779 "zh-chs": "總",
26780 "xloc": [
26774 - "default.handlebars->27->1519"
26781 + "default.handlebars->27->1521"
26782 ]
26783 },
26784 {
views/default.handlebars
+45 -9
@@ -2419,6 +2419,7 @@
2419 node.tags = message.event.node.tags;
2420 node.userloc = message.event.node.userloc;
2421 node.rdpport = message.event.node.rdpport;
2422 + if (message.event.node.links != null) { node.links = message.event.node.links; } else { delete node.links; }
2423 if (message.event.node.agent != null) {
2424 if (node.agent == null) node.agent = {};
2425 if (message.event.node.agent.ver != null) { node.agent.ver = message.event.node.agent.ver; }
@@ -8433,10 +8434,10 @@
8434 } else if (userid === 4) {
8435 var y = '', firstMeshId = null;
8436 for (var i in meshes) { y += '<option value=' + encodeURIComponent(meshes[i]._id) + '>' + EscapeHtml(meshes[i].name) + '</option>'; if (firstMeshId == null) { firstMeshId = meshes[i]._id; } }
8436 - x += addHtmlValue("Device Group", '<div style=width:230px;margin:0;padding:0><select onchange=p20changeMeshAddMeshUserDialog() id=dp2meshid style=width:100%>' + y + '</select></div>');
8437 + x += addHtmlValue("Device Group", '<div style=width:230px;margin:0;padding:0><select onchange=p20changeMeshAddMeshUserDialog(4) id=dp2meshid style=width:100%>' + y + '</select></div>');
8438 y = '';
8439 for (var i in nodes) { if (nodes[i].meshid == firstMeshId) { y += '<option value=' + encodeURIComponent(nodes[i]._id) + '>' + EscapeHtml(nodes[i].name) + '</option>'; } }
8439 - x += addHtmlValue("Device", '<div style=width:230px;margin:0;padding:0><select onchange=p20validateAddMeshUserDialog() id=dp2nodeid style=width:100%>' + y + '</select></div>');
8440 + x += addHtmlValue("Device", '<div style=width:230px;margin:0;padding:0><select onchange=p20validateAddMeshUserDialog(4) id=dp2nodeid style=width:100%>' + y + '</select></div>');
8441 } else {
8442 userid = decodeURIComponent(userid);
8443 var uname = userid.split('/')[2];
@@ -8513,7 +8514,7 @@
8514 if (meshrights & 32768) { Q('p20uninstall').checked = true; }
8515 }
8516 }
8516 - p20validateAddMeshUserDialog();
8517 + p20validateAddMeshUserDialog(userid);
8518 return false;
8519 }
8520
@@ -8521,6 +8522,7 @@
8522 var y = '', meshid = decodeURIComponent(Q('dp2meshid').value);
8523 for (var i in nodes) { if (nodes[i].meshid == meshid) { y += '<option value=' + encodeURIComponent(nodes[i]._id) + '>' + EscapeHtml(nodes[i].name) + '</option>'; } }
8524 QH('dp2nodeid', y);
8525 + p20validateAddMeshUserDialog(4);
8526 }
8527
8528 function p20setname(name) {
@@ -8533,14 +8535,36 @@
8535 return false;
8536 }
8537
8536 - function p20validateAddMeshUserDialog() {
8538 + function p20validateAddMeshUserDialog(updateId) {
8539 + var ok = true;
8540 +
8541 + if (updateId === 4) {
8542 + // Update user device rights
8543 + var devrights = 0, nodeid = decodeURIComponent(Q('dp2nodeid').value);
8544 + if ((nodeid != '') && (currentUser.links != null) && (currentUser.links[nodeid] != null)) { devrights = currentUser.links[nodeid].rights; }
8545 + Q('p20remotecontrol').checked = ((devrights & 8) != 0);
8546 + Q('p20meshagentconsole').checked = ((devrights & 16) != 0);
8547 + Q('p20meshserverfiles').checked = ((devrights & 32) != 0);
8548 + Q('p20wakedevices').checked = ((devrights & 64) != 0);
8549 + Q('p20editnotes').checked = ((devrights & 128) != 0);
8550 + Q('p20remoteview').checked = ((devrights & 256) != 0);
8551 + Q('p20noterminal').checked = ((devrights & 512) != 0);
8552 + Q('p20nofiles').checked = ((devrights & 1024) != 0);
8553 + Q('p20noamt').checked = ((devrights & 2048) != 0);
8554 + Q('p20remotelimitedinput').checked = ((devrights & 4096) != 0);
8555 + Q('p20limitevents').checked = ((devrights & 8192) != 0);
8556 + Q('p20chatnotify').checked = ((devrights & 16384) != 0);
8557 + Q('p20uninstall').checked = ((devrights & 32768) != 0);
8558 + Q('p20nodesktop').checked = ((devrights & 65536) != 0);
8559 + ok = (nodeid != '');
8560 + }
8561 +
8562 var meshrights = null;
8563 if ((xxdialogTag === 1) || (xxdialogTag === 3)) {
8564 meshrights = GetMeshRights(decodeURIComponent(Q('dp2groupid').value));
8565 } else {
8566 meshrights = GetMeshRights(currentMesh);
8567 }
8543 - var ok = true;
8568 if (Q('dp20username')) {
8569 var xusers = Q('dp20username').value.split(',');
8570 for (var i in xusers) {
@@ -8569,14 +8593,15 @@
8593 }
8594 QE('idx_dlgOkButton', ok);
8595
8596 + var nc;
8597 if (Q('p20fulladmin') != null) {
8573 - var nc = !Q('p20fulladmin').checked;
8598 + nc = !Q('p20fulladmin').checked;
8599 QE('p20fulladmin', meshrights == 0xFFFFFFFF);
8600 QE('p20editmesh', nc && (meshrights == 0xFFFFFFFF));
8601 QE('p20manageusers', nc);
8602 QE('p20managecomputers', nc);
8603 } else {
8579 - nc = true;
8604 + nc = (nodeid != '');
8605 }
8606 QE('p20remotecontrol', nc);
8607 QE('p20meshagentconsole', nc);
@@ -10205,13 +10230,13 @@
10230 if (currentUser.links) {
10231 for (var i in currentUser.links) {
10232 if (i.startsWith('node/')) {
10208 - var cr = 0, r = currentUser.links[i].rights, node = getNodeFromId(i), trash = '', rights = "Partial Device Rights";
10233 + var r = currentUser.links[i].rights, node = getNodeFromId(i), trash = '', rights = "Partial Device Rights", cr = GetNodeRights(node);
10234 if (node == null) { continue; }
10235 if ((userinfo.links) && (userinfo.links[i] != null) && (userinfo.links[i].rights != null)) { cr = userinfo.links[i].rights; }
10236 var nodename = node?EscapeHtml(node.name):('<i>' + "Unknown Device" + '</i>');
10237 if (r == 0xFFFFFFFF) rights = "Full Device Rights"; else if (r == 0) rights = "No Rights";
10238 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>'; }
10214 - 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>';
10239 + x += '<tr ' + (((++count % 2) == 0) ? 'style=background-color:#DDD' : '') + '><td><div title=\"' + "Device" + '\" class=si' + node.icon + '></div><div>&nbsp;' + nodename + '<div></div></div></td><td><div style=float:right>' + trash + '</div><div>' + rights + '</div></td></tr>';
10240 }
10241 }
10242 }
@@ -10220,6 +10245,7 @@
10245 }
10246
10247 // Display common device groups
10248 + count = 1;
10249 var deviceGroupCount = 0, newDeviceGroup = false;
10250 for (var i in meshes) { deviceGroupCount++; if ((currentUser.links == null) || (currentUser.links[i] == null)) { newDeviceGroup = true; } }
10251 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>'; }
@@ -10267,6 +10293,16 @@
10293 QH('p30html2', x);
10294 }
10295
10296 + function p30removeNodeFromUser(event, nodeid) {
10297 + if (xxdialogMode) return;
10298 + var node = getNodeFromId(decodeURIComponent(nodeid))
10299 + setDialogMode(2, "Remove User", 3, p30removeNodeFromUserEx, format("Confirm removal of device {0}?", node.name), node);
10300 + }
10301 +
10302 + function p30removeNodeFromUserEx(b, node) {
10303 + meshserver.send({ action: 'adddeviceuser', nodeid: node._id, nodename: node.name, userids: [ currentUser._id ], rights: 0 });
10304 + }
10305 +
10306 function p30RemoveUserGroup(button, ugrpid) {
10307 if (xxdialogMode || (usergroups == null)) return;
10308 var groupid = decodeURIComponent(ugrpid), group = usergroups[groupid];
webserver.js
+2 -1
@@ -203,6 +203,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
203 //function EscapeHtmlBreaks(x) { if (typeof x == "string") return x.replace(/&/g, '&amp;').replace(/>/g, '&gt;').replace(/</g, '&lt;').replace(/"/g, '&quot;').replace(/'/g, '&apos;').replace(/\r/g, '<br />').replace(/\n/g, '').replace(/\t/g, '&nbsp;&nbsp;'); if (typeof x == "boolean") return x; if (typeof x == "number") return x; }
204 // Fetch all users from the database, keep this in memory
205 obj.db.GetAllType('user', function (err, docs) {
206 + obj.common.unEscapeAllLinksFieldName(docs);
207 var domainUserCount = {}, i = 0;
208 for (i in parent.config.domains) { domainUserCount[i] = 0; }
209 for (i in docs) { var u = obj.users[docs[i]._id] = docs[i]; domainUserCount[u.domain]++; }
@@ -1354,7 +1355,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1355 var mesh = obj.meshes[meshid];
1356 if (mesh) {
1357 // Remove user from the mesh
1357 - if (mesh.links[userid] != null) { delete mesh.links[userid]; obj.db.Set(obj.common.escapeLinksFieldName(mesh)); }
1358 + if (mesh.links[userid] != null) { delete mesh.links[userid]; obj.db.Set(mesh); }
1359 // Notify mesh change
1360 var change = 'Removed user ' + user.name + ' from group ' + mesh.name;
1361 obj.parent.DispatchEvent(['*', mesh._id, user._id, userid], obj, { etype: 'mesh', userid: user._id, username: user.name, meshid: mesh._id, name: mesh.name, mtype: mesh.mtype, desc: mesh.desc, action: 'meshchange', links: mesh.links, msg: change, domain: domain.id });
x.txt new
+339
@@ -0,0 +1,339 @@
1 +[ { _id: 'user//544849534953415445535453494431',
2 + type: 'user',
3 + name: 'LDAP User1',
4 + creation: 1555361291,
5 + login: 1555365153,
6 + domain: '',
7 + links: { 'mesh//2odhtyJSNw0$wApTgsGPZoF1h5XovNbN9KbetvIzMkAhXsPyFXFfW@Dnwp6BMhis': [Object] },
8 + siteadmin: 0,
9 + email: 'aa@bb.com' },
10 + { _id: 'user//a@a.com',
11 + creation: 1562625646,
12 + domain: '',
13 + email: 'a@a.com',
14 + emailVerified: true,
15 + hash: 'm9/LFPJ2HI/bXQdjBC1jGUF6ymLv3Zc0TClv34pEimRpWWtaslTu40qUXcBDRW4ImT8PCc+EMMsMen5VKfyDlk9hMIsERKVn06EMtT4XJZwqXStk2Pyx5qZy/wmE99bKsGOuXRaq3FXecEf+LK+fxfY4wEnCSQuKfSQll10cKcA=',
16 + name: 'a@a.com',
17 + passchange: 1562625646,
18 + salt: 'OOfnPUaVYtJ7vYGGitFpyMySKdJq8AVspq87B1JoKfrGnMcEGtXlrs7OXbpLDOeYrOcaWQcgjSjNlYLBR4pYTFn71aC2GqDrAUSETPQlBtsxxxT+FA0VJic+q8Fds7Ef1ku+1A//UsK3/smqVEC8qNCzw8CI6OkNLBSU/bMDsZY=',
19 + type: 'user',
20 + login: 1562625674 },
21 + { type: 'user',
22 + _id: 'user//aa',
23 + name: 'aa',
24 + creation: 1585276083,
25 + domain: '',
26 + email: 'aa@aa.com',
27 + passchange: 1585276083,
28 + salt: 'AU9ir/d/tuEgGPn3noRhdsjF3BCAKpVHrG0nEE0/U6x0Sqa+Z9Mf4yRHhn1XYw0tRyX3TVDAD6iNmDGHgxukXRuCfPgog1YIkU+8xKrxy0MF97gkJA+4s9zWpXBUbrTCyo4UQkV2fpQ4SkyTi84cU7lP46nNUIu4kJoUiTHlZLw=',
29 + hash: 'V95ikU9NKh8jLxQJzc3qv1gOM4yK/cOasalrdTsoW2RUvrrWlt81UAy1NKrRFZx9zknYI1HbFtPuyZZyfFsDKtM7JuB4YL5nJeqqpFrPaqMsNw3GZ8tn2au+X4JxHlYeRF1Rrx90lbi7hrxfHHecBSU10reXiEMTLYg8uxpZILY=',
30 + links:
31 + { 'mesh//7b4b43cdad850135f36ab31124b52e47c167fba055ce800267a4dc89fe0e581c': [Object],
32 + 'ugrp//BXQUCOnHMBI14nGBhfTkvMlmb2K3FcP09Bu@3jpffr3nn@hxsm5RlpNLWheqQqYJ': [Object],
33 + 'ugrp//mKkqX0gLZ30jhPOs4cYdeCi5E@1P3OpypcAj1CKK14n04upXON36@5VE9BIez9h3': [Object],
34 + 'node//8wGlXgB8y@@Pe24vbVYUMoOxE2Si9eupK0gJ8wJW6GQCabaTYFmlHMjCyO3p0VEv': [Object] } },
35 + { _id: 'user//admin',
36 + type: 'user',
37 + name: 'admin',
38 + domain: '',
39 + creation: 1417814230,
40 + salt: '5cTXOdvnH0G5ThP0A2clL8+1zmdhhONqEo2t6cYBtLp27eRKCx6eEnONculOtTRd+bCO5795A2aDvWlFLhnxutNONmEc8aTDju+CiAq5f6gCzuZnIY3CA9Oc9fqOM4AZ8l7Bg/IT/7MKYMB0djeBTvJkJ1wkAAUh3nCRbfo2PC8=',
41 + hash: 'Pg7Hb/nA0S3HsacfuGbgRpxHsFchrMy1/XntdCwmqcwh/MvFecqggzZcDEmxhQ+mwjH2rnm+X2nbTxI9vDKgLndAjIDxY5eWN58lfRobniBV3I8zMmC/oQHf4YEPVTHMBxwU/s8MjbR38YjIICJdtkEAXHr4+NoAj8tsVIbQzWg=',
42 + siteadmin: 4294967295,
43 + links:
44 + { 'mesh//1bc82505ef750af28b19292eaf2260eae83bc2939a367f1a885efe865b729193': [Object],
45 + 'mesh//7b4b43cdad850135f36ab31124b52e47c167fba055ce800267a4dc89fe0e581c': [Object],
46 + 'mesh//93c713c5cda428bb06777a7e7cd8075527f8a2f305945ac241852b37b1f30739': [Object],
47 + 'mesh//acf0460d17df45ff977d2ceb3fcc84ced94a68bc67ef513bbdb1fc59a591bd5d': [Object],
48 + 'mesh//sjN2rO85LGJCEXxW50TUI1vOCr@9zVpE4A@9jrAcPjA7n531RHZVMGpksK1yWY4O': [Object],
49 + 'mesh//5LNNn8cM9vKaUFs91inT2SNpTXgp0mlmI6Q29kCFEmoypqxYDfjY5N7Ae3QxwIVO': [Object],
50 + 'ugrp//BXQUCOnHMBI14nGBhfTkvMlmb2K3FcP09Bu@3jpffr3nn@hxsm5RlpNLWheqQqYJ': [Object] },
51 + login: 1584903356,
52 + email: 'ysainthilaire@hotmail.com',
53 + emailVerified: true,
54 + passchange: 1584914891,
55 + pastlogin: 1584903334 },
56 + { type: 'user',
57 + _id: 'user//bb',
58 + name: 'bb',
59 + creation: 1584487582,
60 + domain: '',
61 + email: 'bb@bb.com',
62 + passchange: 1584487582,
63 + salt: 'mccoD17PKETFJ26DUPBpaMdBxQ64WpYgEnUFcHkkFY8E6+J3q74i6Eaj/DrAOwBlXcS0hzbjb1XbCTugoOrUQb2zB32H0Fv5VJjoRUwSu3kO7gYlRTX6V6Gw8vLgcZ6PcSAelL7+Km6Zd1pAx/aiG4iZ816q6L2R7rsg2p7n82A=',
64 + hash: 'CEBlvxFURwI9rGX6n5ucBi+Ukec2waPe++2khiLR1il7SXcUd+XnLVcY34w2t2rFrP0i8RCoC/tLgACko1h/SfIgFf4DWtnQSZ0x4U7YDm9o7go7yhmmbUMaNm+tGNGDTVDeVFBvoiTleE949sIJuOZ6iYHYVdW6VwkUTmy5/Hg=' },
65 + { _id: 'user//bob',
66 + type: 'user',
67 + name: 'bob',
68 + creation: 1523394756,
69 + domain: '',
70 + email: 'bob@bob.com',
71 + salt: '53GmyHZq0DyCEqX8ndsU8gnv/2QfmRb3F/a03Rorl+X/wH7mG5GvvYtXL4aS+NWsr43Mm4jFx38qTmQi961ufGy8RWEKjo3FsAPFq3fnYJvBpmWCDPz8svPe5UtU6yGi8SPUWQD3d5fb4FZ4Qub49agVG52lMAoI7+XPee1aodw=',
72 + hash: 'CtvD7IX3ytdJXmlbYEMRhSq0GuHVmis/a6qKGeJpb6MDvcB1MOPVuR3KMguPHxC2VQci0nkYosft/0V4RFxB1Y0OBCEo480Lprpce/TbJ1OvbUGxTpt0EJ3W8GFDrHW2MEyJlG0DTqrz5fM4cNS4zgYoM6XltEN4YYOcDvoeYFc=',
73 + login: 1578349086,
74 + links: { 'ugrp//BXQUCOnHMBI14nGBhfTkvMlmb2K3FcP09Bu@3jpffr3nn@hxsm5RlpNLWheqQqYJ': [Object] },
75 + siteadmin: 0,
76 + pastlogin: 1578349086 },
77 + { _id: 'user//bryan',
78 + type: 'user',
79 + name: 'Bryan',
80 + domain: '',
81 + creation: 1373413118,
82 + passtype: 1,
83 + salt: 'GoMdgNplNW5Tq1LI38Fi0Q==',
84 + hash: 'HSelSEKY8BJWdAV6D0PD4Gwiazg=',
85 + links: { 'mesh//542dea438e6065bffa9318c149e9982440dba4ce6ba3ba2b577e0e127b6a7f24': [Object] },
86 + siteadmin: 0,
87 + login: null,
88 + groups: [ 'test' ] },
89 + { type: 'user',
90 + _id: 'user//cc',
91 + name: 'cc',
92 + email: 'cc@cc.com',
93 + creation: 1580415619,
94 + login: 1580415619,
95 + domain: '',
96 + salt: 'JKaqzhk6DQDmhPejyA8F60DZ/XuCAY6nHX+jDvIwHVuYOrZU45uYf1R1VJI0UXKGpt/uin3xfdWw/dtfhDyJETKlOb3xdHg52UVJnpkUBrxlumgI/KitDqhmZ7skoKwJmJ8lRn7aN8+j1DJlbhBN9OuhyU8gttzrzbMWhStOHRo=',
97 + hash: '6JpuKMQHg8FwS5PDA7yVqh2/NOlStVc7TGjLkP3ZO2ZqO4jFU8780UgdtEEGaRw8fHiby6gLqxLQZhzGb1cF5ormiH2HSI+n6TDET0GuTYYHnYNrSWXG+EZOEn/sOybqL1I7hXKUeI2bnewUtxRcml9oOifgDVuBbNRDoPrl7I8=',
98 + links: { 'mesh//qbu74CK7bX8AYu9gqZNGSad1poraKWlyay0yCLrx8jPZ@d6$ZQX0XcwMThPWqqRQ': [Object] } },
99 + { _id: 'user//dd',
100 + type: 'user',
101 + name: 'dd',
102 + email: 'dd@dd.com',
103 + creation: 1551389245,
104 + login: 1551389245,
105 + domain: '',
106 + passhint: '',
107 + salt: 'HiFDC9cDOxGKHIohkudzflVT8kNMD8Uy60Qt6/LIahJuBCIxcH3rPIqu/kEdo/+YyrMuHs83mudkvLHrsgCJXz4khqbI4owsJrAJ5UGuGaLbh08coGgzpMDjoDlSoxL3nF09+/ZsL3kPIn3jVxKQeepBgN+Vd5paOOGEy0n3z8o=',
108 + hash: '/ak7hzgp4zbPEjYTe7bvOtamDNsccm/oV1wdZ7DUc4M7AVpXSIiKKNfBCLXgfi5T4FcHs75VEvnCwYeZCbKAFYeN/d4TYOdnPM6fWgAGk//MCScdawbJrnB9fiVXOA6GYU/SyXbHxX2TaRprjKfhk+Zc0vPCauDpg3xzTzISMXo=' },
109 + { _id: 'user//demo',
110 + type: 'user',
111 + name: 'demo',
112 + domain: '',
113 + creation: 1428090949,
114 + salt: 'sGIIlqmi5YN8+BEBOYI2Ub+TGV0nAcE7UdM7itv80HGriQKtAeajer18WdJIsfEvXwEMjqftvEmNE1QLafb7edZ4LVTSe90+mluRxQ6na+GauoXIazTHCola+Ke3ySpedWuHvnKPrwQEWtTFDAp6UjppfwFtd8W6yAPyzYJwpfM=',
115 + hash: '0YfvLDm9NIMOHcbK9lQon+dH70vlQRnTW+b1BdQCBIcx4HyM6NpPeEs+nU6wqDk6nXwBp50OpBNmPLlCslpZAFg6R4sQzIJEcirb8GZnRaABDus8kq3Gq23DWp45j/uwQMAA6Z4orqXmr0OHEMB9Cr+p2jg+c01QTM2FU+TUvBc=',
116 + links: {},
117 + login: 1513299316,
118 + siteadmin: 0 },
119 + { _id: 'user//devbox\\default',
120 + type: 'user',
121 + name: 'DEVBOX\\Default',
122 + domain: '',
123 + sid: 'S-1-5-21-3031010259-3226202738-568380285-1001',
124 + creation: 1548377831,
125 + login: 1548377831 },
126 + { _id: 'user//eee',
127 + creation: 1561833844,
128 + domain: '',
129 + email: 'eee@eee.com',
130 + hash: 'ya2sbB16v1yiYcA/zS8glcrFZoB1uPpzu8kx5G0iELB87KDzMYr1M9WgecvYyhpYL27Qu+G1lM6w+cX1iHigUSB9stZRlBNy4r6go3IiZQqxIPQOwn5eWswgKqRXglAXfCp52b9WwcFLU31KklUZOadkSdGKk4b23ERhd8lMRkI=',
131 + name: 'eee',
132 + passchange: -1,
133 + salt: 'ispJqptip9UX3yaSL7911MCAf577tXC4BF3h2PPGYIQPY4qw4QCMUwPvpo1bnKQUgKBuHVnZRtuyC/1dk87aEnmOgyoZVIhb4KSV8lzTDS1JkgT29ukxwngqbEaDnkzbc9vxQVboWTqveK+FMHqy6qzIVHOirqgfjv6PF26wWeE=',
134 + type: 'user' },
135 + { _id: 'user//joe',
136 + type: 'user',
137 + name: 'joe',
138 + email: 'joe@intel.com',
139 + creation: 1551138573,
140 + login: 1551138573,
141 + domain: '',
142 + passhint: '',
143 + salt: 'z8lIYIkrHboKGo62rF5cyCfvHCrT2IQYpU6uufW5lMO0GWte+p8q9FEHct+xItY96azQmti8Cy/mczr5j53WPRtxnMtnf7DxI65GLJYrGqoQJ/InyNSYd0O4/r2tZlwn5hK8+/E8hi1MxuFBAGlC4guKAoS+W2x996POjgbqsu8=',
144 + hash: 'q0UZypM0R2sk+VKDSXR7ouCMR/EYnaESJtNApE7ZxhHAjhDCxQQdnmTrSTvhPtp2seM9IOCK9YFjMR52sNxBfqtD1F+E4GcyaCxTC6NntEIMizVz1kw+hPmweo6u7Lu1EliDymHtrkmFvpqhfIb9b7ISpb7wL6LPsn7sfN1/R1o=',
145 + groups: [ 'test' ] },
146 + { _id: 'user//joe.bob',
147 + type: 'user',
148 + name: 'joe.bob',
149 + email: 'bob@bob.com',
150 + creation: 1531530565,
151 + login: 1531534497,
152 + domain: '',
153 + passhint: 'bob',
154 + salt: '6P9m1LSHS+S1L7+HJO23pDBHn6eiZmAKXVckawjGNFPz8Py0zu6jDCcbP89lgnqLN8KjyWc7NO4dOPyL26QEkKOA2PghljDwjaWaCnX1EYkYDiJV3b4muHrQ0hVsdbYP/52gtRZAE5f0qM3xZjxfHz2dVyrRCFb+iNvCB/OiikQ=',
155 + hash: 'yMsV9ATYiOcVOAjaH8Gxc6+jM28JwxsK0+GaA6b6Y8kL871sENd8/5nqi0QWYRKKahkpFe+xAaTdze/+/7vXt3Ly/WJsU7q8asZgORxqxWU0wsekFP2tnAjdiC/Grhj5euAXqft84p5aQHQt2PE/CoT+FOIVvUiM5gD/Iq1ev1M=',
156 + links:
157 + { 'mesh//1fHXfQIiCOOOFw8lkIlUnXSQ3A75kFrKw2PvGQFkaAsGCM7mz@3$Mrr5NbPNTmxy': [Object],
158 + 'mesh//PleIaEpGvRNLCx6rLcsKOogtaKfEDI7Tm2YSPGUurBLqNzRgLPd4ZurifZonL$7X': [Object],
159 + 'mesh//8kWnSpFr$cIj2YvibBdMkBxBlcuNZp0yBZQSoWV12DTZV2f@34wJi5CIPMSUoOou': [Object],
160 + 'mesh//CWsMAU4u63zNLLvdmoZP8uPcg$lzLnVcC25buVmqI05r1Wxk3ngk1OEgyHoFg7Oa': [Object],
161 + 'mesh//Gt0Eo1GNpJmQ1WRwvKeIhibHBQ2j@XOV@omqmvsf8ZY6k3oKswvDdjzPn1KA4IQf': [Object],
162 + 'mesh//GXbvFkWNsVKJCBbTvhBHCgFAY5fayzcStTJeZ5TdDfLC0sDL5TDs1ALFm8hMFoQ9': [Object],
163 + 'mesh//7z0GW8pppHVGDw@Rz$fb1E29GnA9yExEKASjAf$r$hyBMP0$BSH$rVqWKCwxQ7D6': [Object],
164 + 'mesh//7b4b43cdad850135f36ab31124b52e47c167fba055ce800267a4dc89fe0e581c': [Object] } },
165 + { _id: 'user//mytestuser',
166 + type: 'user',
167 + name: 'MyTestUser',
168 + email: 'a@a.com',
169 + creation: 1541494376,
170 + login: 1541494376,
171 + domain: '',
172 + passhint: 'a',
173 + salt: '3bURHy0OVDLNGJrEyQGs2UBhktEoJao9p4dIPS+uZwWdzPCcCZr4r7/dWlsjFGyKqCoWoStR6XzIFGElAAW5eUq2dM7lG9GXvrp59TzizKwTUAJWyCTfCmoP2jbTBjFLr5umBNsapiBY1HXXJxoRpJJJDGCt0ysETgIYjJfWUN8=',
174 + hash: 'VzMdJ9paS12tH3KM3yUsVJXYt6tB/LJ8jX3665otE4AmQgaxBOXiEVr5Ff8oYd6MPonr6D93ACUems0R0NiX4EjGcOveT1zNijjaVYxFRu2PzkKayxqeupZQvniz6HdrtptEa96GpWXqXJ0dzsVbMcpfEKz1Tjk5cFku3swfZYw=' },
175 + { _id: 'user//null',
176 + type: 'user',
177 + name: 'Test User',
178 + creation: 1555017483,
179 + login: 1555017682,
180 + domain: '',
181 + links: { 'mesh//k0nAuG45xS5TSYR3s1kT1XGUonCM48sGbuf6D8dDlYFSbbHcxqGk2daZrVC4D@dg': [Object] } },
182 + { _id: 'user//ppp',
183 + type: 'user',
184 + name: 'ppp',
185 + creation: 1557712716,
186 + domain: '',
187 + siteadmin: 192,
188 + email: 'ppp@ppp.com',
189 + passchange: 1557712716,
190 + salt: 'M83AO69eUNCOUlHAoMMf9PoYits3d2+G5ml76VxS8Fve46TOwCK5pwHhCur3iKNDDOOz0/OrzrF1axyiB2kzQUQvs1DZgZlO+1F9DpTI7avibLYljRlrs1KBm7Bb910VYjQNNvKKLI+h7ls45s1wUFgWF2EngpECv9tq05UoX4M=',
191 + hash: 'RDR75KY2bypDWxJEgYznG+HjyCPR3GSJVI4bGtAu4C8XMvnB+4+2g47TKVb8nM9MpWj4/M4XWQ87VhJIMXoCQ5qg6SeWdIXL3ab1UpXSzn7fAeFspqrQ8A9ZcnfN+OARL2gLL8qSchonebVfL3BdDqTgc64pn1MhctQUvylsRYE=' },
192 + { _id: 'user//qqq',
193 + type: 'user',
194 + name: 'qqq',
195 + email: 'qqq@qqq.com',
196 + creation: 1549852967,
197 + login: 1549853132,
198 + domain: '',
199 + passhint: 'allq',
200 + salt: '+pzWoML4DMmYZ3y9DFMEwkJz/sal3qDKHKnhmVu352zzZPzXC+mL/hbmHOSi1Quw65tMMLtcjXn5cquMFToX1DlsURnuDbxaINuzZ9pec6dxIn26EJ8urZ00bVXTSusv2xhcJuYKEabC/gKWpe6E0VR8xctEUjjqAgP1BCOAifo=',
201 + hash: 'n7gXwzoFS9UkTHQbbuuabGjCJmRadzWENmkjwMBnNrhQwG2qLeD5f/A1EPKIwr2P39J0cClFHPt25kX0PtItEyJO5wcnVrbESfc3Jsm6nG+Kze0ayW3Na+iEmnwWMDZYNgFe3k95ubOXzKl/CCUjuW4RAEwj5f631XoTS6ygW1Y=',
202 + siteadmin: 32 },
203 + { _id: 'user//robert',
204 + type: 'user',
205 + name: 'Robert',
206 + email: 'robert@bob.com',
207 + creation: 1543864529,
208 + login: 1543864529,
209 + domain: '',
210 + passhint: 'robert',
211 + salt: '/brZFf8ljdG2eZAFgBl3CaMnY5FGYPB93S3Y97wym/kUAVkF5NHlDVVNfmghC97VzZuHnlIoFlt4IUHbZHSc4/KAOc4pX/ZcyicsacMXyW+4CtDgSllnXeejK0nkVV/AdJSwKMQZ3K5+77TvydXbwLFuGoZ0NVOzCto/CgaWtsQ=',
212 + hash: 'X7OlXcp514ay/HXV2qDsAQVerr2jWGdCUAVnl6FVsvw4XN+jgBsq8E7f0RnuAZp/BFIlqkLaj8TqYtpFPR87LCJdcg8LZ3Y7ygyiZp0rdpztyxBAJ3YyiFRrSvJB/u4JM0GJ88WPCRK6CbHwBlhg4i+VRSMPetn1XiemubK1Qv8=',
213 + links: {} },
214 + { _id: 'user//rrr',
215 + creation: 1561919781,
216 + domain: '',
217 + email: 'rrr@rrrt.com',
218 + hash: 'o85W/QlWhRXHrIeyw+L2TXWnW5MDr+Dc+66MeH58iCxKIh/aMuLdOD9on3ViNbW9Wqt4f7wKxjletFVhJYwmd/3VvPLBxdvZ4r3c4El9I49vGavCngqlaHc69ohh30KVEXUYy3zzxyOFn7HukSSkCMmnsq/IKIpA6ZVR95GNQ54=',
219 + name: 'rrr',
220 + passchange: 1561919781,
221 + salt: '1crF6xIQlbO2GYPRPksF7HUu1ytB9zJrDl6zd09OYFdDEQRuK+DhCLPJq5CTJU5Tg7GjVmIq/rXqGKQFlvTZ2/cLmELwN9l9UQeBsiyb7lxSusU3SRTCbYAZV4aPy97xHw+F1JlLtEaXSJ0TM1WwcBECW/qJ4ZeIDpQfNUw6HAY=',
222 + type: 'user' },
223 + { _id: 'user//sampleuser',
224 + creation: 1562012207,
225 + domain: '',
226 + hash: 'clVpJBetcpCd20KcvCJ4K1cCdodNIHSZW11tR/PzKnZDek0XjLCINucUK1wbXbsmqvE36AXPFDy0URSmJB3ohjkP02TDl3mDUGg+tmM+0Gh9CGTzImRG0xnPLoUtBo5QpRBItLUEz2wzzHn3Pds4fecAUSZUGH2K+icFBWG/2BU=',
227 + name: 'SampleUser',
228 + passchange: 1562012207,
229 + salt: 'XQ9F2M9E2kumUFxqxFv48UxDyhHQroBS46ud7e1iaDH1cGZ+V78YQ3fo58NjTn0XkiJmS1usxlu+qXQEbGSM5e8EAS3qK9rXdZ78CMm7+NEz8AoxkzpmAeICuIXikOP488eseXJYItZzbr3jOMjvKra+nw1kpeVRbW3R0XHVVtc=',
230 + type: 'user' },
231 + { _id: 'user//test',
232 + creation: 1562534252,
233 + domain: '',
234 + email: 'test@test.com',
235 + hash: 'FYtXnIWEW7fIrZSNwGx/Rl5Blsvqpl1LGs8exXWYrNJc3X6UzS7+qziti+i5M1m4yjiQLp5JzGuJkfdVDexua6y5Ixh15dEsoLSndE0QOSa+7Yo01FEy5LGuwGd6Rbs1yRsH4P4pGyMZhj5DsaYGLeNKiXgcMqjTKAhF0VGXxVs=',
236 + login: 1562534252,
237 + name: 'test',
238 + salt: 'Kj1I+Xf9Bh+3uMNpH/LNzmonk/+kOjaW2rRKEFAolqQ1ngELtkqeEipBESGUNvNDblx8kTiNIIFda9e4fdAxZlHuX/AAIiBpw2saS5zYUPtmFnoBom2PTIzurHNYYXBz8vS3VCcTFv3ZbW3tg38jYX8z5h6blNzgwI51GkgDOP4=',
239 + type: 'user' },
240 + { _id: 'user//test.user',
241 + creation: 1558462786,
242 + domain: '',
243 + email: 'test.user@user.com',
244 + hash: 'RVL0gdctx/WMMlrRkflAMURL7UxN4c1jos6/ZzVSAcTXbOozfWJeE5JzCZQFNnze0OTSltq1WQtRk5dJFhum8KhKkUGe/dVvC+u4qPs27RmzNdc3rNLKDLPXKyPqe0008e0pkjPiEYBZAVj9Cy8r4Aew5mrgpx4/fBIhzGz/6bo=',
245 + login: 1558462857,
246 + name: 'test.user',
247 + salt: 'hH8ABQQ0srookeRbjIcl5uDz7tDYZYotaPTgTQVaoPuXNwBdXJanrfPtIfPSuruZTUeEP5/2kWgEakfMO/on09iZgcuLCSvS4nySNZZuZ7VbApgmsqfNAtPOULrHMuZchsBtCvUwiyTAOKyXmUNDD8txnmlfZmyCnqF49nc0DnU=',
248 + siteadmin: 0,
249 + type: 'user',
250 + links: { 'mesh//MAIhngk0XrQaFqDWpvBBrLnGwQWUTKQ6Aa8UMNFVJ9dmtZoAEkZF1DAMKsTHQbXt': [Object] },
251 + otphkeys: [ [Object] ],
252 + otpkeys: { keys: [Object] },
253 + passchange: 1558473367 },
254 + { _id: 'user//testuser',
255 + type: 'user',
256 + name: 'TestUser',
257 + creation: 1523658499,
258 + domain: '',
259 + email: 'testuser@meshcentral.com',
260 + salt: 'KsM9DOWsz3Ub8Q1m5ex/Ge7XP6fBJ+MMA8LqjXmSRhLE0HWfv4uWAarWjZYYYM4/kWKZZSjkQWMMzCeZul3krBTogZRqMUar+VgKgZbjW0vX6NvMFn32Y2m+K/YSyl0XQoN09nmU5EN/RA95bkTz3RK/pXsOYVNdCcojs1uISj0=',
261 + hash: 'uMO6etn7jwT1BBFqIY+DSqozcMIlpIAu9d4ruhxNmu/5smo/8M7Pvwa42tCza0bNsBNybPB6xOEYa4z+2W30WQ2dnN1AaHvRltdllxrPjmW0PjuD/4cNG+Z6Lb3v6R6QIUxYpUwo7gC87rM4+KyGiMFUq83VG67T4AcBxtKhzm4=',
262 + siteadmin: 32,
263 + login: null,
264 + links: {} },
265 + { _id: 'user//x1',
266 + type: 'user',
267 + name: 'x1',
268 + creation: 1557869247,
269 + domain: '',
270 + siteadmin: 192,
271 + email: 'x1@x',
272 + passchange: 1557869247,
273 + salt: 'X3E7xiTou1fRcRr+Rf5xBnCd6M7RtKishIjZyu+dm5KayLm6D/CCFkR9zuTyxqzuw4NZlp994jCvegryqBow0Db8sstcs/Vp8A2l4WUGcaNW6Yy9zVomJZE9xHuqRlUUU1J8SIlnrBrpcu3nXp4LRI3UOLroGSLbO9ojzYHnn/g=',
274 + hash: 'sc3wb1cP/R4lngyKmI4rqK1nXM4RCa+ZQmhbF48E6D8GejAynmR1kgTTGAqS22CPcTMdHmsxy+nZh0Pncmv5Z9HbxyGhrgFwkeIUYxrq7AO6A0w1dEIG99Qk/Pa3AZO0w917kUFSS7Dz94ZAouskm/F84lynUqSSolTqgpVCkJE=' },
275 + { _id: 'user//x2',
276 + type: 'user',
277 + name: 'x2',
278 + creation: 1557869247,
279 + domain: '',
280 + siteadmin: 192,
281 + email: 'x2@x',
282 + passchange: -1,
283 + salt: 'DFp2VFHhVfSpaqglMTLNpcsbARAqAx4uVb4j9V6az3tSrArGd7MSwQHpA69Jq91PZtw/dkqci3lkq9u74u7PSAttsA5z9IenGiTNGDBCSv5eDqGVHZdTWfcNw7CJM86shJ9NL1OEJR3owLnZFPir3f4ZeOV+GmuRhBLv5NFvBEA=',
284 + hash: 'bQLaZ36j4QuUJnvtbs84qdfTHWn40sL3Qndv3Pn8GtAUy2zgJdx6LGEhPKOyfizONibD2D2kH9SFqFGUDoZX+tQWwao4HRqY9spp6DtvqZu8rza2JR0Kyx0WbfjRtR6yW5TnvQC+xHd/aaSFmefPK/lxViUrGyzvbBM4e455xts=' },
285 + { type: 'user',
286 + _id: 'user//zz',
287 + name: 'zz',
288 + creation: 1577396990,
289 + domain: '',
290 + email: 'zz@zz.vcom',
291 + passchange: 1577396990,
292 + salt: 'KHt8U1w8t/50xXo+9zk5Hra8ypSIuR7fntQRfyg5dvq8TWohl7NP5fYQX+AEvnrsP9lhbYghBV6c68UgiIdUOje0rZh6XA/oHiHmfUzANALZeNp16Czrhb5k8bAFKI7is4A5Hw1sViA3cOgnNO4GhZqM1vmNgE0YuJPnVL1+y9Q=',
293 + hash: 'Ng6aEiTYGuPXG+BfJ2mt3cSJzM3iZslOo/hoX5w/CdRux3gqFkQTzwyHagJCozWHi0hq2omV+O9hzJlPZUU1Er9n7s9Yn0ssVJbT7un93n33gqaKwf2PivMMHMMKNZb7gtkgFwOIiQOSKHPN/eNs29rTixWPqr6JyMByXygvOZ8=' },
294 + { _id: 'user/customer1/admin',
295 + type: 'user',
296 + name: 'admin',
297 + email: 'admin@admin.com',
298 + creation: 1554414308,
299 + login: 1559319199,
300 + domain: 'customer1',
301 + siteadmin: 4294967295,
302 + salt: 'qqjKAHNRtdwcGlRUmlb67dXL8cjR8kur5Mu5j0i0HPqVkCO/oDpyl/xHFMDRt2U4VRT8v5XaD/GDeqYDpA+h6Wy3cJiENpElQx49WKRFlfgyO6t26wSUXFQd5jDjr/XijnktR5LALXRbwCkozbFoyot4uRneXu44OxrSdDDRHaI=',
303 + hash: '32JbzlVq9ge7o/6Qn4ii/a/oYWJRaXmDi/pVtRjPCZAFiR8bBu3gkY2JrimyMAOvkfwQJkrBNZRrDjB2BjvzWofy6BdCMzkhdnYpJ2kbeL16Nz3qqI3IauXI9E5SbYyG5DCo5ERCA75CGGexLH9vaVl8hT5K0N6sgDS/dAGT7u4=',
304 + links: { 'mesh/customer1/EaSw1hJBKjf1QApmilFSAIo1KhA@R@dgRHIDAUUZBaMBGEYJw9qlhOa7p0xfWZvN': [Object] } },
305 + { _id: 'user/devtest/a',
306 + type: 'user',
307 + name: 'a',
308 + email: 'ylian.saint-hilaire@intel.com',
309 + creation: 1514930104,
310 + login: 1515724646,
311 + domain: 'devtest',
312 + passhint: 'a',
313 + siteadmin: 4294967295,
314 + salt: 'g4aZeKUV0aPjzW8YpALfO7SYcyY03vdJVGNSowLqOlWZrFmnActIo+AvDb7ydC+DpSCWBq5fTHBj4Eol++PXeqyjcbVAKfMoZzGA6gdqNJ+UgabpzcddGm3oYEWcuEbvIzlLXSkZA+2LeXwRM9LbiRwH/dY0TrHVO2pwg8Hc3NU=',
315 + hash: '1+l9Wi2xEmoKNEH1jNkQGfI+F1gSId/SL7qAjxfe/lu5QvoFE4X9d3kajaC2GtWn73ilB5qmThOFqbL3nqut84EgHDmGWlxEJfGFytZwN0JlJSrid9OSKbfvS1E4P6jPWnbOLyiiKMWYktFwX2aNHRJZktrwcx07xpNuK7T5zFw=',
316 + links: { 'mesh/devtest/8CvC1wI7ivS289DcIUcMwXivGD2nKuj5jpUQ0qBd5Xd@R@jGkKSAA24A6UA9YRTe': [Object] },
317 + emailVerified: true },
318 + { _id: 'user/devtest/aa',
319 + type: 'user',
320 + name: 'aa',
321 + email: 'aa@aa.com',
322 + creation: 1552685405,
323 + login: 1552685405,
324 + domain: 'devtest',
325 + salt: '7NX9z7hNOFXcVXGccbcyEs1en/dVf6SskT0wGMW46yR7sMWVPOGiCT9AdlaN6huYSbhCprFCu7YIqw4MYFboyq0bhGGAnovFSIVs+XcEjfIG7I7D00HDsRS7Cf5SO2SU8XEzjIr+RirYqZhEzRUQvnHEPNkJg8JT8GI1I+fYWLM=',
326 + hash: 'wgh86y3OwRe+rcygmIYXuZGtetxoNuFKt2gBVClwxuS7tjYGLQu8Q9Hb4M7NWxCUFLUgq4JHmnvh0AMADGT+7NquDny6alTU5Yz8XUa0+qgiuUUX4LA5kuCoxxaqLIB/rsLoEMEMhFI9yRe0j3d1uAItVuHfyejl7+QvShkv26o=' },
327 + { _id: 'user/devtest/admin',
328 + type: 'user',
329 + name: 'admin',
330 + email: 'admin@admin.com',
331 + creation: 1552591371,
332 + login: 1552692388,
333 + domain: 'devtest',
334 + salt: 'MOQqzm7q32/fk27Z00lPwGW1GTASDczli6lDt/7yb8eNhU6d1Wo5sF5Pl/TZcxmNrBzTiVOnqBQbAfwXTYj8fPazyUDarYQ5wYs7I2rVmH5IQAotBUaANwkFv5OBJ+JrlOqiJvoQLiB6yJwk9enQpbZw+2LJOLysPgNkXzAFtCg=',
335 + hash: 'PXWMPJ6xNGlb9iUudI3uptVqZo5tz+fgK5/apDEaEr0W73pJAxekwpeiZy+gFkvdl7eSecYgnN6Krq5xoHbPC4cDNisLZYQNapBeVe5pjzHc7X3/kI364l/jiI2OVKT+GzfzS4sJYVaBvd+tledOFwn1PSzQ7UT4IP3YRywbI74=',
336 + siteadmin: 4294967295,
337 + links:
338 + { 'mesh/devtest/vqbVBqGofP8h3l9Wxgk$$Dh3NgpvGCmaiNiMZLvuHdolSbF3W7@qvwpKbJP4i2Bd': [Object],
339 + 'mesh/devtest/XJEZ5L3trxPBkZc@6E4CAXmzk2D@JvhAKf20RRMutxxE@H$dLW1Eo5PUVYb$k9UK': [Object] } } ]