Add password rating
Thanks @Olli :)
diff --git a/templates/register.htm b/templates/register.htm
index edfab84..bfd6318 100644
--- a/templates/register.htm
+++ b/templates/register.htm
@@ -63,20 +63,31 @@
<input pattern="[^\s]{<?php echo $VAL_USER->min_password.','.$VAL_USER->max_password;?>}" required
title="At least 8 not whitespace characters" name="password" type="password" id="pw1"
class="form-control <?php if(isset($error) && $error && !isset($_POST['password'])){echo 'border-danger';}?>"
- placeholder="********"
+ placeholder="********" oninput="passUpdated()"
value="<?php echo isset($_POST['password']) ? htmlspecialchars($_POST['password']) : '' ?>" />
+ <div class="progress mt-2">
+ <div class="progress-bar bg-danger" role="progressbar" id="pwqbar" aria-valuenow="0" aria-valuemin="0"
+ aria-valuemax="100"></div>
+ </div>
</div>
+ <!--
+ <div class="form-group">
+ <label for="pwqinfo">Password rating</label>
+ <input class="form-control" type="text" name="pwqinfo" id="pwqinfo" readonly>
+ <div class="progress mt-2">
+ <div class="progress-bar bg-danger" role="progressbar" id="pwqbar2" aria-valuenow="0" aria-valuemin="0"
+ aria-valuemax="100"></div>
+ </div>
+ </div>
+ -->
<!-- Password input -->
<div class="form-outline mb-3">
<label class="form-label font-weight-bold" for="pw2">Confirm your Password*</label>
<input pattern="[^\s]{<?php echo $VAL_USER->min_password.','.$VAL_USER->max_password;?>}" required
title="At least 8 not whitespace characters" name="password_confirm" type="password" id="pw2"
class="form-control <?php if(isset($error) && $error && !isset($_POST['password_confirm'])){echo 'border-danger';}?>"
- placeholder="********"
- oninput="validate_pw2(this)"
- />
- </div>
- <hr class="mt-2 mb-3" />
+ placeholder="********" oninput="validate_pw2(this)" />
+ </div> <hr class="mt-2 mb-3" />
<div class="form-outline mb-3">
<label class="form-label font-weight-bold" for="eula">End User License Agreement*</label>
<div class="form-group form-check">
@@ -159,4 +170,223 @@
pw2.setCustomValidity(""); // is valid
}
}
+
+ TOO_SHORT ='Password too short, still %% characters needed';
+ TOO_LONG ='Password too long, please remove %% characters';
+ INVALID_CHARS ='Password contains invalid characters';
+ QUAL_NONE ='Password is very weak'
+ QUAL_LOW ='Password is weak';
+ QUAL_MEDIUM ='Password is average'
+ QUAL_GOOD ='Password is good';
+ QUAL_STRONG ='Password is strong';
+ REP_OK ='Repetition ok';
+ REP_NE ='Passwords not identical';
+ PWNED ='Password found in public password list';
+
+ String.prototype.strReverse=function() {
+ var newstring='';
+ for (var s=0; s < this.length; s++)
+ newstring=this.charAt(s)+newstring;
+ return newstring;
+ };
+
+ //var checkTimer;
+
+ function passUpdated() {
+ var nScore=0;
+ var message='';
+
+ var pass=$('#pw1').val();
+ var pass2=$('#pw2').val();
+
+ //clearTimeout(checkTimer);
+
+ try {
+ if (!pass)
+ throw '';
+
+ if (pass.match(/[^a-zA-Z0-9!@#$%()_+=:;",.?/-]/))
+ throw INVALID_CHARS;
+
+ var nLength=pass.length;
+ if (nLength < 8)
+ throw TOO_SHORT.replace('%%', 8-nLength);
+ if (nLength > 20)
+ throw TOO_LONG.replace('%%', nLength-20);
+
+ nScore=4*nLength;
+
+ // check for upper-/lowercase, numeric and special chars pattern matches
+ var nAlphaUC=0, nAlphaLC=0, nNumber=0, nSpecial=0;
+ var nMidChar=0, nRepChar=0, nRepInc=0;
+ var nConsecAlphaUC=0, nConsecAlphaLC=0, nConsecNumber=0;
+ var nTmpAlphaUC='', nTmpAlphaLC='', nTmpNumber='';
+ for (var i=0; i < nLength; i++) {
+ if (pass[i].match(/[A-Z]/g)) { // uppercase characters
+ if (nTmpAlphaUC !== '' && (nTmpAlphaUC+1) == i) {
+ nConsecAlphaUC++;
+ }
+ nTmpAlphaUC=i;
+ nAlphaUC++;
+ } else if (pass[i].match(/[a-z]/g)) { // lowercase characters
+ if (nTmpAlphaLC !== '' && (nTmpAlphaLC+1) == i) {
+ nConsecAlphaLC++;
+ }
+ nTmpAlphaLC=i;
+ nAlphaLC++;
+ } else if (pass[i].match(/[0-9]/g)) { // numbers
+ if (i > 0 && i < (nLength-1)) {
+ nMidChar++;
+ }
+ if (nTmpNumber !== '' && (nTmpNumber+1) == i) {
+ nConsecNumber++;
+ }
+ nTmpNumber=i;
+ nNumber++;
+ } else { // special characters
+ if (i > 0 && i < (nLength-1)) {
+ nMidChar++;
+ }
+ nSpecial++;
+ }
+
+ // check for repeated characters
+ var bCharExists=false;
+ for (var j=0; j < nLength; j++) {
+ if (pass[i] == pass[j] && i != j) {
+ bCharExists=true;
+ nRepInc+=Math.abs(nLength/(j-i));
+ }
+ }
+ if (bCharExists) {
+ nRepChar++;
+ var nUnqChar=nLength-nRepChar;
+ nRepInc=(nUnqChar) ? Math.ceil(nRepInc/nUnqChar) : Math.ceil(nRepInc);
+ }
+ }
+
+ // check for sequential alpha string patterns (forward and reverse)
+ var sAlphas="abcdefghijklmnopqrstuvwxyz";
+ var nSeqAlpha=0;
+ for (var i=0; i < 23; i++) {
+ var sFwd=sAlphas.substring(i, i+3);
+ var sRev=sFwd.strReverse();
+ if (pass.toLowerCase().indexOf(sFwd) != -1
+ || pass.toLowerCase().indexOf(sRev) != -1)
+ nSeqAlpha++;
+ }
+
+ // check for sequential numeric string patterns (forward and reverse)
+ var sNumerics="01234567890";
+ var nSeqNumber=0;
+ for (var i=0; i < 8; i++) {
+ var sFwd=sNumerics.substring(i, i+3);
+ var sRev=sFwd.strReverse();
+ if (pass.toLowerCase().indexOf(sFwd) != -1
+ || pass.toLowerCase().indexOf(sRev) != -1)
+ nSeqNumber++;
+ }
+
+ // general point assignment
+ if (nAlphaUC > 0 && nAlphaUC < nLength) // uppercase characters
+ nScore+=2*(nLength-nAlphaUC);
+ if (nAlphaLC > 0 && nAlphaLC < nLength) // lowercase characters
+ nScore+=2*(nLength-nAlphaLC);
+ if (nNumber > 0 && nNumber < nLength) // numbers
+ nScore+=2*nNumber;
+ if (nSpecial > 0) // special characters
+ nScore+=4*nSpecial;
+ if (nMidChar > 0) // mid numbers/special characters
+ nScore+=2*nMidChar;
+
+ // point deductions for poor practices
+ if ((nAlphaLC > 0 || nAlphaUC > 0)
+ && nSpecial === 0 && nNumber === 0) // characters only
+ nScore-=nLength;
+ if (nAlphaLC === 0 && nAlphaUC === 0
+ && nSpecial === 0 && nNumber > 0) // numbers only
+ nScore-=nLength;
+ if (nRepChar > 0) // same character exists more than once
+ nScore-=nRepInc;
+ if (nConsecAlphaUC > 0) // consecutive uppercase letters exist
+ nScore-=2*nConsecAlphaUC;
+ if (nConsecAlphaLC > 0) // consecutive lowercase letters exist
+ nScore-=2*nConsecAlphaLC;
+ if (nConsecNumber > 0) // consecutive numbers exist
+ nScore-=2*nConsecNumber;
+ if (nSeqAlpha > 0) // sequential alpha strings exist (3 chars or more)
+ nScore-=3*nSeqAlpha;
+ if (nSeqNumber > 0) // sequential numeric strings exist (3 chars or more)
+ nScore-=3*nSeqNumber;
+
+ // determine if mandatory requirements have been met
+ var arrChars=[nAlphaUC, nAlphaLC, nNumber, nSpecial];
+ var nReqChar=0;
+ for (var i=0; i < arrChars.length; i++) {
+ if (arrChars[i]) {
+ nReqChar++;
+ }
+ }
+ if (nReqChar >= arrChars.length)
+ nScore+=2*nReqChar;
+ else if (nReqChar < arrChars.length-1)
+ nScore-=2*nReqChar;
+
+ // limit points to 3..100
+ nScore=Math.max(3, Math.min(nScore, 100));
+
+ // set message according to points
+ if (nScore >= 80)
+ message=QUAL_STRONG;
+ else if (nScore >= 60)
+ message=QUAL_GOOD;
+ else if (nScore >= 40)
+ message=QUAL_MEDIUM;
+ else if (nScore >= 20)
+ message=QUAL_LOW;
+ else
+ message=QUAL_NONE;
+ } catch (error) {
+ nScore=3;
+ message=error;
+ }
+/*
+ if (pass.length > 0 && pass2.length > 0) {
+ message+=' / ';
+ message+=(pass == pass2) ? REP_OK : REP_NE;
+ }
+*/
+ $('#pwqinfo').val(message);
+
+ var progress=$('#pwqbar');
+ progress.width(nScore + '%');
+ progress.attr('aria-valuenow', nScore);
+ if (nScore >= 60)
+ progress.removeClass('bg-danger bg-warning').addClass('bg-success');
+ else if (nScore >= 40)
+ progress.removeClass('bg-danger bg-success').addClass('bg-warning');
+ else
+ progress.removeClass('bg-warning bg-success').addClass('bg-danger');
+
+ if (nScore > 60) {
+ $('#btn_change').prop('disabled', pass !== pass2);
+ } else {
+ $('#btn_change').prop('disabled', 1);
+ }
+/*
+ if (nScore >= 60) {
+ checkTimer=setTimeout(function() {
+ $.post('checkpass.php', 'pass='+pass, function(ret) {
+ if (ret !== 'PWNED') {
+ $('#btn_change').prop('disabled', pass !== pass2);
+ return;
+ }
+ $('#pwqinfo').val(PWNED);
+ progress.removeClass().addClass('low');
+ progress.val(3);
+ });
+ }, 300);
+ }
+*/
+ }
</script>
\ No newline at end of file