Luv Tomar
Luv Tomar

Reputation: 127

How to do a strong validation of password entry and validate confirm password entry

I have some HTML and Javascript that is asks a user to enter a password with the following rules:

  1. At least 8 characters long
  2. At least 1 capital letter
  3. At least 1 lowercase letter
  4. At least 1 special character
  5. At least 1 numeric character

This is followed by a password confirmation entry. There are div blocks below the password and password confirmation inputs that contain error messages enclosed in p tags, that are supposed to becomes visible when any of the errors occur. It doesn't seem to be working.

I am also using C# Razor code in this CSHTML file, so I'm required to use "@@" instead of @ within strings. If I'm wrong about that though, please let me know.

Password: (Must contain at least 1 lowercase alphabetical character, 1 uppercase alphabetical character, 1 special character, 1 numerica character and at least 8 characters long)

        <input type="password" name="password_admin1_create" oninput="return validate_password()"><br><br>
        <script>
            var password = document.getElementsByName("password_admin1_create")[0];
            function validatePassword(val) {
                var strongRegex = /^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[!@@#\$%\^&\*])(?=.{8,})/;
                console.log(re.test(val))
                return strongRegex.test(val);
            }

            function validate_password() {
                if (validatePassword(password.value)) {
                    document.getElementById("password_result_invalid").style.visibility = "hidden";
                    document.getElementById("password_result_invalid").style.height = "0";
                } else {
                    document.getElementById("password_result_invalid").style.visibility = "visible";
                    document.getElementById("password_result_invalid").style.height = "initial";
                }
            }
        </script>
        <div id="password_result_invalid" class="error_verify">
            <p style="color:red">Invalid password format.</p>
        </div>

        <p>Please confirm the password:</p>
        <input type="password" name="password_admin1_create_confirm" oninput="return validate_password_confirm()"><br><br>
        <script>
            var password_confirm = document.getElementsByName("password_admin1_create_confirm")[0].value;
            var password = document.getElementsByName("password_admin1_create")[0].value;

            function validate_password_confirm() {
                if (password_confirm == password) {
                    document.getElementById("password_confirmation_invalid").style.visibility = "hidden";
                    document.getElementById("password_confirmation_invalid").style.height = "0";
                } else {
                    document.getElementById("password_confirmation_invalid").style.visibility = "visible";
                    document.getElementById("password_confirmation_invalid").style.height = "initial";
                }
            }
        </script>
        <div id="password_confirmation_invalid" class="error_verify">
            <p style="color:red">Passwords do not match.</p>
        </div>

Upvotes: 1

Views: 8604

Answers (5)

The fourth bird
The fourth bird

Reputation: 163477

The reason you keep seeing Invalid password format. is that you first create a variable:

var password = document.getElementsByName("password_admin1_create")[0];

Then later on, you create it again, setting it directly to the value (which is empty)

var password = document.getElementsByName("password_admin1_create")[0].value;

So the variable password will always stay empty and will never pass the regex check.

Note

Also this variable password_confirm is directly set to empty and in console.log(re.test(val)) there is no re

About the pattern

You could make some minor adjustments to your pattern:

  • The lookahead (?=.{8,}) Asserts that what is on the right are 8+ times any char, which will also match a space.
  • You could update that to use a character class to match only the characters that you would allow to match and use an anchor $ to assert the end of the string.
  • The pattern could make use contrast to assert for example not a digit, and then a digit.

For example:

^(?=[^a-z]*[a-z])(?=[^A-Z]*[A-Z])(?=[^0-9]*[0-9])(?=[^!@#$%^&*]*[!@#$%^&*])(?=[!@#$%^&*A-Za-z0-9]{8,}$)

Regex demo

Your updated code might look like:

<input type="password" name="password_admin1_create" oninput="validate_password()"><br><br>
<script>

    function validatePassword(password) {
        return /^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[!@#$%^&*])(?=.{8,})/.test(password);
    }

    var password = document.getElementsByName("password_admin1_create")[0];

    function validate_password() {

        if (validatePassword(password.value)) {
            document.getElementById("password_result_invalid").style.visibility = "hidden";
            document.getElementById("password_result_invalid").style.height = "0";
        } else {
            document.getElementById("password_result_invalid").style.visibility = "visible";
            document.getElementById("password_result_invalid").style.height = "initial";
        }
    }
</script>
<div id="password_result_invalid" class="error_verify">
    <p style="color:red">Invalid password format.</p>
</div>

<p>Please confirm the password:</p>
<input type="password" name="password_admin1_create_confirm" oninput="return validate_password_confirm()"><br><br>
<script>
    var password_confirm = document.getElementsByName("password_admin1_create_confirm")[0];
    var password = document.getElementsByName("password_admin1_create")[0];

    function validate_password_confirm() {
        if (password.value === password_confirm.value) {
            document.getElementById("password_confirmation_invalid").style.visibility = "hidden";
            document.getElementById("password_confirmation_invalid").style.height = "0";
        } else {
            document.getElementById("password_confirmation_invalid").style.visibility = "visible";
            document.getElementById("password_confirmation_invalid").style.height = "initial";
        }
    }
</script>
<div id="password_confirmation_invalid" class="error_verify">
    <p style="color:red">Passwords do not match.</p>
</div>

Upvotes: 0

Emma
Emma

Reputation: 27743

My guess is that this expression might work:

^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[?!%@#$%^&*])[A-Za-z0-9?!%@#$%^&*]{8,}$

which we would add start and end anchors, and remove some of those escapings.

The expression is explained on the top right panel of regex101.com, if you wish to explore/simplify/modify it, and in this link, you can watch how it would match against some sample inputs, if you like.

const regex = /^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[?!%@#$%^&*])[A-Za-z0-9?!%@#$%^&*]{8,}$/gm;
const str = `Az0^AAAA
Az0^AAA
Az0^AAAAA`;
let m;

while ((m = regex.exec(str)) !== null) {
    // This is necessary to avoid infinite loops with zero-width matches
    if (m.index === regex.lastIndex) {
        regex.lastIndex++;
    }
    
    // The result can be accessed through the `m`-variable.
    m.forEach((match, groupIndex) => {
        console.log(`Found match, group ${groupIndex}: ${match}`);
    });
}

Upvotes: 0

Shlomo Sfez
Shlomo Sfez

Reputation: 1

Use pattern Regex:

  1. At least 8 characters long
  2. At least 1 capital letter
  3. At least 1 lowercase letter
  4. At least 1 special character
  5. At least 1 numeric character

"^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$"

Usage:

<input type="password" name="pw" pattern="^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$" title="Strong Password">

Upvotes: 0

Wimanicesir
Wimanicesir

Reputation: 5122

I made this a few weeks ago. Just posting it to see if it can help you (I know it's not the most clean one)

Html

All requirements are shown above and are initially red.

<div class="requirements">
    <ul>
        <li id="length" class="red">Include at least 8 digits and three special characters</li>
        <li id="uppercase" class="red">Include at least one upper case characters (A-Z)</li>
        <li id="lowercase" class="red">Include at least one lower case character (a-z)</li>
        <li id="numbers" class="red">Include a number (0-9)</li>
        <li id="symbols" class="red">Include a symbol (!, #, $, etc.)</li>
    </ul>
</div>

JS

Add key up event handler to input fields on current page:

var inputfields = document.forms["changePasswordForm"].getElementsByTagName("input");
for (var i = 0; i < inputfields.length; i++){
    inputfields[i].addEventListener('keyup', function(e){
        // On every key up, check the password
        var password = document.getElementById('sf_guard_user_password');
        validatePassword(password.value);
    })
}

Then at last my (ugly) validate password function

function validatePassword(password) {

                // Minimum 8 characters
                if (password.length > 7) {
                    document.getElementById('length').classList.remove('red');
                    document.getElementById('length').classList.add('green');
                } else {
                    document.getElementById('length').classList.remove('green');
                    document.getElementById('length').classList.add('red');
                }

                // At least one uppercase
                if (/[A-Z]/.test(password)) {
                    document.getElementById('uppercase').classList.remove('red');
                    document.getElementById('uppercase').classList.add('green');
                } else {
                    document.getElementById('uppercase').classList.remove('green');
                    document.getElementById('uppercase').classList.add('red');
                }

                // At least one lowercase
                if (/[a-z]/.test(password)) {
                    document.getElementById('lowercase').classList.remove('red');
                    document.getElementById('lowercase').classList.add('green');
                } else {
                    document.getElementById('lowercase').classList.remove('green');
                    document.getElementById('lowercase').classList.add('red');
                }

                // At least one number
                if (/[0-9]/.test(password)) {
                    document.getElementById('numbers').classList.remove('red');
                    document.getElementById('numbers').classList.add('green');
                } else {
                    document.getElementById('numbers').classList.remove('green');
                    document.getElementById('numbers').classList.add('red');
                }

                // At least one symbol
                if (/[$@$!%*#?&]/.test(password)) {
                    document.getElementById('symbols').classList.remove('red');
                    document.getElementById('symbols').classList.add('green');
                } else {
                    document.getElementById('symbols').classList.remove('green');
                    document.getElementById('symbols').classList.add('red');
                }

            }

At last I'm checking on submit if all requirements are met:

document.getElementById('changePasswordForm').addEventListener('submit',  function(e){
    e.preventDefault();
    // Once again ugly because length is fixed
    if (document.getElementsByClassName('green').length > 4) {
        document.getElementById('changePasswordForm').submit();
    }
})

I don't know if this is going to help you. But I tried :)

Upvotes: 1

Ezi CS
Ezi CS

Reputation: 24

You should assign the "pattern" attribute to whatever regex expression fits your password requirements. For example:

<  input type="password" id="psw" name="psw" 
pattern="(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,}" 
title="Must contain at least one number and one uppercase and lowercase letter, and at least 8 or more characters" 
required >

This link might also help: https://www.w3schools.com/howto/howto_js_password_validation.asp

Upvotes: 0

Related Questions