Jump to content

Frontend validation regex for username and password?


bernhard
 Share

Recommended Posts

Does anybody (maybe @Juergen) know if there is a regex somewhere that I can use to validate user input in a frontend registration form?

Of course I will sanitize/validate input on the server as well, but it would save some unnecessary form submissions and server requests 🙂 

Thx!

Link to comment
Share on other sites

Hello @bernhard

I have created these validators for my FrontendForms module, maybe this can help you to create your own validations.

Check username syntax

This is the regex that I use:

$regex = '/[a-z\d\-_.@]$/';

It contains all the allowed characters. I guess all allowed characters are listed somewhere inside a file of PW or in the API docs. I have found them somewhere, but I cannot remember where 🤪

You will find the code of my validation here.

Check password syntax

The password is a little bit more elaborate, because you can set the characters that can be used by yourself.

This is the code, that I use:

$value = $_POST['yourpasswordfield']; // the post value of your password field on the frontend

// get the password field module
$passwordModule = $this->wire('modules')->get('InputfieldPassword'); // get the password field module

// get the password field by the name of the field inside the user template, usually "pass"
$passwordField = $this->wire('fields')->get('nameofyourpasswordfield');

// get the default requirements of the password module as stored inside the DB
$requirements = $passwordModule->requirements;  

// password conditions can be overwritten on per field base, so check before if they are overwritten. Otherwise take the default from the module
if (!$passwordField->requirements) { 
    // if no requirements are stored in the database, take the default data from the inputfield default configuration
    $requirements = $passwordModule->requirements;
} else {
    $requirements = $passwordField->requirements;
}

// set the requirements for the validation on the next line, so you can be sure that you take the correct requirements 
$passwordModule->set('requirements', $requirements); 

// Now check the password if the syntax fits the requirements
return $passwordModule->isValidPassword($value); // returns true or false

You will find the code of my validator here.

As you can see, I take methods from the ProcessWire password module class to validate the password.

I hope this helps you to solve your issues. Maybe you will find a better solution and I adapt my codes to your changes too.

Have a nice Sunday!!

 

  • Like 3
Link to comment
Share on other sites

Thanks @kongondo

You are right, I have overread this 🤪 - it was Sunday morning!!

Maybe the regex for the username could be used with Javascript too. The validation of the password is not so easy in this case but you can use the password requirements as posted above, put them inside a Javascript variable and check them against multiple if conditions. This is what comes into my mind.

Something like this:

if(contains letters){
	if(contains number){
		if(contains symbols {
			....
		} else {
			return false;
	} else {
		return false;
} else {
	return false;
}

 

  • Like 3
Link to comment
Share on other sites

Ok, thank you both 🙂 

Here are my learnings:

Then I took a breath and thought about it as I somewhere read that forcing the user to use numbers might not be the best/most secure option and using a random string instead could be better in terms of UX and also security. Also when creating users in PW via the API the password requirements do not apply - so I can choose whatever syntax/requirements I wanted.

So I created created an array of 100 random german words with the help of AI and then played around with that a little. This is the result:

https://github.com/baumrock/PassPhraseJS

demo.png

I've also built an interactive calculator to see how many random passwords are possible with your chosen settings:

https://baumrock.github.io/PassPhraseJS/example.html

TaIE3ix.png

What do you guys think? Any suggestions for improvements? I'm already working on making the separators configurable so that will increase the number of possible passwords tremendously.

  • Like 4
Link to comment
Share on other sites

I think this is already quite impressive! I've updated the tool to support custom separators. This leads to an enormous number of possible combinations even if you only have 4 words in the dictionary, namely over 2 million!

abCoOYz.png

  • Like 2
Link to comment
Share on other sites

Very good work @bernhard!!!

I think the number of possibilities is enough!

13 hours ago, bernhard said:

Also when creating users in PW via the API the password requirements do not apply - so I can choose whatever syntax/requirements I wanted.

I have never thought about this, but it is logical, because no validation takes place. I have always used the same requirements on the frontend as in backend for consistency.

What comes into my mind by using pre-defined passwords is, that I do not have experience about the acceptance for choosing a given password instead of your own. Personally I prefer creating my own password.

From the point of security I guess it is a very good technique, because a lot of people tend to use the same password in different accounts and these randomly created passwords are passwords that probably no human would think of.

Do you think of to create a regex which only allows the letters which are used for the four words in combination with the separators or what is your plan to validate the password?

 

 

Link to comment
Share on other sites

Inspired by this topic, I have created my own solution: Creating dynamically a regex using positive look aheads.

On my FrontendForms module I offer HTML5 browser validation beside the server side validation. Til now, it was not possible to validate the requirements of a password field by the browser, because I have not implemented a regex solution to this.

Now I have created a method (function) to create a regex dynamically depending on the settings of the password requirements in the backend.

The password field offers following options for the requirements:

0 => 'letter' // letter
1 => 'lower'  // lowercase letter
2 => 'upper'   // uppercase letter
3 => 'digit' // number
4 => 'other' // punctuation, symbol
4 => 'none'

Starting form this array I have written the following method, which outputs a regex that can be used with the HTML5 pattern attribute to validate the password syntax.

/**
     * Method to generate a regex for the password validation depending on the settings of the password field
     * @return string|null - returns the regex for usage in HTML5 validation attribute or null if requirements are set
     * to "none" in the backend
     * @throws WireException
     * @throws WirePermissionException
     */
    public function createPasswordRegex(): string|null
    {
        // get the password field module
        $passwordModule = $this->wire('modules')->get('InputfieldPassword'); // get the password field module
        // get the password field by the name of the field inside the user template, usually "pass"
        $passwordField = $this->wire('fields')->get('pass');
        // get the default requirements of the password module as stored inside the DB
        $requirements = $passwordModule->requirements;
        // password conditions can be overwritten on per field base, so check before if they are overwritten. Otherwise take the default from the module
        if (!$passwordField->requirements) {
            // if no requirements are stored in the database, take the default data from the inputfield default configuration
            $requirements = $passwordModule->requirements;
        } else {
            $requirements = $passwordField->requirements;
        }
        if(!in_array('none', $requirements)){

            // create array of positive look ahead for all options of the password as defined in the backend
            $regex_requirements = [
                'letter' => '(?=.*[A-Za-z])', // at least 1 letter (upper and lowercase)
                'lower' => '(?=.*[a-z])', // at least 1 lower case letter
                'upper' => '(?=.*[A-Z])', // at least 1 upper case letter
                'digit' => '(?=.*\d)', // at least 1 number
                'other' => '(?=.*\W)' // at least 1 non-word character
            ];

            $regex_parameters = [];
            foreach($regex_requirements as $key => $look_ahead){
                if(in_array($key, $requirements)){
                    $regex_parameters[$key] = $look_ahead;
                }
            }

            // get the default min length value as set in the input field if present
            if($passwordField->minlength){
                $length = (string)$passwordField->minlength;
            } else {
                // get the default value from the module
                $length = (string)$passwordModule->minlength;
            }

            // Concatenate all look ahead to working regex string and return it
            return implode('',$regex_parameters).'.{'.$length.',}$';
        }
        return null;
    }

 

Now I will show you some examples with different settings - please take a closer look at the pattern attribute.

Just to mention: the min length of the password (in this case 5), will also be taken from the password settings.

Example 1: only letters

<input id="validators-required" name="validators-required" type="text" class="input" required="" pattern="(?=.*[A-Za-z]).{5,}$">

Example 2: letters with at least 1 uppercase letter

<input id="validators-required" name="validators-required" type="text" class="input" required="" pattern="(?=.*[A-Za-z])(?=.*[A-Z]).{5,}$">

Example 3: letter, digits and symbols

<input id="validators-required" name="validators-required" type="text" class="input" required="" pattern="(?=.*[A-Za-z])(?=.*\d)(?=.*\W).{5,}$">

Example 4: upper and lower case letters

<input id="validators-required" name="validators-required" type="text" class="input" required="" pattern="(?=.*[a-z])(?=.*[A-Z]).{5,}$">

As you can see the pattern differs depending on the settings of the password field in the backend.

Of course, this method needs a little bit more testing, but it works on every case that I have tested. The only parameter, that will not be taken into account is the complexity factor, but this could be solved with another Javascript function if necessary.

Maybe this method helps or inspires others solving this issue.

BTW: After testing, this method will be a added to the next version of my FrontendForms module😀

Link to comment
Share on other sites

3 hours ago, Juergen said:

What comes into my mind by using pre-defined passwords is, that I do not have experience about the acceptance for choosing a given password instead of your own. Personally I prefer creating my own password.

You see in the screenshot that it's a regular form inputfield, so you can enter whatever password you want 😉 I just wanted to have a nice little helper to choose from a random generated one. First thought was to just create a random string with a random length, but it's a product targeted for non-tech people and should be as simple to use as possible, so a password like 237u89gdisjv783z9rfre90fuds is for sure not a good option in terms of UX 🙂 But if anyone wants to use such a password (because he/she is using a password manager for example) then that's no problem.

3 hours ago, Juergen said:

Do you think of to create a regex which only allows the letters which are used for the four words in combination with the separators or what is your plan to validate the password?

No, I don't force the user to use this syntax, so he/she can use whatever he/she wants. I only add a minimum length rule to the password (using RockForms, so all rules apply both on the frontend and on the backend!):

    $this->addPassword('pass', 'Passwort')
      ->addRule(
        $this::MIN_LENGTH,
        'Das Passwort muss mindestens %d Zeichen lang sein.',
        $dev ? 1 : 10
      )
      ->setRequired('Bitte gib dein gewünschtes Passwort ein.')
      ->setHtmlAttribute('autocomplete', 'new-password');

And an equal rule to the password confirmation field:

    $this->addPassword('pass2', 'Passwort bestätigen')
      ->addRule($this::EQUAL, 'Die Passwörter stimmen nicht überein.', $this['pass'])
      ->setRequired('Bitte bestätige dein Passwort um Tippfehler zu vermeiden.');

And then the markup for PassPhraseJS:

    $this->addMarkup("<div class='tm-pass-suggest'>Zufallspasswort verwenden: "
      . '<a href=# passphrasejs-renew="#pass">-- svg reload icon --</a>'
      . '<a href=# passphrasejs-copyto="input[type=password]">'
      . '<span id="pass" passphrasejs></span>'
      . '--svg copy icon--'
      . "</a>"
      . "</div>");

I've done some research on how to sanitize the password on the backend, but it looks like there is no method for it. I've tried setting "foo bar" as password via the API and that works and the user can log in. But I will disallow spaces in my passwords for sure.

So I think it's enough to use $sanitizer->text() and then additionally check if the password has a space in it. But I'm not sure yet, so any input is welcome 🙂 

Link to comment
Share on other sites

Ok, I have misunderstood the field a little bit 😉. I have thought you only want to allow passwords containing the pre-defined words and symbols, so it will be easier for frontend validation to write the regex for.

I find the idea great to offer password examples, that can be used or not. Maybe I am thinking of implementing such a feature to my module too.

9 minutes ago, bernhard said:

So I think it's enough to use $sanitizer->text() and then additionally check if the password has a space in it. But I'm not sure yet, so any input is welcome

Yes, thats exactly what I have used too. For the username saniziation I have used "pageName" sanitizer instead.

Link to comment
Share on other sites

Just now, Juergen said:

Maybe I am thinking of implementing such a feature to my module too.

Have you had a look at https://github.com/baumrock/PassPhraseJS ? You can simply include the js file and add 3 html attributes and you are done 🙂 

5 minutes ago, Juergen said:

Ok, I have misunderstood the field a little bit 😉. I have thought you only want to allow passwords containing the pre-defined words and symbols, so it will be easier for frontend validation to write the regex for.

Yeah I've had such a misconception in my head initially so I might have communicated that confusingly.

  • Like 1
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...