Add pwned validation for passwords
diff --git a/templates/bottom.htm b/templates/bottom.htm
index 90e40b5..2a5f068 100644
--- a/templates/bottom.htm
+++ b/templates/bottom.htm
@@ -1,6 +1,6 @@
<!-- Optional JavaScript -->
<!-- jQuery first, then Popper.js, then Bootstrap JS -->
- <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.3/jquery.min.js" integrity="sha512-STof4xm1wgkfm7heWqFJVn58Hm3EtS31XFaagaa8VMReCXAkQnJZ+jEy8PCC/iT18dFy95WcExNHFTqLyp72eQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
diff --git a/templates/header.htm b/templates/header.htm
index 8c8411f..256613e 100644
--- a/templates/header.htm
+++ b/templates/header.htm
@@ -9,9 +9,12 @@
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<link href="//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap-glyphicons.css" rel="stylesheet">
<link rel="stylesheet" href="<?php echo $BASE_URL?>/static/main.css" >
- <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.3/jquery.min.js" integrity="sha512-STof4xm1wgkfm7heWqFJVn58Hm3EtS31XFaagaa8VMReCXAkQnJZ+jEy8PCC/iT18dFy95WcExNHFTqLyp72eQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/core.min.js" integrity="sha512-t8vdA86yKUE154D1VlNn78JbDkjv3HxdK/0MJDMBUXUjshuzRgET0ERp/0MAgYS+8YD9YmFwnz6+FWLz1gRZaw==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/enc-hex.min.js" integrity="sha512-jDU0YCduSP8z0cvjfPFm7/zN/viOcmNWlq0GUIcjVhuv4WoKcMppghamg4aeuBtJaA0wjtYfxwQjPpVuYGEsBA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/sha1.min.js" integrity="sha512-NHw1e1pc4RtmcynK88fHt8lpuetTUC0frnLBH6OrjmKGNnwY4nAnNBMjez4DRr9G1b+NtufOXLsF+apmkRCEIw==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="<?php echo $BASE_URL?>/static/main.js"></script>
<style>
diff --git a/templates/register.htm b/templates/register.htm
index 4f116d2..624a0cf 100644
--- a/templates/register.htm
+++ b/templates/register.htm
@@ -58,17 +58,18 @@
</div>
<!-- Password input -->
- <div class="form-outline mb-3">
+ <div id="password-div" class="form-outline mb-3">
<label class="form-label font-weight-bold" for="pw1">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" type="password" id="pw1"
- class="form-control <?php if(isset($error) && $error && !isset($_POST['password'])){echo 'border-danger';}?>"
+ <input required
+ title="Combination of upper and lowercase letters, numbers, punctuation, and special symbols" name="password" type="password" id="pw1"
+ class="form-control"
placeholder="********" oninput="check_password_match()"
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>
+ <input class="form-control" type="text" name="pwqinfo" id="pwqinfo" readonly>
</div>
<!--
<div class="form-group">
@@ -80,11 +81,11 @@
</div>
</div>
-->
- <!-- Password input -->
+ <!-- Password confirmation input -->
<div id="pwconfirm" 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"
+ <input required
+ name="password_confirm" type="password" id="pw2"
class="form-control <?php if(isset($error) && $error && !isset($_POST['password_confirm'])){echo 'border-danger';}?>"
placeholder="********" oninput="check_password_match()" />
<div class="invalid-feedback">
@@ -147,260 +148,3 @@
</form>
</div>
-
-<script>
- // Example starter JavaScript for disabling form submissions if there are invalid fields
- (function () {
- 'use strict';
- window.addEventListener('load', function () {
- // Fetch all the forms we want to apply custom Bootstrap validation styles to
- var forms = document.getElementsByClassName('needs-validation');
- // Loop over them and prevent submission
- var validation = Array.prototype.filter.call(forms, function (form) {
- form.addEventListener('submit', function (event) {
- if (form.checkValidity() === false) {
- event.preventDefault();
- event.stopPropagation();
- }
- form.classList.add('was-validated');
- }, false);
- });
- }, false);
- })();
-
- function check_password_match() {
- pass = $("#pw1").val();
- pass2 = $("#pw2").val();
-
- if (pass2.length > 0) {
- $("#pwconfirm")[0].classList.add('was-validated')
- if (pass != pass2) {
- $("#pw2")[0].setCustomValidity("Passwords do not match");
- } else {
- $("#pw2")[0].setCustomValidity(""); // is valid
- }
- } else {
- $("#pwconfirm")[0].classList.remove('was-validated')
- }
- passUpdated();
- }
-
- 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 >= 10)
- 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