Added user account real name support.

Ylian Saint-Hilaire committed Jul 10, 2020 at 10:33 UTC 4b10e225dd2236688048b9f8704b5cc09702aad8
7 files changed +62 -23
agents/meshcore.js
+15 -14
@@ -712,6 +712,7 @@ function createMeshCore(agent) {
712 tunnel.consent = data.consent;
713 tunnel.privacybartext = data.privacybartext ? data.privacybartext : "Sharing desktop with: {0}";
714 tunnel.username = data.username;
715 + tunnel.realname = data.realname ? data.realname : data.username;
716 tunnel.userid = data.userid;
717 tunnel.remoteaddr = data.remoteaddr;
718 tunnel.state = 0;
@@ -1624,10 +1625,10 @@ function createMeshCore(agent) {
1625 };
1626 if (this.httprequest.desktop.kvm.hasOwnProperty('connectionCount')) {
1627 this.httprequest.desktop.kvm.connectionCount++;
1627 - this.httprequest.desktop.kvm.users.push(this.httprequest.username);
1628 + this.httprequest.desktop.kvm.users.push(this.httprequest.realname);
1629 } else {
1630 this.httprequest.desktop.kvm.connectionCount = 1;
1630 - this.httprequest.desktop.kvm.users = [this.httprequest.username];
1631 + this.httprequest.desktop.kvm.users = [this.httprequest.realname];
1632 }
1633
1634 if ((this.httprequest.rights == 0xFFFFFFFF) || (((this.httprequest.rights & MESHRIGHT_REMOTECONTROL) != 0) && ((this.httprequest.rights & MESHRIGHT_REMOTEVIEW) == 0))) {
@@ -1645,10 +1646,10 @@ function createMeshCore(agent) {
1646 // User Consent Prompt is required
1647 // Send a console message back using the console channel, "\n" is supported.
1648 this.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: "Waiting for user to grant access...", msgid: 1 }));
1648 - var consentMessage = this.httprequest.username + " requesting remote desktop access. Grant access?", consentTitle = 'MeshCentral';
1649 + var consentMessage = this.httprequest.realname + " requesting remote desktop access. Grant access?", consentTitle = 'MeshCentral';
1650 if (this.httprequest.soptions != null) {
1651 if (this.httprequest.soptions.consentTitle != null) { consentTitle = this.httprequest.soptions.consentTitle; }
1651 - if (this.httprequest.soptions.consentMsgDesktop != null) { consentMessage = this.httprequest.soptions.consentMsgDesktop.replace('{0}', this.httprequest.username); }
1652 + if (this.httprequest.soptions.consentMsgDesktop != null) { consentMessage = this.httprequest.soptions.consentMsgDesktop.replace('{0}', this.httprequest.realname); }
1653 }
1654 var pr = require('message-box').create(consentTitle, consentMessage, 30, null, tsid);
1655 pr.ws = this;
@@ -1664,10 +1665,10 @@ function createMeshCore(agent) {
1665 this.ws.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: null, msgid: 0 }));
1666 if (this.ws.httprequest.consent && (this.ws.httprequest.consent & 1)) {
1667 // User Notifications is required
1667 - var notifyMessage = this.ws.httprequest.username + " started a remote desktop session.", notifyTitle = "MeshCentral";
1668 + var notifyMessage = this.ws.httprequest.realname + " started a remote desktop session.", notifyTitle = "MeshCentral";
1669 if (this.ws.httprequest.soptions != null) {
1670 if (this.ws.httprequest.soptions.notifyTitle != null) { notifyTitle = this.ws.httprequest.soptions.notifyTitle; }
1670 - if (this.ws.httprequest.soptions.notifyMsgDesktop != null) { notifyMessage = this.ws.httprequest.soptions.notifyMsgDesktop.replace('{0}', this.ws.httprequest.username); }
1671 + if (this.ws.httprequest.soptions.notifyMsgDesktop != null) { notifyMessage = this.ws.httprequest.soptions.notifyMsgDesktop.replace('{0}', this.ws.httprequest.realname); }
1672 }
1673 try { require('toaster').Toast(notifyTitle, notifyMessage, tsid); } catch (ex) { }
1674 }
@@ -1713,10 +1714,10 @@ function createMeshCore(agent) {
1714 if (this.httprequest.consent && (this.httprequest.consent & 1)) {
1715 // User Notifications is required
1716 MeshServerLog("Started remote desktop with toast notification (" + this.httprequest.remoteaddr + ")", this.httprequest);
1716 - var notifyMessage = this.httprequest.username + " started a remote desktop session.", notifyTitle = "MeshCentral";
1717 + var notifyMessage = this.httprequest.realname + " started a remote desktop session.", notifyTitle = "MeshCentral";
1718 if (this.httprequest.soptions != null) {
1719 if (this.httprequest.soptions.notifyTitle != null) { notifyTitle = this.httprequest.soptions.notifyTitle; }
1719 - if (this.httprequest.soptions.notifyMsgDesktop != null) { notifyMessage = this.httprequest.soptions.notifyMsgDesktop.replace('{0}', this.httprequest.username); }
1720 + if (this.httprequest.soptions.notifyMsgDesktop != null) { notifyMessage = this.httprequest.soptions.notifyMsgDesktop.replace('{0}', this.httprequest.realname); }
1721 }
1722 try { require('toaster').Toast(notifyTitle, notifyMessage, tsid); } catch (ex) { }
1723 } else {
@@ -1789,10 +1790,10 @@ function createMeshCore(agent) {
1790 // User Consent Prompt is required
1791 // Send a console message back using the console channel, "\n" is supported.
1792 this.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: "Waiting for user to grant access...", msgid: 1 }));
1792 - var consentMessage = this.httprequest.username + " requesting remote file Access. Grant access?", consentTitle = 'MeshCentral';
1793 + var consentMessage = this.httprequest.realname + " requesting remote file Access. Grant access?", consentTitle = 'MeshCentral';
1794 if (this.httprequest.soptions != null) {
1795 if (this.httprequest.soptions.consentTitle != null) { consentTitle = this.httprequest.soptions.consentTitle; }
1795 - if (this.httprequest.soptions.consentMsgFiles != null) { consentMessage = this.httprequest.soptions.consentMsgFiles.replace('{0}', this.httprequest.username); }
1796 + if (this.httprequest.soptions.consentMsgFiles != null) { consentMessage = this.httprequest.soptions.consentMsgFiles.replace('{0}', this.httprequest.realname); }
1797 }
1798 var pr = require('message-box').create(consentTitle, consentMessage, 30);
1799 pr.ws = this;
@@ -1808,10 +1809,10 @@ function createMeshCore(agent) {
1809 this.ws.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: null }));
1810 if (this.ws.httprequest.consent && (this.ws.httprequest.consent & 4)) {
1811 // User Notifications is required
1811 - var notifyMessage = this.ws.httprequest.username + " started a remote file session.", notifyTitle = "MeshCentral";
1812 + var notifyMessage = this.ws.httprequest.realname + " started a remote file session.", notifyTitle = "MeshCentral";
1813 if (this.ws.httprequest.soptions != null) {
1814 if (this.ws.httprequest.soptions.notifyTitle != null) { notifyTitle = this.ws.httprequest.soptions.notifyTitle; }
1814 - if (this.ws.httprequest.soptions.notifyMsgFiles != null) { notifyMessage = this.ws.httprequest.soptions.notifyMsgFiles.replace('{0}', this.ws.httprequest.username); }
1815 + if (this.ws.httprequest.soptions.notifyMsgFiles != null) { notifyMessage = this.ws.httprequest.soptions.notifyMsgFiles.replace('{0}', this.ws.httprequest.realname); }
1816 }
1817 try { require('toaster').Toast(notifyTitle, notifyMessage); } catch (ex) { }
1818 }
@@ -1829,10 +1830,10 @@ function createMeshCore(agent) {
1830 if (this.httprequest.consent && (this.httprequest.consent & 4)) {
1831 // User Notifications is required
1832 MeshServerLog("Started remote files with toast notification (" + this.httprequest.remoteaddr + ")", this.httprequest);
1832 - var notifyMessage = this.httprequest.username + " started a remote file session.", notifyTitle = "MeshCentral";
1833 + var notifyMessage = this.httprequest.realname + " started a remote file session.", notifyTitle = "MeshCentral";
1834 if (this.httprequest.soptions != null) {
1835 if (this.httprequest.soptions.notifyTitle != null) { notifyTitle = this.httprequest.soptions.notifyTitle; }
1835 - if (this.httprequest.soptions.notifyMsgFiles != null) { notifyMessage = this.httprequest.soptions.notifyMsgFiles.replace('{0}', this.httprequest.username); }
1836 + if (this.httprequest.soptions.notifyMsgFiles != null) { notifyMessage = this.httprequest.soptions.notifyMsgFiles.replace('{0}', this.httprequest.realname); }
1837 }
1838 try { require('toaster').Toast(notifyTitle, notifyMessage); } catch (ex) { }
1839 } else {
meshcentral-config-schema.json
+8 -5
@@ -159,14 +159,16 @@
159 "skip2factor": { "type": "string" }
160 }
161 },
162 - "agentInviteCodes": { "type": "boolean", "default": false },
163 - "agentNoProxy": { "type": "boolean", "default": false },
164 - "geoLocation": { "type": "boolean", "default": false },
165 - "novnc": { "type": "boolean", "default": true },
166 - "mstsc": { "type": "boolean", "default": false },
162 + "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." },
163 + "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" },
164 + "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." },
165 + "novnc": { "type": "boolean", "default": true, "description": "When enabled, activates the built-in web-based noVNC client." },
166 + "mstsc": { "type": "boolean", "default": false, "description": "When enabled, activates the built-in web-based RDP client." },
167 + "webEmailsPath": { "type": "string", "description": "Path where to find custom email templates for this domain." },
168 "customUI": { "type": "object" },
169 "consentMessages": {
170 "type": "object",
171 + "description": "This section is user to customize user consent prompts, these show up when asking if a remote session is allowed or not.",
172 "additionalProperties": false,
173 "properties": {
174 "Title": { "type": "string" },
@@ -178,6 +180,7 @@
180 "notificationMessages": {
181 "type": "object",
182 "additionalProperties": false,
183 + "description": "This section is user to customize user notifications when a remote desktop, terminal or file session is connected to a remote system.",
184 "properties": {
185 "Title": { "type": "string" },
186 "Desktop": { "type": "string" },
meshdesktopmultiplex.js
+2
@@ -888,6 +888,7 @@ module.exports.CreateMeshRelay = function (parent, ws, req, domain, user, cookie
888 command.consent = mesh.consent; // Add user consent
889 if (typeof domain.userconsentflags == 'number') { command.consent |= domain.userconsentflags; } // Add server required consent flags
890 command.username = user.name; // Add user name
891 + command.realname = user.realname; // Add real name
892 if (typeof domain.desktopprivacybartext == 'string') { command.privacybartext = domain.desktopprivacybartext; } // Privacy bar text
893 delete command.nodeid; // Remove the nodeid since it's implyed.
894 agent.send(JSON.stringify(command));
@@ -906,6 +907,7 @@ module.exports.CreateMeshRelay = function (parent, ws, req, domain, user, cookie
907 command.consent = mesh.consent; // Add user consent
908 if (typeof domain.userconsentflags == 'number') { command.consent |= domain.userconsentflags; } // Add server required consent flags
909 command.username = user.name; // Add user name
910 + command.realname = user.realname; // Add real name
911 if (typeof domain.desktopprivacybartext == 'string') { command.privacybartext = domain.desktopprivacybartext; } // Privacy bar text
912 parent.parent.multiServer.DispatchMessageSingleServer(command, routing.serverid);
913 return true;
meshrelay.js
+2
@@ -95,6 +95,7 @@ module.exports.CreateMeshRelay = function (parent, ws, req, domain, user, cookie
95 command.consent = mesh.consent; // Add user consent
96 if (typeof domain.userconsentflags == 'number') { command.consent |= domain.userconsentflags; } // Add server required consent flags
97 command.username = user.name; // Add user name
98 + command.realname = user.realname; // Add real name
99 if (typeof domain.desktopprivacybartext == 'string') { command.privacybartext = domain.desktopprivacybartext; } // Privacy bar text
100 delete command.nodeid; // Remove the nodeid since it's implyed.
101 agent.send(JSON.stringify(command));
@@ -113,6 +114,7 @@ module.exports.CreateMeshRelay = function (parent, ws, req, domain, user, cookie
114 command.consent = mesh.consent; // Add user consent
115 if (typeof domain.userconsentflags == 'number') { command.consent |= domain.userconsentflags; } // Add server required consent flags
116 command.username = user.name; // Add user name
117 + command.realname = user.realname; // Add real name
118 if (typeof domain.desktopprivacybartext == 'string') { command.privacybartext = domain.desktopprivacybartext; } // Privacy bar text
119 parent.parent.multiServer.DispatchMessageSingleServer(command, routing.serverid);
120 return true;
meshuser.js
+14 -3
@@ -195,8 +195,9 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
195 if (typeof node.consent == 'number') { command.consent |= node.consent; } // Add node user consent
196 if (typeof user.consent == 'number') { command.consent |= user.consent; } // Add user consent
197 command.username = user.name; // Add user name
198 + command.realname = user.realname; // Add real name
199 command.userid = user._id; // Add user id
199 - command.remoteaddr = req.clientIp; // User's IP address
200 + command.remoteaddr = req.clientIp; // User's IP address
201 if (typeof domain.desktopprivacybartext == 'string') { command.privacybartext = domain.desktopprivacybartext; } // Privacy bar text
202 delete command.nodeid; // Remove the nodeid since it's implied
203 try { agent.send(JSON.stringify(command)); } catch (ex) { }
@@ -218,8 +219,9 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
219 if (typeof node.consent == 'number') { command.consent |= node.consent; } // Add node user consent
220 if (typeof user.consent == 'number') { command.consent |= user.consent; } // Add user consent
221 command.username = user.name; // Add user name
222 + command.realname = user.realname; // Add real name
223 command.userid = user._id; // Add user id
222 - command.remoteaddr = req.clientIp; // User's IP address
224 + command.remoteaddr = req.clientIp; // User's IP address
225 if (typeof domain.desktopprivacybartext == 'string') { command.privacybartext = domain.desktopprivacybartext; } // Privacy bar text
226 parent.parent.multiServer.DispatchMessageSingleServer(command, routing.serverid);
227 }
@@ -1835,7 +1837,16 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
1837
1838 // Validate and change email
1839 if (edituserdomain.usernameisemail !== true) {
1838 - if (common.validateString(command.email, 1, 1024) && (chguser.email != command.email)) { chguser.email = command.email.toLowerCase(); change = 1; }
1840 + if (common.validateString(command.email, 1, 1024) && (chguser.email != command.email)) {
1841 + if (command.email == '') { delete chguser.email; } else { chguser.email = command.email.toLowerCase(); }
1842 + change = 1;
1843 + }
1844 + }
1845 +
1846 + // Validate and change realm name
1847 + if (common.validateString(command.realname, 1, 256) && (chguser.realname != command.realname)) {
1848 + if (command.realname == '') { delete chguser.realname; } else { chguser.realname = command.realname; }
1849 + change = 1;
1850 }
1851
1852 // Make changes
sample-config-advanced.json
+1
@@ -140,6 +140,7 @@
140 "_geoLocation": true,
141 "_novnc": false,
142 "_mstsc": true,
143 + "_WebEmailsPath": "/myserver/email-templates",
144 "_consentMessages": {
145 "title": "MeshCentral",
146 "desktop": "{0} requesting remote desktop access. Grant access?",
views/default.handlebars
+20 -1
@@ -11349,6 +11349,7 @@
11349 var x = '<div style=min-height:80px><table style=width:100%>';
11350 if ((args.hide & 8) != 0) { x += '<br />' + addDeviceAttribute("Name", user.name); } // If title bar is hidden, display the user name here
11351 var email = user.email?EscapeHtml(user.email):'<i>' + "Not set" + '</i>', everify = '';
11352 + var realname = user.realname?EscapeHtml(user.realname):'<i>' + "Not set" + '</i>';
11353 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> '); }
11354
11355 if ((serverinfo.crossDomain) || (debugmode != 0)) {
@@ -11359,10 +11360,12 @@
11360 if (user.name.toLowerCase() != user._id.split('/')[2]) { x += addDeviceAttribute("User Identifier", EscapeHtml(user._id.split('/')[2])); }
11361 }
11362
11362 - if (((user.siteadmin != 0xFFFFFFFF) || (userinfo.siteadmin == 0xFFFFFFFF))) { // If we are not site admin, we can't change a admin email.
11363 + if (((user.siteadmin != 0xFFFFFFFF) || (userinfo.siteadmin == 0xFFFFFFFF))) { // If we are not site admin, we can't change a admin email or real name
11364 x += addDeviceAttribute("Email", everify + email + ' <a href="mailto:' + EscapeHtml(user.email) + '" \'><img class=hoverButton src="images/link1.png" /></a>' + ' <img class=hoverButton style=cursor:pointer src="images/link5.png" onclick=p30showUserEmailChangeDialog(event,"' + userid + '") />');
11365 + x += addDeviceAttribute("Real Name", realname + ' <img class=hoverButton style=cursor:pointer src="images/link5.png" onclick=p30showUserRealNameChangeDialog(event,"' + userid + '") />');
11366 } else {
11367 x += addDeviceAttribute("Email", everify + email + ' <a href="mailto:' + EscapeHtml(user.email) + '" \'><img class=hoverButton src="images/link1.png" /></a>');
11368 + x += addDeviceAttribute("Real Name", realname);
11369 }
11370
11371 if ((features & 0x02000000) || (user.phone != null)) { // If SMS is enabled on the server or user has a phone number
@@ -11483,6 +11486,22 @@
11486 // Send to the server the user's new phone number
11487 function p30editPhoneEx() { meshserver.send({ action: 'edituser', id: currentUser._id, phone: Q('d2phoneinput').value }); }
11488
11489 + // Display the user's real name change dialog box
11490 + function p30showUserRealNameChangeDialog(event) {
11491 + if (xxdialogMode) return false;
11492 + var x = '';
11493 + x += addHtmlValue("Real Name", '<input id=dp30realname style=width:230px maxlength=256 />');
11494 + setDialogMode(2, format("Change Real Name for {0}", EscapeHtml(currentUser.name)), 3, p30showUserRealNameChangeDialogEx, x);
11495 + Q('dp30realname').focus();
11496 + Q('dp30realname').value = (currentUser.realname?currentUser.realname:'');
11497 + return false;
11498 + }
11499 +
11500 + // Send to the server the new user's real name
11501 + function p30showUserRealNameChangeDialogEx() {
11502 + meshserver.send({ action: 'edituser', id: currentUser._id, realname: Q('dp30realname').value });
11503 + }
11504 +
11505 // Display the user's email change dialog box
11506 function p30showUserEmailChangeDialog(event) {
11507 if (xxdialogMode) return false;