mirror of
https://github.com/Ylianst/MeshCentral.git
synced 2024-09-11 08:55:32 +03:00
Added password requirements checking.
This commit is contained in:
parent
f8dcd0c244
commit
b66e74766f
19
common.js
19
common.js
@ -153,3 +153,22 @@ module.exports.validateStrArray = function (array, minlen, maxlen) { if (((array
|
||||
module.exports.validateObject = function (obj) { return ((obj != null) && (typeof obj == 'object')); };
|
||||
module.exports.validateEmail = function (email, minlen, maxlen) { if (module.exports.validateString(email, minlen, maxlen) == false) return false; var emailReg = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; return emailReg.test(email); };
|
||||
module.exports.validateUsername = function (username, minlen, maxlen) { return (module.exports.validateString(username, minlen, maxlen) && (username.indexOf(' ') == -1)); };
|
||||
|
||||
// Check password requirements
|
||||
module.exports.checkPasswordRequirements = function(password, requirements) {
|
||||
if ((requirements == null) || (requirements == '') || (typeof requirements != 'object')) return true;
|
||||
if (requirements.min) { if (password.length < requirements.min) return false; }
|
||||
if (requirements.max) { if (password.length > requirements.max) return false; }
|
||||
var num = 0, lower = 0, upper = 0, nonalpha = 0;
|
||||
for (var i = 0; i < password.length; i++) {
|
||||
if (/\d/.test(password[i])) { num++; }
|
||||
if (/[a-z]/.test(password[i])) { lower++; }
|
||||
if (/[A-Z]/.test(password[i])) { upper++; }
|
||||
if (/\W/.test(password[i])) { nonalpha++; }
|
||||
}
|
||||
if (requirements.num && (num < requirements.num)) return false;
|
||||
if (requirements.lower && (lower < requirements.lower)) return false;
|
||||
if (requirements.upper && (upper < requirements.upper)) return false;
|
||||
if (requirements.nonalpha && (nonalpha < requirements.nonalpha)) return false;
|
||||
return true;
|
||||
}
|
@ -517,6 +517,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
|
||||
if ((user.siteadmin & 2) == 0) break;
|
||||
if (obj.common.validateUsername(command.username, 1, 64) == false) break; // Username is between 1 and 64 characters, no spaces
|
||||
if (obj.common.validateString(command.pass, 1, 256) == false) break; // Password is between 1 and 256 characters
|
||||
if (obj.common.checkPasswordRequirements(command.pass, domain.passwordrequirements) == false) break; // Password does not meet requirements
|
||||
if ((command.email != null) && (obj.common.validateEmail(command.email, 1, 256) == false)) break; // Check if this is a valid email address
|
||||
var newusername = command.username, newuserid = 'user/' + domain.id + '/' + command.username.toLowerCase();
|
||||
if (newusername == '~') break; // This is a reserved user name
|
||||
@ -576,6 +577,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
|
||||
if (user.siteadmin != 0xFFFFFFFF) break;
|
||||
if (obj.common.validateString(command.user, 1, 256) == false) break;
|
||||
if (obj.common.validateString(command.pass, 1, 256) == false) break;
|
||||
if (obj.common.checkPasswordRequirements(command.pass, domain.passwordrequirements) == false) break; // Password does not meet requirements
|
||||
var chguserid = 'user/' + domain.id + '/' + command.user.toLowerCase(), chguser = obj.parent.users[chguserid];
|
||||
if (chguser && chguser.salt) {
|
||||
// Compute the password hash & save it
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "meshcentral",
|
||||
"version": "0.2.4-y",
|
||||
"version": "0.2.4-z",
|
||||
"keywords": [
|
||||
"Remote Management",
|
||||
"Intel AMT",
|
||||
|
@ -23,22 +23,23 @@
|
||||
},
|
||||
"_domains": {
|
||||
"": {
|
||||
"title": "MyServer",
|
||||
"title2": "Servername",
|
||||
"userQuota": 1048576,
|
||||
"meshQuota": 248576,
|
||||
"newAccounts": 1,
|
||||
"footer": "<a href='https://twitter.com/mytwitter'>Twitter</a>",
|
||||
"_certUrl": "https://192.168.2.106:443/"
|
||||
"Title": "MyServer",
|
||||
"Title2": "Servername",
|
||||
"UserQuota": 1048576,
|
||||
"MeshQuota": 248576,
|
||||
"NewAccounts": 1,
|
||||
"Footer": "<a href='https://twitter.com/mytwitter'>Twitter</a>",
|
||||
"_CertUrl": "https://192.168.2.106:443/",
|
||||
"_PasswordRequirements": { "min": 8, "max": 128, "upper": 1, "lower": 1, "numeric": 1, "nonalpha": 1 }
|
||||
},
|
||||
"customer1": {
|
||||
"dns": "customer1.myserver.com",
|
||||
"title": "Customer1",
|
||||
"title2": "TestServer",
|
||||
"newAccounts": 1,
|
||||
"auth": "sspi",
|
||||
"footer": "Test",
|
||||
"_certUrl": "https://192.168.2.106:443/"
|
||||
"DNS": "customer1.myserver.com",
|
||||
"Title": "Customer1",
|
||||
"Title2": "TestServer",
|
||||
"NewAccounts": 1,
|
||||
"Auth": "sspi",
|
||||
"Footer": "Test",
|
||||
"_CertUrl": "https://192.168.2.106:443/"
|
||||
},
|
||||
"info": {
|
||||
"share": "C:\\ExtraWebSite"
|
||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -585,6 +585,8 @@
|
||||
var attemptWebRTC = ((features & 128) != 0);
|
||||
var StatusStrs = ['Disconnected', 'Connecting...', 'Setup...', 'Connected', 'Intel® AMT Connected'];
|
||||
var files;
|
||||
var passRequirements = "{{{passRequirements}}}";
|
||||
if (passRequirements != "") { passRequirements = JSON.parse(decodeURIComponent(passRequirements)); }
|
||||
|
||||
function startup() {
|
||||
if ((features & 32) == 0) {
|
||||
@ -989,15 +991,15 @@
|
||||
function account_showChangePassword() {
|
||||
if (xxdialogMode) return;
|
||||
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() /> <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() /></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>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 += '<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 += '</div><br /></form>';
|
||||
setDialogMode(2, "Change Password", 0, null, x);
|
||||
account_validateDeleteAccount();
|
||||
account_validateNewPassword();
|
||||
Q('apassword1').focus();
|
||||
}
|
||||
|
||||
@ -1024,13 +1026,20 @@
|
||||
}
|
||||
|
||||
function account_validateNewPassword() {
|
||||
QE('account_dlgOkButton', (Q('apassword1').value.length > 0) && (Q('apassword1').value == Q('apassword2').value));
|
||||
var r = '';
|
||||
var r = '', ok = (Q('apassword1').value.length > 0) && (Q('apassword1').value == Q('apassword2').value);
|
||||
if (Q('apassword1').value != '') {
|
||||
var passStrength = checkPasswordStrength(Q('apassword1').value);
|
||||
if (passStrength >= 80) { r = '<span style=color:green>Strong<span>'; } else if (passStrength >= 60) { r = '<span style=color:blue>Good<span>'; } else { r = '<span style=color:red>Weak<span>'; }
|
||||
if (passRequirements == null || passRequirements == '') {
|
||||
// No password requirements, display password strength
|
||||
var passStrength = checkPasswordStrength(Q('apassword1').value);
|
||||
if (passStrength >= 80) { r = '<span style=color:green>●<span>'; } else if (passStrength >= 60) { r = '<span style=color:blue>●<span>'; } else { r = '<span style=color:red>●<span>'; }
|
||||
} else {
|
||||
// Password requirements provided, use that
|
||||
var passReq = checkPasswordRequirements(Q('apassword1').value, passRequirements);
|
||||
if (passReq == false) { ok = false; r = '<span style=color:red>●<span>' }
|
||||
}
|
||||
}
|
||||
QH('dxPassWarn', r);
|
||||
QE('account_dlgOkButton', ok);
|
||||
}
|
||||
|
||||
// Return a password strength score
|
||||
@ -1042,6 +1051,25 @@
|
||||
return parseInt(r + (varCount - 1) * 10);
|
||||
}
|
||||
|
||||
// Check password requirements
|
||||
function checkPasswordRequirements(password, requirements) {
|
||||
if ((requirements == null) || (requirements == '') || (typeof requirements != 'object')) return true;
|
||||
if (requirements.min) { if (password.length < requirements.min) return false; }
|
||||
if (requirements.max) { if (password.length > requirements.max) return false; }
|
||||
var num = 0, lower = 0, upper = 0, nonalpha = 0;
|
||||
for (var i = 0; i < password.length; i++) {
|
||||
if (/\d/.test(password[i])) { num++; }
|
||||
if (/[a-z]/.test(password[i])) { lower++; }
|
||||
if (/[A-Z]/.test(password[i])) { upper++; }
|
||||
if (/\W/.test(password[i])) { nonalpha++; }
|
||||
}
|
||||
if (requirements.num && (num < requirements.num)) return false;
|
||||
if (requirements.lower && (lower < requirements.lower)) return false;
|
||||
if (requirements.upper && (upper < requirements.upper)) return false;
|
||||
if (requirements.nonalpha && (nonalpha < requirements.nonalpha)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
function updateMeshes() {
|
||||
var r = '', count = 0;
|
||||
for (i in meshes) {
|
||||
|
@ -874,6 +874,8 @@
|
||||
var webPageFullScreen = getstore('webPageFullScreen', true);
|
||||
if (webPageFullScreen == 'false') { webPageFullScreen = false; }
|
||||
if (webPageFullScreen == 'true') { webPageFullScreen = true; }
|
||||
var passRequirements = "{{{passRequirements}}}";
|
||||
if (passRequirements != "") { passRequirements = JSON.parse(decodeURIComponent(passRequirements)); }
|
||||
|
||||
function startup() {
|
||||
if ((features & 32) == 0) {
|
||||
@ -5025,7 +5027,7 @@
|
||||
|
||||
function account_validateEmail(e, email) {
|
||||
QE('idx_dlgOkButton', validateEmail(Q('dp2email').value) && (Q('dp2email').value != userinfo.email));
|
||||
if ((x == true) && (e != null) && (e.keyCode == 13)) { dialogclose(1); }
|
||||
if ((e != null) && (e.keyCode == 13)) { dialogclose(1); }
|
||||
}
|
||||
|
||||
function account_changeEmail() {
|
||||
@ -5051,16 +5053,16 @@
|
||||
if (xxdialogMode) return;
|
||||
var x = "Change your account password by entering the new password twice in the boxes below.<br /><br />";
|
||||
x += "<form action='" + domainUrl + "changepassword' method=post><table style=margin-left:60px><tr>";
|
||||
x += "<td align=right>Password:</td><td><input id=apassword1 type=password name=apassword1 autocomplete=off onchange=account_validateNewPassword() onkeyup=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() /></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 Hint:</td><td><input id=apasswordhint name=apasswordhint maxlength=250 type=text autocomplete=off /></td>";
|
||||
x += '</tr></table><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_dlgOkButton type=submit value=OK style="float:right;width:80px" onclick=dialogclose(1)>';
|
||||
x += '</div><br /></form>';
|
||||
setDialogMode(2, "Change Password", 0, null, x);
|
||||
account_validateDeleteAccount();
|
||||
Q('apassword1').focus();
|
||||
account_validateNewPassword();
|
||||
}
|
||||
|
||||
function account_createMesh() {
|
||||
@ -5087,13 +5089,20 @@
|
||||
}
|
||||
|
||||
function account_validateNewPassword() {
|
||||
QE('account_dlgOkButton', (Q('apassword1').value.length > 0) && (Q('apassword1').value == Q('apassword2').value));
|
||||
var r = '';
|
||||
var r = '', ok = (Q('apassword1').value.length > 0) && (Q('apassword1').value == Q('apassword2').value);
|
||||
if (Q('apassword1').value != '') {
|
||||
var passStrength = checkPasswordStrength(Q('apassword1').value);
|
||||
if (passStrength >= 80) { r = '<span style=color:green>Strong<span>'; } else if (passStrength >= 60) { r = '<span style=color:blue>Good<span>'; } else { r = '<span style=color:red>Weak<span>'; }
|
||||
if (passRequirements == null || passRequirements == '') {
|
||||
// No password requirements, display password strength
|
||||
var passStrength = checkPasswordStrength(Q('apassword1').value);
|
||||
if (passStrength >= 80) { r = '<span style=color:green>Strong<span>'; } else if (passStrength >= 60) { r = '<span style=color:blue>Good<span>'; } else { r = '<span style=color:red>Weak<span>'; }
|
||||
} else {
|
||||
// Password requirements provided, use that
|
||||
var passReq = checkPasswordRequirements(Q('apassword1').value, passRequirements);
|
||||
if (passReq == false) { ok = false; r = '<span style=color:red>Policy<span>' }
|
||||
}
|
||||
}
|
||||
QH('dxPassWarn', r);
|
||||
QE('account_dlgOkButton', ok);
|
||||
}
|
||||
|
||||
// Return a password strength score
|
||||
@ -5105,6 +5114,25 @@
|
||||
return parseInt(r + (varCount - 1) * 10);
|
||||
}
|
||||
|
||||
// Check password requirements
|
||||
function checkPasswordRequirements(password, requirements) {
|
||||
if ((requirements == null) || (requirements == '') || (typeof requirements != 'object')) return true;
|
||||
if (requirements.min) { if (password.length < requirements.min) return false; }
|
||||
if (requirements.max) { if (password.length > requirements.max) return false; }
|
||||
var num = 0, lower = 0, upper = 0, nonalpha = 0;
|
||||
for (var i = 0; i < password.length; i++) {
|
||||
if (/\d/.test(password[i])) { num++; }
|
||||
if (/[a-z]/.test(password[i])) { lower++; }
|
||||
if (/[A-Z]/.test(password[i])) { upper++; }
|
||||
if (/\W/.test(password[i])) { nonalpha++; }
|
||||
}
|
||||
if (requirements.num && (num < requirements.num)) return false;
|
||||
if (requirements.lower && (lower < requirements.lower)) return false;
|
||||
if (requirements.upper && (upper < requirements.upper)) return false;
|
||||
if (requirements.nonalpha && (nonalpha < requirements.nonalpha)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
function updateMeshes() {
|
||||
var r = '';
|
||||
var c = 0, count = 0;
|
||||
@ -5826,7 +5854,7 @@
|
||||
|
||||
function showCreateNewAccountDialogValidate() {
|
||||
if ((Q('p4email').value.length > 0) && (validateEmail(Q('p4email').value)) == false) { QE('idx_dlgOkButton', false); return; }
|
||||
QE('idx_dlgOkButton', (!Q('p4name') || ((Q('p4name').value.length > 0) && (Q('p4name').value.indexOf(' ') == -1))) && Q('p4pass1').value.length > 0 && Q('p4pass1').value == Q('p4pass2').value);
|
||||
QE('idx_dlgOkButton', (!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));
|
||||
}
|
||||
|
||||
function showCreateNewAccountDialogEx() {
|
||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -179,6 +179,8 @@
|
||||
var newAccountPass = parseInt('{{{newAccountPass}}}');
|
||||
var emailCheck = ('{{{emailcheck}}}' == 'true');
|
||||
var features = parseInt('{{{features}}}');
|
||||
var passRequirements = "{{{passRequirements}}}";
|
||||
if (passRequirements != "") { passRequirements = JSON.parse(decodeURIComponent(passRequirements)); }
|
||||
|
||||
function startup() {
|
||||
if ((features & 32) == 0) {
|
||||
@ -233,15 +235,29 @@
|
||||
setDialogMode(0);
|
||||
var ok = ((Q('ausername').value.length > 0) && (Q('ausername').value.indexOf(' ') == -1) && (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; }
|
||||
QE('createButton', ok);
|
||||
if (Q('apassword1').value == '') {
|
||||
QH('passWarning', '');
|
||||
} else {
|
||||
var passStrength = checkPasswordStrength(Q('apassword1').value);
|
||||
if (passStrength >= 80) { QH('passWarning', '<span style=color:green><b>Strong Password</b><span>'); }
|
||||
else if (passStrength >= 60) { QH('passWarning', '<span style=color:blue><b>Good Password</b><span>'); }
|
||||
else { QH('passWarning', '<span style=color:red><b>Weak Password</b><span>'); }
|
||||
if (passRequirements == null || passRequirements == '') {
|
||||
// No password requirements, display password strength
|
||||
var passStrength = checkPasswordStrength(Q('apassword1').value);
|
||||
if (passStrength >= 80) { QH('passWarning', '<span style=color:green><b>Strong Password</b><span>'); }
|
||||
else if (passStrength >= 60) { QH('passWarning', '<span style=color:blue><b>Good Password</b><span>'); }
|
||||
else { QH('passWarning', '<span style=color:red><b>Weak Password</b><span>'); }
|
||||
} else {
|
||||
// Password requirements provided, use that
|
||||
var passReq = checkPasswordRequirements(Q('apassword1').value, passRequirements);
|
||||
if (passReq == false) {
|
||||
ok = false;
|
||||
//QS('nuPass1').color = '#7b241c';
|
||||
//QS('nuPass2').color = '#7b241c';
|
||||
QH('passWarning', '<span style=color:red><b>Password Policy</b><span>'); // TODO: Display problem hint
|
||||
} else {
|
||||
QH('passWarning', '');
|
||||
}
|
||||
}
|
||||
}
|
||||
QE('createButton', ok);
|
||||
if ((e != null) && (e.keyCode == 13)) {
|
||||
if (box == 1) { Q('aemail').focus(); }
|
||||
if (box == 2) { Q('apassword1').focus(); }
|
||||
@ -272,6 +288,24 @@
|
||||
return parseInt(r + (varCount - 1) * 10);
|
||||
}
|
||||
|
||||
// Check password requirements
|
||||
function checkPasswordRequirements(password, requirements) {
|
||||
if ((requirements == null) || (requirements == '') || (typeof requirements != 'object')) return true;
|
||||
if (requirements.min) { if (password.length < requirements.min) return false; }
|
||||
if (requirements.max) { if (password.length > requirements.max) return false; }
|
||||
var num = 0, lower = 0, upper = 0, nonalpha = 0;
|
||||
for (var i = 0; i < password.length; i++) {
|
||||
if (/\d/.test(password[i])) { num++; }
|
||||
if (/[a-z]/.test(password[i])) { lower++; }
|
||||
if (/[A-Z]/.test(password[i])) { upper++; }
|
||||
if (/\W/.test(password[i])) { nonalpha++; }
|
||||
}
|
||||
if (requirements.num && (num < requirements.num)) return false;
|
||||
if (requirements.lower && (lower < requirements.lower)) return false;
|
||||
if (requirements.upper && (upper < requirements.upper)) return false;
|
||||
if (requirements.nonalpha && (nonalpha < requirements.nonalpha)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
//
|
||||
// POPUP DIALOG
|
||||
|
@ -257,6 +257,8 @@
|
||||
var passhint = "{{{passhint}}}";
|
||||
var newAccountPass = parseInt('{{{newAccountPass}}}');
|
||||
var emailCheck = ('{{{emailcheck}}}' == 'true');
|
||||
var passRequirements = "{{{passRequirements}}}";
|
||||
if (passRequirements != "") { passRequirements = JSON.parse(decodeURIComponent(passRequirements)); }
|
||||
var features = parseInt('{{{features}}}');
|
||||
var webPageFullScreen = getstore('webPageFullScreen', true);
|
||||
if (webPageFullScreen == 'false') { webPageFullScreen = false; }
|
||||
@ -312,7 +314,7 @@
|
||||
if (e != null) { haltEvent(e); }
|
||||
}
|
||||
|
||||
function validateCreate(box,e) {
|
||||
function validateCreate(box, e) {
|
||||
setDialogMode(0);
|
||||
var userok = (Q('ausername').value.length > 0) && (Q('ausername').value.indexOf(' ') == -1);
|
||||
var emailok = (validateEmail(Q('aemail').value) == true);
|
||||
@ -328,14 +330,27 @@
|
||||
QS('nuPass2').color = pass2ok?'black':'#7b241c';
|
||||
QS('nuToken').color = newAccOk?'black':'#7b241c';
|
||||
|
||||
QE('createButton', ok);
|
||||
if (Q('apassword1').value == '') {
|
||||
QH('passWarning', '');
|
||||
} else {
|
||||
var passStrength = checkPasswordStrength(Q('apassword1').value);
|
||||
if (passStrength >= 80) { QH('passWarning', '<span style=color:green><b>Strong Password</b><span>'); }
|
||||
else if (passStrength >= 60) { QH('passWarning', '<span style=color:blue><b>Good Password</b><span>'); }
|
||||
else { QH('passWarning', '<span style=color:red><b>Weak Password</b><span>'); }
|
||||
if (passRequirements == null || passRequirements == '') {
|
||||
// No password requirements, display password strength
|
||||
var passStrength = checkPasswordStrength(Q('apassword1').value);
|
||||
if (passStrength >= 80) { QH('passWarning', '<span style=color:green><b>Strong Password</b><span>'); }
|
||||
else if (passStrength >= 60) { QH('passWarning', '<span style=color:blue><b>Good Password</b><span>'); }
|
||||
else { QH('passWarning', '<span style=color:red><b>Weak Password</b><span>'); }
|
||||
} else {
|
||||
// Password requirements provided, use that
|
||||
var passReq = checkPasswordRequirements(Q('apassword1').value, passRequirements);
|
||||
if (passReq == false) {
|
||||
ok = false;
|
||||
QS('nuPass1').color = '#7b241c';
|
||||
QS('nuPass2').color = '#7b241c';
|
||||
QH('passWarning', '<span style=color:red><b>Password Policy</b><span>'); // TODO: Display problem hint
|
||||
} else {
|
||||
QH('passWarning', '');
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((e != null) && (e.keyCode == 13)) {
|
||||
if (box == 1) { Q('aemail').focus(); }
|
||||
@ -346,6 +361,7 @@
|
||||
if (box == 6) { Q('createButton').click(); }
|
||||
}
|
||||
if (e != null) { haltEvent(e); }
|
||||
QE('createButton', ok);
|
||||
}
|
||||
|
||||
function validateReset(e) {
|
||||
@ -367,6 +383,24 @@
|
||||
return parseInt(r + (varCount - 1) * 10);
|
||||
}
|
||||
|
||||
// Check password requirements
|
||||
function checkPasswordRequirements(password, requirements) {
|
||||
if ((requirements == null) || (requirements == '') || (typeof requirements != 'object')) return true;
|
||||
if (requirements.min) { if (password.length < requirements.min) return false; }
|
||||
if (requirements.max) { if (password.length > requirements.max) return false; }
|
||||
var num = 0, lower = 0, upper = 0, nonalpha = 0;
|
||||
for (var i = 0; i < password.length; i++) {
|
||||
if (/\d/.test(password[i])) { num++; }
|
||||
if (/[a-z]/.test(password[i])) { lower++; }
|
||||
if (/[A-Z]/.test(password[i])) { upper++; }
|
||||
if (/\W/.test(password[i])) { nonalpha++; }
|
||||
}
|
||||
if (requirements.num && (num < requirements.num)) return false;
|
||||
if (requirements.lower && (lower < requirements.lower)) return false;
|
||||
if (requirements.upper && (upper < requirements.upper)) return false;
|
||||
if (requirements.nonalpha && (nonalpha < requirements.nonalpha)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
//
|
||||
// POPUP DIALOG
|
||||
|
File diff suppressed because one or more lines are too long
21
webserver.js
21
webserver.js
@ -398,7 +398,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
||||
var domain = checkUserIpAddress(req, res);
|
||||
if (domain == null) return;
|
||||
if ((domain.newaccounts === 0) || (domain.newaccounts === false)) { res.sendStatus(401); return; }
|
||||
if (!obj.common.validateUsername(req.body.username, 1, 64) || !obj.common.validateEmail(req.body.email, 1, 256) || !obj.common.validateString(req.body.password1, 1, 256) || !obj.common.validateString(req.body.password2, 1, 256) || (req.body.password1 != req.body.password2) || req.body.username == '~') {
|
||||
if (!obj.common.validateUsername(req.body.username, 1, 64) || !obj.common.validateEmail(req.body.email, 1, 256) || !obj.common.validateString(req.body.password1, 1, 256) || !obj.common.validateString(req.body.password2, 1, 256) || (req.body.password1 != req.body.password2) || req.body.username == '~' || !obj.common.checkPasswordRequirements(req.body.password1, domain.passwordrequirements)) {
|
||||
req.session.loginmode = 2;
|
||||
req.session.error = '<b style=color:#8C001A>Unable to create account.</b>';
|
||||
res.redirect(domain.url);
|
||||
@ -733,6 +733,13 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
||||
}
|
||||
}
|
||||
|
||||
// Figure out the minimal password requirement
|
||||
var passRequirements = null;
|
||||
if (domain.passwordrequirements != null) {
|
||||
if (domain.passrequirementstr == null) { domain.passwordrequirementsstr = encodeURIComponent(JSON.stringify(domain.passwordrequirements)); }
|
||||
passRequirements = domain.passwordrequirementsstr;
|
||||
}
|
||||
|
||||
// If a user exists and is logged in, serve the default app, otherwise server the login app.
|
||||
if (req.session && req.session.userid && obj.users[req.session.userid]) {
|
||||
var user = obj.users[req.session.userid];
|
||||
@ -776,14 +783,14 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
||||
if (obj.args.minify && !req.query.nominify) {
|
||||
// Try to server the minified version if we can.
|
||||
try {
|
||||
res.render(obj.path.join(__dirname, isMobileBrowser(req) ? 'views/default-mobile-min' : 'views/default-min'), { viewmode: viewmode, currentNode: currentNode, logoutControl: logoutcontrol, title: domain.title, title2: domain.title2, domainurl: domain.url, domain: domain.id, debuglevel: parent.debugLevel, serverDnsName: obj.getWebServerName(domain), serverRedirPort: args.redirport, serverPublicPort: httpsPort, noServerBackup: (args.noserverbackup == 1 ? 1 : 0), features: features, sessiontime: args.sessiontime, mpspass: args.mpspass, webcerthash: new Buffer(obj.webCertificateFullHashs[domain.id], 'binary').toString('base64').replace(/\+/g, '@').replace(/\//g, '$'), footer: (domain.footer == null) ? '' : domain.footer });
|
||||
res.render(obj.path.join(__dirname, isMobileBrowser(req) ? 'views/default-mobile-min' : 'views/default-min'), { viewmode: viewmode, currentNode: currentNode, logoutControl: logoutcontrol, title: domain.title, title2: domain.title2, domainurl: domain.url, domain: domain.id, debuglevel: parent.debugLevel, serverDnsName: obj.getWebServerName(domain), serverRedirPort: args.redirport, serverPublicPort: httpsPort, noServerBackup: (args.noserverbackup == 1 ? 1 : 0), features: features, sessiontime: args.sessiontime, mpspass: args.mpspass, passRequirements: passRequirements, webcerthash: new Buffer(obj.webCertificateFullHashs[domain.id], 'binary').toString('base64').replace(/\+/g, '@').replace(/\//g, '$'), footer: (domain.footer == null) ? '' : domain.footer });
|
||||
} catch (ex) {
|
||||
// In case of an exception, serve the non-minified version.
|
||||
res.render(obj.path.join(__dirname, isMobileBrowser(req) ? 'views/default-mobile' : 'views/default'), { viewmode: viewmode, currentNode: currentNode, logoutControl: logoutcontrol, title: domain.title, title2: domain.title2, domainurl: domain.url, domain: domain.id, debuglevel: parent.debugLevel, serverDnsName: obj.getWebServerName(domain), serverRedirPort: args.redirport, serverPublicPort: httpsPort, noServerBackup: (args.noserverbackup == 1 ? 1 : 0), features: features, sessiontime: args.sessiontime, mpspass: args.mpspass, webcerthash: new Buffer(obj.webCertificateFullHashs[domain.id], 'binary').toString('base64').replace(/\+/g, '@').replace(/\//g, '$'), footer: (domain.footer == null) ? '' : domain.footer });
|
||||
res.render(obj.path.join(__dirname, isMobileBrowser(req) ? 'views/default-mobile' : 'views/default'), { viewmode: viewmode, currentNode: currentNode, logoutControl: logoutcontrol, title: domain.title, title2: domain.title2, domainurl: domain.url, domain: domain.id, debuglevel: parent.debugLevel, serverDnsName: obj.getWebServerName(domain), serverRedirPort: args.redirport, serverPublicPort: httpsPort, noServerBackup: (args.noserverbackup == 1 ? 1 : 0), features: features, sessiontime: args.sessiontime, mpspass: args.mpspass, passRequirements: passRequirements, webcerthash: new Buffer(obj.webCertificateFullHashs[domain.id], 'binary').toString('base64').replace(/\+/g, '@').replace(/\//g, '$'), footer: (domain.footer == null) ? '' : domain.footer });
|
||||
}
|
||||
} else {
|
||||
// Serve non-minified version of web pages.
|
||||
res.render(obj.path.join(__dirname, isMobileBrowser(req) ? 'views/default-mobile' : 'views/default'), { viewmode: viewmode, currentNode: currentNode, logoutControl: logoutcontrol, title: domain.title, title2: domain.title2, domainurl: domain.url, domain: domain.id, debuglevel: parent.debugLevel, serverDnsName: obj.getWebServerName(domain), serverRedirPort: args.redirport, serverPublicPort: httpsPort, noServerBackup: (args.noserverbackup == 1 ? 1 : 0), features: features, sessiontime: args.sessiontime, mpspass: args.mpspass, webcerthash: new Buffer(obj.webCertificateFullHashs[domain.id], 'binary').toString('base64').replace(/\+/g, '@').replace(/\//g, '$'), footer: (domain.footer == null) ? '' : domain.footer });
|
||||
res.render(obj.path.join(__dirname, isMobileBrowser(req) ? 'views/default-mobile' : 'views/default'), { viewmode: viewmode, currentNode: currentNode, logoutControl: logoutcontrol, title: domain.title, title2: domain.title2, domainurl: domain.url, domain: domain.id, debuglevel: parent.debugLevel, serverDnsName: obj.getWebServerName(domain), serverRedirPort: args.redirport, serverPublicPort: httpsPort, noServerBackup: (args.noserverbackup == 1 ? 1 : 0), features: features, sessiontime: args.sessiontime, mpspass: args.mpspass, passRequirements: passRequirements, webcerthash: new Buffer(obj.webCertificateFullHashs[domain.id], 'binary').toString('base64').replace(/\+/g, '@').replace(/\//g, '$'), footer: (domain.footer == null) ? '' : domain.footer });
|
||||
}
|
||||
} else {
|
||||
// Send back the login application
|
||||
@ -796,14 +803,14 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
||||
if (obj.args.minify && !req.query.nominify) {
|
||||
// Try to server the minified version if we can.
|
||||
try {
|
||||
res.render(obj.path.join(__dirname, isMobileBrowser(req) ? 'views/login-mobile-min' : 'views/login-min'), { loginmode: loginmode, rootCertLink: getRootCertLink(), title: domain.title, title2: domain.title2, newAccount: domain.newaccounts, newAccountPass: (((domain.newaccountspass == null) || (domain.newaccountspass == '')) ? 0 : 1), serverDnsName: obj.getWebServerName(domain), serverPublicPort: httpsPort, emailcheck: obj.parent.mailserver != null, features: features, sessiontime: args.sessiontime, footer: (domain.footer == null) ? '' : domain.footer });
|
||||
res.render(obj.path.join(__dirname, isMobileBrowser(req) ? 'views/login-mobile-min' : 'views/login-min'), { loginmode: loginmode, rootCertLink: getRootCertLink(), title: domain.title, title2: domain.title2, newAccount: domain.newaccounts, newAccountPass: (((domain.newaccountspass == null) || (domain.newaccountspass == '')) ? 0 : 1), serverDnsName: obj.getWebServerName(domain), serverPublicPort: httpsPort, emailcheck: obj.parent.mailserver != null, features: features, sessiontime: args.sessiontime, passRequirements: passRequirements, footer: (domain.footer == null) ? '' : domain.footer });
|
||||
} catch (ex) {
|
||||
// In case of an exception, serve the non-minified version.
|
||||
res.render(obj.path.join(__dirname, isMobileBrowser(req) ? 'views/login-mobile' : 'views/login'), { loginmode: loginmode, rootCertLink: getRootCertLink(), title: domain.title, title2: domain.title2, newAccount: domain.newaccounts, newAccountPass: (((domain.newaccountspass == null) || (domain.newaccountspass == '')) ? 0 : 1), serverDnsName: obj.getWebServerName(domain), serverPublicPort: httpsPort, emailcheck: obj.parent.mailserver != null, features: features, sessiontime: args.sessiontime, footer: (domain.footer == null) ? '' : domain.footer });
|
||||
res.render(obj.path.join(__dirname, isMobileBrowser(req) ? 'views/login-mobile' : 'views/login'), { loginmode: loginmode, rootCertLink: getRootCertLink(), title: domain.title, title2: domain.title2, newAccount: domain.newaccounts, newAccountPass: (((domain.newaccountspass == null) || (domain.newaccountspass == '')) ? 0 : 1), serverDnsName: obj.getWebServerName(domain), serverPublicPort: httpsPort, emailcheck: obj.parent.mailserver != null, features: features, sessiontime: args.sessiontime, passRequirements: passRequirements, footer: (domain.footer == null) ? '' : domain.footer });
|
||||
}
|
||||
} else {
|
||||
// Serve non-minified version of web pages.
|
||||
res.render(obj.path.join(__dirname, isMobileBrowser(req) ? 'views/login-mobile' : 'views/login'), { loginmode: loginmode, rootCertLink: getRootCertLink(), title: domain.title, title2: domain.title2, newAccount: domain.newaccounts, newAccountPass: (((domain.newaccountspass == null) || (domain.newaccountspass == '')) ? 0 : 1), serverDnsName: obj.getWebServerName(domain), serverPublicPort: httpsPort, emailcheck: obj.parent.mailserver != null, features: features, sessiontime: args.sessiontime, footer: (domain.footer == null) ? '' : domain.footer });
|
||||
res.render(obj.path.join(__dirname, isMobileBrowser(req) ? 'views/login-mobile' : 'views/login'), { loginmode: loginmode, rootCertLink: getRootCertLink(), title: domain.title, title2: domain.title2, newAccount: domain.newaccounts, newAccountPass: (((domain.newaccountspass == null) || (domain.newaccountspass == '')) ? 0 : 1), serverDnsName: obj.getWebServerName(domain), serverPublicPort: httpsPort, emailcheck: obj.parent.mailserver != null, features: features, sessiontime: args.sessiontime, passRequirements: passRequirements, footer: (domain.footer == null) ? '' : domain.footer });
|
||||
}
|
||||
|
||||
/*
|
||||
|
Loading…
Reference in New Issue
Block a user