Two great catalyst time savers.

Today we're going to go through some CPAN modules that are great time savers. First up, we'll look at CatalystX::Starter which provides a sane helper for you to write other Catalyst extensions, then secondly we'll show you the easiest way to integrate a robust Captcha into your application with Catalyst::Controller::ReCAPTCHA in order to protect public parts of your application from scripts.

CatalystX::Starter

When you're writing a catalyst application, or just trying to scope out how a part of an app that you're working on, it's useful to be able to write a minimal application for testing. While you can use Module::Starter or h2xs for this, CatalystX::Starter provides a convenient and minimal scheme for getting your work up and running.

First up you need to install CatalystX::Starter from cpan:

 $ sudo cpan
 cpan[1]> install CatalystX::Starter
 # output snipped
    /usr/bin/make install  -- OK
 cpan[9]> exit




CatalystX::Starter is pretty light on dependencies, so shouldn't prove troublesome to install.

CatalystX::Stater provides the script catalystx-starter with which you can bootstrap the extension that you're writing, as follows:

 $ catalystx-starter 'Catalyst::Controller::reCAPTCHA'
 Created files in Catalyst-Controller-reCAPTCHA
 $ cd Catalyst-Controller-reCAPTCHA
 $ ls
 Changes       MANIFEST.SKIP Makefile.PL   README        gitignore     lib           t

Unless you're using git as your version control system you can delete the gitignore file. Everything else here provides you with the means to get your extension/minimal app up and running in no time. For this example, in the lib directory we have the directory structure Catalyst/Controller/ with the file reCAPTCHA at the bottom of this tree.

in the t/ directory we have the complete test harness with a minimal Catalyst application with which to test our work:

 $ cd t
 $ ls
 00-load.t   author      lib         live-test.t

The lib directory underneath this is where our example application lives:

 $ cd lib
 $ ls

Rather than the "kitchen sink" approach taken by the catalyst.pl script the example app that's here doesn't provide us with Model or View directories, but purely with a Controller directory and the root controller ( Root.pm ) directly underneath this. The application is called "TestApp". For Catalyst::Controller::reCAPTCHA our test application only requires a little bit of configuration in the file TestApp.pm :

 package TestApp;
 use strict;
 use warnings;
 use Catalyst;
 __PACKAGE__->config->{recaptcha}->{pub_key} = '6LcsbAAAAAAAAPDSlBaVGXjMo1kJHwUiHzO2TDze';
 __PACKAGE__->config->{recaptcha}->{priv_key} = '6LcsbAAAAAAAANQQGqwsnkrTd7QTGRBKQQZwBH-L';
 __PACKAGE__->setup;
 1;

which is essential configuration needed for the base controller to work. We can then provide test subs for everything in the root controller TestApp/Controller/Root.pm :

 package TestApp::Controller::Root;
 use strict;
 use warnings;
 __PACKAGE__->config(namespace => q{});
 use base 'Catalyst::Controller::reCAPTCHA';
 sub index :Private {
     my ($self, $c) = @_;
     $c->forward('captcha_get');
     my $body ='<html>  <body> <p> recaptcha error: '. $c->stash->{recaptcha_ok} 
. " " . $c->stash->{recaptcha_error} . '</p><form name="recaptcha" action="'. $c
->uri_for('/check') . '" method="post">'. $c->stash->{recaptcha}.' <br/> <input 
type="submit" value="submit" /> </form>';
     $c->res->body($body);
 }

 sub check : Local {
     my ($self, $c) = @_;
     $c->forward('captcha_check');
     $c->detach('index');
 }
1;

Unfortunately automated testing for this extension is not completely straightforward, and isn't available yet, as the reCAPTCHA service requires a javascript enabled browser, which WWW::Mechanize is not, so in this instance the test app provides for manual testing only (we could work around this with Selenium but haven't got around to this yet).

If you can use automated tests for your application, the following will work to test your application. Issue this command form the TestApp directory:

 $ perl -Ilib t/live-test.t

In some situations the comment prove -l t/live-test.t may also work, but not in the following situation.

You can also run your test server to test interactively with the following command (also from the application root directory):

 $ perl -Ilib  t/lib/script/testapp_server.pl
 You can connect to your server at http://localhost:3000

Of course you have to write the code in your extension library as well! Next up I'll demonstrate what I did to get Catalyst::Controller::reCAPTCHA in a state suitable for CPAN.

Catalyst::Controller::reCAPTCHA

What is reCAPTCHA

From the perldoc for the module Captcha::reCAPTCHA which does all the heavy lifting for the Catalyst base controller:

"reCAPTCHA is a hybrid mechanical turk and captcha that allows visitors who complete the captcha to assist in the digitization of books."

It's a service provided by Carnegie-Melon University in order to provide human assistance with digitisation of books in their library, and is currently the recommended Captcha implementation of the original Captcha developers.

Preparation

If your site is only going to run at localhost then you can use the default public and private keys provided by the Catalyst::Controller::reCAPTCHA distribution on CPAN. Otherwise you'll need to go to http://recaptcha.net/ and sign up for a key for your own site. This is provided in the catalyst configuration as follows (in .conf format):

 <recaptcha>
    pub_key "public key string"
    priv_key "private key string"
 </recaptcha>

where the "key string" is the one provided by the service for your site.

Implementation

This is extremely simple. In any controller that you want to use reCAPTCHA, instead of the line:

 use base 'Catalyst::Controller';

you do:

 use base 'Catalyst::Controller::reCAPTCHA';

and this provides the following methods to your controller:

 sub captcha_get : Private {}

which sets the $c-stash->{recaptcha} > item with your recaptcha form provided by the reCAPTCHA servers, so all you need to do in an action that needs a reCAPTCHA challenge is issue the following code:

 $c->forward('capcha_get');

And that's it.

Once you have an action that needs to validate the reCAPTCHA all you do is issue the command:

 $c->forward('captcha_check');

which sets the stash with a data structure that tells you whether the captcha is ok or not which sets the stash item $c->stash->{recaptcha_error} with as undefined unless there's an error in which case you get a useful data structure back describing the error.

That's it

Pretty simple stuff. Thanks to Bill Mosely and Nothingmuch for fixing my original somewhat amatuerish code for this.

Wrap up

That's all there is to this entry. Firstly a handy timesaver for making your own Catalyst extensions with CatalystX::Starter and secondly easy provision of the recommended implementation of reCAPTCHA with the recommend Captcha implemetnation all wrapped up in a catalyst base controller. And yes, I did use CatalystX::Starter to write Catalyst::Controller::reCAPTCHA!