Skip to content

Commit de9a4e6

Browse files
committed
add entropy validator in the frontend, set minimum to 30
1 parent 31887af commit de9a4e6

File tree

2 files changed

+102
-3
lines changed

2 files changed

+102
-3
lines changed

config.php.example

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,9 @@
2929
// the test suite :)
3030
const TRUSTED_APPS = [];
3131

32-
// Minimum entropy level for a password to be acceptable.
33-
const MINIMUM_PASSWORD_ENTROPY = 15;
32+
// Minimum entropy level for a password to be acceptable. Make sure
33+
// to update the minimum in the frontend as well!
34+
const MINIMUM_PASSWORD_ENTROPY = 30;
3435

3536
/**
3637
* The list is made up of entries from the following sources, and made all lower case:

frontend/generated.html

Lines changed: 99 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -536,6 +536,81 @@
536536
let result = await simplyDataApi.deleteAccount(deleteAccountParams);
537537
return result;
538538
},
539+
"getPasswordEntropy" : function(password) {
540+
let base = simplyApp.actions.getPasswordEntropyBase(password);
541+
let length = simplyApp.actions.getPasswordEntropyLength(password);
542+
let decimalPlaces = 2;
543+
return Math.log(Math.pow(base, length)).toFixed(decimalPlaces);
544+
},
545+
"getPasswordEntropyBase" : function(password) {
546+
/**
547+
* Get the base amount of characters from the characters used in the password.
548+
* This is the number of possible characters to pick from in the used character sets
549+
* i.e. 26 for only lower case passwords
550+
*/
551+
let specialCharacters = ' !"#$%&\'()*+,-./:;<=>?@[\]^_{|}~';
552+
let lowerCharacters = 'abcdefghijklmnopqrstuvwxyz';
553+
let upperCharacters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
554+
let digitCharacters = '0123456789';
555+
556+
let hasSpecial = false;
557+
let hasLower = false;
558+
let hasUpper = false;
559+
let hasDigits = false;
560+
561+
let base = 0;
562+
for (let i=0; i<password.length; i++) {
563+
if (!hasSpecial && (specialCharacters.indexOf(password[i]) !== -1)) {
564+
hasSpecial = true;
565+
base += specialCharacters.length;
566+
}
567+
if (!hasLower && (lowerCharacters.indexOf(password[i]) !== -1)) {
568+
hasLower = true;
569+
base += lowerCharacters.length;
570+
}
571+
if (!hasUpper && (upperCharacters.indexOf(password[i]) !== -1)) {
572+
hasUpper = true;
573+
base += upperCharacters.length;
574+
}
575+
if (!hasDigits && (digitCharacters.indexOf(password[i]) !== -1)) {
576+
hasDigits = true;
577+
base += digitCharacters.length;
578+
}
579+
if (
580+
(specialCharacters.indexOf(password[i]) === -1) &&
581+
(lowerCharacters.indexOf(password[i]) === -1) &&
582+
(upperCharacters.indexOf(password[i]) === -1) &&
583+
(digitCharacters.indexOf(password[i]) === -1)
584+
) {
585+
base++;
586+
}
587+
}
588+
return base;
589+
},
590+
"getPasswordEntropyLength" : function (password) {
591+
/**
592+
* Check the length of the password based on known rules
593+
* Characters will only be counted a maximum of 2 times e.g. aaa has length 2
594+
*/
595+
let maxOccurances = 2;
596+
let usedCharacters = {};
597+
let length = 0;
598+
599+
for (let i=0; i<password.length; i++) {
600+
if (typeof (usedCharacters[password[i]]) === 'undefined') {
601+
length++;
602+
usedCharacters[password[i]] = 1;
603+
} else if (usedCharacters[password[i]] < maxOccurances) {
604+
length++;
605+
usedCharacters[password[i]]++;
606+
}
607+
}
608+
return length;
609+
},
610+
"validatePasswordEntropy" : function(password) {
611+
let minimumEntropy = 30;
612+
return simplyApp.actions.getPasswordEntropy(password) > minimumEntropy;
613+
},
539614
"register" : async function() {
540615
let registerParams = editor.pageData.register;
541616
registerParams['repeat_password'] = registerParams['password'];
@@ -612,6 +687,11 @@
612687
simplyApp.commands.autofocus();
613688
},
614689
"registerVerify" : function(el) {
690+
let password = el.querySelector("input[type=password]");
691+
let entropyValid = simplyApp.actions.validatePasswordEntropy(password.value);
692+
if (!entropyValid) {
693+
return;
694+
}
615695
simplyApp.actions.verifyEmail()
616696
.then(function() {
617697
document.location.hash="#register-verify";
@@ -915,7 +995,7 @@ <h1>Registreren</h1>
915995
<form class="solid-form" data-simply-command="registerVerify" action="#">
916996
<p>Kies je wachtwoord</p>
917997
<input type="hidden" data-simply-field="register.email">
918-
<input autofocus class="solid-input" data-simply-field="register.password" type="password" placeholder="Wachtwoord" required>
998+
<input data-simply-transformer="validateEntropy" autofocus class="solid-input" data-simply-field="register.password" type="password" placeholder="Wachtwoord" required>
919999
<button class="solid-button solid-button-primary">Opslaan</button>
9201000
</form>
9211001
</section>
@@ -1190,6 +1270,24 @@ <h1>Je bent uitgelogd.</h1>
11901270
<script>
11911271
/* Transformers */
11921272
editor.transformers = {
1273+
"validateEntropy" : {
1274+
render : function(data) {
1275+
if (!this.entropyChecker) {
1276+
this.entropyChecker = this.addEventListener("input", function() {
1277+
let entropyValid = simplyApp.actions.validatePasswordEntropy(this.value);
1278+
if (!entropyValid) {
1279+
this.setCustomValidity("Maak een sterk wachtwoord. Gebruik meer verschillende en speciale tekens.");
1280+
} else {
1281+
this.setCustomValidity("");
1282+
}
1283+
});
1284+
}
1285+
return data;
1286+
},
1287+
extract : function(data) {
1288+
return data;
1289+
}
1290+
},
11931291
"appOrigin" : {
11941292
render : function(data) {
11951293
this.originalData = data;

0 commit comments

Comments
 (0)