Updated clickonce, password hint is configurable.

This commit is contained in:
Ylian Saint-Hilaire 2019-02-28 16:17:22 -08:00
parent 8709d56bd0
commit 6c851c9a6d
20 changed files with 353 additions and 177 deletions

View File

@ -789,7 +789,9 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
// Check if this is an existing user // Check if this is an existing user
var newuser = { type: 'user', _id: newuserid, name: newusername, creation: Math.floor(Date.now() / 1000), domain: domain.id }; var newuser = { type: 'user', _id: newuserid, name: newusername, creation: Math.floor(Date.now() / 1000), domain: domain.id };
if (command.email != null) { newuser.email = command.email; } // Email if (command.email != null) { newuser.email = command.email; } // Email
if (command.resetNextLogin === true) { newuser.passchange = -1; } else { newuser.passchange = Math.floor(Date.now() / 1000); }
obj.parent.users[newuserid] = newuser; obj.parent.users[newuserid] = newuser;
// Create a user, generate a salt and hash the password // Create a user, generate a salt and hash the password
require('./pass').hash(command.pass, function (err, salt, hash) { require('./pass').hash(command.pass, function (err, salt, hash) {
if (err) throw err; if (err) throw err;
@ -830,7 +832,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
// Change our own password // Change our own password
if (obj.common.validateString(command.oldpass, 1, 256) == false) break; if (obj.common.validateString(command.oldpass, 1, 256) == false) break;
if (obj.common.validateString(command.newpass, 1, 256) == false) break; if (obj.common.validateString(command.newpass, 1, 256) == false) break;
if (obj.common.validateString(command.hint, 0, 256) == false) break; if ((command.hint != null) && (obj.common.validateString(command.hint, 0, 256) == false)) break;
if (obj.common.checkPasswordRequirements(command.newpass, domain.passwordrequirements) == false) break; // Password does not meet requirements if (obj.common.checkPasswordRequirements(command.newpass, domain.passwordrequirements) == false) break; // Password does not meet requirements
// Start by checking the old password // Start by checking the old password
@ -843,11 +845,13 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
displayNotificationMessage('Error, password not changed.'); displayNotificationMessage('Error, password not changed.');
} else { } else {
// Change the password // Change the password
var hint = command.hint; if ((domain.passwordrequirements != null) && (domain.passwordrequirements.hint === true) && (command.hint != null)) {
if (hint.length > 250) hint = hint.substring(0, 250); var hint = command.hint;
if (hint.length > 250) { hint = hint.substring(0, 250); }
user.passhint = hint;
}
user.salt = salt; user.salt = salt;
user.hash = hash; user.hash = hash;
user.passhint = hint;
user.passchange = Math.floor(Date.now() / 1000); user.passchange = Math.floor(Date.now() / 1000);
delete user.passtype; delete user.passtype;
obj.db.SetUser(user); obj.db.SetUser(user);
@ -870,7 +874,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
if (user.siteadmin != 0xFFFFFFFF) break; if (user.siteadmin != 0xFFFFFFFF) break;
if (obj.common.validateString(command.user, 1, 256) == false) break; if (obj.common.validateString(command.user, 1, 256) == false) break;
if (obj.common.validateString(command.pass, 1, 256) == false) break; if (obj.common.validateString(command.pass, 1, 256) == false) break;
if (obj.common.validateString(command.hint, 0, 256) == false) break; if ((command.hint != null) && (obj.common.validateString(command.hint, 0, 256) == false)) break;
if (typeof command.removeMultiFactor != 'boolean') break; if (typeof command.removeMultiFactor != 'boolean') break;
if (obj.common.checkPasswordRequirements(command.pass, domain.passwordrequirements) == false) break; // Password does not meet requirements if (obj.common.checkPasswordRequirements(command.pass, domain.passwordrequirements) == false) break; // Password does not meet requirements
@ -881,8 +885,12 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
if (!err) { if (!err) {
chguser.salt = salt; chguser.salt = salt;
chguser.hash = hash; chguser.hash = hash;
chguser.passhint = command.hint; if ((domain.passwordrequirements != null) && (domain.passwordrequirements.hint === true) && (command.hint != null)) {
if (command.resetNextLogin == true) { chguser.passchange = -1; } else { chguser.passchange = Math.floor(Date.now() / 1000); } var hint = command.hint;
if (hint.length > 250) { hint = hint.substring(0, 250); }
chguser.passhint = hint;
}
if (command.resetNextLogin === true) { chguser.passchange = -1; } else { chguser.passchange = Math.floor(Date.now() / 1000); }
delete chguser.passtype; // Remove the password type if one was present. delete chguser.passtype; // Remove the password type if one was present.
if (command.removeMultiFactor == true) { if (command.removeMultiFactor == true) {
if (chguser.otpsecret) { delete chguser.otpsecret; } if (chguser.otpsecret) { delete chguser.otpsecret; }

View File

@ -1,6 +1,6 @@
{ {
"name": "meshcentral", "name": "meshcentral",
"version": "0.2.9-h", "version": "0.2.9-i",
"keywords": [ "keywords": [
"Remote Management", "Remote Management",
"Intel AMT", "Intel AMT",

View File

@ -1,21 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<asmv1:assembly xsi:schemaLocation="urn:schemas-microsoft-com:asm.v1 assembly.adaptive.xsd" manifestVersion="1.0" xmlns:asmv1="urn:schemas-microsoft-com:asm.v1" xmlns="urn:schemas-microsoft-com:asm.v2" xmlns:asmv2="urn:schemas-microsoft-com:asm.v2" xmlns:xrml="urn:mpeg:mpeg21:2003:01-REL-R-NS" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3" xmlns:dsig="http://www.w3.org/2000/09/xmldsig#" xmlns:co.v1="urn:schemas-microsoft-com:clickonce.v1" xmlns:co.v2="urn:schemas-microsoft-com:clickonce.v2">
<assemblyIdentity name="MeshMiniRouter.application" version="2.0.0.22" publicKeyToken="0000000000000000" language="neutral" processorArchitecture="msil" xmlns="urn:schemas-microsoft-com:asm.v1" />
<description asmv2:publisher="Meshcentral.com" asmv2:product="MeshCentral Mini-Router" asmv2:supportUrl="https://meshcentral.com/" xmlns="urn:schemas-microsoft-com:asm.v1" />
<deployment install="false" mapFileExtensions="true" trustURLParameters="true" />
<compatibleFrameworks xmlns="urn:schemas-microsoft-com:clickonce.v2">
<framework targetVersion="4.5" profile="Full" supportedRuntime="4.0.30319" />
</compatibleFrameworks>
<dependency>
<dependentAssembly dependencyType="install" codebase="Application Files\MeshMiniRouter_2_0_0_22\MeshMiniRouter.exe.manifest" size="4712">
<assemblyIdentity name="MeshMiniRouter.exe" version="2.0.0.22" publicKeyToken="0000000000000000" language="neutral" processorArchitecture="msil" type="win32" />
<hash>
<dsig:Transforms>
<dsig:Transform Algorithm="urn:schemas-microsoft-com:HashTransforms.Identity" />
</dsig:Transforms>
<dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha256" />
<dsig:DigestValue>WOFMexmFiT1cRB5ZPY6zmeQ7x/Cbx//7QyPjwnjKGnA=</dsig:DigestValue>
</hash>
</dependentAssembly>
</dependency>
</asmv1:assembly>

View File

@ -1,82 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<asmv1:assembly xsi:schemaLocation="urn:schemas-microsoft-com:asm.v1 assembly.adaptive.xsd" manifestVersion="1.0" xmlns:asmv1="urn:schemas-microsoft-com:asm.v1" xmlns="urn:schemas-microsoft-com:asm.v2" xmlns:asmv2="urn:schemas-microsoft-com:asm.v2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:co.v1="urn:schemas-microsoft-com:clickonce.v1" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3" xmlns:dsig="http://www.w3.org/2000/09/xmldsig#" xmlns:co.v2="urn:schemas-microsoft-com:clickonce.v2">
<asmv1:assemblyIdentity name="MeshMiniRouter.exe" version="2.0.0.22" publicKeyToken="0000000000000000" language="neutral" processorArchitecture="msil" type="win32" />
<description asmv2:iconFile="MeshMiniRouter.ico" xmlns="urn:schemas-microsoft-com:asm.v1" />
<application />
<entryPoint>
<assemblyIdentity name="MeshMiniRouter" version="1.0.6919.31937" language="neutral" processorArchitecture="msil" />
<commandLine file="MeshMiniRouter.exe" parameters="" />
</entryPoint>
<trustInfo>
<security>
<applicationRequestMinimum>
<PermissionSet version="1" class="System.Security.NamedPermissionSet" Name="Internet" Description="Default rights given to Internet applications" Unrestricted="true" ID="Custom" SameSite="site" />
<defaultAssemblyRequest permissionSetReference="Custom" />
</applicationRequestMinimum>
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
<!-- UAC Manifest Options
If you want to change the Windows User Account Control level replace the
requestedExecutionLevel node with one of the following.
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
<requestedExecutionLevel level="highestAvailable" uiAccess="false" />
Specifying requestedExecutionLevel node will disable file and registry virtualization.
If you want to utilize File and Registry Virtualization for backward
compatibility then delete the requestedExecutionLevel node.
-->
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
</requestedPrivileges>
</security>
</trustInfo>
<dependency>
<dependentOS>
<osVersionInfo>
<os majorVersion="5" minorVersion="1" buildNumber="2600" servicePackMajor="0" />
</osVersionInfo>
</dependentOS>
</dependency>
<dependency>
<dependentAssembly dependencyType="preRequisite" allowDelayedBinding="true">
<assemblyIdentity name="Microsoft.Windows.CommonLanguageRuntime" version="4.0.30319.0" />
</dependentAssembly>
</dependency>
<dependency>
<dependentAssembly dependencyType="install" allowDelayedBinding="true" codebase="MeshMiniRouter.exe" size="186880">
<assemblyIdentity name="MeshMiniRouter" version="1.0.6919.31937" language="neutral" processorArchitecture="msil" />
<hash>
<dsig:Transforms>
<dsig:Transform Algorithm="urn:schemas-microsoft-com:HashTransforms.Identity" />
</dsig:Transforms>
<dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha256" />
<dsig:DigestValue>e/EE2UyAOSDkWCqJcDJPIiu7cOLRXJszqGGnayICf5I=</dsig:DigestValue>
</hash>
</dependentAssembly>
</dependency>
<file name="MeshMiniRouter.exe.config" size="2397">
<hash>
<dsig:Transforms>
<dsig:Transform Algorithm="urn:schemas-microsoft-com:HashTransforms.Identity" />
</dsig:Transforms>
<dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha256" />
<dsig:DigestValue>UylUFD4/o0KBti+5/eodTDgq4BkUJD0J0aUXNd3yHbY=</dsig:DigestValue>
</hash>
</file>
<file name="MeshMiniRouter.ico" size="1078">
<hash>
<dsig:Transforms>
<dsig:Transform Algorithm="urn:schemas-microsoft-com:HashTransforms.Identity" />
</dsig:Transforms>
<dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha256" />
<dsig:DigestValue>mkjbDQuo7YXa8wZxdKEu/ECXrORwwtpRgNj8NBKbzHo=</dsig:DigestValue>
</hash>
</file>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!-- A list of all Windows versions that this application is designed to work with. Windows will automatically select the most compatible environment.-->
<!-- If your application is designed to work with Windows 7, uncomment the following supportedOS node-->
<!--<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>-->
</application>
</compatibility>
</asmv1:assembly>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -59,7 +59,7 @@ FONT.key {font-weight: bold; color: darkgreen}
<TR><TD ALIGN="LEFT"><TABLE CELLPADDING="2" CELLSPACING="0" BORDER="0" WIDTH="540"><TR><TD WIDTH="496"> <TR><TD ALIGN="LEFT"><TABLE CELLPADDING="2" CELLSPACING="0" BORDER="0" WIDTH="540"><TR><TD WIDTH="496">
<!-- Begin AppInfo --> <!-- Begin AppInfo -->
<TABLE><TR><TD COLSPAN="3">&nbsp;</TD></TR><TR><TD><B>Name:</B></TD><TD WIDTH="5"><SPACER TYPE="block" WIDTH="10" /></TD><TD>MeshCentral Mini-Router</TD></TR><TR><TD COLSPAN="3">&nbsp;</TD></TR><TR><TD><B>Version:</B></TD><TD WIDTH="5"><SPACER TYPE="block" WIDTH="10" /></TD><TD>2.0.0.22</TD></TR><TR><TD COLSPAN="3">&nbsp;</TD></TR><TR><TD><B>Publisher:</B></TD><TD WIDTH="5"><SPACER TYPE="block" WIDTH="10" /></TD><TD>Meshcentral.com</TD></TR><tr><td colspan="3">&nbsp;</td></tr></TABLE> <TABLE><TR><TD COLSPAN="3">&nbsp;</TD></TR><TR><TD><B>Name:</B></TD><TD WIDTH="5"><SPACER TYPE="block" WIDTH="10" /></TD><TD>MeshCentral Mini-Router</TD></TR><TR><TD COLSPAN="3">&nbsp;</TD></TR><TR><TD><B>Version:</B></TD><TD WIDTH="5"><SPACER TYPE="block" WIDTH="10" /></TD><TD>2.0.0.25</TD></TR><TR><TD COLSPAN="3">&nbsp;</TD></TR><TR><TD><B>Publisher:</B></TD><TD WIDTH="5"><SPACER TYPE="block" WIDTH="10" /></TD><TD>Meshcentral.com</TD></TR><tr><td colspan="3">&nbsp;</td></tr></TABLE>
<!-- End AppInfo --> <!-- End AppInfo -->

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1152,7 +1152,7 @@
var x = "<form action='" + domainUrl + "changepassword' method=post><table style=margin-left:10px><tr>"; var x = "<form action='" + domainUrl + "changepassword' method=post><table style=margin-left:10px><tr>";
x += "<td align=right>Password:</td><td><input id=apassword1 type=password name=apassword1 autocomplete=off onchange=account_validateNewPassword() onkeyup=account_validateNewPassword() onkeydown=account_validateNewPassword() /> <b><span id=dxPassWarn></span></b></td>"; x += "<td align=right>Password:</td><td><input id=apassword1 type=password name=apassword1 autocomplete=off onchange=account_validateNewPassword() onkeyup=account_validateNewPassword() onkeydown=account_validateNewPassword() /> <b><span id=dxPassWarn></span></b></td>";
x += "</tr><tr><td align=right>Password:</td><td><input id=apassword2 type=password name=apassword2 autocomplete=off onchange=account_validateNewPassword() onkeyup=account_validateNewPassword() onkeydown=account_validateNewPassword() /></td>"; x += "</tr><tr><td align=right>Password:</td><td><input id=apassword2 type=password name=apassword2 autocomplete=off onchange=account_validateNewPassword() onkeyup=account_validateNewPassword() onkeydown=account_validateNewPassword() /></td>";
x += "</tr><tr><td align=right>Hint:</td><td><input id=apasswordhint name=apasswordhint maxlength=250 type=text autocomplete=off /></td>"; if (features & 0x00010000) { x += "</tr><tr><td align=right>Hint:</td><td><input id=apasswordhint name=apasswordhint maxlength=250 type=text autocomplete=off /></td>"; }
x += '</tr></table><div style=padding:10px;margin-bottom:4px>'; x += '</tr></table><div style=padding:10px;margin-bottom:4px>';
x += '<input id=account_dlgCancelButton type=button value=Cancel style=float:right;width:80px;margin-left:5px onclick=dialogclose(0)>'; x += '<input id=account_dlgCancelButton type=button value=Cancel style=float:right;width:80px;margin-left:5px onclick=dialogclose(0)>';
x += '<input id=account_dlgOkButton type=submit value=OK style="float:right;width:80px" onclick=dialogclose(1)>'; x += '<input id=account_dlgOkButton type=submit value=OK style="float:right;width:80px" onclick=dialogclose(1)>';

View File

@ -5593,9 +5593,13 @@
x += "<tr><td align=right>Old password:</td><td><input id=apassword0 type=password name=apassword0 autocomplete=off onchange=account_validateNewPassword() onkeyup=account_validateNewPassword() onkeydown=account_validateNewPassword() /> <b></b></td></tr>"; x += "<tr><td align=right>Old password:</td><td><input id=apassword0 type=password name=apassword0 autocomplete=off onchange=account_validateNewPassword() onkeyup=account_validateNewPassword() onkeydown=account_validateNewPassword() /> <b></b></td></tr>";
x += "<tr><td align=right>New password:</td><td><input id=apassword1 type=password name=apassword1 autocomplete=off onchange=account_validateNewPassword() onkeyup=account_validateNewPassword() onkeydown=account_validateNewPassword() /> <b><span id=dxPassWarn></span></b></td></tr>"; x += "<tr><td align=right>New password:</td><td><input id=apassword1 type=password name=apassword1 autocomplete=off onchange=account_validateNewPassword() onkeyup=account_validateNewPassword() onkeydown=account_validateNewPassword() /> <b><span id=dxPassWarn></span></b></td></tr>";
x += "<tr><td align=right>New password:</td><td><input id=apassword2 type=password name=apassword2 autocomplete=off onchange=account_validateNewPassword() onkeyup=account_validateNewPassword() onkeydown=account_validateNewPassword() /></td></tr>"; x += "<tr><td align=right>New password:</td><td><input id=apassword2 type=password name=apassword2 autocomplete=off onchange=account_validateNewPassword() onkeyup=account_validateNewPassword() onkeydown=account_validateNewPassword() /></td></tr>";
x += "<tr><td align=right>Password hint:</td><td><input id=apasswordhint name=apasswordhint maxlength=250 type=text autocomplete=off onchange=account_validateNewPassword() onkeyup=account_validateNewPassword() onkeydown=account_validateNewPassword() /></td></tr>"; if (features & 0x00010000) { x += "<tr><td align=right>Password hint:</td><td><input id=apasswordhint name=apasswordhint maxlength=250 type=text autocomplete=off onchange=account_validateNewPassword() onkeyup=account_validateNewPassword() onkeydown=account_validateNewPassword() /></td></tr>"; }
x += '</table>' x += '</table>'
if (passRequirements) { var r = []; for (var i in passRequirements) { r.push(i + ':' + passRequirements[i]); } x += '<br /><span style=font-size:x-small>Requirements: ' + r.join(', ') + '.</span>'; } if (passRequirements) {
var r = [], rc = 0;
for (var i in passRequirements) { if ((i != 'reset') && (i != 'hint')) { r.push(i + ':' + passRequirements[i]); rc++; } }
if (rc > 0) { x += '<br /><span style=font-size:x-small>Requirements: ' + r.join(', ') + '.</span>'; }
}
x += '<br />'; x += '<br />';
//x += '<br /><div style=padding:10px;margin-bottom:4px>'; //x += '<br /><div style=padding:10px;margin-bottom:4px>';
//x += '<input id=account_dlgCancelButton type=button value=Cancel style=float:right;width:80px;margin-left:5px onclick=dialogclose(0)>'; //x += '<input id=account_dlgCancelButton type=button value=Cancel style=float:right;width:80px;margin-left:5px onclick=dialogclose(0)>';
@ -5608,7 +5612,9 @@
function account_showChangePasswordEx() { function account_showChangePasswordEx() {
if (Q('apassword1').value == Q('apassword2').value) { if (Q('apassword1').value == Q('apassword2').value) {
meshserver.send({ action: 'changepassword', oldpass: Q('apassword0').value, newpass: Q('apassword1').value, hint: Q('apasswordhint').value }); var r = { action: 'changepassword', oldpass: Q('apassword0').value, newpass: Q('apassword1').value };
if (features & 0x00010000) { r.hint = Q('apasswordhint').value; }
meshserver.send(r);
} }
} }
@ -6487,7 +6493,14 @@
x += addHtmlValue('Email', '<input id=p4email style=width:230px maxlength=256 onchange=showCreateNewAccountDialogValidate() onkeyup=showCreateNewAccountDialogValidate() />'); x += addHtmlValue('Email', '<input id=p4email style=width:230px maxlength=256 onchange=showCreateNewAccountDialogValidate() onkeyup=showCreateNewAccountDialogValidate() />');
x += addHtmlValue('Password', '<input id=p4pass1 type=password style=width:230px maxlength=256 onchange=showCreateNewAccountDialogValidate() onkeyup=showCreateNewAccountDialogValidate() />'); x += addHtmlValue('Password', '<input id=p4pass1 type=password style=width:230px maxlength=256 onchange=showCreateNewAccountDialogValidate() onkeyup=showCreateNewAccountDialogValidate() />');
x += addHtmlValue('Password', '<input id=p4pass2 type=password style=width:230px maxlength=256 onchange=showCreateNewAccountDialogValidate() onkeyup=showCreateNewAccountDialogValidate() />'); x += addHtmlValue('Password', '<input id=p4pass2 type=password style=width:230px maxlength=256 onchange=showCreateNewAccountDialogValidate() onkeyup=showCreateNewAccountDialogValidate() />');
if (passRequirements) { var r = []; for (var i in passRequirements) { r.push(i + ':' + passRequirements[i]); } x += '<div style=font-size:x-small;padding:6px>Requirements: ' + r.join(', ') + '.</div>'; } x += '<div><input id=p4resetNextLogin type=checkbox />Force password reset on next login.</div>';
if (passRequirements) {
var r = [], rc = 0;
for (var i in passRequirements) { if ((i != 'reset') && (i != 'hint')) { r.push(i + ':' + passRequirements[i]); rc++; } }
if (rc > 0) { x += '<div style=font-size:x-small;padding:6px>Requirements: ' + r.join(', ') + '.</div>'; }
}
setDialogMode(2, "Create Account", 3, showCreateNewAccountDialogEx, x); setDialogMode(2, "Create Account", 3, showCreateNewAccountDialogEx, x);
showCreateNewAccountDialogValidate(); showCreateNewAccountDialogValidate();
Q('p4name').focus(); Q('p4name').focus();
@ -6501,7 +6514,7 @@
} }
function showCreateNewAccountDialogEx() { function showCreateNewAccountDialogEx() {
meshserver.send({ action: 'adduser', username: Q('p4name').value, email: Q('p4email').value, pass: Q('p4pass1').value }); meshserver.send({ action: 'adduser', username: Q('p4name').value, email: Q('p4email').value, pass: Q('p4pass1').value, resetNextLogin: Q('p4resetNextLogin').checked });
} }
function showUserAdminDialog(e, userid) { function showUserAdminDialog(e, userid) {
@ -6689,8 +6702,14 @@
var x = ''; var x = '';
x += addHtmlValue('Password', '<input id=p4pass1 type=password style=width:230px maxlength=256 onchange=showCreateNewAccountDialogValidate(1) onkeyup=showCreateNewAccountDialogValidate(1)></input>'); x += addHtmlValue('Password', '<input id=p4pass1 type=password style=width:230px maxlength=256 onchange=showCreateNewAccountDialogValidate(1) onkeyup=showCreateNewAccountDialogValidate(1)></input>');
x += addHtmlValue('Password', '<input id=p4pass2 type=password style=width:230px maxlength=256 onchange=showCreateNewAccountDialogValidate(1) onkeyup=showCreateNewAccountDialogValidate(1)></input>'); x += addHtmlValue('Password', '<input id=p4pass2 type=password style=width:230px maxlength=256 onchange=showCreateNewAccountDialogValidate(1) onkeyup=showCreateNewAccountDialogValidate(1)></input>');
x += addHtmlValue('Password hint', '<input id=p4hint type=text style=width:230px maxlength=256></input>'); if (features & 0x00010000) { x += addHtmlValue('Password hint', '<input id=p4hint type=text style=width:230px maxlength=256></input>'); }
if (passRequirements) { var r = []; for (var i in passRequirements) { r.push(i + ':' + passRequirements[i]); } x += '<div style=font-size:x-small;padding:6px>Requirements: ' + r.join(', ') + '.</div>'; }
if (passRequirements) {
var r = [], rc = 0;
for (var i in passRequirements) { if ((i != 'reset') && (i != 'hint')) { r.push(i + ':' + passRequirements[i]); rc++; } }
if (rc > 0) { x += '<div style=font-size:x-small;padding:6px>Requirements: ' + r.join(', ') + '.</div>'; }
}
x += '<div><input id=p4resetNextLogin type=checkbox />Force password reset on next login.</div>'; x += '<div><input id=p4resetNextLogin type=checkbox />Force password reset on next login.</div>';
if (multiFactor == 1) { x += '<div><input id=p4twoFactorRemove type=checkbox />Remove all 2nd factor authentication.</div>'; } if (multiFactor == 1) { x += '<div><input id=p4twoFactorRemove type=checkbox />Remove all 2nd factor authentication.</div>'; }
setDialogMode(2, "Change Password for " + EscapeHtml(currentUser.name), 3, p30showUserChangePassDialogEx, x, multiFactor); setDialogMode(2, "Change Password for " + EscapeHtml(currentUser.name), 3, p30showUserChangePassDialogEx, x, multiFactor);
@ -6701,7 +6720,11 @@
function p30showUserChangePassDialogEx(b, tag) { function p30showUserChangePassDialogEx(b, tag) {
var removeMultiFactor = false; var removeMultiFactor = false;
if ((tag == 1) && (Q('p4twoFactorRemove').checked == true)) { removeMultiFactor = true; } if ((tag == 1) && (Q('p4twoFactorRemove').checked == true)) { removeMultiFactor = true; }
if (Q('p4pass1').value == Q('p4pass2').value) { meshserver.send({ action: 'changeuserpass', user: currentUser.name, pass: Q('p4pass1').value, hint: Q('p4hint').value, removeMultiFactor: removeMultiFactor, resetNextLogin: Q('p4resetNextLogin').checked }); } if (Q('p4pass1').value == Q('p4pass2').value) {
var r = { action: 'changeuserpass', user: currentUser.name, pass: Q('p4pass1').value, removeMultiFactor: removeMultiFactor, resetNextLogin: Q('p4resetNextLogin').checked };
if (features & 0x00010000) { r.hint = Q('p4hint').value; }
meshserver.send(r);
}
} }
function p30showDeleteUserDialog() { function p30showDeleteUserDialog() {

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -100,7 +100,7 @@
<td align=right>Password:</td> <td align=right>Password:</td>
<td><input id=apassword2 type=password name=password2 autocomplete=off maxlength=256 onkeydown=haltReturn(event) onchange=validateCreate(4) onkeyup=validateCreate(4,event) /></td> <td><input id=apassword2 type=password name=password2 autocomplete=off maxlength=256 onkeydown=haltReturn(event) onchange=validateCreate(4) onkeyup=validateCreate(4,event) /></td>
</tr> </tr>
<tr> <tr id="createPanelHint" style="display:none">
<td align=right>Pass Hint:</td> <td align=right>Pass Hint:</td>
<td><input id=apasswordhint type=text name=apasswordhint autocomplete=off maxlength=256 onkeydown=haltReturn(event) onchange=validateCreate(5) onkeyup=validateCreate(5,event) /></td> <td><input id=apasswordhint type=text name=apasswordhint autocomplete=off maxlength=256 onkeydown=haltReturn(event) onchange=validateCreate(5) onkeyup=validateCreate(5,event) /></td>
</tr> </tr>
@ -151,7 +151,7 @@
<tr> <tr>
<td align=right width=100>Login token:</td> <td align=right width=100>Login token:</td>
<td> <td>
<input id=tokenInput type=text name=token maxlength=50 onchange=checkToken(event) onkeyup=checkToken(event) onkeydown=checkToken(event) /> <input id=tokenInput type=text name=token maxlength=50 onchange=checkToken(event) onkeyup=checkToken(event) onkeydown=checkToken(event) onfocus=checkTokenTimer(1) onblur=checkTokenTimer(0) />
<input id=hwtokenInput type=text name=hwtoken style="display:none" /> <input id=hwtokenInput type=text name=hwtoken style="display:none" />
</td> </td>
</tr> </tr>
@ -203,7 +203,7 @@
<td id="rnuPass2" align=right>Password:</td> <td id="rnuPass2" align=right>Password:</td>
<td><input id=rapassword2 type=password name=rpassword2 autocomplete=off maxlength=256 onkeydown=haltReturn(event) onchange=validatePassReset(4,event) onkeyup=validatePassReset(4,event) /></td> <td><input id=rapassword2 type=password name=rpassword2 autocomplete=off maxlength=256 onkeydown=haltReturn(event) onchange=validatePassReset(4,event) onkeyup=validatePassReset(4,event) /></td>
</tr> </tr>
<tr> <tr id="resetpasswordpanelHint" style="display:none">
<td id="rnuHint" align=right>Password Hint:</td> <td id="rnuHint" align=right>Password Hint:</td>
<td><input id=rapasswordhint type=text name=rpasswordhint autocomplete=off maxlength=256 onkeydown=haltReturn(event) onchange=validatePassReset(5,event) onkeyup=validatePassReset(5,event) /></td> <td><input id=rapasswordhint type=text name=rpasswordhint autocomplete=off maxlength=256 onkeydown=haltReturn(event) onchange=validatePassReset(5,event) onkeyup=validatePassReset(5,event) /></td>
</tr> </tr>
@ -258,8 +258,10 @@
var emailCheck = ('{{{emailcheck}}}' == 'true'); var emailCheck = ('{{{emailcheck}}}' == 'true');
var features = parseInt('{{{features}}}'); var features = parseInt('{{{features}}}');
var passRequirements = "{{{passRequirements}}}"; var passRequirements = "{{{passRequirements}}}";
if (passRequirements != "") { passRequirements = JSON.parse(decodeURIComponent(passRequirements)); } if (passRequirements != "") { passRequirements = JSON.parse(decodeURIComponent(passRequirements)); } else { passRequirements = {}; }
var passRequirementsEx = ((passRequirements.min != null) || (passRequirements.max != null) || (passRequirements.upper != null) || (passRequirements.lower != null) || (passRequirements.numeric != null) || (passRequirements.nonalpha != null));
var hardwareKeyChallenge = '{{{hkey}}}'; var hardwareKeyChallenge = '{{{hkey}}}';
var currentpanel = 0;
function startup() { function startup() {
if ((features & 32) == 0) { if ((features & 32) == 0) {
@ -269,13 +271,16 @@
if (top != self && (loc == null || top.active == false)) { top.location = self.location; return; } if (top != self && (loc == null || top.active == false)) { top.location = self.location; return; }
} }
QV('createPanelHint', passRequirements.hint === true);
QV('resetpasswordpanelHint', passRequirements.hint === true);
window.onresize = center; window.onresize = center;
center(); center();
validateLogin(); validateLogin();
validateCreate(); validateCreate();
if ('{{loginmode}}' != '') { go(parseInt('{{loginmode}}')); } else { go(1); } if ('{{loginmode}}' != '') { go(parseInt('{{loginmode}}')); } else { go(1); }
QV('newAccountDiv', ('{{{newAccount}}}' != '0') && ('{{{newAccount}}}' != 'false')); // If new accounts are not allowed, don't display the new account link. QV('newAccountDiv', ('{{{newAccount}}}' != '0') && ('{{{newAccount}}}' != 'false')); // If new accounts are not allowed, don't display the new account link.
if ((passhint != null) && (passhint.length > 0)) { QV("showPassHintLink", true); } if ((passRequirements.hint === true) && (passhint != null) && (passhint.length > 0)) { QV("showPassHintLink", true); }
QV("newAccountPass", (newAccountPass == 1)); QV("newAccountPass", (newAccountPass == 1));
QV("resetAccountDiv", (emailCheck == true)); QV("resetAccountDiv", (emailCheck == true));
QV("hrAccountDiv", (emailCheck == true) || (newAccountPass == 1)); QV("hrAccountDiv", (emailCheck == true) || (newAccountPass == 1));
@ -284,7 +289,7 @@
try { if (hardwareKeyChallenge.length > 0) { hardwareKeyChallenge = JSON.parse(hardwareKeyChallenge); } else { hardwareKeyChallenge = null; } } catch (ex) { hardwareKeyChallenge = null } try { if (hardwareKeyChallenge.length > 0) { hardwareKeyChallenge = JSON.parse(hardwareKeyChallenge); } else { hardwareKeyChallenge = null; } } catch (ex) { hardwareKeyChallenge = null }
if ((hardwareKeyChallenge != null) && u2fSupported()) { if ((hardwareKeyChallenge != null) && u2fSupported()) {
window.u2f.sign(hardwareKeyChallenge.appId, hardwareKeyChallenge.challenge, hardwareKeyChallenge.registeredKeys, function (authResponse) { window.u2f.sign(hardwareKeyChallenge.appId, hardwareKeyChallenge.challenge, hardwareKeyChallenge.registeredKeys, function (authResponse) {
if (authResponse.signatureData) { if ((currentpanel == 4) && authResponse.signatureData) {
Q('hwtokenInput').value = JSON.stringify(authResponse); Q('hwtokenInput').value = JSON.stringify(authResponse);
QE('tokenOkButton', true); QE('tokenOkButton', true);
Q('tokenOkButton').click(); Q('tokenOkButton').click();
@ -297,7 +302,7 @@
try { if (hardwareKeyChallenge.length > 0) { hardwareKeyChallenge = JSON.parse(hardwareKeyChallenge); } else { hardwareKeyChallenge = null; } } catch (ex) { hardwareKeyChallenge = null } try { if (hardwareKeyChallenge.length > 0) { hardwareKeyChallenge = JSON.parse(hardwareKeyChallenge); } else { hardwareKeyChallenge = null; } } catch (ex) { hardwareKeyChallenge = null }
if ((hardwareKeyChallenge != null) && u2fSupported()) { if ((hardwareKeyChallenge != null) && u2fSupported()) {
window.u2f.sign(hardwareKeyChallenge.appId, hardwareKeyChallenge.challenge, hardwareKeyChallenge.registeredKeys, function (authResponse) { window.u2f.sign(hardwareKeyChallenge.appId, hardwareKeyChallenge.challenge, hardwareKeyChallenge.registeredKeys, function (authResponse) {
if (authResponse.signatureData) { if ((currentpanel == 5) && authResponse.signatureData) {
Q('resetHwtokenInput').value = JSON.stringify(authResponse); Q('resetHwtokenInput').value = JSON.stringify(authResponse);
QE('resetTokenOkButton', true); QE('resetTokenOkButton', true);
Q('resetTokenOkButton').click(); Q('resetTokenOkButton').click();
@ -308,7 +313,7 @@
} }
function showPassHint() { function showPassHint() {
messagebox("Password Hint", passhint); if (passRequirements.hint === true) { messagebox("Password Hint", passhint); }
} }
function xgo(x) { function xgo(x) {
@ -322,6 +327,7 @@
} }
function go(x) { function go(x) {
currentpanel = x;
setDialogMode(0); setDialogMode(0);
QV("showPassHintLink", false); QV("showPassHintLink", false);
QV('loginpanel', x == 1); QV('loginpanel', x == 1);
@ -354,7 +360,7 @@
QH('passWarning', ''); QH('passWarning', '');
QV('passwordPolicyCallout', false); QV('passwordPolicyCallout', false);
} else { } else {
if (passRequirements == null || passRequirements == '') { if (!passRequirementsEx) {
// No password requirements, display password strength // No password requirements, display password strength
var passStrength = checkPasswordStrength(Q('apassword1').value); var passStrength = checkPasswordStrength(Q('apassword1').value);
if (passStrength >= 80) { QH('passWarning', '<span style=color:green><b>Strong Password</b><span>'); } if (passStrength >= 80) { QH('passWarning', '<span style=color:green><b>Strong Password</b><span>'); }
@ -402,7 +408,7 @@
QH('rpassWarning', ''); QH('rpassWarning', '');
QV('rpasswordPolicyCallout', false); QV('rpasswordPolicyCallout', false);
} else { } else {
if (passRequirements == null || passRequirements == '') { if (!passRequirementsEx) {
// No password requirements, display password strength // No password requirements, display password strength
var passStrength = checkPasswordStrength(Q('rapassword1').value); var passStrength = checkPasswordStrength(Q('rapassword1').value);
if (passStrength >= 80) { QH('rpassWarning', '<span style=color:green><b>Strong Password</b><span>'); } if (passStrength >= 80) { QH('rpassWarning', '<span style=color:green><b>Strong Password</b><span>'); }
@ -491,16 +497,20 @@
return counts; return counts;
} }
var xcheckTokenTimer = null;
function checkTokenTimer(enter) {
if ((enter == 0) && (xcheckTokenTimer != null)) { clearInterval(xcheckTokenTimer); xcheckTokenTimer = null; }
if ((enter == 1) && (xcheckTokenTimer == null)) { xcheckTokenTimer = setInterval(checkToken, 200); }
}
function checkToken() { function checkToken() {
var t1 = Q('tokenInput').value; var t1 = Q('tokenInput').value, t2 = t1.split(' ').join('');
var t2 = t1.split(' ').join('');
if (t1 != t2) { Q('tokenInput').value = t2; } if (t1 != t2) { Q('tokenInput').value = t2; }
QE('tokenOkButton', (Q('tokenInput').value.length == 6) || (Q('tokenInput').value.length == 8) || (Q('tokenInput').value.length == 44)); QE('tokenOkButton', (Q('tokenInput').value.length == 6) || (Q('tokenInput').value.length == 8) || (Q('tokenInput').value.length == 44));
} }
function resetCheckToken() { function resetCheckToken() {
var t1 = Q('resetTokenInput').value; var t1 = Q('resetTokenInput').value, t2 = t1.split(' ').join('');
var t2 = t1.split(' ').join('');
if (t1 != t2) { Q('resetTokenInput').value = t2; } if (t1 != t2) { Q('resetTokenInput').value = t2; }
QE('resetTokenOkButton', (Q('resetTokenInput').value.length == 6) || (Q('resetTokenInput').value.length == 8) || (Q('resetTokenInput').value.length == 44)); QE('resetTokenOkButton', (Q('resetTokenInput').value.length == 6) || (Q('resetTokenInput').value.length == 8) || (Q('resetTokenInput').value.length == 44));
} }

View File

@ -173,7 +173,7 @@
<td id="nuPass2" align=right>Password:</td> <td id="nuPass2" align=right>Password:</td>
<td><input id=apassword2 type=password name=password2 autocomplete=off maxlength=256 onkeydown=haltReturn(event) onchange=validateCreate(4,event) onkeyup=validateCreate(4,event) /></td> <td><input id=apassword2 type=password name=password2 autocomplete=off maxlength=256 onkeydown=haltReturn(event) onchange=validateCreate(4,event) onkeyup=validateCreate(4,event) /></td>
</tr> </tr>
<tr> <tr id="createPanelHint" style="display:none">
<td id="nuHint" align=right>Password Hint:</td> <td id="nuHint" align=right>Password Hint:</td>
<td><input id=apasswordhint type=text name=apasswordhint autocomplete=off maxlength=256 onkeydown=haltReturn(event) onchange=validateCreate(5,event) onkeyup=validateCreate(5,event) /></td> <td><input id=apasswordhint type=text name=apasswordhint autocomplete=off maxlength=256 onkeydown=haltReturn(event) onchange=validateCreate(5,event) onkeyup=validateCreate(5,event) /></td>
</tr> </tr>
@ -273,7 +273,7 @@
<td id="rnuPass2" align=right>Password:</td> <td id="rnuPass2" align=right>Password:</td>
<td><input id=rapassword2 type=password name=rpassword2 autocomplete=off maxlength=256 onkeydown=haltReturn(event) onchange=validatePassReset(4,event) onkeyup=validatePassReset(4,event) /></td> <td><input id=rapassword2 type=password name=rpassword2 autocomplete=off maxlength=256 onkeydown=haltReturn(event) onchange=validatePassReset(4,event) onkeyup=validatePassReset(4,event) /></td>
</tr> </tr>
<tr> <tr id="resetpasswordpanelHint" style="display:none">
<td id="rnuHint" align=right>Password Hint:</td> <td id="rnuHint" align=right>Password Hint:</td>
<td><input id=rapasswordhint type=text name=rpasswordhint autocomplete=off maxlength=256 onkeydown=haltReturn(event) onchange=validatePassReset(5,event) onkeyup=validatePassReset(5,event) /></td> <td><input id=rapasswordhint type=text name=rpasswordhint autocomplete=off maxlength=256 onkeydown=haltReturn(event) onchange=validatePassReset(5,event) onkeyup=validatePassReset(5,event) /></td>
</tr> </tr>
@ -333,12 +333,14 @@
var emailCheck = ('{{{emailcheck}}}' == 'true'); var emailCheck = ('{{{emailcheck}}}' == 'true');
var passRequirements = "{{{passRequirements}}}"; var passRequirements = "{{{passRequirements}}}";
var hardwareKeyChallenge = '{{{hkey}}}'; var hardwareKeyChallenge = '{{{hkey}}}';
if (passRequirements != "") { passRequirements = JSON.parse(decodeURIComponent(passRequirements)); } if (passRequirements != "") { passRequirements = JSON.parse(decodeURIComponent(passRequirements)); } else { passRequirements = {}; }
var passRequirementsEx = ((passRequirements.min != null) || (passRequirements.max != null) || (passRequirements.upper != null) || (passRequirements.lower != null) || (passRequirements.numeric != null) || (passRequirements.nonalpha != null));
var features = parseInt('{{{features}}}'); var features = parseInt('{{{features}}}');
var webPageFullScreen = getstore('webPageFullScreen', true); var webPageFullScreen = getstore('webPageFullScreen', true);
if (webPageFullScreen == 'false') { webPageFullScreen = false; } if (webPageFullScreen == 'false') { webPageFullScreen = false; }
if (webPageFullScreen == 'true') { webPageFullScreen = true; } if (webPageFullScreen == 'true') { webPageFullScreen = true; }
var welcomeText = decodeURIComponent("{{{welcometext}}}"); var welcomeText = decodeURIComponent("{{{welcometext}}}");
var currentpanel = 0;
toggleFullScreen(); toggleFullScreen();
function startup() { function startup() {
@ -349,6 +351,9 @@
if (top != self && (loc == null || top.active == false)) { top.location = self.location; return; } if (top != self && (loc == null || top.active == false)) { top.location = self.location; return; }
} }
QV('createPanelHint', passRequirements.hint === true);
QV('resetpasswordpanelHint', passRequirements.hint === true);
// Display the welcome text // Display the welcome text
if (welcomeText) { QH('welcomeText', welcomeText); } if (welcomeText) { QH('welcomeText', welcomeText); }
QV('welcomeText', true); QV('welcomeText', true);
@ -369,7 +374,7 @@
try { if (hardwareKeyChallenge.length > 0) { hardwareKeyChallenge = JSON.parse(hardwareKeyChallenge); } else { hardwareKeyChallenge = null; } } catch (ex) { hardwareKeyChallenge = null } try { if (hardwareKeyChallenge.length > 0) { hardwareKeyChallenge = JSON.parse(hardwareKeyChallenge); } else { hardwareKeyChallenge = null; } } catch (ex) { hardwareKeyChallenge = null }
if ((hardwareKeyChallenge != null) && u2fSupported()) { if ((hardwareKeyChallenge != null) && u2fSupported()) {
window.u2f.sign(hardwareKeyChallenge.appId, hardwareKeyChallenge.challenge, hardwareKeyChallenge.registeredKeys, function (authResponse) { window.u2f.sign(hardwareKeyChallenge.appId, hardwareKeyChallenge.challenge, hardwareKeyChallenge.registeredKeys, function (authResponse) {
if (authResponse.signatureData) { if ((currentpanel == 4) && authResponse.signatureData) {
Q('hwtokenInput').value = JSON.stringify(authResponse); Q('hwtokenInput').value = JSON.stringify(authResponse);
QE('tokenOkButton', true); QE('tokenOkButton', true);
Q('tokenOkButton').click(); Q('tokenOkButton').click();
@ -382,7 +387,7 @@
try { if (hardwareKeyChallenge.length > 0) { hardwareKeyChallenge = JSON.parse(hardwareKeyChallenge); } else { hardwareKeyChallenge = null; } } catch (ex) { hardwareKeyChallenge = null } try { if (hardwareKeyChallenge.length > 0) { hardwareKeyChallenge = JSON.parse(hardwareKeyChallenge); } else { hardwareKeyChallenge = null; } } catch (ex) { hardwareKeyChallenge = null }
if ((hardwareKeyChallenge != null) && u2fSupported()) { if ((hardwareKeyChallenge != null) && u2fSupported()) {
window.u2f.sign(hardwareKeyChallenge.appId, hardwareKeyChallenge.challenge, hardwareKeyChallenge.registeredKeys, function (authResponse) { window.u2f.sign(hardwareKeyChallenge.appId, hardwareKeyChallenge.challenge, hardwareKeyChallenge.registeredKeys, function (authResponse) {
if (authResponse.signatureData) { if ((currentpanel == 5) && authResponse.signatureData) {
Q('resetHwtokenInput').value = JSON.stringify(authResponse); Q('resetHwtokenInput').value = JSON.stringify(authResponse);
QE('resetTokenOkButton', true); QE('resetTokenOkButton', true);
Q('resetTokenOkButton').click(); Q('resetTokenOkButton').click();
@ -407,6 +412,7 @@
} }
function go(x) { function go(x) {
currentpanel = x;
setDialogMode(0); setDialogMode(0);
QV("showPassHintLink", false); QV("showPassHintLink", false);
QV('loginpanel', x == 1); QV('loginpanel', x == 1);
@ -451,7 +457,7 @@
QH('passWarning', ''); QH('passWarning', '');
QV('passwordPolicyCallout', false); QV('passwordPolicyCallout', false);
} else { } else {
if (passRequirements == null || passRequirements == '') { if (!passRequirementsEx) {
// No password requirements, display password strength // No password requirements, display password strength
var passStrength = checkPasswordStrength(Q('apassword1').value); var passStrength = checkPasswordStrength(Q('apassword1').value);
if (passStrength >= 80) { QH('passWarning', '<span style=color:green><b>Strong Password</b><span>'); } if (passStrength >= 80) { QH('passWarning', '<span style=color:green><b>Strong Password</b><span>'); }
@ -499,7 +505,7 @@
QH('rpassWarning', ''); QH('rpassWarning', '');
QV('rpasswordPolicyCallout', false); QV('rpasswordPolicyCallout', false);
} else { } else {
if (passRequirements == null || passRequirements == '') { if (!passRequirementsEx) {
// No password requirements, display password strength // No password requirements, display password strength
var passStrength = checkPasswordStrength(Q('rapassword1').value); var passStrength = checkPasswordStrength(Q('rapassword1').value);
if (passStrength >= 80) { QH('rpassWarning', '<span style=color:green><b>Strong Password</b><span>'); } if (passStrength >= 80) { QH('rpassWarning', '<span style=color:green><b>Strong Password</b><span>'); }

View File

@ -578,9 +578,8 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
req.session.loginmode = '2'; req.session.loginmode = '2';
req.session.error = '<b style=color:#8C001A>Username already exists.</b>'; req.session.error = '<b style=color:#8C001A>Username already exists.</b>';
} else { } else {
var hint = req.body.apasswordhint; var user = { type: 'user', _id: 'user/' + domain.id + '/' + req.body.username.toLowerCase(), name: req.body.username, email: req.body.email, creation: Math.floor(Date.now() / 1000), login: Math.floor(Date.now() / 1000), domain: domain.id };
if (hint.length > 250) hint = hint.substring(0, 250); if ((domain.passwordrequirements != null) && (domain.passwordrequirements.hint === true) && (req.body.apasswordhint)) { var hint = req.body.apasswordhint; if (hint.length > 250) { hint = hint.substring(0, 250); } user.passhint = hint; }
var user = { type: 'user', _id: 'user/' + domain.id + '/' + req.body.username.toLowerCase(), name: req.body.username, email: req.body.email, creation: Math.floor(Date.now() / 1000), login: Math.floor(Date.now() / 1000), domain: domain.id, passhint: hint };
var usercount = 0; var usercount = 0;
for (var i in obj.users) { if (obj.users[i].domain == domain.id) { usercount++; } } for (var i in obj.users) { if (obj.users[i].domain == domain.id) { usercount++; } }
if (usercount == 0) { user.siteadmin = 0xFFFFFFFF; if (domain.newaccounts === 2) { domain.newaccounts = 0; } } // If this is the first user, give the account site admin. if (usercount == 0) { user.siteadmin = 0xFFFFFFFF; if (domain.newaccounts === 2) { domain.newaccounts = 0; } } // If this is the first user, give the account site admin.
@ -655,7 +654,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
if (err) throw err; if (err) throw err;
user.salt = salt; user.salt = salt;
user.hash = hash; user.hash = hash;
user.passhint = req.body.rpasswordhint; if ((domain.passwordrequirements != null) && (domain.passwordrequirements.hint === true)) { var hint = req.body.rpasswordhint; if (hint.length > 250) { hint = hint.substring(0, 250); } user.passhint = hint; } else { delete user.passhint; }
user.passchange = Math.floor(Date.now() / 1000); user.passchange = Math.floor(Date.now() / 1000);
delete user.passtype; delete user.passtype;
obj.db.SetUser(user); obj.db.SetUser(user);
@ -812,7 +811,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
userinfo.hash = hash; userinfo.hash = hash;
delete userinfo.passtype; delete userinfo.passtype;
userinfo.passchange = Math.floor(Date.now() / 1000); userinfo.passchange = Math.floor(Date.now() / 1000);
userinfo.passhint = null; delete userinfo.passhint;
//delete userinfo.otpsecret; // Currently a email password reset will turn off 2-step login. //delete userinfo.otpsecret; // Currently a email password reset will turn off 2-step login.
obj.db.SetUser(userinfo); obj.db.SetUser(userinfo);
@ -925,11 +924,9 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
// Update the password // Update the password
require('./pass').hash(req.body.apassword1, function (err, salt, hash) { require('./pass').hash(req.body.apassword1, function (err, salt, hash) {
if (err) throw err; if (err) throw err;
var hint = req.body.apasswordhint;
if (hint.length > 250) hint = hint.substring(0, 250);
user.salt = salt; user.salt = salt;
user.hash = hash; user.hash = hash;
user.passhint = req.body.apasswordhint; if ((domain.passwordrequirements != null) && (domain.passwordrequirements.hint === true) && (req.body.apasswordhint)) { var hint = req.body.apasswordhint; if (hint.length > 250) hint = hint.substring(0, 250); user.passhint = hint; } else { delete user.passhint; }
user.passchange = Math.floor(Date.now() / 1000); user.passchange = Math.floor(Date.now() / 1000);
delete user.passtype; delete user.passtype;
obj.db.SetUser(user); obj.db.SetUser(user);
@ -1070,22 +1067,23 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
// Give the web page a list of supported server features // Give the web page a list of supported server features
features = 0; features = 0;
if (obj.args.wanonly == true) { features += 0x0001; } // WAN-only mode if (obj.args.wanonly == true) { features += 0x00000001; } // WAN-only mode
if (obj.args.lanonly == true) { features += 0x0002; } // LAN-only mode if (obj.args.lanonly == true) { features += 0x00000002; } // LAN-only mode
if (obj.args.nousers == true) { features += 0x0004; } // Single user mode if (obj.args.nousers == true) { features += 0x00000004; } // Single user mode
if (domain.userQuota == -1) { features += 0x0008; } // No server files mode if (domain.userQuota == -1) { features += 0x00000008; } // No server files mode
if (obj.args.mpstlsoffload) { features += 0x0010; } // No mutual-auth CIRA if (obj.args.mpstlsoffload) { features += 0x00000010; } // No mutual-auth CIRA
if ((parent.config != null) && (parent.config.settings != null) && (parent.config.settings.allowframing == true)) { features += 0x0020; } // Allow site within iframe if ((parent.config != null) && (parent.config.settings != null) && (parent.config.settings.allowframing == true)) { features += 0x00000020; } // Allow site within iframe
if ((obj.parent.mailserver != null) && (obj.parent.certificates.CommonName != null) && (obj.parent.certificates.CommonName != 'un-configured') && (obj.args.lanonly != true)) { features += 0x0040; } // Email invites if ((obj.parent.mailserver != null) && (obj.parent.certificates.CommonName != null) && (obj.parent.certificates.CommonName != 'un-configured') && (obj.args.lanonly != true)) { features += 0x00000040; } // Email invites
if (obj.args.webrtc == true) { features += 0x0080; } // Enable WebRTC (Default false for now) if (obj.args.webrtc == true) { features += 0x00000080; } // Enable WebRTC (Default false for now)
if (obj.args.clickonce !== false) { features += 0x0100; } // Enable ClickOnce (Default true) if (obj.args.clickonce !== false) { features += 0x00000100; } // Enable ClickOnce (Default true)
if (obj.args.allowhighqualitydesktop == true) { features += 0x0200; } // Enable AllowHighQualityDesktop (Default false) if (obj.args.allowhighqualitydesktop == true) { features += 0x00000200; } // Enable AllowHighQualityDesktop (Default false)
if (obj.args.lanonly == true || obj.args.mpsport == 0) { features += 0x0400; } // No CIRA if (obj.args.lanonly == true || obj.args.mpsport == 0) { features += 0x00000400; } // No CIRA
if ((obj.parent.serverSelfWriteAllowed == true) && (user != null) && (user.siteadmin == 0xFFFFFFFF)) { features += 0x0800; } // Server can self-write (Allows self-update) if ((obj.parent.serverSelfWriteAllowed == true) && (user != null) && (user.siteadmin == 0xFFFFFFFF)) { features += 0x00000800; } // Server can self-write (Allows self-update)
if ((domain.auth != 'sspi') && (obj.parent.certificates.CommonName != 'un-configured') && (obj.args.nousers !== true)) { features += 0x1000; } // 2-step login supported if ((domain.auth != 'sspi') && (obj.parent.certificates.CommonName != 'un-configured') && (obj.args.nousers !== true)) { features += 0x00001000; } // 2-step login supported
if (domain.agentnoproxy === true) { features += 0x2000; } // Indicates that agents should be installed without using a HTTP proxy if (domain.agentnoproxy === true) { features += 0x00002000; } // Indicates that agents should be installed without using a HTTP proxy
if (domain.yubikey && domain.yubikey.id && domain.yubikey.secret) { features += 0x4000; } // Indicates Yubikey support if (domain.yubikey && domain.yubikey.id && domain.yubikey.secret) { features += 0x00004000; } // Indicates Yubikey support
if (domain.geolocation == true) { features += 0x8000; } // Enable geo-location features if (domain.geolocation == true) { features += 0x00008000; } // Enable geo-location features
if ((domain.passwordrequirements != null) && (domain.passwordrequirements.hint === true)) { features += 0x00010000; } // Enable password hints
// Create a authentication cookie // Create a authentication cookie
const authCookie = obj.parent.encodeCookie({ userid: user._id, domainid: domain.id }, obj.parent.loginCookieEncryptionKey); const authCookie = obj.parent.encodeCookie({ userid: user._id, domainid: domain.id }, obj.parent.loginCookieEncryptionKey);
@ -1151,7 +1149,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
if (req.session != null) { if (req.session != null) {
err = req.session.error; err = req.session.error;
msg = req.session.success; msg = req.session.success;
passhint = req.session.passhint; if ((domain.passwordrequirements != null) && (domain.passwordrequirements.hint === true)) { passhint = EscapeHtml(req.session.passhint); }
delete req.session.error; delete req.session.error;
delete req.session.success; delete req.session.success;
delete req.session.passhint; delete req.session.passhint;
@ -1159,7 +1157,6 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
var message = ''; var message = '';
if (err != null) message = '<p class="msg error">' + err + '</p>'; if (err != null) message = '<p class="msg error">' + err + '</p>';
if (msg != null) message = '<p class="msg success">' + msg + '</p>'; if (msg != null) message = '<p class="msg success">' + msg + '</p>';
if (passhint != null) passhint = EscapeHtml(passhint);
var emailcheck = ((obj.parent.mailserver != null) && (domain.auth != 'sspi')); var emailcheck = ((obj.parent.mailserver != null) && (domain.auth != 'sspi'));
if (obj.args.minify && !req.query.nominify) { if (obj.args.minify && !req.query.nominify) {