web commit by http://willu.myopenid.com/: Add (buggy) code for todo item

master
Joey Hess 2008-06-22 03:10:25 -04:00
parent 33bfb7bfc7
commit 1020550375
1 changed files with 220 additions and 0 deletions

View File

@ -13,3 +13,223 @@ I imagine a plugin that modifies the login screen to use <http://recaptcha.net/>
>> white/black lists, were you thinking of listing the openids, or the content? >> white/black lists, were you thinking of listing the openids, or the content?
>> Something like the moinmoin global <http://master.moinmo.in/BadContent> >> Something like the moinmoin global <http://master.moinmo.in/BadContent>
>> list? >> list?
Okie - I have a first pass of this. There are still some issues.
Currently the code verifies the CAPTCHA. If you get it right then you're fine.
If you get the CAPTCHA wrong then the current code tells formbuilder that
one of the fields in invalid. This stops the login from going through.
Unfortunately, formbuilder is caching this validity somewhere, and I haven't
found a way around that yet. This means that if you get the CAPTCHA
wrong, it will continue to fail. You need to load the login page again so
it doesn't have the error message on the screen, then it'll work again.
A second issue is that the OpenID login system resets the 'required' flags
of all the other fields, so using OpenID will cause the CAPTCHA to be
ignored.
Instructions
=====
You need to go to <http://recaptcha.net/api/getkey> and get a key set.
The keys are added as options.
reCaptchaPubKey => "LONGPUBLICKEYSTRING",
reCaptchaPrivKey => "LONGPRIVATEKEYSTRING",
You can also use "signInSSL" if you're using ssl for your login screen.
The following code is just inline. It will probably not display correctly, and you should just grab it from the page source.
----------
#!/usr/bin/perl
# Ikiwiki password authentication.
package IkiWiki::Plugin::recaptcha;
use warnings;
use strict;
use IkiWiki 2.00;
sub import { #{{{
hook(type => "formbuilder_setup", id => "recaptcha", call => \&formbuilder_setup);
} # }}}
sub getopt () { #{{{
eval q{use Getopt::Long};
error($@) if $@;
Getopt::Long::Configure('pass_through');
GetOptions("reCaptchaPubKey=s" => \$config{reCaptchaPubKey});
GetOptions("reCaptchaPrivKey=s" => \$config{reCaptchaPrivKey});
} #}}}
sub formbuilder_setup (@) { #{{{
my %params=@_;
my $form=$params{form};
my $session=$params{session};
my $cgi=$params{cgi};
my $pubkey=$config{reCaptchaPubKey};
my $privkey=$config{reCaptchaPrivKey};
debug("Unknown Public Key. To use reCAPTCHA you must get an API key from http://recaptcha.net/api/getkey")
unless defined $config{reCaptchaPubKey};
debug("Unknown Private Key. To use reCAPTCHA you must get an API key from http://recaptcha.net/api/getkey")
unless defined $config{reCaptchaPrivKey};
my $tagtextPlain=<<EOTAG;
<script type="text/javascript"
src="http://api.recaptcha.net/challenge?k=$pubkey">
</script>
<noscript>
<iframe src="http://api.recaptcha.net/noscript?k=$pubkey"
height="300" width="500" frameborder="0"></iframe><br>
<textarea name="recaptcha_challenge_field" rows="3" cols="40"></textarea>
<input type="hidden" name="recaptcha_response_field"
value="manual_challenge">
</noscript>
EOTAG
my $tagtextSSL=<<EOTAGS;
<script type="text/javascript"
src="https://api-secure.recaptcha.net/challenge?k=$pubkey">
</script>
<noscript>
<iframe src="https://api-secure.recaptcha.net/noscript?k=$pubkey"
height="300" width="500" frameborder="0"></iframe><br>
<textarea name="recaptcha_challenge_field" rows="3" cols="40"></textarea>
<input type="hidden" name="recaptcha_response_field"
value="manual_challenge">
</noscript>
EOTAGS
my $tagtext;
if ($config{signInSSL}) {
$tagtext = $tagtextSSL;
} else {
$tagtext = $tagtextPlain;
}
if ($form->title eq "signin") {
# Give up if module is unavailable to avoid
# needing to depend on it.
eval q{use LWP::UserAgent};
if ($@) {
debug("unable to load LWP::UserAgent, not enabling reCaptcha");
return;
}
debug("To use reCAPTCHA you must get an API key from http://recaptcha.net/api/getkey")
unless $pubkey;
debug("To use reCAPTCHA you must get an API key from http://recaptcha.net/api/getkey")
unless $privkey;
debug("To use reCAPTCHA you must know the remote IP address")
unless $session->remote_addr();
my $extras = $form->keepextras();
if ($extras) {
push ( @$extras, qw(recaptcha_challenge_field recaptcha_response_field) );
} else {
$extras = [qw(recaptcha_challenge_field recaptcha_response_field)];
}
$form->keepextras($extras);
my $challenge = "invalid";
my $response = "invalid";
my $result = { is_valid => 0, error => 'recaptcha-not-tested' };
$form->field(
name => "recaptcha",
label => "",
type => 'static',
comment => $tagtext,
required => 1,
message => "CAPTCHA verification failed",
);
# validate the captcha.
if ($form->submitted && $form->submitted eq "Login" &&
defined $form->cgi_param("recaptcha_challenge_field") &&
length $form->cgi_param("recaptcha_challenge_field") &&
defined $form->cgi_param("recaptcha_response_field") &&
length $form->cgi_param("recaptcha_response_field")) {
$form->field(name => "recaptcha",
message => "CAPTCHA verification failed",
required => 1,
validate => sub {
if ($challenge ne $form->cgi_param("recaptcha_challenge_field") or
$response ne $form->cgi_param("recaptcha_response_field")) {
$challenge = $form->cgi_param("recaptcha_challenge_field");
$response = $form->cgi_param("recaptcha_response_field");
warn("Validating: ".$challenge." ".$response);
$result = check_answer($privkey,
$session->remote_addr(),
$challenge, $response);
} else {
warn("re-Validating");
}
if ($result->{is_valid}) {
warn("valid");
return 1;
} else {
warn("invalid");
return 0;
}
});
}
}
} # }}}
# The following function is borrowed with modifications from
# Captcha::reCAPTCHA by Andy Armstrong and is under the PERL Artistic License
sub check_answer {
my ( $privkey, $remoteip, $challenge, $response ) = @_;
die
"To use reCAPTCHA you must get an API key from http://recaptcha.net/api/getkey"
unless $privkey;
die "For security reasons, you must pass the remote ip to reCAPTCHA"
unless $remoteip;
if (! ($challenge && $response)) {
warn("Challenge or response not set!");
return { is_valid => 0, error => 'incorrect-captcha-sol' };
}
my $ua = LWP::UserAgent->new();
my $resp = $ua->post(
'http://api-verify.recaptcha.net/verify',
{
privatekey => $privkey,
remoteip => $remoteip,
challenge => $challenge,
response => $response
}
);
if ( $resp->is_success ) {
my ( $answer, $message ) = split( /\n/, $resp->content, 2 );
if ( $answer =~ /true/ ) {
warn("CAPTCHA valid");
return { is_valid => 1 };
}
else {
chomp $message;
warn("CAPTCHA failed: ".$message);
return { is_valid => 0, error => $message };
}
}
else {
warn("Unable to contact reCaptcha verification host!");
return { is_valid => 0, error => 'recaptcha-not-reachable' };
}
}
1;