From 797705e7c54610d12bd9aea7a5d63d8eaa361347 Mon Sep 17 00:00:00 2001 From: Ylian Saint-Hilaire Date: Mon, 8 Jul 2019 15:59:44 -0700 Subject: [PATCH] Improved keyboard support, new email as username mode. --- meshcentral.js | 6 +- meshuser.js | 17 +- package.json | 2 +- public/images/mail12.png | Bin 0 -> 246 bytes sample-config.json | 2 + views/default-min.handlebars | 2 +- views/default-mobile-min.handlebars | 2 +- views/default-mobile.handlebars | 3 +- views/default.handlebars | 333 ++++++++++++++++------------ views/login-min.handlebars | 2 +- views/login-mobile-min.handlebars | 2 +- views/login-mobile.handlebars | 18 +- views/login.handlebars | 17 +- webserver.js | 5 + 14 files changed, 252 insertions(+), 159 deletions(-) create mode 100644 public/images/mail12.png diff --git a/meshcentral.js b/meshcentral.js index 1aeba6d1..7df61d37 100644 --- a/meshcentral.js +++ b/meshcentral.js @@ -198,7 +198,11 @@ function CreateMeshCentralServer(config, args) { xprocess.stderr.on('data', function (data) { if (data.startsWith('le.challenges[tls-sni-01].loopback')) { return; } // Ignore this error output from GreenLock if (data[data.length - 1] == '\n') { data = data.substring(0, data.length - 1); } - try { obj.fs.appendFileSync(obj.getConfigFilePath('mesherrors.txt'), '-------- ' + new Date().toLocaleString() + ' ---- ' + obj.currentVer + ' --------\r\n\r\n' + data + '\r\n\r\n\r\n'); } catch (ex) { console.log('ERROR: Unable to write to mesherrors.txt.'); } + try { + var errlogpath = null; + if (typeof obj.args.mesherrorlogpath == 'string') { errlogpath = obj.path.join(obj.args.mesherrorlogpath, 'mesherrors.txt'); } else { errlogpath = obj.getConfigFilePath('mesherrors.txt'); } + obj.fs.appendFileSync(obj.getConfigFilePath('mesherrors.txt'), '-------- ' + new Date().toLocaleString() + ' ---- ' + obj.currentVer + ' --------\r\n\r\n' + data + '\r\n\r\n\r\n'); + } catch (ex) { console.log('ERROR: Unable to write to mesherrors.txt.'); } }); xprocess.on('close', function (code) { if ((code != 0) && (code != 123)) { /* console.log("Exited with code " + code); */ } }); }; diff --git a/meshuser.js b/meshuser.js index 17a3eae1..607c5548 100644 --- a/meshuser.js +++ b/meshuser.js @@ -850,6 +850,9 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use } case 'changeemail': { + // If the email is the username, this command is not allowed. + if (domain.usernameisemail) return; + // Change our own email address if ((domain.auth == 'sspi') || (domain.auth == 'ldap')) return; if (common.validateEmail(command.email, 1, 256) == false) return; @@ -1049,7 +1052,8 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use if (!Array.isArray(command.users)) break; var userCount = 0; for (var i in command.users) { - if (common.validateUsername(command.users[i].user, 1, 64) == false) break; // Username is between 1 and 64 characters, no spaces + if (domain.usernameisemail) { if (command.users[i].email) { command.users[i].user = command.users[i].email; } else { command.users[i].email = command.users[i].user; } } // If the email is the username, set this here. + if (common.validateUsername(command.users[i].user, 1, 256) == false) break; // Username is between 1 and 64 characters, no spaces if ((command.users[i].user == '~') || (command.users[i].user.indexOf('/') >= 0)) break; // This is a reserved user name if (common.validateString(command.users[i].pass, 1, 256) == false) break; // Password is between 1 and 256 characters if (common.checkPasswordRequirements(command.users[i].pass, domain.passwordrequirements) == false) break; // Password does not meet requirements @@ -1108,12 +1112,15 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use } case 'adduser': { + // If the email is the username, set this here. + if (domain.usernameisemail) { if (command.email) { command.username = command.email; } else { command.email = command.username; } } + // Add a new user account var err = null, newusername, newuserid; 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, 64) == false) { err = 'Invalid username'; } // Username is between 1 and 64 characters, no spaces + else if (common.validateUsername(command.username, 1, 256) == false) { err = 'Invalid username'; } // Username is between 1 and 64 characters, no spaces else if (common.validateString(command.pass, 1, 256) == false) { err = 'Invalid password'; } // Password is between 1 and 256 characters else if (command.username.indexOf('/') >= 0) { err = 'Invalid username'; } // Usernames can't have '/' else if (common.checkPasswordRequirements(command.pass, domain.passwordrequirements) == false) { err = 'Invalid password'; } // Password does not meet requirements @@ -1204,8 +1211,10 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use if ((user.groups != null) && (user.groups.length > 0) && ((chguser.groups == null) || (findOne(chguser.groups, user.groups) == false))) return; } - // Validate input - if (common.validateString(command.email, 1, 256) && (chguser.email != command.email)) { chguser.email = command.email; change = 1; } + // Validate and change email + if (domain.usernameisemail !== true) { + if (common.validateString(command.email, 1, 256) && (chguser.email != command.email)) { chguser.email = command.email; change = 1; } + } // Make changes if ((command.emailVerified === true || command.emailVerified === false) && (chguser.emailVerified != command.emailVerified)) { chguser.emailVerified = command.emailVerified; change = 1; } diff --git a/package.json b/package.json index fb822a6b..d652d354 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "meshcentral", - "version": "0.3.7-j", + "version": "0.3.7-k", "keywords": [ "Remote Management", "Intel AMT", diff --git a/public/images/mail12.png b/public/images/mail12.png new file mode 100644 index 0000000000000000000000000000000000000000..b06d06e821294f3091fbd5594dd7e3824a9bd603 GIT binary patch literal 246 zcmeAS@N?(olHy`uVBq!ia0vp^JV4CJ!3HGRcAO0XQjEnx?oJHr&dIz4a#+$GeH|GX zHuiJ>Nn{17EbxddW?->Of(mh=qLo|Y?o;}Fx5FpU=5*|Zr;rzt*G`#k$Jzu8OU mch&zn_O(2mZJ@JZ3-iCtiK+>wcDw^x$>8bg=d#Wzp$P!1Qdk}U literal 0 HcmV?d00001 diff --git a/sample-config.json b/sample-config.json index c94da1c2..0354346b 100644 --- a/sample-config.json +++ b/sample-config.json @@ -24,6 +24,7 @@ "_AgentPing": 60, "_AgentPong": 60, "_AgentIdleTimeout": 150, + "_MeshErrorLogPath": "c:\\tmp", "_AllowHighQualityDesktop": true, "_UserAllowedIP": "127.0.0.1,192.168.1.0/24", "_UserBlockedIP": "127.0.0.1,::1,192.168.0.100", @@ -60,6 +61,7 @@ "_UserQuota": 1048576, "_MeshQuota": 248576, "_NewAccounts": true, + "_UserNameIsEmail": true, "_NewAccountEmailDomains": [ "sample.com" ], "_NewAccountsRights": [ "nonewgroups", "notools" ], "Footer": "Twitter", diff --git a/views/default-min.handlebars b/views/default-min.handlebars index 0f8754f5..8cbcefa3 100644 --- a/views/default-min.handlebars +++ b/views/default-min.handlebars @@ -1 +1 @@ - {{{title}}}
{{{title}}}
{{{title2}}}

{{{logoutControl}}}

 

\ No newline at end of file + {{{title}}}
{{{title}}}
{{{title2}}}

{{{logoutControl}}}

 

\ No newline at end of file diff --git a/views/default-mobile-min.handlebars b/views/default-mobile-min.handlebars index b188f9bc..edf80fd0 100644 --- a/views/default-mobile-min.handlebars +++ b/views/default-mobile-min.handlebars @@ -1 +1 @@ - {{{title}}}
{{{title}}}
{{{title2}}}
\ No newline at end of file + {{{title}}}
{{{title}}}
{{{title2}}}
\ No newline at end of file diff --git a/views/default-mobile.handlebars b/views/default-mobile.handlebars index 2792b435..f1b18abf 100644 --- a/views/default-mobile.handlebars +++ b/views/default-mobile.handlebars @@ -243,7 +243,7 @@

Account Actions

-
Change email address
+
Change password
Delete account
@@ -607,6 +607,7 @@ window.onresize = center; center(); + QV('changeEmailId', (features & 0x200000) == 0); QH('p1message', 'Connecting...'); go(1); diff --git a/views/default.handlebars b/views/default.handlebars index 9d973936..009ff4c6 100644 --- a/views/default.handlebars +++ b/views/default.handlebars @@ -225,7 +225,7 @@ - +
No device groups.
@@ -250,27 +250,27 @@ Device Groups - ( New ) + ( New )

- +

Server Statistics

@@ -576,11 +576,11 @@
- +
- - + + Disconnected
@@ -590,15 +590,15 @@
  -   -   -   -   -   -   -   -   -   +   +   +   +   +   +   +   +   +  
@@ -784,7 +784,7 @@ @@ -1047,6 +1047,7 @@ Q('RealNameCheckBox').checked = showRealNames; Q('viewselect').value = getstore("_deviceView", 1); Q('DeskControl').checked = (getstore('DeskControl', 1) == 1); + QV('accountChangeEmailAddressSpan', (features & 0x200000) == 0); // Display the page devices masterUpdate(3) @@ -1164,7 +1165,11 @@ } function getNodeFromId(id) { if (nodes != null) { for (var i in nodes) { if (nodes[i]._id == id) return nodes[i]; } } return null; } - function reload() { window.location.href = window.location.href; } + function reload() { + var x = window.location.href; + if (x.endsWith('/#')) { x = x.substring(0, x.length - 2); } + window.location.href = x; + } function onStateChanged(server, state, prevState, errorCode) { if (state == 0) { @@ -2401,11 +2406,11 @@ r += ''; if (mesh.mtype == 1) { r += '
No Intel® AMT devices in this mesh'; - if ((meshrights & 4) != 0) { r += ', add one'; } + if ((meshrights & 4) != 0) { r += ', add one'; } } if (mesh.mtype == 2) { r += '
No devices in this mesh'; - if ((meshrights & 4) != 0) { r += ', add one'; } + if ((meshrights & 4) != 0) { r += ', add one'; } } r += '.
'; current = mesh._id; @@ -2419,11 +2424,11 @@ // Add a "Add Device Group" option r += '
'; if ((view < 3) && (sort == 0) && (meshcount > 0) && ((userinfo.siteadmin == 0xFFFFFFFF) || ((userinfo.siteadmin & 64) == 0))) { - r += 'Add Device Group '; + r += 'Add Device Group '; } if ((userinfo.siteadmin == 0xFFFFFFFF) || ((userinfo.siteadmin & 128) == 0)) { - r += 'MeshCmd '; - if (navigator.platform.toLowerCase() == 'win32') { r += 'Router '; } + r += 'MeshCmd '; + if (navigator.platform.toLowerCase() == 'win32') { r += 'Router '; } } r += '

'; @@ -2599,28 +2604,28 @@ if ((meshrights & 4) == 0) return ''; var r = ''; if ((features & 1024) == 0) { // If CIRA is allowed - r += ' Add CIRA'; + r += ' Add CIRA'; } if (mesh.mtype == 1) { if ((features & 1) == 0) { // If not WAN-Only - r += ' Add Local'; - r += ' Scan Network'; + r += ' Add Local'; + r += ' Scan Network'; } if (mesh.amt && (mesh.amt.type == 2)) { // CCM activation - r += ' Activation'; + r += ' Activation'; } else if (mesh.amt && (mesh.amt.type == 3) && ((features & 0x00100000) != 0)) { // ACM activation - r += ' Activation'; + r += ' Activation'; } } if (mesh.mtype == 2) { - r += ' Add Agent'; - r += ' Invite'; + r += ' Add Agent'; + r += ' Invite'; } return r; } function addDeviceToMesh(meshid) { - if (xxdialogMode) return; + if (xxdialogMode) return false; var mesh = meshes[meshid]; var x = "Add a new Intel® AMT device to device group \"" + EscapeHtml(mesh.name) + "\".

"; x += addHtmlValue('Device Name', ''); @@ -2631,11 +2636,12 @@ setDialogMode(2, "Add Intel® AMT device", 3, addDeviceToMeshEx, x, meshid); validateDeviceToMesh(); Q('dp1devicename').focus(); + return false; } // Intel AMT CCM Activation function showCcmActivation(meshid) { - if (xxdialogMode) return; + if (xxdialogMode) return false; var servername = serverinfo.name, mesh = meshes[meshid]; if ((servername.indexOf('.') == -1) || ((features & 2) != 0)) { servername = window.location.hostname; } // If the server name is not set or it's in LAN-only mode, use the URL hostname as server name. var url, domainUrlNoSlash = domainUrl.substring(0, domainUrl.length - 1); @@ -2649,11 +2655,13 @@ var x = "Perform Intel AMT client control mode (CCM) activation to group \"" + EscapeHtml(mesh.name) + "\" by downloading the MeshCMD tool and running it like this:

"; x += ''; setDialogMode(2, "Intel® AMT activation", 9, null, x); + Q('idx_dlgOkButton').focus(); + return false; } // Intel AMT ACM Activation function showAcmActivation(meshid) { - if (xxdialogMode) return; + if (xxdialogMode) return false; var servername = serverinfo.name, mesh = meshes[meshid]; if ((servername.indexOf('.') == -1) || ((features & 2) != 0)) { servername = window.location.hostname; } // If the server name is not set or it's in LAN-only mode, use the URL hostname as server name. var url, domainUrlNoSlash = domainUrl.substring(0, domainUrl.length - 1); @@ -2670,11 +2678,13 @@ x += '
Intel AMT will need to be set with a Trusted FQDN in MEBx or have a wired LAN on the network: ' + serverinfo.amtAcmFqdn.join(', ') + '
'; } setDialogMode(2, "Intel® AMT activation", 9, null, x); + Q('idx_dlgOkButton').focus(); + return false; } // Display the Intel AMT scanning dialog box function addAmtScanToMesh(meshid) { - if (xxdialogMode) return; + if (xxdialogMode) return false; var x = "Enter a range of IP addresses to scan for Intel AMT devices.

"; x += addHtmlValue('IP Range', ''); x += '
'; @@ -2682,6 +2692,7 @@ QE('idx_dlgOkButton', false); QH('dp1results', '
Sample IP range values
192.168.0.100
192.168.1.0/24
192.167.0.1-192.168.0.100
'); focusTextBox('dp1range'); + return false; } function addAmtScanToMeshKeyUp(e) { @@ -2716,7 +2727,7 @@ } function addCiraDeviceToMesh(meshid) { - if (xxdialogMode) return; + if (xxdialogMode) return false; var mesh = meshes[meshid]; // Replace non alphabetic characters (@ and $) with 'X' because MPS username cannot accept it. @@ -2754,6 +2765,8 @@ } setDialogMode(2, "Add Intel® AMT CIRA device", 2, null, x, 'fileDownload'); + Q('dlgAddCiraSel').focus(); + return false; } function dlgAddCiraSelClick() { @@ -2772,7 +2785,7 @@ } function inviteAgentToMesh(meshid) { - if (xxdialogMode) return; + if (xxdialogMode) return false; var x = '', mesh = meshes[meshid]; if (features & 64) { x += addHtmlValue('Invitation Type', '') + "
"; @@ -2789,10 +2802,11 @@ } x += '
Invite someone to install the mesh agent by sharing an invitation link. This link points the user to installation instructions for the \"' + EscapeHtml(mesh.name) + '\" device group. The link is public and no account for this server is needed.

'; x += addHtmlValue('Link Expiration', ''); - x += '
'; + x += '
'; setDialogMode(2, "Invite", 3, performAgentInvite, x, meshid); - if (features & 64) { d2ChangedInviteType(); } else { validateAgentInvite(); } + if (features & 64) { Q('d2InviteType').focus(); d2ChangedInviteType(); } else { Q('d2inviteExpire').focus(); validateAgentInvite(); } d2RequestInvitationLink(); + return false; } function d2RequestInvitationLink() { @@ -2825,7 +2839,7 @@ } function addAgentToMesh(meshid) { - if (xxdialogMode) return; + if (xxdialogMode) return false; var mesh = meshes[meshid], x = '', installType = 0; x += addHtmlValue('Operating System', ''); x += '
'; @@ -2902,6 +2916,7 @@ } Q('aginsSelect').focus(); addAgentToMeshClick(); + return false; } function copyAgentUrl(url,addflag) { @@ -3839,7 +3854,7 @@ var x = ''; // Attribute: Mesh - x += addDeviceAttribute('Group', '' + EscapeHtml(meshes[node.meshid].name) + ''); + x += addDeviceAttribute('Group', '' + EscapeHtml(meshes[node.meshid].name) + ''); // Attribute: Name if ((node.rname != null) && (node.name != node.rname)) { x += addDeviceAttribute('Name', '' + EscapeHtml(node.rname) + ''); } @@ -3964,20 +3979,20 @@ x = '
'; if ((meshrights & 4) != 0) { // TODO: Show change group only if there is another mesh of the same type. - x += ' Change Group'; - x += ' Delete Device'; + x += ' Change Group'; + x += ' Delete Device'; } x += '
'; - if (mesh.mtype == 2) x += 'Interfaces '; - if (xxmap != null) x += 'Location '; + if (mesh.mtype == 2) x += 'Interfaces '; + if (xxmap != null) x += 'Location '; if (((meshrights & 8) != 0) && (mesh.mtype == 2)) x += 'Router '; // RDP link, show this link only of the remote machine is Windows. if (((connectivity & 1) != 0) && (clickOnce == true) && (mesh.mtype == 2) && ((meshrights & 8) != 0)) { - if ((node.agent.id > 0) && (node.agent.id < 5)) { x += 'RDP '; } + if ((node.agent.id > 0) && (node.agent.id < 5)) { x += 'RDP '; } if (node.agent.id > 4) { - x += 'Putty '; - x += 'WinSCP '; + x += 'Putty '; + x += 'WinSCP '; } } x += '

' @@ -4240,7 +4255,7 @@ } function p10showChangeGroupDialog(nodeids) { - if (xxdialogMode) return; + if (xxdialogMode) return false; var targetMeshId = null; if (nodeids.length == 1) { try { targetMeshId = meshes[getNodeFromId(nodeids[0])]._id; } catch (ex) { } } @@ -4259,6 +4274,7 @@ } else { setDialogMode(2, "Change Group", 1, null, "No other device group of same type exists."); } + return false; } function p10showChangeGroupDialogEx(b, nodeids) { @@ -4266,11 +4282,12 @@ } function p10showDeleteNodeDialog(nodeid) { - if (xxdialogMode) return; + if (xxdialogMode) return false; var x = "Are you sure you want to delete node \"" + EscapeHtml(currentNode.name) + "\"?

"; x += ""; setDialogMode(2, "Delete Node", 3, p10showDeleteNodeDialogEx, x, nodeid); p10validateDeleteNodeDialog(); + return false; } function p10validateDeleteNodeDialog() { @@ -4283,12 +4300,13 @@ function p10clickOnce(nodeid, protocol, port) { meshserver.send({ action: 'getcookie', nodeid: nodeid, tcpport: port, tag: 'clickonce', protocol: protocol }); + return false; } // Show current location var d2map = null; function p10showNodeLocationDialog() { - if ((xxdialogMode != null) && (xxdialogTag == '@xxmap')) { setDialogMode(0); } else { if (xxdialogMode) return; } + if ((xxdialogMode != null) && (xxdialogTag == '@xxmap')) { setDialogMode(0); } else { if (xxdialogMode) return false; } var markers = [], types = ['iploc', 'wifiloc', 'gpsloc', 'userloc'], boundingBox = null; for (var loctype in types) { @@ -4330,13 +4348,15 @@ layers: [ new ol.layer.Tile({ source: new ol.source.OSM() }), vectorLayer ], view: new ol.View({ center: ol.proj.fromLonLat([clng, clat]), zoom: zoom }) }); + return false; } // Show network interfaces function p10showNodeNetInfoDialog() { - if (xxdialogMode) return; + if (xxdialogMode) return false; setDialogMode(2, "Network Interfaces", 1, null, "
Loading...
", 'if' + currentNode._id ); meshserver.send({ action: 'getnetworkinfo', nodeid: currentNode._id }); + return false; } // Show MeshCentral Router dialog @@ -4993,7 +5013,7 @@ for (var pid in processes) { p.push( { p:parseInt(pid), c:processes[pid].cmd, d:processes[pid].cmd.toLowerCase(), u: processes[pid].user } ); } if (deskTools.sort == 0) { p.sort(sortProcessPid); } else if (deskTools.sort == 1) { p.sort(sortProcessName); } var x = ''; - for (var i in p) { if (p[i].p != 0) { x += '
' + p[i].p + '
' + (p[i].u?p[i].u:'') + '
' + p[i].c + '
'; } } + for (var i in p) { if (p[i].p != 0) { x += '
' + p[i].p + '
' + (p[i].u?p[i].u:'') + '
' + p[i].c + '
'; } } QH('DeskToolsProcesses', x); } } @@ -5041,7 +5061,7 @@ function dmousemove(e) { setSessionActivity(); e.addx = Q('DeskParent').scrollLeft; e.addy = Q('DeskParent').scrollTop; if (!xxdialogMode && desktop != null && Q('DeskControl').checked) { if ((webRtcDesktop != null) && (webRtcDesktop.softdesktop != null)) { webRtcDesktop.softdesktop.m.mousemove(e); desktop.m.sendKeepAlive(); } else { desktop.m.mousemove(e); } } } function dmousewheel(e) { setSessionActivity(); e.addx = Q('DeskParent').scrollLeft; e.addy = Q('DeskParent').scrollTop; if (!xxdialogMode && desktop != null && Q('DeskControl').checked) { if ((webRtcDesktop != null) && (webRtcDesktop.softdesktop != null)) { webRtcDesktop.softdesktop.m.mousewheel(e); desktop.m.sendKeepAlive(); } else { if (desktop.m.mousewheel) { desktop.m.mousewheel(e); } } haltEvent(e); return true; } return false; } function drotate(x) { if (!xxdialogMode && desktop != null) { desktop.m.setRotation(desktop.m.rotation + x); deskAdjust(); deskAdjust(); } } - function stopProcess(id, name) { setDialogMode(2, "Process Control", 3, stopProcessEx, 'Stop process #' + id + ' "' + name + '"?', id); } + function stopProcess(id, name) { setDialogMode(2, "Process Control", 3, stopProcessEx, 'Stop process #' + id + ' "' + name + '"?', id); return false; } function stopProcessEx(buttons, tag) { meshserver.send({ action: 'msg', type:'pskill', nodeid: currentNode._id, value: tag }); setTimeout(refreshDeskTools, 300); } // @@ -5339,13 +5359,13 @@ } function p13updateFiles(checkedNames) { - var html1 = '', html2 = '', displayPath = 'Root', fullPath = 'Root'; + var html1 = '', html2 = '', displayPath = 'Root', fullPath = 'Root'; // Work on parsing the file path var x = p13filetree.path.split('\\'); p13filetreelocation = []; for (var i in x) { if (x[i] != '') { p13filetreelocation.push(x[i]); } } // Remove empty spaces - for (var i in p13filetreelocation) { displayPath += ' / ' + p13filetreelocation[i] + '' } // Setup the path we display + for (var i in p13filetreelocation) { displayPath += ' / ' + p13filetreelocation[i] + '' } // Setup the path we display var newlinkpath = p13filetreelocation.join('/'); // Sort the files @@ -5370,10 +5390,10 @@ var h = ''; if (f.t < 3) { var right = '', title = ''; - h = "
 " + right + "
" + shortname + "
"; + h = "
 " + right + "
" + shortname + "
"; } else { var link = shortname; - if (f.s > 0) { link = "" + shortname + ""; } + if (f.s > 0) { link = "" + shortname + ""; } h = "
 " + fdatestr + "" + fsize + "
" + link + "
"; } @@ -5401,6 +5421,7 @@ if (x == null) { p13filetreelocation.pop(); } else { while (p13filetreelocation.length > x) { p13filetreelocation.pop(); } } p13targetpath = p13filetreelocation.join('/'); files.sendText({ action: 'ls', reqid: 1, path: p13targetpath }); + return false; } var p13sortorder; @@ -5465,8 +5486,8 @@ function p13copyFile(cut) { var checkboxes = document.getElementsByName('fd'); p13clipboard = []; p13clipboardCut = cut, p13clipboardFolder = p13targetpath; for (var i = 0; i < checkboxes.length; i++) { if ((checkboxes[i].checked) && (checkboxes[i].attributes.file.value == "3")) { p13clipboard.push(p13filetree.dir[checkboxes[i].value].n); } } p13updateClipview(); } function p13pasteFile() { var x = ''; if ((p13clipboard != null) && (p13clipboard.length > 0)) { x = 'Confim ' + (p13clipboardCut == 0?'copy':'move') + ' of ' + p13clipboard.length + ' entrie' + ((p13clipboard.length > 1)?'s':'') + ' to this location?' } setDialogMode(2, "Paste", 3, p13pasteFileEx, x); } function p13pasteFileEx() { files.sendText({ action: (p13clipboardCut == 0?'copy':'move'), reqid: 1, scpath: p13clipboardFolder, dspath: p13targetpath, names: p13clipboard }); p13folderup(999); if (p13clipboardCut == 1) { p13clipboard = null, p13clipboardFolder = null, p13clipboardCut = 0; p13updateClipview(); } } - function p13updateClipview() { var x = ''; if ((p13clipboard != null) && (p13clipboard.length > 0)) { x = 'Holding ' + p13clipboard.length + ' entrie' + ((p13clipboard.length > 1)?'s':'') + ' for ' + (p13clipboardCut == 0?'copy':'move') + ', Clear.' } QH('p13bottomstatus', x); p13setActions(); } - function p13clearClip() { p13clipboard = null; p13clipboardFolder = null; p13clipboardCut = 0; p13updateClipview(); } + function p13updateClipview() { var x = ''; if ((p13clipboard != null) && (p13clipboard.length > 0)) { x = 'Holding ' + p13clipboard.length + ' entrie' + ((p13clipboard.length > 1)?'s':'') + ' for ' + (p13clipboardCut == 0?'copy':'move') + ', Clear.' } QH('p13bottomstatus', x); p13setActions(); } + function p13clearClip() { p13clipboard = null; p13clipboardFolder = null; p13clipboardCut = 0; p13updateClipview(); return false; } function p13fileDragDrop(e) { haltEvent(e); @@ -5958,6 +5979,7 @@ function account_manageAuthApp() { if (xxdialogMode || ((features & 4096) == 0)) return; if (userinfo.otpsecret == 1) { account_removeOtp(); } else { account_addOtp(); } + return false; } function account_addOtp() { @@ -5979,14 +6001,16 @@ function account_manageOtp(action) { if ((xxdialogMode == 2) && (xxdialogTag == 'otpauth-manage')) { dialogclose(0); } - if (xxdialogMode || ((features & 4096) == 0)) return; + if (xxdialogMode || ((features & 4096) == 0)) return false; if ((userinfo.otpsecret == 1) || (userinfo.otphkeys > 0)) { meshserver.send({ action: 'otpauth-getpasswords', subaction: action }); } + return false; } function account_manageHardwareOtp() { if ((xxdialogMode == 2) && (xxdialogTag == 'otpauth-hardware-manage')) { dialogclose(0); } - if (xxdialogMode || ((features & 4096) == 0)) return; + if (xxdialogMode || ((features & 4096) == 0)) return false; meshserver.send({ action: 'otp-hkey-get' }); + return false; } function account_addhkey(type) { @@ -6024,12 +6048,14 @@ function account_enableNotifications() { if (Notification) { Notification.requestPermission().then(function (permission) { QV('accountEnableNotificationsSpan', permission != "granted"); }); } + return false; } function account_showVerifyEmail() { - if (xxdialogMode || (userinfo.emailVerified == true) || (serverinfo.emailcheck != true)) return; + if (xxdialogMode || (userinfo.emailVerified == true) || (serverinfo.emailcheck != true)) return false; var x = "Click ok to send a verification mail to:
" + EscapeHtml(userinfo.email) + "
Please wait a few minute to receive the verification."; setDialogMode(2, "Email Verification", 3, account_showVerifyEmailEx, x); + return false; } function account_showVerifyEmailEx() { @@ -6037,13 +6063,14 @@ } function account_showChangeEmail() { - if (xxdialogMode) return; + if (xxdialogMode) return false; var x = "Change your account email address here.

"; x += addHtmlValue('Email', ''); setDialogMode(2, "Email Address Change", 3, account_changeEmail, x); if (userinfo.email != null) { Q('dp2email').value = userinfo.email; } account_validateEmail(); Q('dp2email').focus(); + return false; } function account_validateEmail(e, email) { @@ -6056,7 +6083,7 @@ } function account_showDeleteAccount() { - if (xxdialogMode) return; + if (xxdialogMode) return false; var x = "To delete this account, type in the account password in both boxes below and hit ok.

"; x += "
"; x += ""; @@ -6068,10 +6095,11 @@ setDialogMode(2, "Delete Account", 0, null, x); account_validateDeleteAccount(); Q('apassword1').focus(); + return false; } function account_showChangePassword() { - if (xxdialogMode) return; + if (xxdialogMode) return false; var x = "Change your account password by entering the old password and new password twice in the boxes below."; if (features & 0x00010000) { " Password hint can be used but is not recommanded."; } x += "

";; @@ -6095,6 +6123,7 @@ setDialogMode(2, "Change Password", 3, account_showChangePasswordEx, x); Q('apassword0').focus(); account_validateNewPassword(); + return false; } function account_showChangePasswordEx() { @@ -6106,16 +6135,16 @@ } function account_createMesh() { - if (xxdialogMode) return; + if (xxdialogMode) return false; // Check if we are disallowed from creating a device group - if ((userinfo.siteadmin != 0xFFFFFFFF) && ((userinfo.siteadmin & 64) != 0)) { setDialogMode(2, "New Device Group", 1, null, "This account does not have the rights to create a new device group."); return; } + if ((userinfo.siteadmin != 0xFFFFFFFF) && ((userinfo.siteadmin & 64) != 0)) { setDialogMode(2, "New Device Group", 1, null, "This account does not have the rights to create a new device group."); return false; } // Remind the user to verify the email address - if ((userinfo.emailVerified !== true) && (serverinfo.emailcheck == true) && (userinfo.siteadmin != 0xFFFFFFFF)) { setDialogMode(2, "Account Security", 1, null, "Unable to access a device until a email address is verified. This is required for password recovery. Go to the \"My Account\" tab to change and verify an email address."); return; } + if ((userinfo.emailVerified !== true) && (serverinfo.emailcheck == true) && (userinfo.siteadmin != 0xFFFFFFFF)) { setDialogMode(2, "Account Security", 1, null, "Unable to access a device until a email address is verified. This is required for password recovery. Go to the \"My Account\" tab to change and verify an email address."); return false; } // Remind the user to add two factor authentication - if ((features & 0x00040000) && !((userinfo.otpsecret == 1) || (userinfo.otphkeys > 0) || (userinfo.otpkeys > 0))) { setDialogMode(2, "Account Security", 1, null, "Unable to access a device until two-factor authentication is enabled. This is required for extra security. Go to the \"My Account\" tab and look at the \"Account Security\" section."); return; } + if ((features & 0x00040000) && !((userinfo.otpsecret == 1) || (userinfo.otphkeys > 0) || (userinfo.otpkeys > 0))) { setDialogMode(2, "Account Security", 1, null, "Unable to access a device until two-factor authentication is enabled. This is required for extra security. Go to the \"My Account\" tab and look at the \"Account Security\" section."); return false; } // We are allowed, let's prompt to information var x = "Create a new device group using the options below.

"; @@ -6125,6 +6154,7 @@ setDialogMode(2, "New Device Group", 3, account_createMeshEx, x); account_validateMeshCreate(); Q('dp2meshname').focus(); + return false; } function account_validateMeshCreate() { @@ -6214,10 +6244,11 @@ currentMesh = meshes[meshid]; p20updateMesh(); go(20); + return false; } function server_showRestoreDlg() { - if (xxdialogMode) return; + if (xxdialogMode) return false; var x = 'Restore the server using a backup, this will delete the existing server data. Only do this if you know what you are doing.

'; x += '
'; x += ''; @@ -6226,6 +6257,7 @@ x += '


'; setDialogMode(2, "Restore Server", 0, null, x); account_validateServerRestore(); + return false; } function account_validateServerRestore() { @@ -6233,18 +6265,20 @@ } function server_showVersionDlg() { - if (xxdialogMode) return; + if (xxdialogMode) return false; setDialogMode(2, "MeshCentral Version", 1, null, "Loading...", 'MeshCentralServerUpdate'); meshserver.send({ action: 'serverversion' }); + return false; } function server_showVersionDlgUpdate() { QE('idx_dlgOkButton', Q('d2updateCheck').checked); } function server_showVersionDlgEx() { meshserver.send({ action: 'serverupdate' }); } function server_showErrorsDlg() { - if (xxdialogMode) return; + if (xxdialogMode) return false; setDialogMode(2, "MeshCentral Errors", 1, null, "Loading...", 'MeshCentralServerErrors'); meshserver.send({ action: 'servererrors' }); + return false; } function server_showErrorsDlgUpdate() { QE('idx_dlgOkButton', Q('d2updateCheck').checked); } function server_showErrorsDlgEx() { meshserver.send({ action: 'serverclearerrorlog' }); } @@ -6319,21 +6353,21 @@ x += '

'; var currentMeshLinks = currentMesh.links[userinfo._id]; - if (currentMeshLinks && ((currentMeshLinks.rights & 2) != 0)) { x += ' Add Users'; } + if (currentMeshLinks && ((currentMeshLinks.rights & 2) != 0)) { x += ' Add Users'; } if ((meshrights & 4) != 0) { if (currentMesh.mtype == 1) { - x += ' Install CIRA'; - x += ' Install local'; + x += ' Install CIRA'; + x += ' Install local'; if (currentMesh.amt && (currentMesh.amt.type == 2)) { // CCM activation - x += ' Activation'; + x += ' Activation'; } else if (currentMesh.amt && (currentMesh.amt.type == 3) && ((features & 0x00100000) != 0)) { // ACM activation - x += ' Activation'; + x += ' Activation'; } } if (currentMesh.mtype == 2) { - x += ' Install'; - x += ' Invite'; + x += ' Install'; + x += ' Invite'; } } @@ -6342,11 +6376,11 @@ if ((meshrights & 4) == 0) return ''; var r = ''; if (mesh.mtype == 1) { - r += ' Add CIRA'; - r += ' Add Local'; + r += ' Add CIRA'; + r += ' Add Local'; } if (mesh.mtype == 2) { - r += ' Add Agent'; + r += ' Add Agent'; } return r; } @@ -6368,7 +6402,7 @@ for (var i in sortedusers) { var trash = '', rights = 'Partial Rights', r = sortedusers[i].rights; if (r == 0xFFFFFFFF) rights = 'Full Administrator'; else if (r == 0) rights = 'No Rights'; - if ((sortedusers[i].id != userinfo._id) && (meshrights == 0xFFFFFFFF || (((meshrights & 2) != 0)))) { trash = ''; } + if ((sortedusers[i].id != userinfo._id) && (meshrights == 0xFFFFFFFF || (((meshrights & 2) != 0)))) { trash = ''; } x += ''; ++count; } @@ -6376,7 +6410,7 @@ x += '
Password:
 ' + EscapeHtml(decodeURIComponent(sortedusers[i].name)) + '
' + trash + '
' + rights + '
'; // If we are full administrator on this mesh, allow deletion of the mesh - if (meshrights == 0xFFFFFFFF) { x += ''; } + if (meshrights == 0xFFFFFFFF) { x += ''; } QH('p20info', x); } @@ -6455,11 +6489,12 @@ } function p20showDeleteMeshDialog() { - if (xxdialogMode) return; + if (xxdialogMode) return false; var x = "Are you sure you want to delete group \"" + EscapeHtml(currentMesh.name) + "\"? Deleting the device group will also delete all information about devices within this group.

"; x += "Confirm"; setDialogMode(2, "Delete Group", 3, p20showDeleteMeshDialogEx, x); p20validateDeleteMeshDialog(); + return false; } function p20validateDeleteMeshDialog() { @@ -6545,7 +6580,7 @@ } function p20showAddMeshUserDialog() { - if (xxdialogMode) return; + if (xxdialogMode) return false; 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." } x += "

"; @@ -6571,6 +6606,7 @@ setDialogMode(2, "Add Users to Device Group", 3, p20showAddMeshUserDialogEx, x); p20validateAddMeshUserDialog(); Q('dp20username').focus(); + return false; } function p20setname(name) { @@ -6580,6 +6616,7 @@ xusers[xusers.length - 1] = name; Q('dp20username').value = xusers.join(', '); p20validateAddMeshUserDialog(); + return false; } function p20validateAddMeshUserDialog() { @@ -6599,7 +6636,7 @@ } if ((exactMatch == false) && (matchingUsers.length > 0)) { var x = ''; - for (var i in matchingUsers) { x += '' + matchingUsers[i] + '
'; } + for (var i in matchingUsers) { x += '' + matchingUsers[i] + '
'; } QH('dp20usersuggest', x); showsuggestbox = true; } @@ -6685,7 +6722,7 @@ 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)); return false; } function p20viewuserEx2(button, userid) { meshserver.send({ action: 'removemeshuser', meshid: currentMesh._id, meshname: currentMesh.name, userid: userid }); } // @@ -6698,7 +6735,7 @@ function updateFiles() { QV('MainMenuMyFiles', ((features & 8) == 0)); if ((features & 8) != 0) return; // If running on a server without files, exit now. - var html1 = '', html2 = '', displayPath = 'Root', fullPath = 'Root', publicPath, filetreex = filetree, folderdepth = 1; + var html1 = '', html2 = '', displayPath = 'Root', fullPath = 'Root', publicPath, filetreex = filetree, folderdepth = 1; // Navigate to path location, build the paths at the same time var filetreelocation2 = [], oldlinkpath = filetreelinkpath, checkedBoxes = [], checkboxes = document.getElementsByName('fc'); @@ -6718,7 +6755,7 @@ if (filetreelinkpath != '') { filetreelinkpath += '/' + filetreelocation[i]; if (folderdepth > 2) { publicPath += '/' + filetreelocation[i]; } } } filetreex = filetreex.f[filetreelocation[i]]; - displayPath += ' / ' + (filetreex.n != null?filetreex.n:filetreelocation[i]) + ''; + displayPath += ' / ' + (filetreex.n != null?filetreex.n:filetreelocation[i]) + ''; folderdepth++; } else { break; @@ -6749,11 +6786,11 @@ var h = ''; if (f.t < 3 || f.t == 4) { var right = (f.t == 1 || f.t == 4)?p5getQuotabar(f):'', title = ''; - h = "
 " + right + "
" + shortname + "
"; + h = "
 " + right + "
" + shortname + "
"; } else { var link = shortname; var publiclink = ''; - if (publicfolder) { publiclink = ' (Link)'; } + if (publicfolder) { publiclink = ' (Link)'; } if (f.s > 0) { link = "" + shortname + "" + publiclink; } h = "
 " + fdatestr + "" + fsize + "
" + link + "
"; } @@ -6840,7 +6877,7 @@ function p5selectallfile() { var nv = (getFileSelCount() == 0), checkboxes = document.getElementsByName('fc'); for (var i = 0; i < checkboxes.length; i++) { checkboxes[i].checked = nv; } p5setActions(); } function setupBackPointers(x) { if (x.f != null) { var fs = 0, fc = 0; for (var i in x.f) { setupBackPointers(x.f[i]); x.f[i].parent = x; if (x.f[i].s) { fs += x.f[i].s; } if (x.f[i].c) { fc += x.f[i].c; } if (x.f[i].t == 3) { fc++; } } x.s = fs; x.c = fc; } return x; } function getFileSizeStr(size) { if (size == 1) return "1 byte"; return "" + size + " bytes"; } - function p5folderup(x) { if (x == null) { filetreelocation.pop(); } else { while (filetreelocation.length > x) { filetreelocation.pop(); } } updateFiles(); } + function p5folderup(x) { if (x == null) { filetreelocation.pop(); } else { while (filetreelocation.length > x) { filetreelocation.pop(); } } updateFiles(); return false; } function p5folderset(x) { filetreelocation.push(decodeURIComponent(x)); updateFiles(); } function p5createfolder() { setDialogMode(2, "New Folder", 3, p5createfolderEx, ''); focusTextBox('p5renameinput'); p5fileNameCheck(); } function p5createfolderEx() { meshserver.send({ action: 'fileoperation', fileop: 'createfolder', path: filetreelocation, newfolder: Q('p5renameinput').value}); } @@ -6858,8 +6895,8 @@ function p5copyFile(cut) { var checkboxes = document.getElementsByName('fc'); p5clipboard = []; p5clipboardCut = cut, p5clipboardFolder = Clone(filetreelocation); for (var i = 0; i < checkboxes.length; i++) { if ((checkboxes[i].checked) && (checkboxes[i].attributes.file.value == "3")) { p5clipboard.push(checkboxes[i].value); } } p5updateClipview(); } function p5pasteFile() { var x = ''; if ((p5clipboard != null) && (p5clipboard.length > 0)) { x = 'Confim ' + (p5clipboardCut == 0?'copy':'move') + ' of ' + p5clipboard.length + ' entrie' + ((p5clipboard.length > 1)?'s':'') + ' to this location?' } setDialogMode(2, "Paste", 3, p5pasteFileEx, x); } function p5pasteFileEx() { meshserver.send({ action: 'fileoperation', fileop: (p5clipboardCut == 0?'copy':'move'), scpath: p5clipboardFolder, path: filetreelocation, names: p5clipboard }); p5folderup(999); if (p5clipboardCut == 1) { p5clipboard = null, p5clipboardFolder = null, p5clipboardCut = 0; p5updateClipview(); } } - function p5updateClipview() { var x = ''; if ((p5clipboard != null) && (p5clipboard.length > 0)) { x = 'Holding ' + p5clipboard.length + ' entrie' + ((p5clipboard.length > 1)?'s':'') + ' for ' + (p5clipboardCut == 0?'copy':'move') + ', Clear.' } QH('p5bottomstatus', x); p5setActions(); } - function p5clearClip() { p5clipboard = null; p5clipboardFolder = null; p5clipboardCut = 0; p5updateClipview(); } + function p5updateClipview() { var x = ''; if ((p5clipboard != null) && (p5clipboard.length > 0)) { x = 'Holding ' + p5clipboard.length + ' entrie' + ((p5clipboard.length > 1)?'s':'') + ' for ' + (p5clipboardCut == 0?'copy':'move') + ', Clear.' } QH('p5bottomstatus', x); p5setActions(); } + function p5clearClip() { p5clipboard = null; p5clipboardFolder = null; p5clipboardCut = 0; p5updateClipview(); return false; } function p5fileDragDrop(e) { if (xxdialogMode) return; @@ -6993,8 +7030,8 @@ function p3showDownloadEventsDialog() { if (xxdialogMode) return; var x = 'Download the list of events with one of the file formats below.

'; - x += addHtmlValue('CSV Format', 'eventslist.csv'); - x += addHtmlValue('JSON Format', 'eventslist.json'); + x += addHtmlValue('CSV Format', 'eventslist.csv'); + x += addHtmlValue('JSON Format', 'eventslist.json'); setDialogMode(2, "Event List Export", 1, null, x); } @@ -7002,12 +7039,14 @@ var csv = "time, type, action, user, message\r\n"; for (var i in events) { csv += '\"' + events[i].time + '\",\"' + events[i].etype + '\",\"' + ((events[i].action != null)?events[i].action:'') + '\",\"' + ((events[i].username != null)?events[i].username:'') + '\",\"' + ((events[i].msg != null)?events[i].msg:'') + '\"\r\n'; } saveAs(new Blob([csv], { type: "application/octet-stream" }), "eventslist.csv"); + return false; } function p3downloadEventsDialogJSON() { var r = [] for (var i in events) { r.push(events[i]); } saveAs(new Blob([JSON.stringify(r)], { type: "application/octet-stream" }), "eventslist.json"); + return false; } // @@ -7087,14 +7126,14 @@ if (sessions != null) { gray = ''; if (self) { - msg = ""; - msg += ""; + msg = ""; + msg += ""; } if (sessions == 1) { lastAccess += '1 session'; } else { lastAccess += sessions + ' sessions'; } } else { if (user.login) { lastAccess += '' + printDate(new Date(user.login * 1000)) + ''; } } - if (self) { permissions += ""; } + if (self) { permissions += ""; } if ((user.siteadmin != null) && ((user.siteadmin & 32) != 0) && (user.siteadmin != 0xFFFFFFFF)) { permissions += "Locked, "; } permissions += ""; @@ -7120,7 +7159,16 @@ var username = EscapeHtml(user.name), emailVerified = ''; if (serverinfo.emailcheck == true) { emailVerified = ((user.emailVerified != true) ? ' ' : ' '); } - if (user.email != null) { username += ', ' + user.email + '' + emailVerified; } + if (user.email != null) { + if (((features & 0x200000) == 0) || (user.email.toLowerCase() != user.name.toLowerCase())) { + // Username & email are different + username += ', ' + user.email + '' + emailVerified; + } else { + // Username & email are the same + username += ' ' + emailVerified; + } + + } if ((user.otpsecret > 0) || (user.otphkeys > 0)) { username += ' '; } if ((user.siteadmin != null) && ((user.siteadmin & 32) != 0) && (user.siteadmin != 0xFFFFFFFF)) { username += ' '; } @@ -7162,7 +7210,7 @@ function showUserAlertDialogEx(button, userid) { meshserver.send({ action: 'notifyuser', userid: decodeURIComponent(userid), msg: Q('d2notifyText').value }); } function doemail(e, addr) { - if (xxdialogMode) return; + if (xxdialogMode) return false; haltEvent(e); window.open("mailto:" + addr); return false; @@ -7201,8 +7249,8 @@ function p4downloadUserInfo() { if (xxdialogMode) return; var x = 'Download the list of users with one of the file formats below.

'; - x += addHtmlValue('CSV Format', 'userlist.csv'); - x += addHtmlValue('JSON Format', 'userlist.json'); + x += addHtmlValue('CSV Format', 'userlist.csv'); + x += addHtmlValue('JSON Format', 'userlist.json'); setDialogMode(2, "User List Export", 1, null, x); } @@ -7219,12 +7267,14 @@ csv += '\"' + users[i]._id + '\",\"' + users[i].name + '\",\"' + (users[i].email ? users[i].email : '') + '\",\"' + (users[i].creation ? new Date(users[i].creation * 1000) : '') + '\",\"' + (users[i].login ? new Date(users[i].login * 1000) : '') + '\",\"' + (users[i].groups ? users[i].groups.join(',') : '') + '\",\"' + (multiFactor ? factors.join(',') : '') + '\"\r\n'; } saveAs(new Blob([csv], { type: "application/octet-stream" }), "userlist.csv"); + return false; } function p4downloadUserInfoJSON() { var r = [] for (var i in users) { r.push(users[i]); } saveAs(new Blob([JSON.stringify(r)], { type: "application/octet-stream" }), "userlist.json"); + return false; } function showUserBroadcastDialog() { @@ -7241,11 +7291,12 @@ function showCreateNewAccountDialog() { if (xxdialogMode) return; var x = ''; - x += addHtmlValue('Name', ''); + if ((features & 0x200000) == 0) { x += addHtmlValue('Name', ''); } x += addHtmlValue('Email', ''); x += addHtmlValue('Password', ''); x += addHtmlValue('Password', ''); x += '
Force password reset on next login.
'; + if (serverinfo.emailcheck) { x += '
Email is verified.
'; } if (passRequirements) { var r = [], rc = 0; @@ -7255,18 +7306,23 @@ setDialogMode(2, "Create Account", 3, showCreateNewAccountDialogEx, x); showCreateNewAccountDialogValidate(); - Q('p4name').focus(); + if ((features & 0x200000) == 0) { Q('p4name').focus(); } else { Q('p4email').focus(); } } function showCreateNewAccountDialogValidate(x) { if ((x == null) && (Q('p4email').value.length > 0) && (validateEmail(Q('p4email').value)) == false) { QE('idx_dlgOkButton', false); return; } - var ok = (!Q('p4name') || ((Q('p4name').value.length > 0) && (Q('p4name').value.indexOf(' ') == -1))) && Q('p4pass1').value.length > 0 && Q('p4pass1').value == Q('p4pass2').value && checkPasswordRequirements(Q('p4pass1').value, passRequirements); + var ok = true; + if ((features & 0x200000) == 0) { ok &= (!Q('p4name') || ((Q('p4name').value.length > 0) && (Q('p4name').value.indexOf(' ') == -1))); } + ok &= (Q('p4pass1').value.length > 0 && Q('p4pass1').value == Q('p4pass2').value && checkPasswordRequirements(Q('p4pass1').value, passRequirements)); if (ok && passRequirements) { if (checkPasswordRequirements(Q('p4pass1').value, passRequirements) == false) { ok = false; } } QE('idx_dlgOkButton', ok); } function showCreateNewAccountDialogEx() { - meshserver.send({ action: 'adduser', username: Q('p4name').value, email: Q('p4email').value, pass: Q('p4pass1').value, resetNextLogin: Q('p4resetNextLogin').checked }); + var username = ((features & 0x200000) == 0) ? Q('p4name').value : Q('p4email').value; + var x = { action: 'adduser', username: username, email: Q('p4email').value, pass: Q('p4pass1').value, resetNextLogin: Q('p4resetNextLogin').checked }; + if (serverinfo.emailcheck) { x.emailVerified = Q('p4verifiedEmail').checked; } + meshserver.send(x); } function showUserGroupDialog(e, userid) { @@ -7403,12 +7459,12 @@ var email = user.email?EscapeHtml(user.email):'Not set', everify = ''; if (serverinfo.emailcheck) { everify = ((user.emailVerified == true) ? ' ' : ' '); } if (user.name.toLowerCase() != user._id.split('/')[2]) { x += addDeviceAttribute('User Identifier', 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 + ' '); + if (((features & 0x200000) == 0) && ((user.siteadmin != 0xFFFFFFFF) || (userinfo.siteadmin == 0xFFFFFFFF))) { // If we are not site admin, we can't change a admin email. + x += addDeviceAttribute('Email', everify + "" + email + ' '); } else { - x += addDeviceAttribute('Email', everify + email + ' '); + x += addDeviceAttribute('Email', everify + email + ' '); } - x += addDeviceAttribute('Server Rights', premsg + "" + msg.join(', ') + ""); + x += addDeviceAttribute('Server Rights', premsg + "" + msg.join(', ') + ""); if (user.quota) x += addDeviceAttribute('Server Quota', EscapeHtml(parseInt(user.quota) / 1024) + ' k'); x += addDeviceAttribute('Creation', printDateTime(new Date(user.creation * 1000))); if (user.login) x += addDeviceAttribute('Last Login', printDateTime(new Date(user.login * 1000))); @@ -7457,9 +7513,9 @@ // Show bottom buttons x = '
'; - if (deletePossible) x += 'Delete User'; + if (deletePossible) x += 'Delete User'; x += '
'; - if (userinfo.siteadmin == 0xFFFFFFFF) x += 'Change Password'; + if (userinfo.siteadmin == 0xFFFFFFFF) x += 'Change Password'; x += '

' QH('p30html3', x); @@ -7477,7 +7533,7 @@ // Display the user's email change dialog box function p30showUserEmailChangeDialog(event) { - if (xxdialogMode) return; + if (xxdialogMode) return false; var x = ''; x += addHtmlValue('Email', ''); if (serverinfo.emailcheck) { x += addHtmlValue('Status', ''); } @@ -7486,6 +7542,7 @@ Q('dp30email').value = (currentUser.email?currentUser.email:''); if (serverinfo.emailcheck) { Q('dp30verified').value = currentUser.emailVerified?1:0; } p30validateEmail(); + return false; } // Perform validation on the user's email change dialog box @@ -7701,7 +7758,7 @@ var h = ''; if (f.t < 3) { var title = ''; - h = ""; + h = ""; } else { var link = shortname; //if (f.s > 0) { link = "" + shortname + ""; } @@ -7716,7 +7773,7 @@ d3setActions(); } - function d3folderset(x) { d3filetreelocation.push(decodeURIComponent(x)); d3updatefiles(); } + function d3folderset(x) { d3filetreelocation.push(decodeURIComponent(x)); d3updatefiles(); return false; } function d3folderup(x) { if (x == null) { d3filetreelocation.pop(); } else { while (d3filetreelocation.length > x) { d3filetreelocation.pop(); } } d3updatefiles(); } function d3getFileSel() { var cc = []; var checkboxes = document.getElementsByName('fcx'); for (var i = 0; i < checkboxes.length; i++) { if (checkboxes[i].checked) { cc.push(checkboxes[i].value) } } return cc; } function d3setActions() { @@ -8211,8 +8268,8 @@ function AddButton(v, f) { return ""; } function AddButton2(v, f) { return ""; } function AddRefreshButton(f) { return ""; } - function MoreStart() { return "▼ More"; }; + function MoreStart() { return "▼ More"; }; function getSelectedOptions(sel) { var opts = [], opt; for (var i = 0, len = sel.options.length; i < len; i++) { opt = sel.options[i]; if (opt.selected) { opts.push(opt.value); } } return opts; } function getInstance(x, y) { for (var i in x) { if (x[i]["InstanceID"] == y) return x[i]; } return null; } function getItem(x, y, z) { for (var i in x) { if (x[i][y] == z) return x[i]; } return null; } diff --git a/views/login-min.handlebars b/views/login-min.handlebars index 739c034c..ef4836f9 100644 --- a/views/login-min.handlebars +++ b/views/login-min.handlebars @@ -1 +1 @@ - {{{title}}} - Login
{{{title}}}
{{{title2}}}

Welcome


\ No newline at end of file + {{{title}}} - Login
{{{title}}}
{{{title2}}}

Welcome


\ No newline at end of file diff --git a/views/login-mobile-min.handlebars b/views/login-mobile-min.handlebars index 2e5312b0..96cf72df 100644 --- a/views/login-mobile-min.handlebars +++ b/views/login-mobile-min.handlebars @@ -1 +1 @@ - MeshCentral - Login
{{{title}}}
{{{title2}}}
\ No newline at end of file + MeshCentral - Login
{{{title}}}
{{{title2}}}
\ No newline at end of file diff --git a/views/login-mobile.handlebars b/views/login-mobile.handlebars index 39ec84d6..966722f2 100644 --- a/views/login-mobile.handlebars +++ b/views/login-mobile.handlebars @@ -53,7 +53,7 @@
- + @@ -67,7 +67,7 @@
Username:Username:
- + @@ -289,6 +289,12 @@ if (top != self && (loc == null || top.active == false)) { top.location = self.location; return; } } + if (features & 0x200000) { // Email is username + QH('loginusername', 'Email:'); + QH('resetAccountSpan', 'Forgot password?'); + QV('nuUserRow', false); + } + QV('createPanelHint', passRequirements.hint === true); QV('resetpasswordpanelHint', passRequirements.hint === true); @@ -391,7 +397,7 @@ QV('resettokenpanel', x == 5); QV('resetpasswordpanel', x == 6); if (x == 1) { Q('username').focus(); } - if (x == 2) { Q('ausername').focus(); } + if (x == 2) { if (features & 0x200000) { Q('aemail').focus(); } else { Q('ausername').focus(); } } // Email is username if (x == 3) { Q('remail').focus(); } if (x == 4) { Q('tokenInput').focus(); } if (x == 5) { Q('resetTokenInput').focus(); } @@ -408,7 +414,9 @@ function validateCreate(box,e) { setDialogMode(0); - 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)); + var ok = false; + if (features & 0x200000) { ok = true; } else { ok = (Q('ausername').value.length > 0) && (Q('ausername').value.indexOf(' ') == -1) && (Q('ausername').value.indexOf('"') == -1) && (Q('ausername').value.indexOf(',') == -1); } + ok &= ((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 (Q('apassword1').value == '') { QH('passWarning', ''); diff --git a/views/login.handlebars b/views/login.handlebars index 6894da05..2faae12f 100644 --- a/views/login.handlebars +++ b/views/login.handlebars @@ -50,7 +50,7 @@
Username:
- + @@ -64,7 +64,7 @@
Username:Username:
- + @@ -290,6 +290,12 @@ if (top != self && (loc == null || top.active == false)) { top.location = self.location; return; } } + if (features & 0x200000) { // Email is username + QH('loginusername', 'Email:'); + QH('resetAccountSpan', 'Forgot password?'); + QV('nuUserRow', false); + } + if (nightMode) { QC('body').add('night'); } QV('createPanelHint', passRequirements.hint === true); @@ -406,7 +412,7 @@ QV('resettokenpanel', x == 5); QV('resetpasswordpanel', x == 6); if (x == 1) { Q('username').focus(); } - if (x == 2) { Q('ausername').focus(); } + if (x == 2) { if (features & 0x200000) { Q('aemail').focus(); } else { Q('ausername').focus(); } } // Email is username if (x == 3) { Q('remail').focus(); } if (x == 4) { Q('tokenInput').focus(); } if (x == 5) { Q('resetTokenInput').focus(); } @@ -423,7 +429,8 @@ function validateCreate(box, e) { setDialogMode(0); - var userok = (Q('ausername').value.length > 0) && (Q('ausername').value.indexOf(' ') == -1) && (Q('ausername').value.indexOf('"') == -1) && (Q('ausername').value.indexOf(',') == -1); + var userok = false; + if (features & 0x200000) { userok = true; } else { 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 pass1ok = (Q('apassword1').value.length > 0); var pass2ok = (Q('apassword2').value.length > 0) && (Q('apassword2').value == Q('apassword1').value); diff --git a/webserver.js b/webserver.js index 01370bf1..421b4611 100644 --- a/webserver.js +++ b/webserver.js @@ -740,6 +740,9 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) { const domain = checkUserIpAddress(req, res); if ((domain == null) || (domain.auth == 'sspi') || (domain.auth == 'ldap')) { res.sendStatus(404); return; } + // If the email is the username, set this here. + if (domain.usernameisemail) { req.body.username = req.body.email; } + // Check if we are allowed to create new users using the login screen var domainUserCount = -1; if ((domain.newaccounts !== 1) && (domain.newaccounts !== true)) { @@ -1354,6 +1357,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) { if ((obj.args.nousers != true) && (domain.passwordrequirements != null) && (domain.passwordrequirements.force2factor === true)) { features += 0x00040000; } // Force 2-factor auth if ((domain.auth == 'sspi') || (domain.auth == 'ldap')) { features += 0x00080000; } // LDAP or SSPI in use, warn that users must login first before adding a user to a group. if (domain.amtacmactivation) { features += 0x00100000; } // Intel AMT ACM activation/upgrade is possible + if (domain.usernameisemail) { features += 0x00200000; } // Username is email address // Create a authentication cookie const authCookie = obj.parent.encodeCookie({ userid: user._id, domainid: domain.id }, obj.parent.loginCookieEncryptionKey); @@ -1414,6 +1418,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) { function handleRootRequestLogin(req, res, domain, hardwareKeyChallenge, passRequirements) { var features = 0; if ((parent.config != null) && (parent.config.settings != null) && (parent.config.settings.allowframing == true)) { features += 32; } // Allow site within iframe + if (domain.usernameisemail) { features += 0x00200000; } // Username is email address var httpsPort = ((obj.args.aliasport == null) ? obj.args.port : obj.args.aliasport); // Use HTTPS alias port is specified var loginmode = req.session.loginmode; delete req.session.loginmode; // Clear this state, if the user hits refresh, we want to go back to the login page.
Username: