Initial work on cross-domain administrator.

This commit is contained in:
Ylian Saint-Hilaire 2020-05-27 03:35:43 -07:00
parent d8bebb719e
commit 288813ccda
4 changed files with 468 additions and 408 deletions

View File

@ -64,6 +64,9 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
obj.domain = domain;
obj.ws = ws;
// Check if we are a cross-domain administrator
if (parent.parent.config.settings.managecrossdomain && (parent.parent.config.settings.managecrossdomain.indexOf(user._id) >= 0)) { obj.crossDomain = true; }
// Server side Intel AMT stack
const WsmanComm = require('./amt/amt-wsman-comm.js');
const Wsman = require('./amt/amt-wsman.js');
@ -281,7 +284,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
// Handle events
ws.HandleEvent = function (source, event, ids, id) {
if ((event.domain == null) || (event.domain == domain.id)) {
if ((event.domain == null) || (event.domain == domain.id) || (obj.crossDomain === true)) {
try {
if (event == 'close') { try { delete req.session; } catch (ex) { } obj.close(); }
else if (event == 'resubscribe') { user.subscriptions = parent.subscribe(user._id, ws); }
@ -400,7 +403,10 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
// Send user information to web socket, this is the first thing we send
try {
var xuserinfo = parent.CloneSafeUser(parent.users[user._id]);
if ((user.siteadmin == 0xFFFFFFFF) && (parent.parent.config.settings.managealldevicegroups.indexOf(user._id) >= 0)) { xuserinfo.manageAllDeviceGroups = true; }
if (user.siteadmin == 0xFFFFFFFF) {
if (parent.parent.config.settings.managealldevicegroups.indexOf(user._id) >= 0) { xuserinfo.manageAllDeviceGroups = true; }
if (obj.crossDomain === true) { xuserinfo.crossDomain = []; for (var i in parent.parent.config.domains) { xuserinfo.crossDomain.push(i); } }
}
ws.send(JSON.stringify({ action: 'userinfo', userinfo: xuserinfo }));
} catch (ex) { }
@ -1291,9 +1297,9 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
if ((user.siteadmin & 2) == 0) break;
var docs = [];
for (i in parent.users) {
if ((parent.users[i].domain == domain.id) && (parent.users[i].name != '~')) {
if (((obj.crossDomain === true) || (parent.users[i].domain == domain.id)) && (parent.users[i].name != '~')) {
// If we are part of a user group, we can only see other members of our own group
if ((user.groups == null) || (user.groups.length == 0) || ((parent.users[i].groups != null) && (findOne(parent.users[i].groups, user.groups)))) {
if ((obj.crossDomain === true) || (user.groups == null) || (user.groups.length == 0) || ((parent.users[i].groups != null) && (findOne(parent.users[i].groups, user.groups)))) {
docs.push(parent.CloneSafeUser(parent.users[i]));
}
}
@ -1430,8 +1436,10 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
}
case 'deleteuser':
{
console.log(command);
// Delete a user account
var err = null, delusersplit, deluserid, deluser;
var err = null, delusersplit, deluserid, deluser, deluserdomain;
try {
if ((user.siteadmin & 2) == 0) { err = 'Permission denied'; }
else if (common.validateString(command.userid, 1, 2048) == false) { err = 'Invalid userid'; }
@ -1440,12 +1448,17 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
deluserid = command.userid;
deluser = parent.users[deluserid];
if (deluser == null) { err = 'User does not exists'; }
else if ((delusersplit.length != 3) || (delusersplit[1] != domain.id)) { err = 'Invalid domain'; } // Invalid domain, operation only valid for current domain
else if ((obj.crossDomain !== true) && ((delusersplit.length != 3) || (delusersplit[1] != domain.id))) { err = 'Invalid domain'; } // Invalid domain, operation only valid for current domain
else if ((deluser.siteadmin == 0xFFFFFFFF) && (user.siteadmin != 0xFFFFFFFF)) { err = 'Permission denied'; } // Need full admin to remote another administrator
else if ((user.groups != null) && (user.groups.length > 0) && ((deluser.groups == null) || (findOne(deluser.groups, user.groups) == false))) { err = 'Invalid user group'; } // Can only perform this operation on other users of our group.
else if ((obj.crossDomain !== true) && (user.groups != null) && (user.groups.length > 0) && ((deluser.groups == null) || (findOne(deluser.groups, user.groups) == false))) { err = 'Invalid user group'; } // Can only perform this operation on other users of our group.
}
} catch (ex) { err = 'Validation exception: ' + ex; }
// Get domain
deluserdomain = domain;
if (obj.crossDomain === true) { deluserdomain = parent.parent.config.domains[delusersplit[1]]; }
if (deluserdomain == null) { err = 'Invalid domain'; }
// Handle any errors
if (err != null) {
if (command.responseid != null) { try { ws.send(JSON.stringify({ action: 'deleteuser', responseid: command.responseid, result: err })); } catch (ex) { } }
@ -1464,13 +1477,13 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
// 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 };
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: deluserdomain.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(parent.CreateMeshDispatchTargets(mesh, [deluser._id, user._id]), obj, event);
}
} else if (i.startsWith('node/')) {
// Get the node and the rights for this node
parent.GetNodeWithRights(domain, deluser, i, function (node, rights, visible) {
parent.GetNodeWithRights(deluserdomain, deluser, i, function (node, rights, visible) {
if ((node == null) || (node.links == null) || (node.links[deluser._id] == null)) return;
// Remove the link and save the node to the database
@ -1479,7 +1492,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
db.Set(parent.cleanDevice(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) }
var event = { etype: 'node', userid: user._id, username: user.name, action: 'changenode', nodeid: node._id, domain: deluserdomain.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(parent.CreateNodeDispatchTargets(node.meshid, node._id), obj, event);
});
@ -1503,7 +1516,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
var targets = ['*', 'server-users'];
if (deluser.groups) { for (var i in deluser.groups) { targets.push('server-users:' + i); } }
parent.parent.DispatchEvent(targets, obj, { etype: 'user', userid: deluserid, username: deluser.name, action: 'accountremove', msg: 'Account removed', domain: domain.id });
parent.parent.DispatchEvent(targets, obj, { etype: 'user', userid: deluserid, username: deluser.name, action: 'accountremove', msg: 'Account removed', domain: deluserdomain.id });
parent.parent.DispatchEvent([deluserid], obj, 'close');
if (command.responseid != null) { try { ws.send(JSON.stringify({ action: 'deleteuser', responseid: command.responseid, result: 'ok' })); } catch (ex) { } }
@ -1634,23 +1647,26 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
if (command.randomPassword === true) { command.pass = getRandomPassword(); }
// Add a new user account
var err = null, newusername, newuserid;
var err = null, newusername, newuserid, newuserdomain;
try {
if ((user.siteadmin & 2) == 0) { err = 'Permission denied'; }
else if ((domain.auth == 'sspi') || (domain.auth == 'ldap')) { err = 'Unable to add user in this mode'; }
else if (common.validateUsername(command.username, 1, 256) == false) { err = 'Invalid username'; } // Username is between 1 and 64 characters, no spaces
else if ((command.username[0] == '~') || (command.username.indexOf('/') >= 0)) { err = 'Invalid username'; } // Usernames cant' start with ~ and can't have '/'
else if (common.validateString(command.pass, 1, 256) == false) { err = 'Invalid password'; } // Password is between 1 and 256 characters
else if ((command.randomPassword !== true) && (common.checkPasswordRequirements(command.pass, domain.passwordrequirements) == false)) { err = 'Invalid password'; } // Password does not meet requirements
else if ((command.email != null) && (common.validateEmail(command.email, 1, 1024) == false)) { err = 'Invalid email'; } // Check if this is a valid email address
else if ((obj.crossDomain === true) && (command.domain != null) && ((typeof command.domain != 'string') || (parent.parent.config.domains[command.domain] == null))) { err = 'Invalid domain'; } // Check if this is a valid domain
else {
newuserdomain = domain;
if ((obj.crossDomain === true) && (command.domain != null)) { newuserdomain = parent.parent.config.domains[command.domain]; }
newusername = command.username;
newuserid = 'user/' + domain.id + '/' + command.username.toLowerCase();
newuserid = 'user/' + newuserdomain.id + '/' + command.username.toLowerCase();
if (command.siteadmin != null) {
if ((typeof command.siteadmin != 'number') || (Number.isInteger(command.siteadmin) == false)) { err = 'Invalid site permissions'; } // Check permissions
else if ((user.siteadmin != 0xFFFFFFFF) && ((command.siteadmin & (0xFFFFFFFF - 224)) != 0)) { err = 'Invalid site permissions'; }
}
if (parent.users[newuserid]) { err = 'User already exists'; } // Account already exists
else if ((newuserdomain.auth == 'sspi') || (newuserdomain.auth == 'ldap')) { err = 'Unable to add user in this mode'; }
}
} catch (ex) { err = 'Validation exception'; }
@ -1666,7 +1682,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
}
// Check if we exceed the maximum number of user accounts
db.isMaxType(domain.limits.maxuseraccounts, 'user', domain.id, function (maxExceed) {
db.isMaxType(newuserdomain.limits.maxuseraccounts, 'user', newuserdomain.id, function (maxExceed) {
if (maxExceed) {
// Account count exceed, do notification
if (command.responseid != null) {
@ -1674,21 +1690,21 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
try { ws.send(JSON.stringify({ action: 'adduser', responseid: command.responseid, result: 'maxUsersExceed' })); } catch (ex) { }
} else {
// Create the notification message
var notification = { action: 'msg', type: 'notify', id: Math.random(), value: "Account limit reached.", title: "Server Limit", userid: user._id, username: user.name, domain: domain.id };
var notification = { action: 'msg', type: 'notify', id: Math.random(), value: "Account limit reached.", title: "Server Limit", userid: user._id, username: user.name, domain: newuserdomain.id };
// Get the list of sessions for this user
var sessions = parent.wssessions[user._id];
if (sessions != null) { for (i in sessions) { try { if (sessions[i].domainid == domain.id) { sessions[i].send(JSON.stringify(notification)); } } catch (ex) { } } }
if (sessions != null) { for (i in sessions) { try { if (sessions[i].domainid == newuserdomain.id) { sessions[i].send(JSON.stringify(notification)); } } catch (ex) { } } }
// TODO: Notify all sessions on other peers.
}
} else {
// Remove any events for this userid
if (command.removeEvents === true) { db.RemoveAllUserEvents(domain.id, newuserid); }
if (command.removeEvents === true) { db.RemoveAllUserEvents(newuserdomain.id, newuserid); }
// Create a new user
var newuser = { type: 'user', _id: newuserid, name: newusername, creation: Math.floor(Date.now() / 1000), domain: domain.id };
var newuser = { type: 'user', _id: newuserid, name: newusername, creation: Math.floor(Date.now() / 1000), domain: newuserdomain.id };
if (command.siteadmin != null) { newuser.siteadmin = command.siteadmin; }
else if (domain.newaccountsrights) { newuser.siteadmin = domain.newaccountsrights; }
else if (newuserdomain.newaccountsrights) { newuser.siteadmin = newuserdomain.newaccountsrights; }
if (command.email != null) { newuser.email = command.email.toLowerCase(); if (command.emailVerified === true) { newuser.emailVerified = true; } } // Email
if (command.resetNextLogin === true) { newuser.passchange = -1; } else { newuser.passchange = Math.floor(Date.now() / 1000); }
if (user.groups) { newuser.groups = user.groups; } // New accounts are automatically part of our groups (Realms).
@ -1705,16 +1721,16 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
var event, targets = ['*', 'server-users'];
if (newuser.groups) { for (var i in newuser.groups) { targets.push('server-users:' + i); } }
if (command.email == null) {
event = { etype: 'user', userid: newuser._id, username: newusername, account: parent.CloneSafeUser(newuser), action: 'accountcreate', msg: 'Account created, username is ' + command.username, domain: domain.id };
event = { etype: 'user', userid: newuser._id, username: newusername, account: parent.CloneSafeUser(newuser), action: 'accountcreate', msg: 'Account created, username is ' + command.username, domain: newuserdomain.id };
} else {
event = { etype: 'user', userid: newuser._id, username: newusername, account: parent.CloneSafeUser(newuser), action: 'accountcreate', msg: 'Account created, email is ' + command.email.toLowerCase(), domain: domain.id };
event = { etype: 'user', userid: newuser._id, username: newusername, account: parent.CloneSafeUser(newuser), action: 'accountcreate', msg: 'Account created, email is ' + command.email.toLowerCase(), domain: newuserdomain.id };
}
if (parent.db.changeStream) { event.noact = 1; } // If DB change stream is active, don't use this event to create the user. Another event will come.
parent.parent.DispatchEvent(targets, obj, event);
// Perform email invitation
if ((command.emailInvitation == true) && (command.emailVerified == true) && command.email && parent.parent.mailserver) {
parent.parent.mailserver.sendAccountInviteMail(domain, user.name, newusername, command.email.toLowerCase(), command.pass, parent.getLanguageCodes(req));
parent.parent.mailserver.sendAccountInviteMail(newuserdomain, user.name, newusername, command.email.toLowerCase(), command.pass, parent.getLanguageCodes(req));
}
// Log in the auth log
@ -1732,78 +1748,85 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
}
case 'edituser':
{
// Must be user administrator or edit self.
if (((user.siteadmin & 2) == 0) && (user._id != command.id)) break;
// Edit a user account, may involve changing email or administrator permissions
if (((user.siteadmin & 2) != 0) || (user._id == command.id)) {
var chguser = parent.users[command.id];
change = 0;
if (chguser) {
// If the target user is admin and we are not admin, no changes can be made.
if ((chguser.siteadmin == 0xFFFFFFFF) && (user.siteadmin != 0xFFFFFFFF)) return;
var chguser = parent.users[command.id];
change = 0;
if (chguser) {
// If the target user is admin and we are not admin, no changes can be made.
if ((chguser.siteadmin == 0xFFFFFFFF) && (user.siteadmin != 0xFFFFFFFF)) return;
// Can only perform this operation on other users of our group.
if (user.siteadmin != 0xFFFFFFFF) {
if ((user.groups != null) && (user.groups.length > 0) && ((chguser.groups == null) || (findOne(chguser.groups, user.groups) == false))) return;
}
// Can only perform this operation on other users of our group.
if (user.siteadmin != 0xFFFFFFFF) {
if ((user.groups != null) && (user.groups.length > 0) && ((chguser.groups == null) || (findOne(chguser.groups, user.groups) == false))) return;
}
// Validate and change email
if (domain.usernameisemail !== true) {
if (common.validateString(command.email, 1, 1024) && (chguser.email != command.email)) { chguser.email = command.email.toLowerCase(); change = 1; }
}
// Fetch and validate the user domain
var edituserdomainid = command.id.split('/')[1];
if ((obj.crossDomain !== true) && (edituserdomainid != domain.id)) break;
var edituserdomain = parent.parent.config.domains[edituserdomainid];
if (edituserdomain == null) break;
// Make changes
if ((command.emailVerified === true || command.emailVerified === false) && (chguser.emailVerified != command.emailVerified)) { chguser.emailVerified = command.emailVerified; change = 1; }
if ((common.validateInt(command.quota, 0) || command.quota == null) && (command.quota != chguser.quota)) { chguser.quota = command.quota; if (chguser.quota == null) { delete chguser.quota; } change = 1; }
if ((command.consent != null) && (typeof command.consent == 'number')) { if (command.consent == 0) { delete chguser.consent; } else { chguser.consent = command.consent; } change = 1; }
if ((command.phone != null) && (typeof command.phone == 'string') && ((command.phone == '') || isPhoneNumber(command.phone))) { if (command.phone == '') { delete chguser.phone; } else { chguser.phone = command.phone; } change = 1; }
// Validate and change email
if (edituserdomain.usernameisemail !== true) {
if (common.validateString(command.email, 1, 1024) && (chguser.email != command.email)) { chguser.email = command.email.toLowerCase(); change = 1; }
}
// Site admins can change any server rights, user managers can only change AccountLock, NoMeshCmd and NoNewGroups
if (chguser._id !== user._id) { // We can't change our own siteadmin permissions.
var chgusersiteadmin = chguser.siteadmin ? chguser.siteadmin : 0;
if (((user.siteadmin == 0xFFFFFFFF) || ((user.siteadmin & 2) && (((chgusersiteadmin ^ command.siteadmin) & 0xFFFFFF1F) == 0))) && common.validateInt(command.siteadmin) && (chguser.siteadmin != command.siteadmin)) { chguser.siteadmin = command.siteadmin; change = 1; }
}
// Make changes
if ((command.emailVerified === true || command.emailVerified === false) && (chguser.emailVerified != command.emailVerified)) { chguser.emailVerified = command.emailVerified; change = 1; }
if ((common.validateInt(command.quota, 0) || command.quota == null) && (command.quota != chguser.quota)) { chguser.quota = command.quota; if (chguser.quota == null) { delete chguser.quota; } change = 1; }
if ((command.consent != null) && (typeof command.consent == 'number')) { if (command.consent == 0) { delete chguser.consent; } else { chguser.consent = command.consent; } change = 1; }
if ((command.phone != null) && (typeof command.phone == 'string') && ((command.phone == '') || isPhoneNumber(command.phone))) { if (command.phone == '') { delete chguser.phone; } else { chguser.phone = command.phone; } change = 1; }
// When sending a notification about a group change, we need to send to all the previous and new groups.
var allTargetGroups = chguser.groups;
if ((Array.isArray(command.groups)) && ((user._id != command.id) || (user.siteadmin == 0xFFFFFFFF))) {
if (command.groups.length == 0) {
// Remove the user groups
if (chguser.groups != null) { delete chguser.groups; change = 1; }
} else {
// Arrange the user groups
var groups2 = [];
for (var i in command.groups) {
if (typeof command.groups[i] == 'string') {
var gname = command.groups[i].trim().toLowerCase();
if ((gname.length > 0) && (gname.length <= 64) && (groups2.indexOf(gname) == -1)) { groups2.push(gname); }
}
// Site admins can change any server rights, user managers can only change AccountLock, NoMeshCmd and NoNewGroups
if (chguser._id !== user._id) { // We can't change our own siteadmin permissions.
var chgusersiteadmin = chguser.siteadmin ? chguser.siteadmin : 0;
if (((user.siteadmin == 0xFFFFFFFF) || ((user.siteadmin & 2) && (((chgusersiteadmin ^ command.siteadmin) & 0xFFFFFF1F) == 0))) && common.validateInt(command.siteadmin) && (chguser.siteadmin != command.siteadmin)) { chguser.siteadmin = command.siteadmin; change = 1; }
}
// When sending a notification about a group change, we need to send to all the previous and new groups.
var allTargetGroups = chguser.groups;
if ((Array.isArray(command.groups)) && ((user._id != command.id) || (user.siteadmin == 0xFFFFFFFF))) {
if (command.groups.length == 0) {
// Remove the user groups
if (chguser.groups != null) { delete chguser.groups; change = 1; }
} else {
// Arrange the user groups
var groups2 = [];
for (var i in command.groups) {
if (typeof command.groups[i] == 'string') {
var gname = command.groups[i].trim().toLowerCase();
if ((gname.length > 0) && (gname.length <= 64) && (groups2.indexOf(gname) == -1)) { groups2.push(gname); }
}
groups2.sort();
// Set the user groups (Realms)
if (chguser.groups != groups2) { chguser.groups = groups2; change = 1; }
// Add any missing groups in the target list
if (allTargetGroups == null) { allTargetGroups = []; }
for (var i in groups2) { if (allTargetGroups.indexOf(i) == -1) { allTargetGroups.push(i); } }
}
}
groups2.sort();
if (change == 1) {
// Update the user
db.SetUser(chguser);
parent.parent.DispatchEvent([chguser._id], obj, 'resubscribe');
// Set the user groups (Realms)
if (chguser.groups != groups2) { chguser.groups = groups2; change = 1; }
var targets = ['*', 'server-users', user._id, chguser._id];
if (allTargetGroups) { for (var i in allTargetGroups) { targets.push('server-users:' + i); } }
var event = { etype: 'user', userid: user._id, username: user.name, account: parent.CloneSafeUser(chguser), action: 'accountchange', msg: 'Account changed: ' + chguser.name, domain: domain.id };
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);
}
if ((chguser.siteadmin) && (chguser.siteadmin != 0xFFFFFFFF) && (chguser.siteadmin & 32)) {
// If the user is locked out of this account, disconnect now
parent.parent.DispatchEvent([chguser._id], obj, 'close'); // Disconnect all this user's sessions
// Add any missing groups in the target list
if (allTargetGroups == null) { allTargetGroups = []; }
for (var i in groups2) { if (allTargetGroups.indexOf(i) == -1) { allTargetGroups.push(i); } }
}
}
if (change == 1) {
// Update the user
db.SetUser(chguser);
parent.parent.DispatchEvent([chguser._id], obj, 'resubscribe');
var targets = ['*', 'server-users', user._id, chguser._id];
if (allTargetGroups) { for (var i in allTargetGroups) { targets.push('server-users:' + i); } }
var event = { etype: 'user', userid: user._id, username: user.name, account: parent.CloneSafeUser(chguser), action: 'accountchange', msg: 'Account changed: ' + chguser.name, domain: edituserdomain.id };
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);
}
if ((chguser.siteadmin) && (chguser.siteadmin != 0xFFFFFFFF) && (chguser.siteadmin & 32)) {
// If the user is locked out of this account, disconnect now
parent.parent.DispatchEvent([chguser._id], obj, 'close'); // Disconnect all this user's sessions
}
}
break;
}

View File

@ -52,6 +52,8 @@
"_AgentAllowedIP": "192.168.0.100/24",
"_AgentBlockedIP": "127.0.0.1,::1",
"_AuthLog": "c:\\temp\\auth.log",
"_ManageAllDeviceGroups": [ "user//admin" ],
"_ManageCrossDomain": [ "user//admin" ],
"_LocalDiscovery": {
"name": "Local server name",
"info": "Information about this server"
@ -104,7 +106,6 @@
"_UserNameIsEmail": true,
"_NewAccountEmailDomains": [ "sample.com" ],
"_NewAccountsRights": [ "nonewgroups", "notools" ],
"_ManageAllDeviceGroups": [ "admin" ],
"_WelcomeText": "Sample Text on Login Page.",
"_WelcomePicture": "mainwelcome.jpg",
"___Hide__": "Sum of: 1 = Hide header, 2 = Hide tab, 4 = Hide footer, 8 = Hide title, 16 = Hide left bar",

File diff suppressed because it is too large Load Diff

View File

@ -2866,8 +2866,10 @@
go(xviewmode);
goBackStack.push(2);
} else if (args.gotouser != null) {
if ((users == null) || (users['user/' + domain + '/' + args.gotouser] == null)) return; // This user is not loaded yet
gotoUser('user/' + domain + '/' + args.gotouser);
var xuserid = args.gotouser;
if (args.gotouser.indexOf('/') < 0) { xuserid = 'user/' + domain + '/' + args.gotouser; }
if ((users == null) || (users[xuserid] == null)) return; // This user is not loaded yet
gotoUser(xuserid);
go(xviewmode);
goBackStack.push(4);
} else if (args.gotougrp != null) {
@ -10025,7 +10027,7 @@
}
function addUserHtml(user, sessions) {
var x = '', gray = ' gray', icon = 'm2', msg = '', self = (user.name != userinfo.name), lastAccess = '', permissions = '';
var x = '', gray = ' gray', icon = 'm2', msg = '', self = (user._id != userinfo._id), lastAccess = '', permissions = '';
if (sessions != null) {
gray = '';
if (self) {
@ -10072,6 +10074,12 @@
}
}
// If we are a cross-domain administrator, add the domain.
if ((userinfo.crossDomain != null)) {
var userdomain = user._id.split('/')[1];
if (userdomain != '') { username += ', <span style=color:#26F>' + userdomain + '</span>'; }
}
if ((user.otpsecret > 0) || (user.otphkeys > 0) || ((user.otpekey == 1) && (features & 0x00800000)) || ((user.phone != null) && (features & 0x04000000))) { username += ' <img src="images/key12.png" height=12 width=11 title="' + "2nd factor authentication enabled" + '" style="margin-top:2px" />'; }
if (user.phone != null) { username += ' <img src="images/phone12.png" height=12 width=7 title="' + "Verified phone number" + '" style="margin-top:2px" />'; }
if ((user.siteadmin != null) && ((user.siteadmin & 32) != 0) && (user.siteadmin != 0xFFFFFFFF)) { username += ' <img src="images/padlock12.png" height=12 width=8 title="' + "Account is locked" + '" style="margin-top:2px" />'; }
@ -10288,6 +10296,14 @@
function showCreateNewAccountDialog() {
if (xxdialogMode) return;
var x = '';
if (userinfo.crossDomain) {
var y = '<select style=width:240px id=p4domain>';
for (var i in userinfo.crossDomain) { y += '<option value=' + i + '>' + ((userinfo.crossDomain[i] == '')?"Default":EscapeHtml(userinfo.crossDomain[i])) + '</option>'; }
y += '</select>';
x += addHtmlValue("Domain", y);
}
if ((features & 0x200000) == 0) { x += addHtmlValue('<span id=p4hname>' + "Username" + '</span>', '<input id=p4name maxlength=64 autocomplete=username onchange=showCreateNewAccountDialogValidate() onkeyup=showCreateNewAccountDialogValidate() />'); }
x += addHtmlValue('<span id=p4hemail>' + "Email" + '</span>', '<input id=p4email maxlength=256 autocomplete="email" inputmode="email" onchange=showCreateNewAccountDialogValidate() onkeyup=showCreateNewAccountDialogValidate() />');
x += addHtmlValue('<span id=p4hp1>' + "Password" + '</span>', '<input id=p4pass1 type=password maxlength=256 autocomplete="new-password" onchange=showCreateNewAccountDialogValidate() onkeyup=showCreateNewAccountDialogValidate() />');
@ -10345,6 +10361,7 @@
x.emailVerified = Q('p4verifiedEmail').checked;
x.emailInvitation = Q('p4invitationEmail').checked;
}
if (userinfo.crossDomain) { x.domain = userinfo.crossDomain[parseInt(Q('p4domain').value)]; }
meshserver.send(x);
}
@ -10916,7 +10933,13 @@
if ((args.hide & 8) != 0) { x += '<br />' + addDeviceAttribute("Name", user.name); } // If title bar is hidden, display the user name here
var email = user.email?EscapeHtml(user.email):'<i>' + "Not set" + '</i>', everify = '';
if (serverinfo.emailcheck) { everify = ((user.emailVerified == true) ? '<b style=color:green;cursor:pointer title="' + "Email is verified" + '">&#x2713</b> ' : '<b style=color:red;cursor:pointer title="' + "Email not verified" + '">&#x2717;</b> '); }
if (user.name.toLowerCase() != user._id.split('/')[2]) { x += addDeviceAttribute("User Identifier", user._id.split('/')[2]); }
if (userinfo.crossDomain) {
x += addDeviceAttribute("User Identifier", EscapeHtml(user._id));
} else {
if (user.name.toLowerCase() != user._id.split('/')[2]) { x += addDeviceAttribute("User Identifier", EscapeHtml(user._id.split('/')[2])); }
}
if (((user.siteadmin != 0xFFFFFFFF) || (userinfo.siteadmin == 0xFFFFFFFF))) { // If we are not site admin, we can't change a admin email.
x += addDeviceAttribute("Email", everify + email + ' <a href="mailto:' + user.email + '" \'><img class=hoverButton src="images/link1.png" /></a>' + ' <img class=hoverButton style=cursor:pointer src="images/link5.png" onclick=p30showUserEmailChangeDialog(event,"' + userid + '") />');
} else {
@ -11016,7 +11039,7 @@
// Change the URL
var urlviewmode = '';
if (((features & 0x10000000) == 0) && (xxcurrentView >= 30) && (xxcurrentView <= 39) && (currentUser != null)) {
urlviewmode = '?viewmode=' + xxcurrentView + '&gotouser=' + currentUser._id.split('/')[2];
urlviewmode = '?viewmode=' + xxcurrentView + '&gotouser=' + ((userinfo.crossDomain)?currentUser._id:currentUser._id.split('/')[2]);
for (var i in urlargs) { urlviewmode += ('&' + i + '=' + urlargs[i]); }
try { window.history.replaceState({}, document.title, window.location.pathname + urlviewmode); } catch (ex) { }
}
@ -12004,7 +12027,7 @@
} else if ((x >= 20) && (x <= 29)) {
if (currentMesh) { window.open(window.location.origin + '{{{domainurl}}}' + '?gotomesh=' + currentMesh._id.split('/')[2] + '&viewmode=' + x + '&hide=16', 'meshcentral:' + currentMesh._id); }
} else if ((x >= 30) && (x <= 39)) {
if (currentUser) { window.open(window.location.origin + '{{{domainurl}}}' + '?gotouser=' + currentUser._id.split('/')[2] + '&viewmode=' + x + '&hide=16', 'meshcentral:' + currentUser._id); }
if (currentUser) { window.open(window.location.origin + '{{{domainurl}}}' + '?gotouser=' + ((userinfo.crossDomain)?currentUser._id:currentUser._id.split('/')[2]) + '&viewmode=' + x + '&hide=16', 'meshcentral:' + currentUser._id); }
} else if ((x >= 50) && (x <= 59)) {
if (currentUserGroup) { window.open(window.location.origin + '{{{domainurl}}}' + '?gotougrp=' + currentUserGroup._id.split('/')[2] + '&viewmode=' + x + '&hide=16', 'meshcentral:' + currentUserGroup._id); }
} else { // if (x < 10))
@ -12043,7 +12066,7 @@
} else if ((xxcurrentView >= 20) && (xxcurrentView <= 29)) { // Device Group Link
if (currentMesh != null) { urlviewmode = '?viewmode=' + xxcurrentView + '&gotomesh=' + currentMesh._id.split('/')[2]; }
} else if ((xxcurrentView >= 30) && (xxcurrentView <= 39)) { // User Link
if (currentUser != null) { urlviewmode = '?viewmode=' + xxcurrentView + '&gotouser=' + currentUser._id.split('/')[2]; }
if (currentUser != null) { urlviewmode = '?viewmode=' + xxcurrentView + '&gotouser=' + ((userinfo.crossDomain)?currentUser._id:currentUser._id.split('/')[2]); }
} else if ((xxcurrentView >= 51) && (xxcurrentView <= 51)) { // User Group Link
if ((currentUserGroup != null) && (currentUserGroup._id != null)) { urlviewmode = '?viewmode=' + xxcurrentView + '&gotougrp=' + currentUserGroup._id.split('/')[2]; }
} else if (xxcurrentView > 1) { urlviewmode = '?viewmode=' + xxcurrentView; }