Sunday 17 June 2018

Web Tutorial: AngularJS Password Strength Validator (Part 1/2)

The strength of a password often depends on many factors. Most commonly, the length and composition of a password is what makes it strong or weak. Basically, the harder it is to guess your password, the stronger it is.

Whenever you're asked to change your password by a system, quite often the password has to conform to certain rules. It can't be too short, too predictable, or entirely alphabetical. Some may even insist that it must be a mix of uppercase and lowercase characters.

We're going to be creating this functionality, using AngularJS along with some CSS.

Is it really necessary to use AngularJS?

Well, no. Just that the templating system is pretty useful and saves me some labor. Use what you like!

Also...

This is a two-part tutorial and the second part of this tutorial will involve some AJAX. Thus, a server is required. But the second part is entirely optional, and if you just want to stop at the first (server-less) part, that's entirely OK.

We first create the body in a file, index.html. Remember that for AngularJS, we need to define an Application Scope, and a Controller Scope. They are passvalApp and passvalCtrl respectively. Also, the link to the AngularJS JavaScript file has been included.

index.html
<!DOCTYPE html>
<html>
    <head>
        <title>Password Validator</title>

        <style>

        </style>

        <script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
    </head>

        <body ng-app="passvalApp">
        <div ng-controller="passvalCtrl">

        </div>
    </body>
</html>


Here, we'll insert one div, and within that div, nest two divs and put a template field in each. One template field will be strengthCode and the other strengthMessage. We will also have a label and text box, and the text box's id will be txtPassword.

index.html
<!DOCTYPE html>
<html>
    <head>
        <title>Password Validator</title>

        <style>

        </style>

        <script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
    </head>

        <body ng-app="passvalApp">
        <div ng-controller="passvalCtrl">
            <label for="txtPassword">Enter your password here: </label>
            <input type="text" id="txtPassword">
            <br />
            <div>
                <div>
                    {{ strengthCode }}
                </div>
                <div>
                    {{ strengthMessage }}
                </div>
            </div>
        </div>
    </body>
</html>


Style the divs.

index.html
            <div class="container">
                <div class="txtStrength">
                    {{ strengthCode }}
                </div>
                <div class="txtMessage">
                    {{ strengthMessage }}
                </div>
            </div>


This is pretty much cosmetic. Just prettying it up a bit.

index.html
        <style>
            .container
            {
                width: 200em;
            }

            .txtStrength
            {
                font-weight: bold;
                font-size: 3em;
                width: 50%;
                float: left;
            }

            .txtMessage
            {
                font-size: 1em;
                width: 50%;
                float: left;
                margin-left: 2em;
                white-space: pre-wrap;
            }
        </style>


So far, this is what we've got.


Now add this. We'll be working on the JavaScript next, which is the main.js file in the js directory. You can choose to embed the JavaScript in the index.html file, but it's a lot neater this way.

index.html
        <script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
        <script src="js/main.js"></script>


This is where we start defining events and rules. First, of course, is the Application Scope.

js/main.js
var app = angular.module("passvalApp", []);

app.controller("passvalCtrl",
function($scope)
{

}
);


Here, we define the scope function processPassword() and the scope variables strengthCode, strengthMessage and enteredPassword.
js/main.js
var app = angular.module("passvalApp", []);

app.controller("passvalCtrl",
function($scope)
{
    $scope.processPassword=
    function()
    {

    };

    $scope.strengthCode = "";
    $scope.strengthMessage = "";
    $scope.enteredPassword = "";
}
);


Back to the index.html file, bind in the scope variables to the appropriate DOM elements. We run processPassword() whenever we change the value in the txtPassword text box, and the value of the text box is enteredPassword.

index.html
        <body ng-app="passvalApp">
        <div ng-controller="passvalCtrl">
            <label for="txtPassword">Enter your password here: </label>
            <input type="text" id="txtPassword" ng-change="processPassword()" ng-model="enteredPassword">
            <br />
            <div class="container">
                <div class="txtStrength">
                    {{ strengthCode }}
                </div>
                <div class="txtMessage">
                    {{ strengthMessage }}
                </div>
            </div>
        </div>
    </body>


Now, let's process the password! In the main.js file, add this to the processPassword() function. This basically says that if enteredPassword is empty, don't bother.

js/main.js
    $scope.processPassword=
    function()
    {
        if ($scope.enteredPassword.length == 0) return;
    };


If enteredPassword is less than 8 characters, set strengthCode to "weak", set strengthMessage, then stop processing.
js/main.js
    $scope.processPassword=
    function()
    {
        if ($scope.enteredPassword.length == 0) return;

        if ($scope.enteredPassword.length < 8)
        {
            $scope.strengthCode = "weak";
            $scope.strengthMessage = "Password is too short. 8 characters or above recommended.";
            return;
        }
    };


Try it. Type in something less than 8 characters. Does the message appear?


OK, let's get really serious. Declare a variable, pts and set it to a default of 1. Set strengthMessage to an empty string. From here on, we are handling cases in which enteredPassword is longer than 8 characters, and evaluating how strong the password is based on the composition of the password.

js/main.js
    $scope.processPassword=
    function()
    {
        if ($scope.enteredPassword.length == 0) return;

        if ($scope.enteredPassword.length < 8)
        {
            $scope.strengthCode = "weak";
            $scope.strengthMessage = "Password is too short. 8 characters or above recommended.";
            return;
        }

        var pts = 1;
        $scope.strengthMessage = "";
    };


Now, let's use a regular expression to determine if the password has any special characters. If there are, increment pts. If not, set strengthMessage.

js/main.js
    $scope.processPassword=
    function()
    {
        if ($scope.enteredPassword.length == 0) return;

        if ($scope.enteredPassword.length < 8)
        {
            $scope.strengthCode = "weak";
            $scope.strengthMessage = "Password is too short. 8 characters or above recommended.";
            return;
        }

        var pts = 1;
        $scope.strengthMessage = "";

        if (/[~`!#$%\^&@*+=\-\[\]\\';,/{}|\\":<>\?]/g.test($scope.enteredPassword))
        {
            pts ++;
        }
        else
        {
            $scope.strengthMessage += "Try using special characters in your password.\n";
        }
    };


Repeat the process, but this time use a regular expression for checking if there are any uppercase letters in enteredPassword.

js/main.js
    $scope.processPassword=
    function()
    {
        if ($scope.enteredPassword.length == 0) return;

        if ($scope.enteredPassword.length < 8)
        {
            $scope.strengthCode = "weak";
            $scope.strengthMessage = "Password is too short. 8 characters or above recommended.";
            return;
        }

        var pts = 1;
        $scope.strengthMessage = "";

        if (/[~`!#$%\^&@*+=\-\[\]\\';,/{}|\\":<>\?]/g.test($scope.enteredPassword))
        {
            pts ++;
        }
        else
        {
            $scope.strengthMessage += "Try using special characters in your password.\n";
        }

        if (/[A-Z]/g.test($scope.enteredPassword))
        {
            pts ++;
        }
        else
        {
            $scope.strengthMessage += "Try using a mix of uppercase letter and lowercase letters.\n";
        }
    };


You know the drill by now. This time, we check for numbers.

js/main.js
    $scope.processPassword=
    function()
    {
        if ($scope.enteredPassword.length == 0) return;

        if ($scope.enteredPassword.length < 8)
        {
            $scope.strengthCode = "weak";
            $scope.strengthMessage = "Password is too short. 8 characters or above recommended.";
            return;
        }

        var pts = 1;
        $scope.strengthMessage = "";

        if (/[~`!#$%\^&@*+=\-\[\]\\';,/{}|\\":<>\?]/g.test($scope.enteredPassword))
        {
            pts ++;
        }
        else
        {
            $scope.strengthMessage += "Try using special characters in your password.\n";
        }

        if (/[A-Z]/g.test($scope.enteredPassword))
        {
            pts ++;
        }
        else
        {
            $scope.strengthMessage += "Try using a mix of uppercase letter and lowercase letters.\n";
        }

        if (/[0-9]/g.test($scope.enteredPassword))
        {
            pts ++;
        }
        else
        {
            $scope.strengthMessage += "Try including numbers in your password.\n";
        }
    };


Now, obtain strengthCode by running the getCode() function, and pass pts in as an argument.

js/main.js
    $scope.processPassword=
    function()
    {
        if ($scope.enteredPassword.length == 0) return;

        if ($scope.enteredPassword.length < 8)
        {
            $scope.strengthCode = "weak";
            $scope.strengthMessage = "Password is too short. 8 characters or above recommended.";
            return;
        }

        var pts = 1;
        $scope.strengthMessage = "";

        if (/[~`!#$%\^&@*+=\-\[\]\\';,/{}|\\":<>\?]/g.test($scope.enteredPassword))
        {
            pts ++;
        }
        else
        {
            $scope.strengthMessage += "Try using special characters in your password.\n";
        }

        if (/[A-Z]/g.test($scope.enteredPassword))
        {
            pts ++;
        }
        else
        {
            $scope.strengthMessage += "Try using a mix of uppercase letter and lowercase letters.\n";
        }

        if (/[0-9]/g.test($scope.enteredPassword))
        {
            pts ++;
        }
        else
        {
            $scope.strengthMessage += "Try including numbers in your password.\n";
        }

        $scope.strengthCode = getCode(pts);
        return;
    };


getCode() is not a scope function because we're not attempting to access it from the front-end. So here we have a series of If statements, returning codes that correspond to the value of pts.

js/main.js
    function getCode(pts)
    {
        if (pts <= 0) return "weak";   
        if (pts == 1) return "moderate";   
        if (pts == 2) return "strong";   
        if (pts >= 3) return "excellent";
    }

    $scope.processPassword=
    function()
    {
        if ($scope.enteredPassword.length == 0) return;

        if ($scope.enteredPassword.length < 8)
        {
            $scope.strengthCode = "weak";
            $scope.strengthMessage = "Password is too short. 8 characters or above recommended.";
            return;
        }

        var pts = 1;
        $scope.strengthMessage = "";

        if (/[~`!#$%\^&@*+=\-\[\]\\';,/{}|\\":<>\?]/g.test($scope.enteredPassword))
        {
            pts ++;
        }
        else
        {
            $scope.strengthMessage += "Try using special characters in your password.\n";
        }

        if (/[A-Z]/g.test($scope.enteredPassword))
        {
            pts ++;
        }
        else
        {
            $scope.strengthMessage += "Try using a mix of uppercase letter and lowercase letters.\n";
        }

        if (/[0-9]/g.test($scope.enteredPassword))
        {
            pts ++;
        }
        else
        {
            $scope.strengthMessage += "Try including numbers in your password.\n";
        }

        $scope.strengthCode = getCode(pts);
        return;
    };


Have fun with this! Type in an eight-letter word. What's the strength code?


Type in something alphanumeric.


What if you enter in a random uppercase letter?


And if you throw in a special character?


One more thing...

Let's spruce it up a bit by changing the colors to fit the strength code. Add this to the CSS.

index.html
            .color_weak { color: #440000; }
            .color_moderate { color: #444400; }
            .color_strong { color: #FFFF00; }
            .color_excellent { color: #44FF00; }

            .container
            {
                width: 200em;
            }


Then add this to the HTML.

index.html
                <div class="txtStrength color_{{ strengthCode }}">
                    {{ strengthCode }}
                </div>


Try this again!








Next

These are merely some of the different ways one can gauge the strength of a password. For the most part, this is enough. But if you want something more advanced, the next part of this tutorial will require a server and internet connection.

No comments:

Post a Comment