Implement a Quick Captcha using JavaScript

Computers are now-a-days becoming super-powerful day by day. The information they gather and store is enormous and with that, they are able to do prediction, analysis, etc. And during this time, Artificial Intelligence is also growing wild. Think about the Google Bot calling a Hair Dresser like a human? No difference!

With all these said, why can't computers automatically fill out forms? We need a Turing Test to tell Computers and Humans apart. That's when CAPTCHA came into existence. CAPTCHA, in other words, Completely Automated Public Turing test to tell Computers and Humans Apart is a type of challenge-response test used in computing to determine whether or not the user is human.

Types of CAPTCHA

Now we have a lot of crazy types of CAPTCHA available on the market. One of my favourite is the drag and drop one by Web Design Beach, a defunct Web Development company.

WDB Fancy CAPTCHA

There's a little demo in my app server here: Demo: Fancy CAPTCHA. And leaving all these, today we'll be implementing a simple JavaScript CAPTCHA.

Implementation

Let's start by creating an array of arrays that contain a few questions and answers.

var qa = [  
  ["What is the colour of Orange?", "orange"],
  ["What is fifteen divided by five?", "three"],
  ["Which side does the sun rise?", "east"],
  ["What is the fifth letter of alphabets?", "e"],
  ["Which planet is the first one in our Solar System?", "mercury"],
  ["What is three minus two?", "one"]
];

Looking at the above questions, there's no possibility that a legitimate website user can make a mistake. Computers, although understand this, they do not attempt to solve such questions on simple forms, making a fool of themselves. They could do much better jobs in vulnerable websites.

The next step is to keep the submit button disabled. On the key up event of CAPTCHA input, we have to trigger a function that checks the correctness of the answer and based on that it should enable the button. Just for an example, I have used addEventListener() here.

document.getElementById("captchaText").addEventListener("onkeyup", function () {  
  // Verify CAPTCHA.
}, false);

Before doing this, we should prepare and show the CAPTCHA. First thing we will be doing is, randomise the array. The function Math.random() helps us in accomplishing this. This function takes up two arguments. First one is the minimum value and the second one is the maximum value. If we give a statement like:

Math.random(0, 1);  

This will have a range of 0 (included) till 1 (excluded), which means 0.00 till 0.9999999999999999. Yep, that's how much is the precision. Who needs such a precision for our use case. We have an array length of, say n, we need a random integer between 0 and 4: Either 0, 1, 2, 3, 4. So let's multiply it with our top value.

To get the whole number out of the floating point decimal, we can either use Math.trunc() or Math.floor() because all we get here will be a positive floating point and to get the previous integer, you just use either of them. There's a nice explanation here on Stack Overflow on what to use and when: Math.trunc() vs. Math.floor().

If we give the lower limit as 0 and upper limit to be 1 and multiply it with the length of the array and truncate the decimals, we will get a random value from the range of the array indices.

Math.trunc(Math.random(0, 1)) * qa.length;  

The above code gives us a random valid index of the array. We'll be using this to select a random question, each time the user loads the page. To do that, we have to use:

var rndQA = qa[Math.trunc(Math.random(0, 1)) * qa.length)];  

Our variable rndQA will always hold a random question & answer now. We just need to display the question and based on the answer (we should inform the user with a clue that it's going to be a string and not a number), we can validate if that's a human entering the form or a computer.

Setting the text:

document.getElementById("captchaLabel").innerHTML = rndQA[0];  

Don't forget to change the case of user inputted value to lowercase using toLowerCase() method before checking the correctness of answer:

document.getElementById("captchaText").addEventListener("onkeyup", function () {  
  // Verify CAPTCHA.
  var userAns = document.getElementById("captchaText").value.toLowerCase();
  var rightAns = rndQA[1];
  if (userAns == rightAns) {
    // User is a human.
  } else {
    // User is a computer.
  }
}, false);

Obviously, this is going to be a very basic level of abstraction and most of the "stronger" versions will have the contents stored in server sessions, convert the word into an array, etc.

See a complete working code and demo here:

See the Pen Quick JavaScript CAPTCHA by Praveen Kumar (@praveenscience) on CodePen.



comments powered by Disqus