Buy Now
Sign in

FAQ search

How can I add a password strength check in CFv5?

Details
Published: Friday, 06 February 2015 16:31

Users will often use  'easy' to remember passwords that may not be very secure. This FAQ shows you how to add a strength 'meter' to a Password input in CFv5.


This FAQ uses jQuery and is written for CFv5 - see here for a CFv4 version.

We will use the jQuery PWStrength plug-in published on GitHub by Alejandro Blanco. You can download the package from this page where you will also find the documentation.

This plug-in may require some jQuery features that are not in the standard Joomla! Framework libraries. If it fails to work as described here please install the jQueryEasy plug-in to enable the use of a fuller version of jQuery.

Unzip the package and find the latest distribution in the dist folder. You can use either the full or the minimised version. Rename a copy of the file to pwstrength.js and upload it to your site in the /components/com_chronoforms5/extras/pwstrength folder.

In your form Designer tab add a Password Box element to your form and give it a name and id. We'll use password but you may want to use something less obvious.

In the Setup tab add a Load JavaScript action to the On Load event, drag it up before the HTML (Render Form) action.

In the JS Code box of the action add this code to configure the plugin:

jQuery(document).ready(function(jQ) {
  jQ('#password').pwstrength({
    ui: {
      showVerdictsInsideProgressBar: true
    }
  });
});

The showVerdicts . . . option puts the 'Weak', 'Strong' message in the Progress Bar and looks better in a ChronoForm.

In the JS Files box add this code to load the plug-in file:

<?php
echo JUri::root().'components/com_chronoforms5/extras/pwstrength/pwstrength.js';
?>

Save your form and test, you should see a result like this:

By default the PWStrength plug-in uses a set of pre-defined rules to assess the strength of the password. (See the documents for ways to turn rules on or off and change the weight they have in the score.)

Adding the zxcvbn strength tester

There is also an option to use the which uses a more rigorous approach including a check against a library of common passwords. See this DropBox blog post for more information.

To add this to PWStrength you need to download the library from this GitHub page.

Unzip the download and copy the files zxcvbn-async.js and zxcvbn.js to the /components/com_chronoforms5/extras/pwstrength folder on your site (the same folder as before).

In the Load JavaScript action set the JS Files code to:

<?php
echo JUri::root().'components/com_chronoforms5/extras/pwstrength/pwstrength.js';
echo "\n";
echo JUri::root().'components/com_chronoforms5/extras/pwstrength/zxcvbn-async.js';
?>

Note that the echo "\n"; line is there to add a line-break between the two file names.

jQuery(document).ready(function(jQ) {
  jQ('#password').pwstrength({
    common: {
      zxcvbn: true,
      userInputs: ['#username'],
      zxcvbnTerms: []
    },
    ui: {
      showVerdictsInsideProgressBar: true
    }
  });
});

Where 'username' is the ID of a username input in the form - this is added to stop the User using their username as a password.

You can use the zxcvbnTerms option - which is empty here - to block terms which are specific to your site e.g. the site name.

Forcing password quality

So far the password checker just provides visual feedback to the user. It does not prevent them from using a weak password. Here are two ways to do this.

Disable the submit button

In the form Designer tab give the submit button an id - I use submit_btn.

Add a new option to the PWStrength settings which will call a new checkPass function when the password changes:

      userInputs: ['#username'],
      onKeyUp: checkPass // add this line
    },

Add the new function: 

  checkPass();

  function checkPass(event, result){
    if ( result && result.score < 40 ) {
      jQ('#submit_btn').prop('disabled', true);
    } else {
      jQ('#submit_btn').prop('disabled', false);
    }
  }

This checks the current score and disables the submit button if it is under 40 (by default this is the setting for a 'strong' password (you can change the scores in the PWStrength options).

Add a custom validation

We can add a validation to the password field to check the score. To do this we have to be able to access the score when the validation is called so we'll add it to a hidden input with the id pw_score. Add a Hidden Field element in the Designer tab of your form set the id to pw_score and the value to 0.

Open the Password element and click the Validation tab, scroll down and add validatePass in the Custom Function box. Add a validation message in the Title box e.g. 'Please use a strong password'.

In the PWStrength options add an onKeyUp option to call a setScore function which will update the hidden input with the new score:

      userInputs: ['#username'],
      onKeyUp: setScore // add this line
    },

Then add the two new functions, first setScore:

  function setScore(event, result){
    jQ('#pw_score').val(result.score);
  }
Then the validatePass function:

	
  function validatePass(){
    var score;
    score = jQ('#pw_score').val();
    score = parseInt(score);
    if ( score < 40 ) {
      return false;
    } else {
      return true;
    }
  }

Save your form and test.

Both together

Not especially recommended but you can run both of these together by calling the checkPass function in the PWStrength options and then calling the setScore function from inside the checkPass function with setScore(event, result);

Potential problems

There was a small bug in version 1.2.4 of PWStrength that requires you to add a userInputs option; also the option to add a fixed list of 'block' words e.g. your site name was not working with zxcvbn. Please make sure that you use version 1.2.5 or later.

The full code - an example

jQuery(document).ready(function(jQ) {
  // the PWStrength option settings
  jQ('#password').pwstrength({
      common: {
      zxcvbn: true,
      zxcvbnWords: ['dropbox', 'horse'],
      userInputs: ['#username'],
      onKeyUp: checkPass
    },
    ui: {
      showVerdictsInsideProgressBar: true
    }
  });

  // update the hidden input with the current score
  function setScore(event, result){
    jQ('#pw_score').val(result.score);
  }

  // enable and disable the submit button
  function checkPass(event, result){
    if ( result.score < 40 ) {
      jQ('#submit_btn').prop('disabled', true);
    } else {
      jQ('#submit_btn').prop('disabled', false);
    }
    setScore(event, result);
  }

  // the ChronoForms validation function
  function validatePass(){
    var score;
    score = jQ('#pw_score').val();
    score = parseInt(score);
    if ( score < 40 ) {
      return false;
    } else {
      return true;
    }
  }
});