Authen-PluggableCaptcha

 view release on metacpan or  search on metacpan

lib/Authen/PluggableCaptcha.pm  view on Meta::CPAN

Initial support includes the ability to have Textual logic Catptchas.  They do silly things like say "What is one plus one ? (as text in english)" 
HTML::Email::Obfuscate makes these hard to scrape, though a better solution is needed and welcome.

One of the main points of PluggableCaptcha is that even if you create a Captcha that is one step ahead of spammers ( read: assholes ) , they're not giving up -- they're just going to take longer to break the Captcha-- and once they do, you're sweatin...

With PluggableCaptcha, it should be easier to :

=over

=item a-
create new captchas cheaply: make a new logic puzzle , a new way of rendering images , or change the random character builder into something that creates strings that look like words, so people can spell them easier.

=item b-
customize existing captchas: subclass captchas from the distribution , or others people submit to CPAN. create some site specific changes on the way fonts are rendered, etc.

=item c-
constantly change captchas ON THE FLY.  mix and match render and challenge classes.  the only thing that would take much work is swapping from a text to an image.  but 1 line of code controls what is in the image, or how to solve it!

=back

Under this system, ideally, people can change / adapt / update so fast , that spammers never get a break in their efforts to break captcha schemes!


=head1 CONSTRUCTOR

=over 4

=item B<new PARAMS>
Returns a new L<Authen::PluggableCaptcha> object constructed according to PARAMS, where PARAMS are name/value pairs.

PARAMS are name/value pairs.  

Required PARAMS are:

=over 8

=item C<type TYPE>

Type of captcha. Valid options are 'new' or 'existing'

=item C<seed TYPE>

seed used for key management.  this could be a session id, a session id + url,  an empty string, or any other defined value.

=item C<site_secret TYPE>

site_secret used for key management.  this could be a shared value for your website.

=back

Optional PARAMS are:

=over 8

=item C<keymanager_args TYPE>

The value for the keymanager_args key will be sent to the KeyManager on instantiation as 'keymanager_args'

This is useful if you need to specify a DB connection or something similar to the keymanager

=item C<do_not_validate_key INT>

This is valid only for 'existing' type captchas.  

passing this argument as the integer '1'(1) will not validate the publickey in the keymanager.

This is useful if you are externally handling the key management, and just use this package for Render + Challenge


=back

=head1 OBJECT METHODS

=over 4

=item B<captcha_type TYPE>

get the captcha type

=item B<keymanager>

returns an instance of the active keymanager

=item B<challenge_instance TYPE>

returns an instance of a challenge class TYPE

=item B<render_instance TYPE>

returns an instance of a render class TYPE

=item B<die_if_invalid>

calls a die if the captcha is invalid

=item B<get_publickey>

returns a publickey from the keymanager.

=item B<expire_publickey>

instructs the keymanager to expire the publickey. on success returns 1 and sets the captcha as invalid and expired.  returns 0 on failure and -1 on error.

=item B<validate_response>

Validates a user response against the key/time for this captcha

returns 1 on sucess, 0 on failure, -1 on error.

=item B<render PARAMS>

renders the captcha based on the kw_args submitted in PARAMS

returns the rendered captcha as a string

PARAMS are required name/value pairs.  Required PARAMS are:

=over 8

=item C<challenge_class TYPE>
Full name of a Authen::PluggableCaptcha::Challenge derived class

lib/Authen/PluggableCaptcha.pm  view on Meta::CPAN

	$self->time_expiry( $kw_args{'time_expiry'} || $Authen::PluggableCaptcha::_DEFAULTS{'time_expiry'} );
	$self->time_expiry_future( $kw_args{'time_expiry_future'} || $Authen::PluggableCaptcha::_DEFAULTS{'time_expiry_future'} );
	$self->time_now( time() );

	my 	$keymanager_class= $kw_args{'keymanager_class'} || 'Authen::PluggableCaptcha::KeyManager';

	unless ( $keymanager_class->can('generate_publickey') ) {
		eval "require $keymanager_class" || die $@ ;
	}
	unless ( $keymanager_class->can('validate_publickey') ) {
		die "keymanager_class can not validate_publickey" ;
	}
	
	$self->__keymanager_class( $keymanager_class );

	my 	$keymanager= $self->__keymanager_class->new(
		seed=> $self->seed ,
		site_secret=> $self->site_secret ,
		time_expiry=> $self->time_expiry ,
		time_expiry_future=> $self->time_expiry_future ,
		time_now=> $self->time_now ,
		keymanager_args=> $kw_args{'keymanager_args'}
	);
	$self->_keymanager( $keymanager );

	if ( $kw_args{'type'} eq 'existing' ) {
		$self->__init_existing( \%kw_args );
	}
	else {
		$self->__init_new( \%kw_args );
	}
	return $self;
}

sub captcha_type {
	my 	( $self )= @_;
	return $self->{'.captcha_type'};
}
sub _captcha_type {
	my 	( $self , $set_val )= @_;
	if 	( !defined $set_val ) {
		die "no captcha_type specified"
	}
	$self->{'.captcha_type'}= $set_val;
	return $self->{'.captcha_type'};
}


sub __init_existing {
=pod
existing captcha specific inits
=cut
	my 	( $self , $kw_args__ref )= @_;
	DEBUG_FUNCTION_NAME && Authen::PluggableCaptcha::ErrorLoggingObject::log_function_name('__init_existing');
	if ( ! defined $$kw_args__ref{'publickey'} || ! $$kw_args__ref{'publickey'} ) {
		die "'publickey' must be supplied during init";
	}
	$self->publickey( $$kw_args__ref{'publickey'} );

	if 	(
			defined $$kw_args__ref{'do_not_validate_key'} 
			&& 
			( $$kw_args__ref{'do_not_validate_key'} == 1 )
		)
	{
		$self->keymanager->publickey( $$kw_args__ref{'publickey'} );
		return 1;
	}

	my 	$validate_result= $self->keymanager->validate_publickey( publickey=> $$kw_args__ref{'publickey'} );
	DEBUG_VALIDATION && print STDERR "\n validate_result -> $validate_result ";

	if ( $validate_result < 0 ) {
		$self->keymanager->ACCEPTABLE_ERROR or die "Could not init_existing on keymanager";
	}
	elsif ( $validate_result == 0 ) {
		$self->keymanager->ACCEPTABLE_ERROR or die "Could not init_existing on keymanager";
	}
	if ( $self->keymanager->EXPIRED ) {
		$self->EXPIRED(1);
		return 0;
	}
	if ( $self->keymanager->INVALID ) {
		$self->INVALID(1);
		return 0;
	}
	return 1;
}


sub __init_new {
=pod
new captcha specific inits
=cut
	my 	( $self , $kw_args__ref )= @_;
	DEBUG_FUNCTION_NAME && Authen::PluggableCaptcha::ErrorLoggingObject::log_function_name('__init_new');

	$self->keymanager->generate_publickey() or die "Could not generate_publickey on keymanager";
	return 1;
}


sub __keymanager_class {
	my 	( $self , $class )= @_;
	if ( defined $class ){
		$self->{'..keymanager_class'}= $class;
	}
	return $self->{'..keymanager_class'};
}

sub _keymanager {
	my 	( $self , $instance )= @_;
	die "no keymanager instance" unless $instance;
	$self->{'..keymanager_instance'}= $instance;
	return $self->{'..keymanager_instance'};
}
sub keymanager {
	my 	( $self )= @_;
	return $self->{'..keymanager_instance'};
}





( run in 1.817 second using v1.01-cache-2.11-cpan-39bf76dae61 )