From 4b10e225dd2236688048b9f8704b5cc09702aad8 Mon Sep 17 00:00:00 2001 From: Ylian Saint-Hilaire Date: Fri, 10 Jul 2020 10:33:41 -0700 Subject: [PATCH] Added user account real name support. --- agents/meshcore.js | 29 +++++++++++++++-------------- meshcentral-config-schema.json | 13 ++++++++----- meshdesktopmultiplex.js | 2 ++ meshrelay.js | 2 ++ meshuser.js | 17 ++++++++++++++--- sample-config-advanced.json | 1 + views/default.handlebars | 21 ++++++++++++++++++++- 7 files changed, 62 insertions(+), 23 deletions(-) diff --git a/agents/meshcore.js b/agents/meshcore.js index a33fe2ad..6a0e45a4 100644 --- a/agents/meshcore.js +++ b/agents/meshcore.js @@ -712,6 +712,7 @@ function createMeshCore(agent) { tunnel.consent = data.consent; tunnel.privacybartext = data.privacybartext ? data.privacybartext : "Sharing desktop with: {0}"; tunnel.username = data.username; + tunnel.realname = data.realname ? data.realname : data.username; tunnel.userid = data.userid; tunnel.remoteaddr = data.remoteaddr; tunnel.state = 0; @@ -1624,10 +1625,10 @@ function createMeshCore(agent) { }; if (this.httprequest.desktop.kvm.hasOwnProperty('connectionCount')) { this.httprequest.desktop.kvm.connectionCount++; - this.httprequest.desktop.kvm.users.push(this.httprequest.username); + this.httprequest.desktop.kvm.users.push(this.httprequest.realname); } else { this.httprequest.desktop.kvm.connectionCount = 1; - this.httprequest.desktop.kvm.users = [this.httprequest.username]; + this.httprequest.desktop.kvm.users = [this.httprequest.realname]; } if ((this.httprequest.rights == 0xFFFFFFFF) || (((this.httprequest.rights & MESHRIGHT_REMOTECONTROL) != 0) && ((this.httprequest.rights & MESHRIGHT_REMOTEVIEW) == 0))) { @@ -1645,10 +1646,10 @@ function createMeshCore(agent) { // User Consent Prompt is required // Send a console message back using the console channel, "\n" is supported. this.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: "Waiting for user to grant access...", msgid: 1 })); - var consentMessage = this.httprequest.username + " requesting remote desktop access. Grant access?", consentTitle = 'MeshCentral'; + var consentMessage = this.httprequest.realname + " requesting remote desktop access. Grant access?", consentTitle = 'MeshCentral'; if (this.httprequest.soptions != null) { if (this.httprequest.soptions.consentTitle != null) { consentTitle = this.httprequest.soptions.consentTitle; } - if (this.httprequest.soptions.consentMsgDesktop != null) { consentMessage = this.httprequest.soptions.consentMsgDesktop.replace('{0}', this.httprequest.username); } + if (this.httprequest.soptions.consentMsgDesktop != null) { consentMessage = this.httprequest.soptions.consentMsgDesktop.replace('{0}', this.httprequest.realname); } } var pr = require('message-box').create(consentTitle, consentMessage, 30, null, tsid); pr.ws = this; @@ -1664,10 +1665,10 @@ function createMeshCore(agent) { this.ws.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: null, msgid: 0 })); if (this.ws.httprequest.consent && (this.ws.httprequest.consent & 1)) { // User Notifications is required - var notifyMessage = this.ws.httprequest.username + " started a remote desktop session.", notifyTitle = "MeshCentral"; + var notifyMessage = this.ws.httprequest.realname + " started a remote desktop session.", notifyTitle = "MeshCentral"; if (this.ws.httprequest.soptions != null) { if (this.ws.httprequest.soptions.notifyTitle != null) { notifyTitle = this.ws.httprequest.soptions.notifyTitle; } - if (this.ws.httprequest.soptions.notifyMsgDesktop != null) { notifyMessage = this.ws.httprequest.soptions.notifyMsgDesktop.replace('{0}', this.ws.httprequest.username); } + if (this.ws.httprequest.soptions.notifyMsgDesktop != null) { notifyMessage = this.ws.httprequest.soptions.notifyMsgDesktop.replace('{0}', this.ws.httprequest.realname); } } try { require('toaster').Toast(notifyTitle, notifyMessage, tsid); } catch (ex) { } } @@ -1713,10 +1714,10 @@ function createMeshCore(agent) { if (this.httprequest.consent && (this.httprequest.consent & 1)) { // User Notifications is required MeshServerLog("Started remote desktop with toast notification (" + this.httprequest.remoteaddr + ")", this.httprequest); - var notifyMessage = this.httprequest.username + " started a remote desktop session.", notifyTitle = "MeshCentral"; + var notifyMessage = this.httprequest.realname + " started a remote desktop session.", notifyTitle = "MeshCentral"; if (this.httprequest.soptions != null) { if (this.httprequest.soptions.notifyTitle != null) { notifyTitle = this.httprequest.soptions.notifyTitle; } - if (this.httprequest.soptions.notifyMsgDesktop != null) { notifyMessage = this.httprequest.soptions.notifyMsgDesktop.replace('{0}', this.httprequest.username); } + if (this.httprequest.soptions.notifyMsgDesktop != null) { notifyMessage = this.httprequest.soptions.notifyMsgDesktop.replace('{0}', this.httprequest.realname); } } try { require('toaster').Toast(notifyTitle, notifyMessage, tsid); } catch (ex) { } } else { @@ -1789,10 +1790,10 @@ function createMeshCore(agent) { // User Consent Prompt is required // Send a console message back using the console channel, "\n" is supported. this.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: "Waiting for user to grant access...", msgid: 1 })); - var consentMessage = this.httprequest.username + " requesting remote file Access. Grant access?", consentTitle = 'MeshCentral'; + var consentMessage = this.httprequest.realname + " requesting remote file Access. Grant access?", consentTitle = 'MeshCentral'; if (this.httprequest.soptions != null) { if (this.httprequest.soptions.consentTitle != null) { consentTitle = this.httprequest.soptions.consentTitle; } - if (this.httprequest.soptions.consentMsgFiles != null) { consentMessage = this.httprequest.soptions.consentMsgFiles.replace('{0}', this.httprequest.username); } + if (this.httprequest.soptions.consentMsgFiles != null) { consentMessage = this.httprequest.soptions.consentMsgFiles.replace('{0}', this.httprequest.realname); } } var pr = require('message-box').create(consentTitle, consentMessage, 30); pr.ws = this; @@ -1808,10 +1809,10 @@ function createMeshCore(agent) { this.ws.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: null })); if (this.ws.httprequest.consent && (this.ws.httprequest.consent & 4)) { // User Notifications is required - var notifyMessage = this.ws.httprequest.username + " started a remote file session.", notifyTitle = "MeshCentral"; + var notifyMessage = this.ws.httprequest.realname + " started a remote file session.", notifyTitle = "MeshCentral"; if (this.ws.httprequest.soptions != null) { if (this.ws.httprequest.soptions.notifyTitle != null) { notifyTitle = this.ws.httprequest.soptions.notifyTitle; } - if (this.ws.httprequest.soptions.notifyMsgFiles != null) { notifyMessage = this.ws.httprequest.soptions.notifyMsgFiles.replace('{0}', this.ws.httprequest.username); } + if (this.ws.httprequest.soptions.notifyMsgFiles != null) { notifyMessage = this.ws.httprequest.soptions.notifyMsgFiles.replace('{0}', this.ws.httprequest.realname); } } try { require('toaster').Toast(notifyTitle, notifyMessage); } catch (ex) { } } @@ -1829,10 +1830,10 @@ function createMeshCore(agent) { if (this.httprequest.consent && (this.httprequest.consent & 4)) { // User Notifications is required MeshServerLog("Started remote files with toast notification (" + this.httprequest.remoteaddr + ")", this.httprequest); - var notifyMessage = this.httprequest.username + " started a remote file session.", notifyTitle = "MeshCentral"; + var notifyMessage = this.httprequest.realname + " started a remote file session.", notifyTitle = "MeshCentral"; if (this.httprequest.soptions != null) { if (this.httprequest.soptions.notifyTitle != null) { notifyTitle = this.httprequest.soptions.notifyTitle; } - if (this.httprequest.soptions.notifyMsgFiles != null) { notifyMessage = this.httprequest.soptions.notifyMsgFiles.replace('{0}', this.httprequest.username); } + if (this.httprequest.soptions.notifyMsgFiles != null) { notifyMessage = this.httprequest.soptions.notifyMsgFiles.replace('{0}', this.httprequest.realname); } } try { require('toaster').Toast(notifyTitle, notifyMessage); } catch (ex) { } } else { diff --git a/meshcentral-config-schema.json b/meshcentral-config-schema.json index c930b3e1..f0fc05e4 100644 --- a/meshcentral-config-schema.json +++ b/meshcentral-config-schema.json @@ -159,14 +159,16 @@ "skip2factor": { "type": "string" } } }, - "agentInviteCodes": { "type": "boolean", "default": false }, - "agentNoProxy": { "type": "boolean", "default": false }, - "geoLocation": { "type": "boolean", "default": false }, - "novnc": { "type": "boolean", "default": true }, - "mstsc": { "type": "boolean", "default": false }, + "agentInviteCodes": { "type": "boolean", "default": false, "description": "Enabled a feature where you can set one or more invitation codes in a device group. You can then give a invitation link to users who can use it to download the agent." }, + "agentNoProxy": { "type": "boolean", "default": false, "description": "When enabled, all newly installed MeshAgents will be instructed to no use a HTTP/HTTPS proxy even if one is configured on the remote system" }, + "geoLocation": { "type": "boolean", "default": false, "description": "Enables the geo-location feature and device location map in the user interface, this feature is not being worked on." }, + "novnc": { "type": "boolean", "default": true, "description": "When enabled, activates the built-in web-based noVNC client." }, + "mstsc": { "type": "boolean", "default": false, "description": "When enabled, activates the built-in web-based RDP client." }, + "webEmailsPath": { "type": "string", "description": "Path where to find custom email templates for this domain." }, "customUI": { "type": "object" }, "consentMessages": { "type": "object", + "description": "This section is user to customize user consent prompts, these show up when asking if a remote session is allowed or not.", "additionalProperties": false, "properties": { "Title": { "type": "string" }, @@ -178,6 +180,7 @@ "notificationMessages": { "type": "object", "additionalProperties": false, + "description": "This section is user to customize user notifications when a remote desktop, terminal or file session is connected to a remote system.", "properties": { "Title": { "type": "string" }, "Desktop": { "type": "string" }, diff --git a/meshdesktopmultiplex.js b/meshdesktopmultiplex.js index 91715b14..9688cb94 100644 --- a/meshdesktopmultiplex.js +++ b/meshdesktopmultiplex.js @@ -888,6 +888,7 @@ module.exports.CreateMeshRelay = function (parent, ws, req, domain, user, cookie command.consent = mesh.consent; // Add user consent if (typeof domain.userconsentflags == 'number') { command.consent |= domain.userconsentflags; } // Add server required consent flags command.username = user.name; // Add user name + command.realname = user.realname; // Add real name if (typeof domain.desktopprivacybartext == 'string') { command.privacybartext = domain.desktopprivacybartext; } // Privacy bar text delete command.nodeid; // Remove the nodeid since it's implyed. agent.send(JSON.stringify(command)); @@ -906,6 +907,7 @@ module.exports.CreateMeshRelay = function (parent, ws, req, domain, user, cookie command.consent = mesh.consent; // Add user consent if (typeof domain.userconsentflags == 'number') { command.consent |= domain.userconsentflags; } // Add server required consent flags command.username = user.name; // Add user name + command.realname = user.realname; // Add real name if (typeof domain.desktopprivacybartext == 'string') { command.privacybartext = domain.desktopprivacybartext; } // Privacy bar text parent.parent.multiServer.DispatchMessageSingleServer(command, routing.serverid); return true; diff --git a/meshrelay.js b/meshrelay.js index 7ee51833..75973466 100644 --- a/meshrelay.js +++ b/meshrelay.js @@ -95,6 +95,7 @@ module.exports.CreateMeshRelay = function (parent, ws, req, domain, user, cookie command.consent = mesh.consent; // Add user consent if (typeof domain.userconsentflags == 'number') { command.consent |= domain.userconsentflags; } // Add server required consent flags command.username = user.name; // Add user name + command.realname = user.realname; // Add real name if (typeof domain.desktopprivacybartext == 'string') { command.privacybartext = domain.desktopprivacybartext; } // Privacy bar text delete command.nodeid; // Remove the nodeid since it's implyed. agent.send(JSON.stringify(command)); @@ -113,6 +114,7 @@ module.exports.CreateMeshRelay = function (parent, ws, req, domain, user, cookie command.consent = mesh.consent; // Add user consent if (typeof domain.userconsentflags == 'number') { command.consent |= domain.userconsentflags; } // Add server required consent flags command.username = user.name; // Add user name + command.realname = user.realname; // Add real name if (typeof domain.desktopprivacybartext == 'string') { command.privacybartext = domain.desktopprivacybartext; } // Privacy bar text parent.parent.multiServer.DispatchMessageSingleServer(command, routing.serverid); return true; diff --git a/meshuser.js b/meshuser.js index 9d9a5908..fd4c9e21 100644 --- a/meshuser.js +++ b/meshuser.js @@ -195,8 +195,9 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use if (typeof node.consent == 'number') { command.consent |= node.consent; } // Add node user consent if (typeof user.consent == 'number') { command.consent |= user.consent; } // Add user consent command.username = user.name; // Add user name + command.realname = user.realname; // Add real name command.userid = user._id; // Add user id - command.remoteaddr = req.clientIp; // User's IP address + command.remoteaddr = req.clientIp; // User's IP address if (typeof domain.desktopprivacybartext == 'string') { command.privacybartext = domain.desktopprivacybartext; } // Privacy bar text delete command.nodeid; // Remove the nodeid since it's implied try { agent.send(JSON.stringify(command)); } catch (ex) { } @@ -218,8 +219,9 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use if (typeof node.consent == 'number') { command.consent |= node.consent; } // Add node user consent if (typeof user.consent == 'number') { command.consent |= user.consent; } // Add user consent command.username = user.name; // Add user name + command.realname = user.realname; // Add real name command.userid = user._id; // Add user id - command.remoteaddr = req.clientIp; // User's IP address + command.remoteaddr = req.clientIp; // User's IP address if (typeof domain.desktopprivacybartext == 'string') { command.privacybartext = domain.desktopprivacybartext; } // Privacy bar text parent.parent.multiServer.DispatchMessageSingleServer(command, routing.serverid); } @@ -1835,7 +1837,16 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use // 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; } + if (common.validateString(command.email, 1, 1024) && (chguser.email != command.email)) { + if (command.email == '') { delete chguser.email; } else { chguser.email = command.email.toLowerCase(); } + change = 1; + } + } + + // Validate and change realm name + if (common.validateString(command.realname, 1, 256) && (chguser.realname != command.realname)) { + if (command.realname == '') { delete chguser.realname; } else { chguser.realname = command.realname; } + change = 1; } // Make changes diff --git a/sample-config-advanced.json b/sample-config-advanced.json index 0d817a64..f3b117b6 100644 --- a/sample-config-advanced.json +++ b/sample-config-advanced.json @@ -140,6 +140,7 @@ "_geoLocation": true, "_novnc": false, "_mstsc": true, + "_WebEmailsPath": "/myserver/email-templates", "_consentMessages": { "title": "MeshCentral", "desktop": "{0} requesting remote desktop access. Grant access?", diff --git a/views/default.handlebars b/views/default.handlebars index 2d56d599..251b0565 100644 --- a/views/default.handlebars +++ b/views/default.handlebars @@ -11349,6 +11349,7 @@ var x = '
'; if ((args.hide & 8) != 0) { x += '
' + addDeviceAttribute("Name", user.name); } // If title bar is hidden, display the user name here var email = user.email?EscapeHtml(user.email):'' + "Not set" + '', everify = ''; + var realname = user.realname?EscapeHtml(user.realname):'' + "Not set" + ''; if (serverinfo.emailcheck) { everify = ((user.emailVerified == true) ? ' ' : ' '); } if ((serverinfo.crossDomain) || (debugmode != 0)) { @@ -11359,10 +11360,12 @@ 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. + if (((user.siteadmin != 0xFFFFFFFF) || (userinfo.siteadmin == 0xFFFFFFFF))) { // If we are not site admin, we can't change a admin email or real name x += addDeviceAttribute("Email", everify + email + ' ' + ' '); + x += addDeviceAttribute("Real Name", realname + ' '); } else { x += addDeviceAttribute("Email", everify + email + ' '); + x += addDeviceAttribute("Real Name", realname); } if ((features & 0x02000000) || (user.phone != null)) { // If SMS is enabled on the server or user has a phone number @@ -11483,6 +11486,22 @@ // Send to the server the user's new phone number function p30editPhoneEx() { meshserver.send({ action: 'edituser', id: currentUser._id, phone: Q('d2phoneinput').value }); } + // Display the user's real name change dialog box + function p30showUserRealNameChangeDialog(event) { + if (xxdialogMode) return false; + var x = ''; + x += addHtmlValue("Real Name", ''); + setDialogMode(2, format("Change Real Name for {0}", EscapeHtml(currentUser.name)), 3, p30showUserRealNameChangeDialogEx, x); + Q('dp30realname').focus(); + Q('dp30realname').value = (currentUser.realname?currentUser.realname:''); + return false; + } + + // Send to the server the new user's real name + function p30showUserRealNameChangeDialogEx() { + meshserver.send({ action: 'edituser', id: currentUser._id, realname: Q('dp30realname').value }); + } + // Display the user's email change dialog box function p30showUserEmailChangeDialog(event) { if (xxdialogMode) return false;