Can now batch add users to a device group.

This commit is contained in:
Ylian Saint-Hilaire 2019-05-30 12:40:10 -07:00
parent 078745b97a
commit b0e2914f92
10 changed files with 59 additions and 38 deletions

View File

@ -154,7 +154,7 @@ module.exports.validateArray = function (array, minlen, maxlen) { return ((array
module.exports.validateStrArray = function (array, minlen, maxlen) { if (((array != null) && Array.isArray(array)) == false) return false; for (var i in array) { if ((typeof array[i] != 'string') && ((minlen == null) || (array[i].length >= minlen)) && ((maxlen == null) || (array[i].length <= maxlen))) return false; } return true; }; module.exports.validateStrArray = function (array, minlen, maxlen) { if (((array != null) && Array.isArray(array)) == false) return false; for (var i in array) { if ((typeof array[i] != 'string') && ((minlen == null) || (array[i].length >= minlen)) && ((maxlen == null) || (array[i].length <= maxlen))) return false; } return true; };
module.exports.validateObject = function (obj) { return ((obj != null) && (typeof obj == 'object')); }; module.exports.validateObject = function (obj) { return ((obj != null) && (typeof obj == 'object')); };
module.exports.validateEmail = function (email, minlen, maxlen) { if (module.exports.validateString(email, minlen, maxlen) == false) return false; var emailReg = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; return emailReg.test(email); }; module.exports.validateEmail = function (email, minlen, maxlen) { if (module.exports.validateString(email, minlen, maxlen) == false) return false; var emailReg = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; return emailReg.test(email); };
module.exports.validateUsername = function (username, minlen, maxlen) { return (module.exports.validateString(username, minlen, maxlen) && (username.indexOf(' ') == -1)); }; module.exports.validateUsername = function (username, minlen, maxlen) { return (module.exports.validateString(username, minlen, maxlen) && (username.indexOf(' ') == -1) && (username.indexOf('"') == -1) && (username.indexOf(',') == -1)); };
// Check password requirements // Check password requirements
module.exports.checkPasswordRequirements = function(password, requirements) { module.exports.checkPasswordRequirements = function(password, requirements) {

4
db.js
View File

@ -545,6 +545,10 @@ module.exports.CreateDB = function (parent, func) {
obj.dispose = function () { for (var x in obj) { if (obj[x].close) { obj[x].close(); } delete obj[x]; } }; obj.dispose = function () { for (var x in obj) { if (obj[x].close) { obj[x].close(); } delete obj[x]; } };
obj.getLocalAmtNodes = function (func) { obj.file.find({ type: 'node', host: { $exists: true, $ne: null }, intelamt: { $exists: true } }).toArray(func); }; obj.getLocalAmtNodes = function (func) { obj.file.find({ type: 'node', host: { $exists: true, $ne: null }, intelamt: { $exists: true } }).toArray(func); };
obj.getAmtUuidNode = function (meshid, uuid, func) { obj.file.find({ type: 'node', meshid: meshid, 'intelamt.uuid': uuid }).toArray(func); }; obj.getAmtUuidNode = function (meshid, uuid, func) { obj.file.find({ type: 'node', meshid: meshid, 'intelamt.uuid': uuid }).toArray(func); };
// TODO: Starting in MongoDB 4.0.3, you should use countDocuments() instead of count() that is deprecated. We should detect MongoDB version and switch.
// https://docs.mongodb.com/manual/reference/method/db.collection.countDocuments/
//obj.isMaxType = function (max, type, domainid, func) { if (max == null) { func(false); } else { obj.file.countDocuments({ type: type, domain: domainid }, function (err, count) { func((err != null) || (count > max)); }); } }
obj.isMaxType = function (max, type, domainid, func) { if (max == null) { func(false); } else { obj.file.count({ type: type, domain: domainid }, function (err, count) { func((err != null) || (count > max)); }); } } obj.isMaxType = function (max, type, domainid, func) { if (max == null) { func(false); } else { obj.file.count({ type: type, domain: domainid }, function (err, count) { func((err != null) || (count > max)); }); } }
// Database actions on the events collection // Database actions on the events collection

View File

@ -1478,16 +1478,8 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
case 'addmeshuser': case 'addmeshuser':
{ {
if (common.validateString(command.meshid, 1, 1024) == false) break; // Check the meshid if (common.validateString(command.meshid, 1, 1024) == false) break; // Check the meshid
if (common.validateString(command.username, 1, 64) == false) break; // Username is between 1 and 64 characters
if (common.validateInt(command.meshadmin) == false) break; // Mesh rights must be an integer if (common.validateInt(command.meshadmin) == false) break; // Mesh rights must be an integer
if (common.validateStrArray(command.usernames, 1, 64) == false) break; // Username is between 1 and 64 characters
// Check if the user exists
var newuserid = 'user/' + domain.id + '/' + command.username.toLowerCase(), newuser = parent.users[newuserid];
if (newuser == null) {
// Send error back, user not found.
displayNotificationMessage('User "' + EscapeHtml(command.username) + '" not found.', 'Device Group', 'ServerNotify');
break;
}
// Get the mesh // Get the mesh
mesh = parent.meshes[command.meshid]; mesh = parent.meshes[command.meshid];
@ -1496,20 +1488,34 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
if (mesh.links[user._id] == null || ((mesh.links[user._id].rights & 2) == 0)) return; if (mesh.links[user._id] == null || ((mesh.links[user._id].rights & 2) == 0)) return;
if ((command.meshid.split('/').length != 3) || (command.meshid.split('/')[1] != domain.id)) return; // Invalid domain, operation only valid for current domain if ((command.meshid.split('/').length != 3) || (command.meshid.split('/')[1] != domain.id)) return; // Invalid domain, operation only valid for current domain
// Add mesh to user var unknownUsers = [];
if (newuser.links == null) newuser.links = {}; for (var i in command.usernames) {
newuser.links[command.meshid] = { rights: command.meshadmin }; // Check if the user exists
db.SetUser(newuser); var newuserid = 'user/' + domain.id + '/' + command.usernames[i].toLowerCase(), newuser = parent.users[newuserid];
parent.parent.DispatchEvent([newuser._id], obj, 'resubscribe'); if (newuser != null) {
// Add mesh to user
if (newuser.links == null) newuser.links = {};
newuser.links[command.meshid] = { rights: command.meshadmin };
db.SetUser(newuser);
parent.parent.DispatchEvent([newuser._id], obj, 'resubscribe');
// Add a user to the mesh // Add a user to the mesh
mesh.links[newuserid] = { userid: newuser.id, name: newuser.name, rights: command.meshadmin }; mesh.links[newuserid] = { userid: newuser.id, name: newuser.name, rights: command.meshadmin };
db.Set(common.escapeLinksFieldName(mesh)); db.Set(common.escapeLinksFieldName(mesh));
// Notify mesh change // Notify mesh change
var event = { etype: 'mesh', username: newuser.name, userid: command.userid, 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 }; var event = { etype: 'mesh', username: newuser.name, userid: command.userid, 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 };
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. 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, newuserid], obj, event); parent.parent.DispatchEvent(['*', mesh._id, user._id, newuserid], obj, event);
} else {
unknownUsers.push(command.usernames[i]);
}
}
if (unknownUsers.length > 0) {
// Send error back, user not found.
displayNotificationMessage('User' + ((unknownUsers.length > 1)?'s':'') + ' ' + EscapeHtml(unknownUsers.join(', ')) + ' not found.', 'Device Group', 'ServerNotify');
}
} }
break; break;
} }

View File

@ -1,6 +1,6 @@
{ {
"name": "meshcentral", "name": "meshcentral",
"version": "0.3.5-n", "version": "0.3.5-o",
"keywords": [ "keywords": [
"Remote Management", "Remote Management",
"Intel AMT", "Intel AMT",

File diff suppressed because one or more lines are too long

View File

@ -6183,7 +6183,7 @@
for (var i in sortedusers) { for (var i in sortedusers) {
var trash = '', rights = 'Partial Rights', r = sortedusers[i].rights; var trash = '', rights = 'Partial Rights', r = sortedusers[i].rights;
if (r == 0xFFFFFFFF) rights = 'Full Administrator'; else if (r == 0) rights = 'No Rights'; if (r == 0xFFFFFFFF) rights = 'Full Administrator'; else if (r == 0) rights = 'No Rights';
if ((i != userinfo._id) && (meshrights == 0xFFFFFFFF || (((meshrights & 2) != 0)))) { trash = '<a onclick=p20deleteUser(event,"' + encodeURIComponent(sortedusers[i].id) + '") title="Remote user rights to this mesh" style=cursor:pointer><img src=images/trash.png border=0 height=10 width=10></a>'; } if ((sortedusers[i].id != userinfo._id) && (meshrights == 0xFFFFFFFF || (((meshrights & 2) != 0)))) { trash = '<a onclick=p20deleteUser(event,"' + encodeURIComponent(sortedusers[i].id) + '") title="Remote user rights to this mesh" style=cursor:pointer><img src=images/trash.png border=0 height=10 width=10></a>'; }
x += '<tr onclick=p20viewuser("' + encodeURIComponent(sortedusers[i].id) + '") style=cursor:pointer' + (((count % 2) == 0) ? ';background-color:#DDD' : '') + '><td><div title="User" class=m2></div><div>&nbsp;' + EscapeHtml(decodeURIComponent(sortedusers[i].name)) + '<div></div></div></td><td><div style=float:right>' + trash + '</div><div>' + rights + '</div></td></tr>'; x += '<tr onclick=p20viewuser("' + encodeURIComponent(sortedusers[i].id) + '") style=cursor:pointer' + (((count % 2) == 0) ? ';background-color:#DDD' : '') + '><td><div title="User" class=m2></div><div>&nbsp;' + EscapeHtml(decodeURIComponent(sortedusers[i].name)) + '<div></div></div></td><td><div style=float:right>' + trash + '</div><div>' + rights + '</div></td></tr>';
++count; ++count;
} }
@ -6335,10 +6335,10 @@
function p20showAddMeshUserDialog() { function p20showAddMeshUserDialog() {
if (xxdialogMode) return; if (xxdialogMode) return;
var x = "Allow a user to manage this device group and devices in this group."; var x = "Allow users to manage this device group and devices in this group.";
if (features & 0x00080000) { x += " Users need to login to this server once before they can be added to a device group." } if (features & 0x00080000) { x += " Users need to login to this server once before they can be added to a device group." }
x += "<br /><br />"; x += "<br /><br />";
x += addHtmlValue('User Name', '<input id=dp20username style=width:230px maxlength=32 onchange=p20validateAddMeshUserDialog() onkeyup=p20validateAddMeshUserDialog() />'); x += addHtmlValue('User Names', '<input id=dp20username style=width:230px maxlength=32 onchange=p20validateAddMeshUserDialog() onkeyup=p20validateAddMeshUserDialog() placeholder="user1, user2, user3" />');
x += '<br><div style="height:120px;overflow-y:scroll;border:1px solid gray">'; x += '<br><div style="height:120px;overflow-y:scroll;border:1px solid gray">';
x += '<input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20fulladmin>Full Administrator<br>'; x += '<input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20fulladmin>Full Administrator<br>';
x += '<input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20editmesh>Edit Device Group<br>'; x += '<input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20editmesh>Edit Device Group<br>';
@ -6355,14 +6355,16 @@
x += '<input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20wakedevices>Wake Devices<br>'; x += '<input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20wakedevices>Wake Devices<br>';
x += '<input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20editnotes>Edit Device Notes<br>'; x += '<input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20editnotes>Edit Device Notes<br>';
x += '</div>'; x += '</div>';
setDialogMode(2, "Add User to Device Group", 3, p20showAddMeshUserDialogEx, x); setDialogMode(2, "Add Users to Device Group", 3, p20showAddMeshUserDialogEx, x);
p20validateAddMeshUserDialog(); p20validateAddMeshUserDialog();
Q('dp20username').focus(); Q('dp20username').focus();
} }
function p20validateAddMeshUserDialog() { function p20validateAddMeshUserDialog() {
var meshrights = currentMesh.links[userinfo._id].rights; var meshrights = currentMesh.links[userinfo._id].rights;
QE('idx_dlgOkButton', (Q('dp20username').value.length > 0)); var ok = true, users = Q('dp20username').value.split(',');
for (var i in users) { var user = users[i].trim(); if (user.length == 0) { ok = false; } else if (user.indexOf('"') >= 0) { ok = false; } }
QE('idx_dlgOkButton', ok);
QE('p20fulladmin', meshrights == 0xFFFFFFFF); QE('p20fulladmin', meshrights == 0xFFFFFFFF);
QE('p20editmesh', (!Q('p20fulladmin').checked) && (meshrights == 0xFFFFFFFF)); QE('p20editmesh', (!Q('p20fulladmin').checked) && (meshrights == 0xFFFFFFFF));
QE('p20manageusers', !Q('p20fulladmin').checked); QE('p20manageusers', !Q('p20fulladmin').checked);
@ -6396,7 +6398,10 @@
if (Q('p20noamt').checked == true) meshadmin += 2048; if (Q('p20noamt').checked == true) meshadmin += 2048;
if (Q('p20remotelimitedinput').checked == true) meshadmin += 4096; if (Q('p20remotelimitedinput').checked == true) meshadmin += 4096;
} }
meshserver.send({ action: 'addmeshuser', meshid: currentMesh._id, meshname: currentMesh.name, username: Q('dp20username').value , meshadmin: meshadmin});
var users = Q('dp20username').value.split(','), users2 = [];
for (var i in users) { users2.push(users[i].trim()); }
meshserver.send({ action: 'addmeshuser', meshid: currentMesh._id, meshname: currentMesh.name, usernames: users2, meshadmin: meshadmin });
} }
function p20viewuser(userid) { function p20viewuser(userid) {
@ -6421,9 +6426,9 @@
r = r.substring(2); r = r.substring(2);
if (r == '') { r = 'No Rights'; } if (r == '') { r = 'No Rights'; }
var uname = userid.split('/')[2]; var uname = userid.split('/')[2];
if (users) { uname = users[userid].name; } if (users && users[userid]) { uname = users[userid].name; }
if (userinfo._id == userid) { uname = userinfo.name; } if (userinfo._id == userid) { uname = userinfo.name; }
var buttons = 1, x = addHtmlValue('User Name', EscapeHtml(uname)); var buttons = 1, x = addHtmlValue('User Name', EscapeHtml(decodeURIComponent(uname)));
if (userid.split('/')[2] != uname) { x += addHtmlValue('User Identifier', EscapeHtml(userid.split('/')[2])); } if (userid.split('/')[2] != uname) { x += addHtmlValue('User Identifier', EscapeHtml(userid.split('/')[2])); }
x += addHtmlValue('Permissions', r); x += addHtmlValue('Permissions', r);
@ -6431,9 +6436,15 @@
setDialogMode(2, "Device Group User", buttons, p20viewuserEx, x, userid); setDialogMode(2, "Device Group User", buttons, p20viewuserEx, x, userid);
} }
function p20viewuserEx(button, userid) { if (button != 2) return; setDialogMode(2, "Remote Mesh User", 3, p20viewuserEx2, "Confirm removal of user " + userid.split('/')[2] + "?", userid); } function p20viewuserEx(button, userid) {
if (button != 2) return;
var uname = userid.split('/')[2];
if (users && users[userid]) { uname = users[userid].name; }
if (userinfo._id == userid) { uname = userinfo.name; }
setDialogMode(2, "Remote Mesh User", 3, p20viewuserEx2, "Confirm removal of user " + EscapeHtml(decodeURIComponent(uname)) + "?", userid);
}
function p20deleteUser(e, userid) { haltEvent(e); p20viewuserEx(2, decodeURIComponent(userid)); } function p20deleteUser(e, userid) { haltEvent(e); p20viewuserEx(2, decodeURIComponent(userid)); }
function p20viewuserEx2(button, userid) { meshserver.send({ action: 'removemeshuser', meshid: currentMesh._id, meshname: currentMesh.name, userid: userid}); } function p20viewuserEx2(button, userid) { meshserver.send({ action: 'removemeshuser', meshid: currentMesh._id, meshname: currentMesh.name, userid: userid }); }
// //
// MY FILES // MY FILES

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -391,7 +391,7 @@
function validateCreate(box,e) { function validateCreate(box,e) {
setDialogMode(0); setDialogMode(0);
var ok = ((Q('ausername').value.length > 0) && (Q('ausername').value.indexOf(' ') == -1) && (validateEmail(Q('aemail').value) == true) && (Q('apassword1').value.length > 0) && (Q('apassword2').value == Q('apassword1').value)); var ok = ((Q('ausername').value.length > 0) && (Q('ausername').value.indexOf('"') == -1) && (Q('ausername').value.indexOf(',') == -1) && (Q('ausername').value.indexOf(' ') == -1) && (validateEmail(Q('aemail').value) == true) && (Q('apassword1').value.length > 0) && (Q('apassword2').value == Q('apassword1').value));
if ((newAccountPass == 1) && (Q('anewaccountpass').value.length == 0)) { ok = false; } if ((newAccountPass == 1) && (Q('anewaccountpass').value.length == 0)) { ok = false; }
if (Q('apassword1').value == '') { if (Q('apassword1').value == '') {
QH('passWarning', ''); QH('passWarning', '');

View File

@ -402,7 +402,7 @@
function validateCreate(box, e) { function validateCreate(box, e) {
setDialogMode(0); setDialogMode(0);
var userok = (Q('ausername').value.length > 0) && (Q('ausername').value.indexOf(' ') == -1); var userok = (Q('ausername').value.length > 0) && (Q('ausername').value.indexOf(' ') == -1) && (Q('ausername').value.indexOf('"') == -1) && (Q('ausername').value.indexOf(',') == -1);
var emailok = (validateEmail(Q('aemail').value) == true); var emailok = (validateEmail(Q('aemail').value) == true);
var pass1ok = (Q('apassword1').value.length > 0); var pass1ok = (Q('apassword1').value.length > 0);
var pass2ok = (Q('apassword2').value.length > 0) && (Q('apassword2').value == Q('apassword1').value); var pass2ok = (Q('apassword2').value.length > 0) && (Q('apassword2').value == Q('apassword1').value);