Wednesday, February 29, 2012

Bot-proofing the contact page

This weekend I've been working on a contact page.
You know, one of those pages which you can use to send an e-mail to the owners of the site.
Like most contact pages, it has only three fields:
  • A 'From' field: the e-mail address of whomever is sending the mail (thank you Email::Valid for the validation :-))
  • A 'Subject' field
  • A 'Mail body' field
The implementation itself is, of course, trivial. But as I was testing it, I noticed how easy it would be for a bot to send an e-mail via that page. One e-mail would not be such a big deal. But what if someone would start spamming me with this. It could overload my mail box, it would eat up all my bandwith, ...
Long story short: It could end up costing me a bunch of money!
So, like any self respecting software developer would do, I set out on a glorious quest for a solution!

The Quest

Five minutes later, I decided that I would add an "are you human"-type of validation via CAPTCHA.
I had heard about the different kinds of CAPTCHA's, and I surely also saw a lot of crappy ones!
After some more investigating, I started reading about reCAPTCHA.

All about reCAPTCHA

reCAPTCHA is very similar to any other type of CAPTCHA, except that it's not just a fixed list of images, or an image that's generated on the spot. No, reCAPTCHAs contains words from scanned books that couldn't be decoded by OCR software. This means that, every time you fill out a reCAPTCHA, you're actually helping in the digitizing of printed books! Isn't that great?!
Because of that, it's also free to use for any web developer, and it also has extra accessibility features:
People can choose to hear an audio recording that they then have to type out.
This way they can still fill out the reCAPTCHA, and they're helping in the digitizing of old time radio shows!

The first thing I was wondering was: "If the OCR software can't read the word correctly, then how do they know wether the submitted answer is correct or not?"
Luckily, the reCAPTCHA website explains this:

Each new word that cannot be read correctly by OCR is given to a user in conjunction with another word for which the answer is already known. The user is then asked to read both words. If they solve the one for which the answer is known, the system assumes their answer is correct for the new one. The system then gives the new image to a number of other people to determine, with higher confidence, whether the original answer was correct.

Implementing reCAPTCHA

To start using reCAPTCHA you have to register on their site. (This is a one time and, as I already said, free registration). After registering, you get two keys: a private key and a public key.
The public key is used to retrieve a new CAPTCHA; The private key is then used (server-side) to validate the answer.

Implementing this in perl was trivial, because, as usual, the CPAN did not let me down and provides the fantastic Captcha::reCAPTCHA module! All I had to do, was try and make it work from a mojolicious application.

The synopsis of Captcha::reCAPTCHA looks like this:

  1. use Captcha::reCAPTCHA;

  2. my $c = Captcha::reCAPTCHA->new;

  3. # Output form
  4. print $c->get_html( 'your public key here' );

  5. # Verify submission
  6. my $result = $c->check_answer(
  7.     'your private key here', $ENV{'REMOTE_ADDR'},
  8.     $challenge, $response
  9. );

  10. if ( $result->{is_valid} ) {
  11.     print "Yes!";
  12. }
  13. else {
  14.     # Error
  15.     $error = $result->{error};
  16. }

On line 6, we notice that the module outputs html. That doesn't look very nice, but it's probably the only way to make it easy to use. This way, we don't need to know anything about the actual interface with reCAPTCHA.
But since it outputs html, it is clear that we'll need to make that call in our view template.
The easiest way to do that is by registering the get_html method as a helper in our mojolicious application:

  1. $self->helper(reCAPTCHA => sub{Captcha::reCAPTCHA->new->get_html($_[1])});

Then we just call the helper from our template:

  1. <div>
  2.     %== reCAPTCHA 'your_public_key_here'
  3. </div>

The %== (instead of the regular %=) indicates that the output of the reCAPTCHA helper must not be html escaped.
These four lines of code (of which two are just markup :-)) is enough to display the reCAPTCHA on our website. 
Next step: validating the user's input. The Captcha::reCAPTCHA documentation states the following:

After the user has filled out the HTML form, including their answer for the CAPTCHA, use check_answer to check their answer when they submit the form. The user's answer will be in two form fields, recaptcha_challenge_field and recaptcha_response_field. The reCAPTCHA library will make an HTTP request to the reCAPTCHA server and verify the user's answer.

That looks easy enough! Get two parameters and use them in a function call.
And really, apart from also passing the users's IP address (which we can easily fetch from the Mojo::Transaction object in the controller), that's all there's to it!

  1. sub send {
  2.   my $c = shift;
  3.   my $captchaChallenge = $c->param('recaptcha_challenge_field');
  4.   my $captchaResponse = $c->param('recaptcha_response_field');
  5.   my $captcha = Captcha::reCAPTCHA->new;
  6.   my $captchaResult = $captcha->check_answer('your_private_key_here',
  7.                                              $c->tx->remote_address,
  8.                                              $captchaChallenge,
  9.                                              $captchaResponse);
  10.   if ($captchaResult->{is_valid}) {
  11.     # continue doing further validations and possibly send the e-mail
  12.     $c->render('Contact/sent');
  13.   } else {
  14.     $c->stash(error => "Invalid reCAPTCHA code: are you human?!");
  15.   }
  16.   $c->render('Contact/index');
  17. }

Ka-pow! we're done! We now have a reCAPTCHA protected contact page!

You're welcome.

Monday, January 23, 2012

More on the header image part two: The title

Hi all,
and welcome back to part two of the step-by-step guide to how I created the header image for the site. In the previous post we created the logo.
Now we will create the title text and we'll combine both the logo and the text into one final image which will be the header image for the site.

The title

Start by creating a new image and make it 450px x 150px large.
Next, delete the default background layer and then create a new one. Name it "main text".
The font I chose for the text is "Ubuntu-title". Choose the text tool from the toolbox. Set the font to Ubuntu-title, set the size to 130 px and set the color to #BFEE00:


Now just click on the image and type "moambe".
Then adjust the location of the text so that it is aproximately in the middle of the canvas:

The next step is adding the dark green border around the text.
We start by selecting the entire text. You can do that easily with the "Select by Color" tool.
Now choose "Select" --> "Grow" from the menu and grow the selection by 3px.
It should now look like this:

Next, create a new layer and name it "Border". Make sure that it is lower in the layer stack than the "main text" layer. otherwise the border layer will hide the main text layer.
Now just set the foreground colour to #53DF00 and choose "Edit" --> "Fill with FG Color" from the menu to fill the entire selection. The result should be this:

Now we will add the glassy effect to the letters. Start by selecting the text with the "Select by Color" tool again. Next pick the "Ellipse select tool" from the toolbox and set the select mode to "Subtract"

Draw the elliptical selection so that the upper half of the ellipse crosses the text.
Like this:

Now create a new layer and name it "Glassy effect". This time, make sure that it is at the top of the layer stack. Set its opacity to 30%. Set your foreground colour to white (#FFFFFF) and select "Edit" --> "Fill with FG Color" from the menu. The selection will be filled in white, but will be 70% transparant, since our layer is only 30% opaque. This creates our desired glassy effect:

As a finishing touch, we will also add some drop shadow. You should know how to do this by now :-)
The end result looks like this:

Putting it all together

Now all that's left is adding both the logo and the title together in one image. That will then be the header of the site.
This is the easiest part of it all: just create an image of 600 px x 150 px and copy-paste both the logo and the title in it: