From 2314a58cd22f75ebac0805e01699aa69ead2aa75 Mon Sep 17 00:00:00 2001 From: Ylian Saint-Hilaire Date: Thu, 26 Mar 2020 19:33:13 -0700 Subject: [PATCH] More work done on per-device permissions. --- common.js | 1 + db.js | 33 +++- meshagent.js | 6 +- meshcentral.js | 4 +- meshuser.js | 101 +++++++++--- translate/translate.json | 183 +++++++++++---------- views/default.handlebars | 54 +++++-- webserver.js | 3 +- x.txt | 339 +++++++++++++++++++++++++++++++++++++++ 9 files changed, 595 insertions(+), 129 deletions(-) create mode 100644 x.txt diff --git a/common.js b/common.js index 456e0292..a7e0aa5a 100644 --- a/common.js +++ b/common.js @@ -147,6 +147,7 @@ module.exports.escapeFieldName = function (name) { if ((name.indexOf('%') == -1) module.exports.unEscapeFieldName = function (name) { if (name.indexOf('%') == -1) return name; return name.split('%2E').join('.').split('%24').join('$').split('%25').join('%'); }; // Escape all links +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; }; 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; }; 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; }; //module.exports.escapeAllLinksFieldName = function (docs) { for (var i in docs) { module.exports.escapeLinksFieldName(docs[i]); } return docs; }; diff --git a/db.js b/db.js index ea3fb25d..1940ebd1 100644 --- a/db.js +++ b/db.js @@ -789,11 +789,17 @@ module.exports.CreateDB = function (parent, func) { // Database actions on the main collection (MariaDB or MySQL) obj.Set = function (value, func) { var extra = null, extraex = null; + value = common.escapeLinksFieldNameEx(value); if (value.meshid) { extra = value.meshid; } else if (value.email) { extra = 'email/' + value.email; } if ((value.type == 'node') && (value.intelamt != null) && (value.intelamt.uuid != null)) { extraex = 'uuid/' + value.intelamt.uuid; } 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); } - obj.Get = function (_id, func) { sqlDbQuery('SELECT doc FROM meshcentral.main WHERE id = ?', [_id], func); } + obj.Get = function (_id, func) { + sqlDbQuery('SELECT doc FROM meshcentral.main WHERE id = ?', [_id], function (err, docs) { + if ((docs != null) && (docs.length > 0) && (docs[0].links != null)) { docs[0] = common.unEscapeLinksFieldName(docs[0]); } + func(_id, func); + }); + } obj.GetAll = function (func) { sqlDbQuery('SELECT domain, doc FROM meshcentral.main', null, func); } obj.GetHash = function (id, func) { sqlDbQuery('SELECT doc FROM meshcentral.main WHERE id = ?', [id], func); } 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) { } } else if (obj.databaseType == 3) { // Database actions on the main collection (MongoDB) - obj.Set = function (data, func) { obj.file.replaceOne({ _id: data._id }, performTypedRecordEncrypt(data), { upsert: true }, func); }; + obj.Set = function (data, func) { data = common.escapeLinksFieldNameEx(data); obj.file.replaceOne({ _id: data._id }, performTypedRecordEncrypt(data), { upsert: true }, func); }; obj.Get = function (id, func) { if (arguments.length > 2) { var parms = [func]; @@ -932,9 +938,15 @@ module.exports.CreateDB = function (parent, func) { userCallback.apply(obj, _func2.userArgs); }; func2.userArgs = parms; - obj.file.find({ _id: id }).toArray(function (err, docs) { func2(err, performTypedRecordDecrypt(docs)); }); + obj.file.find({ _id: id }).toArray(function (err, docs) { + if ((docs != null) && (docs.length > 0) && (docs[0].links != null)) { docs[0] = common.unEscapeLinksFieldName(docs[0]); } + func2(err, performTypedRecordDecrypt(docs)); + }); } else { - obj.file.find({ _id: id }).toArray(function (err, docs) { func(err, performTypedRecordDecrypt(docs)); }); + obj.file.find({ _id: id }).toArray(function (err, docs) { + if ((docs != null) && (docs.length > 0) && (docs[0].links != null)) { docs[0] = common.unEscapeLinksFieldName(docs[0]); } + func(err, performTypedRecordDecrypt(docs)); + }); } }; 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) { } else { // Database actions on the main collection (NeDB and MongoJS) - obj.Set = function (data, func) { var xdata = performTypedRecordEncrypt(data); obj.file.update({ _id: xdata._id }, xdata, { upsert: true }, func); }; + obj.Set = function (data, func) { data = common.escapeLinksFieldNameEx(data); var xdata = performTypedRecordEncrypt(data); obj.file.update({ _id: xdata._id }, xdata, { upsert: true }, func); }; obj.Get = function (id, func) { if (arguments.length > 2) { var parms = [func]; @@ -1064,9 +1076,15 @@ module.exports.CreateDB = function (parent, func) { userCallback.apply(obj, _func2.userArgs); }; func2.userArgs = parms; - obj.file.find({ _id: id }, function (err, docs) { func2(err, performTypedRecordDecrypt(docs)); }); + obj.file.find({ _id: id }, function (err, docs) { + if ((docs != null) && (docs.length > 0) && (docs[0].links != null)) { docs[0] = common.unEscapeLinksFieldName(docs[0]); } + func2(err, performTypedRecordDecrypt(docs)); + }); } else { - obj.file.find({ _id: id }, function (err, docs) { func(err, performTypedRecordDecrypt(docs)); }); + obj.file.find({ _id: id }, function (err, docs) { + if ((docs != null) && (docs.length > 0) && (docs[0].links != null)) { docs[0] = common.unEscapeLinksFieldName(docs[0]); } + func(err, performTypedRecordDecrypt(docs)); + }); } }; obj.GetAll = function (func) { obj.file.find({}, function (err, docs) { func(err, performTypedRecordDecrypt(docs)); }); }; @@ -1323,6 +1341,7 @@ module.exports.CreateDB = function (parent, func) { // Called when a node has changed function dbNodeChange(nodeChange, added) { + common.unEscapeLinksFieldName(nodeChange.fullDocument); const node = nodeChange.fullDocument; if (node.intelamt && node.intelamt.pass) { delete node.intelamt.pass; } // Remove the Intel AMT password before eventing this. parent.DispatchEvent(['*', node.meshid], obj, { etype: 'node', action: (added ? 'addnode' : 'changenode'), node: node, nodeid: node._id, domain: node.domain, nolog: 1 }); diff --git a/meshagent.js b/meshagent.js index e062d491..5841b644 100644 --- a/meshagent.js +++ b/meshagent.js @@ -549,7 +549,7 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) { const links = {}; links[adminUser._id] = { name: adminUser.name, rights: 0xFFFFFFFF }; mesh = { type: 'mesh', _id: obj.dbMeshKey, name: meshname, mtype: 2, desc: '', domain: domain.id, links: links }; - db.Set(common.escapeLinksFieldName(mesh)); + db.Set(mesh); parent.meshes[obj.dbMeshKey] = mesh; if (adminUser.links == null) adminUser.links = {}; @@ -580,7 +580,7 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) { // Mark the mesh as active delete mesh.deleted; - db.Set(common.escapeLinksFieldName(mesh)); + db.Set(mesh); } } return mesh; @@ -638,7 +638,7 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) { var links = {}; links[user._id] = { name: adminUser.name, rights: 0xFFFFFFFF }; mesh = { type: 'mesh', _id: obj.dbMeshKey, name: obj.meshid, mtype: 2, desc: '', domain: domain.id, links: links }; - db.Set(common.escapeLinksFieldName(mesh)); + db.Set(mesh); parent.meshes[obj.meshid] = mesh; parent.parent.AddEventDispatch(parent.CreateMeshDispatchTargets(obj.meshid, [obj.dbNodeKey]), ws); diff --git a/meshcentral.js b/meshcentral.js index 63e6fe1a..4c01aca0 100644 --- a/meshcentral.js +++ b/meshcentral.js @@ -815,8 +815,8 @@ function CreateMeshCentralServer(config, args) { objectToAdd.push(newobj); // Add this user } } else if (newobj.type == 'mesh') { - // Add this object after escaping - objectToAdd.push(obj.common.escapeLinksFieldName(newobj)); + // Add this object + objectToAdd.push(newobj); } // Don't add nodes. } console.log('Importing ' + objectToAdd.length + ' object(s)...'); diff --git a/meshuser.js b/meshuser.js index f51982cf..638a8244 100644 --- a/meshuser.js +++ b/meshuser.js @@ -1268,7 +1268,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use mesh = parent.meshes[meshid]; if (mesh) { // Remove user from the mesh - if (mesh.links[deluser._id] != null) { delete mesh.links[deluser._id]; parent.db.Set(common.escapeLinksFieldName(mesh)); } + if (mesh.links[deluser._id] != null) { delete mesh.links[deluser._id]; parent.db.Set(mesh); } // Notify mesh change change = 'Removed user ' + deluser.name + ' from group ' + mesh.name; 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 if (xmesh && xmesh.links) { ugrp.links[i] = { rights: cgroup.links[i].rights }; xmesh.links[ugrpid] = { rights: cgroup.links[i].rights }; - db.Set(common.escapeLinksFieldName(xmesh)); + db.Set(xmesh); // Notify mesh change 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 } // Save the new group - db.Set(common.escapeLinksFieldName(ugrp)); + db.Set(ugrp); if (db.changeStream == false) { parent.userGroups[ugrpid] = ugrp; } // Event the device group creation @@ -1703,7 +1703,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use db.Get(command.ugrpid, function (err, groups) { if ((err != null) || (groups.length != 1)) return; - var group = common.unEscapeLinksFieldName(groups[0]); + var group = groups[0]; // Unlink any user and meshes that have a link to this group if (group.links) { @@ -1725,7 +1725,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use var xmesh = parent.meshes[i]; if (xmesh && xmesh.links) { delete xmesh.links[group._id]; - db.Set(common.escapeLinksFieldName(xmesh)); + db.Set(xmesh); // Notify mesh change 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 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; } 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; } if (change != '') { - db.Set(common.escapeLinksFieldName(group)); + db.Set(group); 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 }; if (db.changeStream) { event.noact = 1; } // If DB change stream is active, don't use this event to change the mesh. Another event will come. parent.parent.DispatchEvent(['*', group._id, user._id], obj, event); @@ -1822,7 +1822,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use if (addedCount > 0) { // Save the new group to the database - db.Set(common.escapeLinksFieldName(group)); + db.Set(group); // Notify user group change 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 if ((group.links != null) && (group.links[command.userid] != null)) { change = true; delete group.links[command.userid]; - db.Set(common.escapeLinksFieldName(group)); + db.Set(group); // Notify user group change if (change) { @@ -2158,7 +2158,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use var links = {}; links[user._id] = { name: user.name, rights: 4294967295 }; mesh = { type: 'mesh', _id: meshid, name: command.meshname, mtype: command.meshtype, desc: command.desc, domain: domain.id, links: links }; - db.Set(common.escapeLinksFieldName(mesh)); + db.Set(mesh); parent.meshes[meshid] = mesh; parent.parent.AddEventDispatch([meshid], ws); @@ -2230,7 +2230,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use var xgroup = parent.userGroups[j]; if (xgroup && xgroup.links) { delete xgroup.links[mesh._id]; - db.Set(common.escapeLinksFieldName(xgroup)); + db.Set(xgroup); // Notify user group change var targets = ['*', 'server-ugroups', user._id, xgroup._id]; @@ -2251,7 +2251,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use // Mark the mesh as deleted mesh.deleted = new Date(); // Mark the time this mesh was deleted, we can expire it at some point. - db.Set(common.escapeLinksFieldName(mesh)); // We don't really delete meshes because if a device connects to is again, we will un-delete it. + db.Set(mesh); // We don't really delete meshes because if a device connects to is again, we will un-delete it. // Delete all devices attached to this mesh in the database db.RemoveMeshDocuments(command.meshid); @@ -2304,7 +2304,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use } if (change != '') { - db.Set(common.escapeLinksFieldName(mesh)); + db.Set(mesh); 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 }; if (db.changeStream) { event.noact = 1; } // If DB change stream is active, don't use this event to change the mesh. Another event will come. parent.parent.DispatchEvent(['*', mesh._id, user._id], obj, event); @@ -2356,7 +2356,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use if (newuser.links == null) { newuser.links = {}; } if (newuser.links[command.meshid]) { newuser.links[command.meshid].rights = command.meshadmin; } else { newuser.links[command.meshid] = { rights: command.meshadmin }; } if (newuserid.startsWith('user/')) { db.SetUser(newuser); } - else if (newuserid.startsWith('ugrp/')) { db.Set(common.escapeLinksFieldName(newuser)); } + else if (newuserid.startsWith('ugrp/')) { db.Set(newuser); } parent.parent.DispatchEvent([newuser._id], obj, 'resubscribe'); if (newuserid.startsWith('user/')) { @@ -2375,7 +2375,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use // Add userid to the mesh mesh.links[newuserid] = { name: newuser.name, rights: command.meshadmin }; - db.Set(common.escapeLinksFieldName(mesh)); + db.Set(mesh); // Notify mesh change 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 try { if (common.validateString(command.nodeid, 1, 1024) == false) { err = 'Invalid nodeid'; } // Check the nodeid else if (common.validateInt(command.rights) == false) { err = 'Invalid rights'; } // Device rights must be an integer + else if ((command.rights & 7) != 0) { err = 'Invalid rights'; } // EDITMESH, MANAGEUSERS or MANAGECOMPUTERS rights can't be assigned to a user to device link 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 else { 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 for (var i in command.usernames) { command.userids.push('user/' + domain.id + '/' + command.usernames[i].toLowerCase()); } } - // TODO - //console.log(command); + // Get the node and the rights for this node + parent.GetNodeWithRights(domain, user, command.nodeid, function (node, rights, visible) { + // Check if already in the right mesh + if ((node == null) || (node.meshid == command.meshid)) return; + var dispatchTargets = ['*', node.meshid, node._id]; + + // Check that we have rights to manage users on this device + if ((rights & MESHRIGHT_MANAGEUSERS) == 0) return; + + // Add the new link to the users + var nodeChanged = false; + for (var i in command.userids) { + var newuserid = command.userids[i]; + var newuser = parent.users[newuserid]; + if (newuser != null) { + // Add this user to the dispatch target list + dispatchTargets.push(newuser._id); + + if (command.rights == 0) { + // Remove link to this user + if (newuser.links != null) { + delete newuser.links[command.nodeid]; + if (Object.keys(newuser.links).length == 0) { delete newuser.links; } + } + + // Remove link to this device + if (node.links != null) { + delete node.links[newuserid]; + nodeChanged = true; + if (Object.keys(node.links).length == 0) { delete node.links; } + } + } else { + // Add the new link to this user + if (newuser.links == null) { newuser.links = {}; } + newuser.links[command.nodeid] = { rights: command.rights }; + + // Add the new link to the device + if (node.links == null) { node.links = {}; } + node.links[newuserid] = { rights: command.rights } + nodeChanged = true; + } + + // Save the user to the database + db.SetUser(newuser); + + // Notify user change + var targets = ['*', 'server-users', newuserid._id]; + 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) }; + 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. + parent.parent.DispatchEvent(targets, obj, event); + } + } + + // Save the device + if (nodeChanged == true) { + // Save the node to the database + db.Set(node); + + // Event the node change + 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) } + if (db.changeStream) { event.noact = 1; } // If DB change stream is active, don't use this event to change the mesh. Another event will come. + parent.parent.DispatchEvent(dispatchTargets, obj, event); + } + }); break; } @@ -2461,7 +2524,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use if ((delmeshrights == 0xFFFFFFFF) && (mesh.links[deluserid].rights != 0xFFFFFFFF)) return; // A non-admin can't kick out an admin delete deluser.links[command.meshid]; if (deluserid.startsWith('user/')) { db.SetUser(deluser); } - else if (deluserid.startsWith('ugrp/')) { db.Set(common.escapeLinksFieldName(deluser)); } + else if (deluserid.startsWith('ugrp/')) { db.Set(deluser); } parent.parent.DispatchEvent([deluser._id], obj, 'resubscribe'); if (deluserid.startsWith('user/')) { @@ -2483,7 +2546,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use // Remove user from the mesh if (mesh.links[command.userid] != null) { delete mesh.links[command.userid]; - db.Set(common.escapeLinksFieldName(mesh)); + db.Set(mesh); // Notify mesh change var event; @@ -2528,7 +2591,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use if (command.amtpolicy.type === 2) { amtpolicy = { type: command.amtpolicy.type, password: command.amtpolicy.password, badpass: command.amtpolicy.badpass, cirasetup: command.amtpolicy.cirasetup }; } else if (command.amtpolicy.type === 3) { amtpolicy = { type: command.amtpolicy.type, password: command.amtpolicy.password, cirasetup: command.amtpolicy.cirasetup }; } mesh.amt = amtpolicy; - db.Set(common.escapeLinksFieldName(mesh)); + db.Set(mesh); var amtpolicy2 = Object.assign({}, amtpolicy); // Shallow clone delete amtpolicy2.password; 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 }; diff --git a/translate/translate.json b/translate/translate.json index 1bd85633..e6539308 100644 --- a/translate/translate.json +++ b/translate/translate.json @@ -653,7 +653,7 @@ "default-mobile.handlebars->9->246", "default-mobile.handlebars->9->70", "default.handlebars->27->1237", - "default.handlebars->27->1483", + "default.handlebars->27->1485", "default.handlebars->27->653" ] }, @@ -2361,7 +2361,7 @@ "ru": "Добавить участие", "zh-chs": "添加會員", "xloc": [ - "default.handlebars->27->1479" + "default.handlebars->27->1481" ] }, { @@ -2847,7 +2847,7 @@ "ru": "Счетчик ошибок агента", "zh-chs": "座席錯誤計數器", "xloc": [ - "default.handlebars->27->1492" + "default.handlebars->27->1494" ] }, { @@ -2913,7 +2913,7 @@ "ru": "Сессии агентов", "zh-chs": "座席會議", "xloc": [ - "default.handlebars->27->1508" + "default.handlebars->27->1510" ] }, { @@ -3035,7 +3035,7 @@ "ru": "Агенты", "zh-chs": "代理商", "xloc": [ - "default.handlebars->27->1521" + "default.handlebars->27->1523" ] }, { @@ -3766,7 +3766,7 @@ "ru": "Вы уверенны, что {0} плагин: {1}", "zh-chs": "您確定要{0}插件嗎:{1}", "xloc": [ - "default.handlebars->27->1558" + "default.handlebars->27->1560" ] }, { @@ -4158,7 +4158,7 @@ "ru": "Плохой ключ", "zh-chs": "錯誤的簽名", "xloc": [ - "default.handlebars->27->1499" + "default.handlebars->27->1501" ] }, { @@ -4175,7 +4175,7 @@ "ru": "Плохой веб-сертификат", "zh-chs": "錯誤的網絡證書", "xloc": [ - "default.handlebars->27->1498" + "default.handlebars->27->1500" ] }, { @@ -4410,7 +4410,7 @@ "ru": "CIRA Сервер", "zh-chs": "CIRA服務器", "xloc": [ - "default.handlebars->27->1549" + "default.handlebars->27->1551" ] }, { @@ -4427,7 +4427,7 @@ "ru": "CIRA Сервер команды", "zh-chs": "CIRA服務器命令", "xloc": [ - "default.handlebars->27->1550" + "default.handlebars->27->1552" ] }, { @@ -4444,7 +4444,7 @@ "ru": "Загрузка CPU", "zh-chs": "CPU負載", "xloc": [ - "default.handlebars->27->1513" + "default.handlebars->27->1515" ] }, { @@ -4461,7 +4461,7 @@ "ru": "Загрузка CPU за последние 15 минут", "zh-chs": "最近15分鐘的CPU負載", "xloc": [ - "default.handlebars->27->1516" + "default.handlebars->27->1518" ] }, { @@ -4478,7 +4478,7 @@ "ru": "Загрузка CPU за последние 5 минут", "zh-chs": "最近5分鐘的CPU負載", "xloc": [ - "default.handlebars->27->1515" + "default.handlebars->27->1517" ] }, { @@ -4495,7 +4495,7 @@ "ru": "Загрузка CPU за последнюю минуту", "zh-chs": "最後一分鐘的CPU負載", "xloc": [ - "default.handlebars->27->1514" + "default.handlebars->27->1516" ] }, { @@ -4550,7 +4550,7 @@ "ru": "Ошибка вызова", "zh-chs": "通話錯誤", "xloc": [ - "default.handlebars->27->1559" + "default.handlebars->27->1561" ] }, { @@ -4968,7 +4968,7 @@ "ru": "Проверка...", "zh-chs": "檢查...", "xloc": [ - "default.handlebars->27->1555", + "default.handlebars->27->1557", "default.handlebars->27->778" ] }, @@ -5197,7 +5197,7 @@ "en": "Clear this notification", "nl": "Wis deze melding", "xloc": [ - "default.handlebars->27->1486" + "default.handlebars->27->1488" ] }, { @@ -5560,7 +5560,13 @@ "zh-chs": "確認刪除設備組{0}?", "xloc": [ "default.handlebars->27->1384", - "default.handlebars->27->1481" + "default.handlebars->27->1483" + ] + }, + { + "en": "Confirm removal of device {0}?", + "xloc": [ + "default.handlebars->27->1476" ] }, { @@ -5577,7 +5583,7 @@ "ru": "Подтвердить удаление группы {0}?", "zh-chs": "確認刪除組{0}?", "xloc": [ - "default.handlebars->27->1477" + "default.handlebars->27->1479" ] }, { @@ -5728,7 +5734,7 @@ "ru": "Подключено Intel® AMT", "zh-chs": "連接的英特爾®AMT", "xloc": [ - "default.handlebars->27->1504" + "default.handlebars->27->1506" ] }, { @@ -5745,7 +5751,7 @@ "ru": "Подключенные пользователи", "zh-chs": "關聯用戶", "xloc": [ - "default.handlebars->27->1509" + "default.handlebars->27->1511" ] }, { @@ -5817,7 +5823,7 @@ "ru": "Подключений ", "zh-chs": "連接數", "xloc": [ - "default.handlebars->27->1520" + "default.handlebars->27->1522" ] }, { @@ -5834,7 +5840,7 @@ "ru": "Ретранслятор подключения", "zh-chs": "連接繼電器", "xloc": [ - "default.handlebars->27->1548" + "default.handlebars->27->1550" ] }, { @@ -5941,7 +5947,7 @@ "ru": "Cookie-кодировщик", "zh-chs": "Cookie編碼器", "xloc": [ - "default.handlebars->27->1534" + "default.handlebars->27->1536" ] }, { @@ -6201,7 +6207,7 @@ "ru": "Основной сервер", "zh-chs": "核心服務器", "xloc": [ - "default.handlebars->27->1533" + "default.handlebars->27->1535" ] }, { @@ -7235,6 +7241,7 @@ "zh-chs": "設備", "xloc": [ "default.handlebars->27->1150", + "default.handlebars->27->1458", "default.handlebars->container->column_l->p1->devListToolbarSpan->1->0->9->devListToolbarSort->sortselect->5" ] }, @@ -7273,7 +7280,6 @@ "default.handlebars->27->1148", "default.handlebars->27->1149", "default.handlebars->27->1380", - "default.handlebars->27->1458", "default.handlebars->27->1467", "default.handlebars->27->1473" ] @@ -7314,7 +7320,7 @@ "default.handlebars->27->1352", "default.handlebars->27->1365", "default.handlebars->27->1420", - "default.handlebars->27->1507", + "default.handlebars->27->1509", "default.handlebars->container->column_l->p2->9" ] }, @@ -8309,7 +8315,7 @@ "ru": "Скопировать агент", "zh-chs": "代理重複", "xloc": [ - "default.handlebars->27->1503" + "default.handlebars->27->1505" ] }, { @@ -8738,7 +8744,7 @@ "en": "Email Traffic", "nl": "E-mailverkeer", "xloc": [ - "default.handlebars->27->1542" + "default.handlebars->27->1544" ] }, { @@ -9450,7 +9456,7 @@ "ru": "Внешний", "zh-chs": "外部", "xloc": [ - "default.handlebars->27->1527" + "default.handlebars->27->1529" ] }, { @@ -9882,8 +9888,8 @@ "ru": "Свободно", "zh-chs": "自由", "xloc": [ - "default.handlebars->27->1488", - "default.handlebars->27->1490" + "default.handlebars->27->1490", + "default.handlebars->27->1492" ] }, { @@ -10731,7 +10737,7 @@ "pt": "Total da pilha", "zh-chs": "堆總數", "xloc": [ - "default.handlebars->27->1529" + "default.handlebars->27->1531" ] }, { @@ -10746,7 +10752,7 @@ "pt": "Pilha usada", "zh-chs": "堆使用", "xloc": [ - "default.handlebars->27->1528" + "default.handlebars->27->1530" ] }, { @@ -11404,8 +11410,8 @@ "xloc": [ "default.handlebars->27->1226", "default.handlebars->27->1232", - "default.handlebars->27->1525", - "default.handlebars->27->1547" + "default.handlebars->27->1527", + "default.handlebars->27->1549" ] }, { @@ -12098,7 +12104,7 @@ "ru": "Некорректный тип группы устройств", "zh-chs": "無效的設備組類型", "xloc": [ - "default.handlebars->27->1502" + "default.handlebars->27->1504" ] }, { @@ -12115,7 +12121,7 @@ "ru": "Некорректный JSON", "zh-chs": "無效的JSON", "xloc": [ - "default.handlebars->27->1496" + "default.handlebars->27->1498" ] }, { @@ -12167,7 +12173,7 @@ "ru": "Некорректная сигнатура PKCS", "zh-chs": "無效的PKCS簽名", "xloc": [ - "default.handlebars->27->1494" + "default.handlebars->27->1496" ] }, { @@ -12184,7 +12190,7 @@ "ru": "Некорректная сигнатура RSA", "zh-chs": "無效的RSA密碼", "xloc": [ - "default.handlebars->27->1495" + "default.handlebars->27->1497" ] }, { @@ -13205,7 +13211,7 @@ "ru": "Меньше", "zh-chs": "減", "xloc": [ - "default.handlebars->27->1561" + "default.handlebars->27->1563" ] }, { @@ -14222,7 +14228,7 @@ "ru": "Сообщения главного сервера", "zh-chs": "主服務器消息", "xloc": [ - "default.handlebars->27->1536" + "default.handlebars->27->1538" ] }, { @@ -14596,7 +14602,7 @@ "ru": "Достигнуто максимальное число сессий", "zh-chs": "達到的會話數上限", "xloc": [ - "default.handlebars->27->1500" + "default.handlebars->27->1502" ] }, { @@ -14650,7 +14656,7 @@ "ru": "Мегабайт", "zh-chs": "兆字節", "xloc": [ - "default.handlebars->27->1526" + "default.handlebars->27->1528" ] }, { @@ -14667,7 +14673,7 @@ "ru": "ОЗУ", "zh-chs": "記憶", "xloc": [ - "default.handlebars->27->1517", + "default.handlebars->27->1519", "default.handlebars->27->743", "default.handlebars->container->column_l->p40->3->1->p40type->3" ] @@ -14800,7 +14806,7 @@ "ru": "Трафик MeshAgent", "zh-chs": "MeshAgent流量", "xloc": [ - "default.handlebars->27->1538" + "default.handlebars->27->1540" ] }, { @@ -14817,7 +14823,7 @@ "ru": "Обновление MeshAgent", "zh-chs": "MeshAgent更新", "xloc": [ - "default.handlebars->27->1539" + "default.handlebars->27->1541" ] }, { @@ -14916,7 +14922,7 @@ "ru": "Соединения сервера MeshCentral", "zh-chs": "MeshCentral服務器對等", "xloc": [ - "default.handlebars->27->1537" + "default.handlebars->27->1539" ] }, { @@ -15170,7 +15176,7 @@ "ru": "Диспетчер сообщения", "zh-chs": "郵件調度程序", "xloc": [ - "default.handlebars->27->1535" + "default.handlebars->27->1537" ] }, { @@ -15271,7 +15277,7 @@ "ru": "Еще", "zh-chs": "更多", "xloc": [ - "default.handlebars->27->1560" + "default.handlebars->27->1562" ] }, { @@ -15956,7 +15962,7 @@ "zh-chs": "找不到活動", "xloc": [ "default.handlebars->27->1273", - "default.handlebars->27->1482", + "default.handlebars->27->1484", "default.handlebars->27->691" ] }, @@ -17000,7 +17006,7 @@ "ru": "Произошло в {0}", "zh-chs": "發生在{0}", "xloc": [ - "default.handlebars->27->1485" + "default.handlebars->27->1487" ] }, { @@ -18015,7 +18021,7 @@ "ru": "Действие плагина", "zh-chs": "插件動作", "xloc": [ - "default.handlebars->27->1557", + "default.handlebars->27->1559", "default.handlebars->27->159" ] }, @@ -18707,7 +18713,7 @@ "ru": "RSS", "zh-chs": "的RSS", "xloc": [ - "default.handlebars->27->1530" + "default.handlebars->27->1532" ] }, { @@ -18886,7 +18892,7 @@ "ru": "Число ретрансляций", "zh-chs": "中繼計數", "xloc": [ - "default.handlebars->27->1512" + "default.handlebars->27->1514" ] }, { @@ -18902,7 +18908,7 @@ "ru": "Ошибки ретранслятора", "zh-chs": "中繼錯誤", "xloc": [ - "default.handlebars->27->1505" + "default.handlebars->27->1507" ] }, { @@ -18918,8 +18924,8 @@ "ru": "Сессии ретранслятора", "zh-chs": "接力會議", "xloc": [ - "default.handlebars->27->1511", - "default.handlebars->27->1524" + "default.handlebars->27->1513", + "default.handlebars->27->1526" ] }, { @@ -19193,7 +19199,7 @@ "zh-chs": "刪除設備組", "xloc": [ "default.handlebars->27->1383", - "default.handlebars->27->1480" + "default.handlebars->27->1482" ] }, { @@ -19210,7 +19216,8 @@ "ru": "Удалить пользователя", "zh-chs": "刪除用戶", "xloc": [ - "default.handlebars->27->1476" + "default.handlebars->27->1475", + "default.handlebars->27->1478" ] }, { @@ -20603,7 +20610,7 @@ "ru": "Сертификат сервера", "zh-chs": "服務器證書", "xloc": [ - "default.handlebars->27->1540" + "default.handlebars->27->1542" ] }, { @@ -20616,7 +20623,7 @@ "pt": "Banco de Dados do Servidor", "zh-chs": "服務器數據庫", "xloc": [ - "default.handlebars->27->1541" + "default.handlebars->27->1543" ] }, { @@ -20723,7 +20730,7 @@ "ru": "Состояние сервера", "zh-chs": "服務器狀態", "xloc": [ - "default.handlebars->27->1491" + "default.handlebars->27->1493" ] }, { @@ -20757,7 +20764,7 @@ "ru": "Трассировка сервера", "zh-chs": "服務器跟踪", "xloc": [ - "default.handlebars->27->1551" + "default.handlebars->27->1553" ] }, { @@ -20893,7 +20900,7 @@ "ru": "ServerStats.csv", "zh-chs": "ServerStats.csv", "xloc": [ - "default.handlebars->27->1532" + "default.handlebars->27->1534" ] }, { @@ -22869,7 +22876,7 @@ "ru": "На данный момент уведомлений нет", "zh-chs": "目前沒有任何通知", "xloc": [ - "default.handlebars->27->1484" + "default.handlebars->27->1486" ] }, { @@ -23995,7 +24002,7 @@ "default-mobile.handlebars->9->174", "default-mobile.handlebars->9->175", "default.handlebars->27->13", - "default.handlebars->27->1475", + "default.handlebars->27->1477", "default.handlebars->27->364", "default.handlebars->27->41", "default.handlebars->27->42", @@ -24037,7 +24044,7 @@ "ru": "Неизвестное действие", "zh-chs": "未知動作", "xloc": [ - "default.handlebars->27->1497" + "default.handlebars->27->1499" ] }, { @@ -24069,7 +24076,7 @@ "xloc": [ "default.handlebars->27->1376", "default.handlebars->27->1463", - "default.handlebars->27->1501" + "default.handlebars->27->1503" ] }, { @@ -24086,7 +24093,7 @@ "ru": "Неизвестная группа", "zh-chs": "未知群組", "xloc": [ - "default.handlebars->27->1493" + "default.handlebars->27->1495" ] }, { @@ -24196,7 +24203,7 @@ "ru": "Актуально", "zh-chs": "最新", "xloc": [ - "default.handlebars->27->1556" + "default.handlebars->27->1558" ] }, { @@ -24436,8 +24443,8 @@ "ru": "Использовано", "zh-chs": "用過的", "xloc": [ - "default.handlebars->27->1487", - "default.handlebars->27->1489" + "default.handlebars->27->1489", + "default.handlebars->27->1491" ] }, { @@ -24511,7 +24518,7 @@ "ru": "Учетные записи пользователей", "zh-chs": "用戶帳號", "xloc": [ - "default.handlebars->27->1506" + "default.handlebars->27->1508" ] }, { @@ -24565,7 +24572,7 @@ "xloc": [ "default.handlebars->27->1147", "default.handlebars->27->1354", - "default.handlebars->27->1478" + "default.handlebars->27->1480" ] }, { @@ -24703,7 +24710,7 @@ "ru": "Сессии пользователя", "zh-chs": "用戶會話", "xloc": [ - "default.handlebars->27->1523" + "default.handlebars->27->1525" ] }, { @@ -24858,7 +24865,7 @@ "xloc": [ "default.handlebars->27->1353", "default.handlebars->27->1364", - "default.handlebars->27->1522", + "default.handlebars->27->1524", "default.handlebars->container->topbar->1->1->UsersSubMenuSpan->UsersSubMenu->1->0->UsersGeneral" ] }, @@ -24876,7 +24883,7 @@ "ru": "Сессии пользователей", "zh-chs": "用戶會話", "xloc": [ - "default.handlebars->27->1510" + "default.handlebars->27->1512" ] }, { @@ -25270,8 +25277,8 @@ "ru": "Веб-сервер", "zh-chs": "網絡服務器", "xloc": [ - "default.handlebars->27->1543", - "default.handlebars->27->1544" + "default.handlebars->27->1545", + "default.handlebars->27->1546" ] }, { @@ -25288,7 +25295,7 @@ "ru": "Запросы веб-сервера", "zh-chs": "Web服務器請求", "xloc": [ - "default.handlebars->27->1545" + "default.handlebars->27->1547" ] }, { @@ -25305,7 +25312,7 @@ "ru": "Ретранслятор Web Socket", "zh-chs": "Web套接字中繼", "xloc": [ - "default.handlebars->27->1546" + "default.handlebars->27->1548" ] }, { @@ -26142,7 +26149,7 @@ "ru": "\\\\'", "zh-chs": "\\\\'", "xloc": [ - "default.handlebars->27->1554" + "default.handlebars->27->1556" ] }, { @@ -26381,7 +26388,7 @@ "ru": "свободно", "zh-chs": "自由", "xloc": [ - "default.handlebars->27->1518" + "default.handlebars->27->1520" ] }, { @@ -26675,7 +26682,7 @@ "ru": "servertrace.csv", "zh-chs": "servertrace.csv", "xloc": [ - "default.handlebars->27->1553" + "default.handlebars->27->1555" ] }, { @@ -26725,7 +26732,7 @@ "ru": "time, conn.agent, conn.users, conn.usersessions, conn.relaysession, conn.intelamt, mem.external, mem.heapused, mem.heaptotal, mem.rss", "zh-chs": "時間,conn.agent,conn.users,conn.usersessions,conn.relaysession,conn.intelamt,mem.external,mem.heapused,mem.heaptotal,mem.rss", "xloc": [ - "default.handlebars->27->1531" + "default.handlebars->27->1533" ] }, { @@ -26741,7 +26748,7 @@ "ru": "time, source, message", "zh-chs": "時間,來源,訊息", "xloc": [ - "default.handlebars->27->1552" + "default.handlebars->27->1554" ] }, { @@ -26771,7 +26778,7 @@ "ru": "всего", "zh-chs": "總", "xloc": [ - "default.handlebars->27->1519" + "default.handlebars->27->1521" ] }, { diff --git a/views/default.handlebars b/views/default.handlebars index 853235d5..52bb4e46 100644 --- a/views/default.handlebars +++ b/views/default.handlebars @@ -2419,6 +2419,7 @@ node.tags = message.event.node.tags; node.userloc = message.event.node.userloc; node.rdpport = message.event.node.rdpport; + if (message.event.node.links != null) { node.links = message.event.node.links; } else { delete node.links; } if (message.event.node.agent != null) { if (node.agent == null) node.agent = {}; if (message.event.node.agent.ver != null) { node.agent.ver = message.event.node.agent.ver; } @@ -8433,10 +8434,10 @@ } else if (userid === 4) { var y = '', firstMeshId = null; for (var i in meshes) { y += ''; if (firstMeshId == null) { firstMeshId = meshes[i]._id; } } - x += addHtmlValue("Device Group", '
'); + x += addHtmlValue("Device Group", '
'); y = ''; for (var i in nodes) { if (nodes[i].meshid == firstMeshId) { y += ''; } } - x += addHtmlValue("Device", '
'); + x += addHtmlValue("Device", '
'); } else { userid = decodeURIComponent(userid); var uname = userid.split('/')[2]; @@ -8513,7 +8514,7 @@ if (meshrights & 32768) { Q('p20uninstall').checked = true; } } } - p20validateAddMeshUserDialog(); + p20validateAddMeshUserDialog(userid); return false; } @@ -8521,6 +8522,7 @@ var y = '', meshid = decodeURIComponent(Q('dp2meshid').value); for (var i in nodes) { if (nodes[i].meshid == meshid) { y += ''; } } QH('dp2nodeid', y); + p20validateAddMeshUserDialog(4); } function p20setname(name) { @@ -8533,14 +8535,36 @@ return false; } - function p20validateAddMeshUserDialog() { + function p20validateAddMeshUserDialog(updateId) { + var ok = true; + + if (updateId === 4) { + // Update user device rights + var devrights = 0, nodeid = decodeURIComponent(Q('dp2nodeid').value); + if ((nodeid != '') && (currentUser.links != null) && (currentUser.links[nodeid] != null)) { devrights = currentUser.links[nodeid].rights; } + Q('p20remotecontrol').checked = ((devrights & 8) != 0); + Q('p20meshagentconsole').checked = ((devrights & 16) != 0); + Q('p20meshserverfiles').checked = ((devrights & 32) != 0); + Q('p20wakedevices').checked = ((devrights & 64) != 0); + Q('p20editnotes').checked = ((devrights & 128) != 0); + Q('p20remoteview').checked = ((devrights & 256) != 0); + Q('p20noterminal').checked = ((devrights & 512) != 0); + Q('p20nofiles').checked = ((devrights & 1024) != 0); + Q('p20noamt').checked = ((devrights & 2048) != 0); + Q('p20remotelimitedinput').checked = ((devrights & 4096) != 0); + Q('p20limitevents').checked = ((devrights & 8192) != 0); + Q('p20chatnotify').checked = ((devrights & 16384) != 0); + Q('p20uninstall').checked = ((devrights & 32768) != 0); + Q('p20nodesktop').checked = ((devrights & 65536) != 0); + ok = (nodeid != ''); + } + var meshrights = null; if ((xxdialogTag === 1) || (xxdialogTag === 3)) { meshrights = GetMeshRights(decodeURIComponent(Q('dp2groupid').value)); } else { meshrights = GetMeshRights(currentMesh); } - var ok = true; if (Q('dp20username')) { var xusers = Q('dp20username').value.split(','); for (var i in xusers) { @@ -8569,14 +8593,15 @@ } QE('idx_dlgOkButton', ok); + var nc; if (Q('p20fulladmin') != null) { - var nc = !Q('p20fulladmin').checked; + nc = !Q('p20fulladmin').checked; QE('p20fulladmin', meshrights == 0xFFFFFFFF); QE('p20editmesh', nc && (meshrights == 0xFFFFFFFF)); QE('p20manageusers', nc); QE('p20managecomputers', nc); } else { - nc = true; + nc = (nodeid != ''); } QE('p20remotecontrol', nc); QE('p20meshagentconsole', nc); @@ -10205,13 +10230,13 @@ if (currentUser.links) { for (var i in currentUser.links) { if (i.startsWith('node/')) { - var cr = 0, r = currentUser.links[i].rights, node = getNodeFromId(i), trash = '', rights = "Partial Device Rights"; + var r = currentUser.links[i].rights, node = getNodeFromId(i), trash = '', rights = "Partial Device Rights", cr = GetNodeRights(node); if (node == null) { continue; } if ((userinfo.links) && (userinfo.links[i] != null) && (userinfo.links[i].rights != null)) { cr = userinfo.links[i].rights; } var nodename = node?EscapeHtml(node.name):('' + "Unknown Device" + ''); if (r == 0xFFFFFFFF) rights = "Full Device Rights"; else if (r == 0) rights = "No Rights"; if ((currentUser._id != userinfo._id) && ((cr & 2) != 0)) { trash = ''; } - x += '
 ' + nodename + '
' + trash + '
' + rights + '
'; + x += '
 ' + nodename + '
' + trash + '
' + rights + '
'; } } } @@ -10220,6 +10245,7 @@ } // Display common device groups + count = 1; var deviceGroupCount = 0, newDeviceGroup = false; for (var i in meshes) { deviceGroupCount++; if ((currentUser.links == null) || (currentUser.links[i] == null)) { newDeviceGroup = true; } } if ((deviceGroupCount > 0) && (newDeviceGroup)) { x += ' ' + "Add Device Group" + ''; } @@ -10267,6 +10293,16 @@ QH('p30html2', x); } + function p30removeNodeFromUser(event, nodeid) { + if (xxdialogMode) return; + var node = getNodeFromId(decodeURIComponent(nodeid)) + setDialogMode(2, "Remove User", 3, p30removeNodeFromUserEx, format("Confirm removal of device {0}?", node.name), node); + } + + function p30removeNodeFromUserEx(b, node) { + meshserver.send({ action: 'adddeviceuser', nodeid: node._id, nodename: node.name, userids: [ currentUser._id ], rights: 0 }); + } + function p30RemoveUserGroup(button, ugrpid) { if (xxdialogMode || (usergroups == null)) return; var groupid = decodeURIComponent(ugrpid), group = usergroups[groupid]; diff --git a/webserver.js b/webserver.js index 5f5ae938..657e3a3c 100644 --- a/webserver.js +++ b/webserver.js @@ -203,6 +203,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) { //function EscapeHtmlBreaks(x) { if (typeof x == "string") return x.replace(/&/g, '&').replace(/>/g, '>').replace(/').replace(/\n/g, '').replace(/\t/g, '  '); if (typeof x == "boolean") return x; if (typeof x == "number") return x; } // Fetch all users from the database, keep this in memory obj.db.GetAllType('user', function (err, docs) { + obj.common.unEscapeAllLinksFieldName(docs); var domainUserCount = {}, i = 0; for (i in parent.config.domains) { domainUserCount[i] = 0; } 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) { var mesh = obj.meshes[meshid]; if (mesh) { // Remove user from the mesh - if (mesh.links[userid] != null) { delete mesh.links[userid]; obj.db.Set(obj.common.escapeLinksFieldName(mesh)); } + if (mesh.links[userid] != null) { delete mesh.links[userid]; obj.db.Set(mesh); } // Notify mesh change var change = 'Removed user ' + user.name + ' from group ' + mesh.name; 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 }); diff --git a/x.txt b/x.txt new file mode 100644 index 00000000..e98adfeb --- /dev/null +++ b/x.txt @@ -0,0 +1,339 @@ +[ { _id: 'user//544849534953415445535453494431', + type: 'user', + name: 'LDAP User1', + creation: 1555361291, + login: 1555365153, + domain: '', + links: { 'mesh//2odhtyJSNw0$wApTgsGPZoF1h5XovNbN9KbetvIzMkAhXsPyFXFfW@Dnwp6BMhis': [Object] }, + siteadmin: 0, + email: 'aa@bb.com' }, + { _id: 'user//a@a.com', + creation: 1562625646, + domain: '', + email: 'a@a.com', + emailVerified: true, + hash: 'm9/LFPJ2HI/bXQdjBC1jGUF6ymLv3Zc0TClv34pEimRpWWtaslTu40qUXcBDRW4ImT8PCc+EMMsMen5VKfyDlk9hMIsERKVn06EMtT4XJZwqXStk2Pyx5qZy/wmE99bKsGOuXRaq3FXecEf+LK+fxfY4wEnCSQuKfSQll10cKcA=', + name: 'a@a.com', + passchange: 1562625646, + salt: 'OOfnPUaVYtJ7vYGGitFpyMySKdJq8AVspq87B1JoKfrGnMcEGtXlrs7OXbpLDOeYrOcaWQcgjSjNlYLBR4pYTFn71aC2GqDrAUSETPQlBtsxxxT+FA0VJic+q8Fds7Ef1ku+1A//UsK3/smqVEC8qNCzw8CI6OkNLBSU/bMDsZY=', + type: 'user', + login: 1562625674 }, + { type: 'user', + _id: 'user//aa', + name: 'aa', + creation: 1585276083, + domain: '', + email: 'aa@aa.com', + passchange: 1585276083, + salt: 'AU9ir/d/tuEgGPn3noRhdsjF3BCAKpVHrG0nEE0/U6x0Sqa+Z9Mf4yRHhn1XYw0tRyX3TVDAD6iNmDGHgxukXRuCfPgog1YIkU+8xKrxy0MF97gkJA+4s9zWpXBUbrTCyo4UQkV2fpQ4SkyTi84cU7lP46nNUIu4kJoUiTHlZLw=', + hash: 'V95ikU9NKh8jLxQJzc3qv1gOM4yK/cOasalrdTsoW2RUvrrWlt81UAy1NKrRFZx9zknYI1HbFtPuyZZyfFsDKtM7JuB4YL5nJeqqpFrPaqMsNw3GZ8tn2au+X4JxHlYeRF1Rrx90lbi7hrxfHHecBSU10reXiEMTLYg8uxpZILY=', + links: + { 'mesh//7b4b43cdad850135f36ab31124b52e47c167fba055ce800267a4dc89fe0e581c': [Object], + 'ugrp//BXQUCOnHMBI14nGBhfTkvMlmb2K3FcP09Bu@3jpffr3nn@hxsm5RlpNLWheqQqYJ': [Object], + 'ugrp//mKkqX0gLZ30jhPOs4cYdeCi5E@1P3OpypcAj1CKK14n04upXON36@5VE9BIez9h3': [Object], + 'node//8wGlXgB8y@@Pe24vbVYUMoOxE2Si9eupK0gJ8wJW6GQCabaTYFmlHMjCyO3p0VEv': [Object] } }, + { _id: 'user//admin', + type: 'user', + name: 'admin', + domain: '', + creation: 1417814230, + salt: '5cTXOdvnH0G5ThP0A2clL8+1zmdhhONqEo2t6cYBtLp27eRKCx6eEnONculOtTRd+bCO5795A2aDvWlFLhnxutNONmEc8aTDju+CiAq5f6gCzuZnIY3CA9Oc9fqOM4AZ8l7Bg/IT/7MKYMB0djeBTvJkJ1wkAAUh3nCRbfo2PC8=', + hash: 'Pg7Hb/nA0S3HsacfuGbgRpxHsFchrMy1/XntdCwmqcwh/MvFecqggzZcDEmxhQ+mwjH2rnm+X2nbTxI9vDKgLndAjIDxY5eWN58lfRobniBV3I8zMmC/oQHf4YEPVTHMBxwU/s8MjbR38YjIICJdtkEAXHr4+NoAj8tsVIbQzWg=', + siteadmin: 4294967295, + links: + { 'mesh//1bc82505ef750af28b19292eaf2260eae83bc2939a367f1a885efe865b729193': [Object], + 'mesh//7b4b43cdad850135f36ab31124b52e47c167fba055ce800267a4dc89fe0e581c': [Object], + 'mesh//93c713c5cda428bb06777a7e7cd8075527f8a2f305945ac241852b37b1f30739': [Object], + 'mesh//acf0460d17df45ff977d2ceb3fcc84ced94a68bc67ef513bbdb1fc59a591bd5d': [Object], + 'mesh//sjN2rO85LGJCEXxW50TUI1vOCr@9zVpE4A@9jrAcPjA7n531RHZVMGpksK1yWY4O': [Object], + 'mesh//5LNNn8cM9vKaUFs91inT2SNpTXgp0mlmI6Q29kCFEmoypqxYDfjY5N7Ae3QxwIVO': [Object], + 'ugrp//BXQUCOnHMBI14nGBhfTkvMlmb2K3FcP09Bu@3jpffr3nn@hxsm5RlpNLWheqQqYJ': [Object] }, + login: 1584903356, + email: 'ysainthilaire@hotmail.com', + emailVerified: true, + passchange: 1584914891, + pastlogin: 1584903334 }, + { type: 'user', + _id: 'user//bb', + name: 'bb', + creation: 1584487582, + domain: '', + email: 'bb@bb.com', + passchange: 1584487582, + salt: 'mccoD17PKETFJ26DUPBpaMdBxQ64WpYgEnUFcHkkFY8E6+J3q74i6Eaj/DrAOwBlXcS0hzbjb1XbCTugoOrUQb2zB32H0Fv5VJjoRUwSu3kO7gYlRTX6V6Gw8vLgcZ6PcSAelL7+Km6Zd1pAx/aiG4iZ816q6L2R7rsg2p7n82A=', + hash: 'CEBlvxFURwI9rGX6n5ucBi+Ukec2waPe++2khiLR1il7SXcUd+XnLVcY34w2t2rFrP0i8RCoC/tLgACko1h/SfIgFf4DWtnQSZ0x4U7YDm9o7go7yhmmbUMaNm+tGNGDTVDeVFBvoiTleE949sIJuOZ6iYHYVdW6VwkUTmy5/Hg=' }, + { _id: 'user//bob', + type: 'user', + name: 'bob', + creation: 1523394756, + domain: '', + email: 'bob@bob.com', + salt: '53GmyHZq0DyCEqX8ndsU8gnv/2QfmRb3F/a03Rorl+X/wH7mG5GvvYtXL4aS+NWsr43Mm4jFx38qTmQi961ufGy8RWEKjo3FsAPFq3fnYJvBpmWCDPz8svPe5UtU6yGi8SPUWQD3d5fb4FZ4Qub49agVG52lMAoI7+XPee1aodw=', + hash: 'CtvD7IX3ytdJXmlbYEMRhSq0GuHVmis/a6qKGeJpb6MDvcB1MOPVuR3KMguPHxC2VQci0nkYosft/0V4RFxB1Y0OBCEo480Lprpce/TbJ1OvbUGxTpt0EJ3W8GFDrHW2MEyJlG0DTqrz5fM4cNS4zgYoM6XltEN4YYOcDvoeYFc=', + login: 1578349086, + links: { 'ugrp//BXQUCOnHMBI14nGBhfTkvMlmb2K3FcP09Bu@3jpffr3nn@hxsm5RlpNLWheqQqYJ': [Object] }, + siteadmin: 0, + pastlogin: 1578349086 }, + { _id: 'user//bryan', + type: 'user', + name: 'Bryan', + domain: '', + creation: 1373413118, + passtype: 1, + salt: 'GoMdgNplNW5Tq1LI38Fi0Q==', + hash: 'HSelSEKY8BJWdAV6D0PD4Gwiazg=', + links: { 'mesh//542dea438e6065bffa9318c149e9982440dba4ce6ba3ba2b577e0e127b6a7f24': [Object] }, + siteadmin: 0, + login: null, + groups: [ 'test' ] }, + { type: 'user', + _id: 'user//cc', + name: 'cc', + email: 'cc@cc.com', + creation: 1580415619, + login: 1580415619, + domain: '', + salt: 'JKaqzhk6DQDmhPejyA8F60DZ/XuCAY6nHX+jDvIwHVuYOrZU45uYf1R1VJI0UXKGpt/uin3xfdWw/dtfhDyJETKlOb3xdHg52UVJnpkUBrxlumgI/KitDqhmZ7skoKwJmJ8lRn7aN8+j1DJlbhBN9OuhyU8gttzrzbMWhStOHRo=', + hash: '6JpuKMQHg8FwS5PDA7yVqh2/NOlStVc7TGjLkP3ZO2ZqO4jFU8780UgdtEEGaRw8fHiby6gLqxLQZhzGb1cF5ormiH2HSI+n6TDET0GuTYYHnYNrSWXG+EZOEn/sOybqL1I7hXKUeI2bnewUtxRcml9oOifgDVuBbNRDoPrl7I8=', + links: { 'mesh//qbu74CK7bX8AYu9gqZNGSad1poraKWlyay0yCLrx8jPZ@d6$ZQX0XcwMThPWqqRQ': [Object] } }, + { _id: 'user//dd', + type: 'user', + name: 'dd', + email: 'dd@dd.com', + creation: 1551389245, + login: 1551389245, + domain: '', + passhint: '', + salt: 'HiFDC9cDOxGKHIohkudzflVT8kNMD8Uy60Qt6/LIahJuBCIxcH3rPIqu/kEdo/+YyrMuHs83mudkvLHrsgCJXz4khqbI4owsJrAJ5UGuGaLbh08coGgzpMDjoDlSoxL3nF09+/ZsL3kPIn3jVxKQeepBgN+Vd5paOOGEy0n3z8o=', + hash: '/ak7hzgp4zbPEjYTe7bvOtamDNsccm/oV1wdZ7DUc4M7AVpXSIiKKNfBCLXgfi5T4FcHs75VEvnCwYeZCbKAFYeN/d4TYOdnPM6fWgAGk//MCScdawbJrnB9fiVXOA6GYU/SyXbHxX2TaRprjKfhk+Zc0vPCauDpg3xzTzISMXo=' }, + { _id: 'user//demo', + type: 'user', + name: 'demo', + domain: '', + creation: 1428090949, + salt: 'sGIIlqmi5YN8+BEBOYI2Ub+TGV0nAcE7UdM7itv80HGriQKtAeajer18WdJIsfEvXwEMjqftvEmNE1QLafb7edZ4LVTSe90+mluRxQ6na+GauoXIazTHCola+Ke3ySpedWuHvnKPrwQEWtTFDAp6UjppfwFtd8W6yAPyzYJwpfM=', + hash: '0YfvLDm9NIMOHcbK9lQon+dH70vlQRnTW+b1BdQCBIcx4HyM6NpPeEs+nU6wqDk6nXwBp50OpBNmPLlCslpZAFg6R4sQzIJEcirb8GZnRaABDus8kq3Gq23DWp45j/uwQMAA6Z4orqXmr0OHEMB9Cr+p2jg+c01QTM2FU+TUvBc=', + links: {}, + login: 1513299316, + siteadmin: 0 }, + { _id: 'user//devbox\\default', + type: 'user', + name: 'DEVBOX\\Default', + domain: '', + sid: 'S-1-5-21-3031010259-3226202738-568380285-1001', + creation: 1548377831, + login: 1548377831 }, + { _id: 'user//eee', + creation: 1561833844, + domain: '', + email: 'eee@eee.com', + hash: 'ya2sbB16v1yiYcA/zS8glcrFZoB1uPpzu8kx5G0iELB87KDzMYr1M9WgecvYyhpYL27Qu+G1lM6w+cX1iHigUSB9stZRlBNy4r6go3IiZQqxIPQOwn5eWswgKqRXglAXfCp52b9WwcFLU31KklUZOadkSdGKk4b23ERhd8lMRkI=', + name: 'eee', + passchange: -1, + salt: 'ispJqptip9UX3yaSL7911MCAf577tXC4BF3h2PPGYIQPY4qw4QCMUwPvpo1bnKQUgKBuHVnZRtuyC/1dk87aEnmOgyoZVIhb4KSV8lzTDS1JkgT29ukxwngqbEaDnkzbc9vxQVboWTqveK+FMHqy6qzIVHOirqgfjv6PF26wWeE=', + type: 'user' }, + { _id: 'user//joe', + type: 'user', + name: 'joe', + email: 'joe@intel.com', + creation: 1551138573, + login: 1551138573, + domain: '', + passhint: '', + salt: 'z8lIYIkrHboKGo62rF5cyCfvHCrT2IQYpU6uufW5lMO0GWte+p8q9FEHct+xItY96azQmti8Cy/mczr5j53WPRtxnMtnf7DxI65GLJYrGqoQJ/InyNSYd0O4/r2tZlwn5hK8+/E8hi1MxuFBAGlC4guKAoS+W2x996POjgbqsu8=', + hash: 'q0UZypM0R2sk+VKDSXR7ouCMR/EYnaESJtNApE7ZxhHAjhDCxQQdnmTrSTvhPtp2seM9IOCK9YFjMR52sNxBfqtD1F+E4GcyaCxTC6NntEIMizVz1kw+hPmweo6u7Lu1EliDymHtrkmFvpqhfIb9b7ISpb7wL6LPsn7sfN1/R1o=', + groups: [ 'test' ] }, + { _id: 'user//joe.bob', + type: 'user', + name: 'joe.bob', + email: 'bob@bob.com', + creation: 1531530565, + login: 1531534497, + domain: '', + passhint: 'bob', + salt: '6P9m1LSHS+S1L7+HJO23pDBHn6eiZmAKXVckawjGNFPz8Py0zu6jDCcbP89lgnqLN8KjyWc7NO4dOPyL26QEkKOA2PghljDwjaWaCnX1EYkYDiJV3b4muHrQ0hVsdbYP/52gtRZAE5f0qM3xZjxfHz2dVyrRCFb+iNvCB/OiikQ=', + hash: 'yMsV9ATYiOcVOAjaH8Gxc6+jM28JwxsK0+GaA6b6Y8kL871sENd8/5nqi0QWYRKKahkpFe+xAaTdze/+/7vXt3Ly/WJsU7q8asZgORxqxWU0wsekFP2tnAjdiC/Grhj5euAXqft84p5aQHQt2PE/CoT+FOIVvUiM5gD/Iq1ev1M=', + links: + { 'mesh//1fHXfQIiCOOOFw8lkIlUnXSQ3A75kFrKw2PvGQFkaAsGCM7mz@3$Mrr5NbPNTmxy': [Object], + 'mesh//PleIaEpGvRNLCx6rLcsKOogtaKfEDI7Tm2YSPGUurBLqNzRgLPd4ZurifZonL$7X': [Object], + 'mesh//8kWnSpFr$cIj2YvibBdMkBxBlcuNZp0yBZQSoWV12DTZV2f@34wJi5CIPMSUoOou': [Object], + 'mesh//CWsMAU4u63zNLLvdmoZP8uPcg$lzLnVcC25buVmqI05r1Wxk3ngk1OEgyHoFg7Oa': [Object], + 'mesh//Gt0Eo1GNpJmQ1WRwvKeIhibHBQ2j@XOV@omqmvsf8ZY6k3oKswvDdjzPn1KA4IQf': [Object], + 'mesh//GXbvFkWNsVKJCBbTvhBHCgFAY5fayzcStTJeZ5TdDfLC0sDL5TDs1ALFm8hMFoQ9': [Object], + 'mesh//7z0GW8pppHVGDw@Rz$fb1E29GnA9yExEKASjAf$r$hyBMP0$BSH$rVqWKCwxQ7D6': [Object], + 'mesh//7b4b43cdad850135f36ab31124b52e47c167fba055ce800267a4dc89fe0e581c': [Object] } }, + { _id: 'user//mytestuser', + type: 'user', + name: 'MyTestUser', + email: 'a@a.com', + creation: 1541494376, + login: 1541494376, + domain: '', + passhint: 'a', + salt: '3bURHy0OVDLNGJrEyQGs2UBhktEoJao9p4dIPS+uZwWdzPCcCZr4r7/dWlsjFGyKqCoWoStR6XzIFGElAAW5eUq2dM7lG9GXvrp59TzizKwTUAJWyCTfCmoP2jbTBjFLr5umBNsapiBY1HXXJxoRpJJJDGCt0ysETgIYjJfWUN8=', + hash: 'VzMdJ9paS12tH3KM3yUsVJXYt6tB/LJ8jX3665otE4AmQgaxBOXiEVr5Ff8oYd6MPonr6D93ACUems0R0NiX4EjGcOveT1zNijjaVYxFRu2PzkKayxqeupZQvniz6HdrtptEa96GpWXqXJ0dzsVbMcpfEKz1Tjk5cFku3swfZYw=' }, + { _id: 'user//null', + type: 'user', + name: 'Test User', + creation: 1555017483, + login: 1555017682, + domain: '', + links: { 'mesh//k0nAuG45xS5TSYR3s1kT1XGUonCM48sGbuf6D8dDlYFSbbHcxqGk2daZrVC4D@dg': [Object] } }, + { _id: 'user//ppp', + type: 'user', + name: 'ppp', + creation: 1557712716, + domain: '', + siteadmin: 192, + email: 'ppp@ppp.com', + passchange: 1557712716, + salt: 'M83AO69eUNCOUlHAoMMf9PoYits3d2+G5ml76VxS8Fve46TOwCK5pwHhCur3iKNDDOOz0/OrzrF1axyiB2kzQUQvs1DZgZlO+1F9DpTI7avibLYljRlrs1KBm7Bb910VYjQNNvKKLI+h7ls45s1wUFgWF2EngpECv9tq05UoX4M=', + hash: 'RDR75KY2bypDWxJEgYznG+HjyCPR3GSJVI4bGtAu4C8XMvnB+4+2g47TKVb8nM9MpWj4/M4XWQ87VhJIMXoCQ5qg6SeWdIXL3ab1UpXSzn7fAeFspqrQ8A9ZcnfN+OARL2gLL8qSchonebVfL3BdDqTgc64pn1MhctQUvylsRYE=' }, + { _id: 'user//qqq', + type: 'user', + name: 'qqq', + email: 'qqq@qqq.com', + creation: 1549852967, + login: 1549853132, + domain: '', + passhint: 'allq', + salt: '+pzWoML4DMmYZ3y9DFMEwkJz/sal3qDKHKnhmVu352zzZPzXC+mL/hbmHOSi1Quw65tMMLtcjXn5cquMFToX1DlsURnuDbxaINuzZ9pec6dxIn26EJ8urZ00bVXTSusv2xhcJuYKEabC/gKWpe6E0VR8xctEUjjqAgP1BCOAifo=', + hash: 'n7gXwzoFS9UkTHQbbuuabGjCJmRadzWENmkjwMBnNrhQwG2qLeD5f/A1EPKIwr2P39J0cClFHPt25kX0PtItEyJO5wcnVrbESfc3Jsm6nG+Kze0ayW3Na+iEmnwWMDZYNgFe3k95ubOXzKl/CCUjuW4RAEwj5f631XoTS6ygW1Y=', + siteadmin: 32 }, + { _id: 'user//robert', + type: 'user', + name: 'Robert', + email: 'robert@bob.com', + creation: 1543864529, + login: 1543864529, + domain: '', + passhint: 'robert', + salt: '/brZFf8ljdG2eZAFgBl3CaMnY5FGYPB93S3Y97wym/kUAVkF5NHlDVVNfmghC97VzZuHnlIoFlt4IUHbZHSc4/KAOc4pX/ZcyicsacMXyW+4CtDgSllnXeejK0nkVV/AdJSwKMQZ3K5+77TvydXbwLFuGoZ0NVOzCto/CgaWtsQ=', + hash: 'X7OlXcp514ay/HXV2qDsAQVerr2jWGdCUAVnl6FVsvw4XN+jgBsq8E7f0RnuAZp/BFIlqkLaj8TqYtpFPR87LCJdcg8LZ3Y7ygyiZp0rdpztyxBAJ3YyiFRrSvJB/u4JM0GJ88WPCRK6CbHwBlhg4i+VRSMPetn1XiemubK1Qv8=', + links: {} }, + { _id: 'user//rrr', + creation: 1561919781, + domain: '', + email: 'rrr@rrrt.com', + hash: 'o85W/QlWhRXHrIeyw+L2TXWnW5MDr+Dc+66MeH58iCxKIh/aMuLdOD9on3ViNbW9Wqt4f7wKxjletFVhJYwmd/3VvPLBxdvZ4r3c4El9I49vGavCngqlaHc69ohh30KVEXUYy3zzxyOFn7HukSSkCMmnsq/IKIpA6ZVR95GNQ54=', + name: 'rrr', + passchange: 1561919781, + salt: '1crF6xIQlbO2GYPRPksF7HUu1ytB9zJrDl6zd09OYFdDEQRuK+DhCLPJq5CTJU5Tg7GjVmIq/rXqGKQFlvTZ2/cLmELwN9l9UQeBsiyb7lxSusU3SRTCbYAZV4aPy97xHw+F1JlLtEaXSJ0TM1WwcBECW/qJ4ZeIDpQfNUw6HAY=', + type: 'user' }, + { _id: 'user//sampleuser', + creation: 1562012207, + domain: '', + hash: 'clVpJBetcpCd20KcvCJ4K1cCdodNIHSZW11tR/PzKnZDek0XjLCINucUK1wbXbsmqvE36AXPFDy0URSmJB3ohjkP02TDl3mDUGg+tmM+0Gh9CGTzImRG0xnPLoUtBo5QpRBItLUEz2wzzHn3Pds4fecAUSZUGH2K+icFBWG/2BU=', + name: 'SampleUser', + passchange: 1562012207, + salt: 'XQ9F2M9E2kumUFxqxFv48UxDyhHQroBS46ud7e1iaDH1cGZ+V78YQ3fo58NjTn0XkiJmS1usxlu+qXQEbGSM5e8EAS3qK9rXdZ78CMm7+NEz8AoxkzpmAeICuIXikOP488eseXJYItZzbr3jOMjvKra+nw1kpeVRbW3R0XHVVtc=', + type: 'user' }, + { _id: 'user//test', + creation: 1562534252, + domain: '', + email: 'test@test.com', + hash: 'FYtXnIWEW7fIrZSNwGx/Rl5Blsvqpl1LGs8exXWYrNJc3X6UzS7+qziti+i5M1m4yjiQLp5JzGuJkfdVDexua6y5Ixh15dEsoLSndE0QOSa+7Yo01FEy5LGuwGd6Rbs1yRsH4P4pGyMZhj5DsaYGLeNKiXgcMqjTKAhF0VGXxVs=', + login: 1562534252, + name: 'test', + salt: 'Kj1I+Xf9Bh+3uMNpH/LNzmonk/+kOjaW2rRKEFAolqQ1ngELtkqeEipBESGUNvNDblx8kTiNIIFda9e4fdAxZlHuX/AAIiBpw2saS5zYUPtmFnoBom2PTIzurHNYYXBz8vS3VCcTFv3ZbW3tg38jYX8z5h6blNzgwI51GkgDOP4=', + type: 'user' }, + { _id: 'user//test.user', + creation: 1558462786, + domain: '', + email: 'test.user@user.com', + hash: 'RVL0gdctx/WMMlrRkflAMURL7UxN4c1jos6/ZzVSAcTXbOozfWJeE5JzCZQFNnze0OTSltq1WQtRk5dJFhum8KhKkUGe/dVvC+u4qPs27RmzNdc3rNLKDLPXKyPqe0008e0pkjPiEYBZAVj9Cy8r4Aew5mrgpx4/fBIhzGz/6bo=', + login: 1558462857, + name: 'test.user', + salt: 'hH8ABQQ0srookeRbjIcl5uDz7tDYZYotaPTgTQVaoPuXNwBdXJanrfPtIfPSuruZTUeEP5/2kWgEakfMO/on09iZgcuLCSvS4nySNZZuZ7VbApgmsqfNAtPOULrHMuZchsBtCvUwiyTAOKyXmUNDD8txnmlfZmyCnqF49nc0DnU=', + siteadmin: 0, + type: 'user', + links: { 'mesh//MAIhngk0XrQaFqDWpvBBrLnGwQWUTKQ6Aa8UMNFVJ9dmtZoAEkZF1DAMKsTHQbXt': [Object] }, + otphkeys: [ [Object] ], + otpkeys: { keys: [Object] }, + passchange: 1558473367 }, + { _id: 'user//testuser', + type: 'user', + name: 'TestUser', + creation: 1523658499, + domain: '', + email: 'testuser@meshcentral.com', + salt: 'KsM9DOWsz3Ub8Q1m5ex/Ge7XP6fBJ+MMA8LqjXmSRhLE0HWfv4uWAarWjZYYYM4/kWKZZSjkQWMMzCeZul3krBTogZRqMUar+VgKgZbjW0vX6NvMFn32Y2m+K/YSyl0XQoN09nmU5EN/RA95bkTz3RK/pXsOYVNdCcojs1uISj0=', + hash: 'uMO6etn7jwT1BBFqIY+DSqozcMIlpIAu9d4ruhxNmu/5smo/8M7Pvwa42tCza0bNsBNybPB6xOEYa4z+2W30WQ2dnN1AaHvRltdllxrPjmW0PjuD/4cNG+Z6Lb3v6R6QIUxYpUwo7gC87rM4+KyGiMFUq83VG67T4AcBxtKhzm4=', + siteadmin: 32, + login: null, + links: {} }, + { _id: 'user//x1', + type: 'user', + name: 'x1', + creation: 1557869247, + domain: '', + siteadmin: 192, + email: 'x1@x', + passchange: 1557869247, + salt: 'X3E7xiTou1fRcRr+Rf5xBnCd6M7RtKishIjZyu+dm5KayLm6D/CCFkR9zuTyxqzuw4NZlp994jCvegryqBow0Db8sstcs/Vp8A2l4WUGcaNW6Yy9zVomJZE9xHuqRlUUU1J8SIlnrBrpcu3nXp4LRI3UOLroGSLbO9ojzYHnn/g=', + hash: 'sc3wb1cP/R4lngyKmI4rqK1nXM4RCa+ZQmhbF48E6D8GejAynmR1kgTTGAqS22CPcTMdHmsxy+nZh0Pncmv5Z9HbxyGhrgFwkeIUYxrq7AO6A0w1dEIG99Qk/Pa3AZO0w917kUFSS7Dz94ZAouskm/F84lynUqSSolTqgpVCkJE=' }, + { _id: 'user//x2', + type: 'user', + name: 'x2', + creation: 1557869247, + domain: '', + siteadmin: 192, + email: 'x2@x', + passchange: -1, + salt: 'DFp2VFHhVfSpaqglMTLNpcsbARAqAx4uVb4j9V6az3tSrArGd7MSwQHpA69Jq91PZtw/dkqci3lkq9u74u7PSAttsA5z9IenGiTNGDBCSv5eDqGVHZdTWfcNw7CJM86shJ9NL1OEJR3owLnZFPir3f4ZeOV+GmuRhBLv5NFvBEA=', + hash: 'bQLaZ36j4QuUJnvtbs84qdfTHWn40sL3Qndv3Pn8GtAUy2zgJdx6LGEhPKOyfizONibD2D2kH9SFqFGUDoZX+tQWwao4HRqY9spp6DtvqZu8rza2JR0Kyx0WbfjRtR6yW5TnvQC+xHd/aaSFmefPK/lxViUrGyzvbBM4e455xts=' }, + { type: 'user', + _id: 'user//zz', + name: 'zz', + creation: 1577396990, + domain: '', + email: 'zz@zz.vcom', + passchange: 1577396990, + salt: 'KHt8U1w8t/50xXo+9zk5Hra8ypSIuR7fntQRfyg5dvq8TWohl7NP5fYQX+AEvnrsP9lhbYghBV6c68UgiIdUOje0rZh6XA/oHiHmfUzANALZeNp16Czrhb5k8bAFKI7is4A5Hw1sViA3cOgnNO4GhZqM1vmNgE0YuJPnVL1+y9Q=', + hash: 'Ng6aEiTYGuPXG+BfJ2mt3cSJzM3iZslOo/hoX5w/CdRux3gqFkQTzwyHagJCozWHi0hq2omV+O9hzJlPZUU1Er9n7s9Yn0ssVJbT7un93n33gqaKwf2PivMMHMMKNZb7gtkgFwOIiQOSKHPN/eNs29rTixWPqr6JyMByXygvOZ8=' }, + { _id: 'user/customer1/admin', + type: 'user', + name: 'admin', + email: 'admin@admin.com', + creation: 1554414308, + login: 1559319199, + domain: 'customer1', + siteadmin: 4294967295, + salt: 'qqjKAHNRtdwcGlRUmlb67dXL8cjR8kur5Mu5j0i0HPqVkCO/oDpyl/xHFMDRt2U4VRT8v5XaD/GDeqYDpA+h6Wy3cJiENpElQx49WKRFlfgyO6t26wSUXFQd5jDjr/XijnktR5LALXRbwCkozbFoyot4uRneXu44OxrSdDDRHaI=', + hash: '32JbzlVq9ge7o/6Qn4ii/a/oYWJRaXmDi/pVtRjPCZAFiR8bBu3gkY2JrimyMAOvkfwQJkrBNZRrDjB2BjvzWofy6BdCMzkhdnYpJ2kbeL16Nz3qqI3IauXI9E5SbYyG5DCo5ERCA75CGGexLH9vaVl8hT5K0N6sgDS/dAGT7u4=', + links: { 'mesh/customer1/EaSw1hJBKjf1QApmilFSAIo1KhA@R@dgRHIDAUUZBaMBGEYJw9qlhOa7p0xfWZvN': [Object] } }, + { _id: 'user/devtest/a', + type: 'user', + name: 'a', + email: 'ylian.saint-hilaire@intel.com', + creation: 1514930104, + login: 1515724646, + domain: 'devtest', + passhint: 'a', + siteadmin: 4294967295, + salt: 'g4aZeKUV0aPjzW8YpALfO7SYcyY03vdJVGNSowLqOlWZrFmnActIo+AvDb7ydC+DpSCWBq5fTHBj4Eol++PXeqyjcbVAKfMoZzGA6gdqNJ+UgabpzcddGm3oYEWcuEbvIzlLXSkZA+2LeXwRM9LbiRwH/dY0TrHVO2pwg8Hc3NU=', + hash: '1+l9Wi2xEmoKNEH1jNkQGfI+F1gSId/SL7qAjxfe/lu5QvoFE4X9d3kajaC2GtWn73ilB5qmThOFqbL3nqut84EgHDmGWlxEJfGFytZwN0JlJSrid9OSKbfvS1E4P6jPWnbOLyiiKMWYktFwX2aNHRJZktrwcx07xpNuK7T5zFw=', + links: { 'mesh/devtest/8CvC1wI7ivS289DcIUcMwXivGD2nKuj5jpUQ0qBd5Xd@R@jGkKSAA24A6UA9YRTe': [Object] }, + emailVerified: true }, + { _id: 'user/devtest/aa', + type: 'user', + name: 'aa', + email: 'aa@aa.com', + creation: 1552685405, + login: 1552685405, + domain: 'devtest', + salt: '7NX9z7hNOFXcVXGccbcyEs1en/dVf6SskT0wGMW46yR7sMWVPOGiCT9AdlaN6huYSbhCprFCu7YIqw4MYFboyq0bhGGAnovFSIVs+XcEjfIG7I7D00HDsRS7Cf5SO2SU8XEzjIr+RirYqZhEzRUQvnHEPNkJg8JT8GI1I+fYWLM=', + hash: 'wgh86y3OwRe+rcygmIYXuZGtetxoNuFKt2gBVClwxuS7tjYGLQu8Q9Hb4M7NWxCUFLUgq4JHmnvh0AMADGT+7NquDny6alTU5Yz8XUa0+qgiuUUX4LA5kuCoxxaqLIB/rsLoEMEMhFI9yRe0j3d1uAItVuHfyejl7+QvShkv26o=' }, + { _id: 'user/devtest/admin', + type: 'user', + name: 'admin', + email: 'admin@admin.com', + creation: 1552591371, + login: 1552692388, + domain: 'devtest', + salt: 'MOQqzm7q32/fk27Z00lPwGW1GTASDczli6lDt/7yb8eNhU6d1Wo5sF5Pl/TZcxmNrBzTiVOnqBQbAfwXTYj8fPazyUDarYQ5wYs7I2rVmH5IQAotBUaANwkFv5OBJ+JrlOqiJvoQLiB6yJwk9enQpbZw+2LJOLysPgNkXzAFtCg=', + hash: 'PXWMPJ6xNGlb9iUudI3uptVqZo5tz+fgK5/apDEaEr0W73pJAxekwpeiZy+gFkvdl7eSecYgnN6Krq5xoHbPC4cDNisLZYQNapBeVe5pjzHc7X3/kI364l/jiI2OVKT+GzfzS4sJYVaBvd+tledOFwn1PSzQ7UT4IP3YRywbI74=', + siteadmin: 4294967295, + links: + { 'mesh/devtest/vqbVBqGofP8h3l9Wxgk$$Dh3NgpvGCmaiNiMZLvuHdolSbF3W7@qvwpKbJP4i2Bd': [Object], + 'mesh/devtest/XJEZ5L3trxPBkZc@6E4CAXmzk2D@JvhAKf20RRMutxxE@H$dLW1Eo5PUVYb$k9UK': [Object] } } ]