Skip Menu |

This queue is for tickets about the Captcha-reCAPTCHA CPAN distribution.

Report information
The Basics
Id: 100714
Status: resolved
Priority: 0/
Queue: Captcha-reCAPTCHA

People
Owner: SUNNYP [...] cpan.org
Requestors: tlhackque [...] yahoo.com
Cc:
AdminCc:

Bug Information
Severity: Important
Broken in: 0.97
Fixed in: 0.97



Subject: Doesn't support new API
Google has introduced a new API, which supports the new, easier to solve captchas. It needs to be supported. See https://developers.google.com/recaptcha/ for the documentation. It's actually easier to use. I updated the squirrelmail php plugin in a few minutes. For reference, here's the PHP code (The globals are configurable options; the script ideally goes in <head>, but can be placed *anywhere*): Display: $output .= "<script src=\"https://www.google.com/recaptcha/api.js"; if ($recaptcha_fallback) // force old-style captcha { $output .= "?fallback=true"; if (!empty($recaptcha_language)) // force language (default is autodetect) { $output .= "&hl=" . $recaptcha_language; } } elseif( !empty($recaptcha_language) ) { $output .= "?hl=" . $recaptcha_language; } $output .= "\" async defer></script>"; $output .= "<div class = \"g-recaptcha\" data-SiteKey = \"" . $recaptcha_public_key . "\""; if (!empty($recaptcha_theme)) { $output .= " data-theme=\"" . $recaptcha_theme . "\""; } if (!empty($recaptcha_type)) { $output .= " data-type=\"" . $recaptcha_type . "\""; } $output .= "> </div>\n"; if ($recaptcha_noscript) // Not recommended if site requires JS { $output .= "<noscript> <div style=\"width: 302px; height: 352px;\"> <div style=\"width: 302px; height: 352px; position: relative;\"> <div style=\"width: 302px; height: 352px; position: absolute;\"> <iframe src=\"https://www.google.com/recaptcha/api/fallback?k=" . urlencode($recaptcha_public_key) . "\" frameborder=\"0\" scrolling=\"no\" style=\"width: 302px; height:352px; border-style: none;\"> </iframe> </div> <div style=\"width: 250px; height: 80px; position: absolute; border-style: none; bottom: 21px; left: 25px; margin: 0px; padding: 0px; right: 25px;\"> <textarea id=\"g-recaptcha-response\" name=\"g-recaptcha-response\" class=\"g-recaptcha-response\" style=\"width: 250px; height: 80px; border: 1px solid #c1c1c1; margin: 0px; padding: 0px; resize: none;\" value=\"\"> </textarea> </div> </div> </div> </noscript>\n"; } Validate: if (!sqGetGlobalVar('g-recaptcha-response', $recaptcha_response_field, SQ_FORM) || !sqGetGlobalVar('REMOTE_ADDR', $remote_addr, SQ_SERVER)) return FALSE; // test for no user input // if ($recaptcha_response_field === '') return NULL; global $recaptcha_private_key; $recapcha_verify_host = 'www.google.com'; // set up GET payload // $payload = '?secret=' . urlencode($recaptcha_private_key) . '&remoteip=' . urlencode($remote_addr) . '&response=' . urlencode($recaptcha_response_field); ini_set( "user_agent", "SquirrelMail CAPTCHA Plugin" ); // ask reCAPTCHA server if response was correct // $srv = fopen( "https://" . $recapcha_verify_host . "/recaptcha/api/siteverify" . $payload, "r" ); if( !$srv ) { return FALSE; } // get response // $verify_response = ''; while (!feof($srv)) $verify_response .= fgets($srv, 4096); fclose($srv); $rsp = json_decode( $verify_response, FALSE ); if (!$rsp ) { return FALSE; } if( $rsp->{'success'} == 'true' ) { return TRUE; } // $rsp->{'error-codes'} : [ ... ] /* Error code Description missing-input-secret The secret parameter is missing. invalid-input-secret The secret parameter is invalid or malformed. missing-input-response The response parameter is missing. invalid-input-response The response parameter is invalid or malformed. */ return FALSE;
Subject: Code for new API
From: tlhackque [...] yahoo.com
On Fri Dec 05 00:26:48 2014, tlhackque wrote: Show quoted text
> Google has introduced a new API, which supports the new, easier to > solve captchas. It needs to be supported. >
Here is a Perl module that I wrote that has a similar application API, but supports the new Google API. Feel free to add it or borrow code. There are comments, but I didn't do POD. Brief summary: For your application, call new() with at least the secret and SiteKey (and any other options). Case in the keywords is ignored. The following are object methods: Call getHead for the stuff to put in your <head>. Call renderCaptcha to display the new UI inside your <form> Call check_answer( $response, $remote_ip ) to see if the response is OK. Call get_error to retrieve any error codes if it fails. This module depends on JSON and LPW::Simple. Enjoy. # Copyright (C) 2014 Timothe Litt, Southborough, Massachusetts. # ALL RIGHTS RESERVED. # Perl artistic license. use strict; use warnings; package TL::Captcha; use Carp; use JSON; use LWP::Simple; # reCAPTCHA Server address and API # With the current API, https MUST be used. use constant SERVER => 'https://www.google.com/recaptcha/'; use constant JSAPI => SERVER . 'api.js'; use constant FBAPI => SERVER . 'api/fallback'; use constant VFYAPI => SERVER . 'api/siteverify?secret=%s&response=%s&remote_ip=%s'; my %validkeys = ( map { lc( $_ ) => 1 } qw( PublicKey PrivateKey SiteKey Secret theme type language noscript fallback ) ); # Create a captcha object # PublicKey/SiteKey => required \_ Obtain from https://www.google.com/recaptcha/admin # PrivateKey/Secret => required / # # Optional parameters - see http://developers.google.com/recaptcha/docs for allowed values # # theme => light, dark # type => image, audio # language => fr (default auto if not specified) - codes at https://developers.google.com/recaptcha/docs/language # noscript => 1 generate non-js interface - Not recommended if site requires javascript. # fallback => 1 force fallback API - for debugging site appearance for browsers not supporting required features. sub new { my $class = shift; croak "Invalid argument list of " . __PACKAGE__ . "::new" unless( @_ && !( @_ % 2 ) ); my $self = { }; while( @_ ) { my $k = shift; my $v = shift; $self->{lc $k} = $v; } foreach my $arg (keys %$self) { croak "Invalid argument $arg to " . __PACKAGE__ . "::new" unless( $validkeys{$arg} ); } croak "PublicKey and SiteKey are aliases: only one can be specified to " . __PACKAGE__ . "::new" if( exists $self->{publickey} && exists $self->{sitekey} ); croak "PrivateKey and Secret are aliases: only one can be specified to " . __PACKAGE__ . "::new" if( exists $self->{privatekey} && exists $self->{secret} ); $self->{sitekey} = delete $self->{publickey} if( exists $self->{publickey} ); $self->{secret} = delete $self->{privatekey} if( exists $self->{privatekey} ); croak "Missing key in argument list of " . __PACKAGE__ . "::new" unless( defined $self->{sitekey} && defined $self->{secret} && length $self->{sitekey} && length $self->{secret} ); return bless $self, $class; } # Get string to be put into the <head> # Actually, while it should go in <head>, it can be placed anywhere # Currently, this loads the <script> for the configuration specified by new(). sub getHead { my $self = shift; my $q = ''; $q .= "?fallback=true" if( $self->{fallback} ); if( $self->{language} ) { $q .= (length $q)? '&' : '?'; $q .= "hl=$self->{language}"; } return sprintf( qq(<script src="%s%s" async defer></script>), JSAPI, $q ) ; } # render the captcha -- inside a form # Currently, a <div> is generated for the JS api, and optionally, a <noscript> fallback. # The captcha response will be in a parameter 'g-recaptcha-response'. sub renderCaptcha { my $self = shift; my $output = qq(<div class="g-recaptcha" data-sitekey="$self->{sitekey}"); $output .= qq( data-theme="$self->{theme}") if( defined $self->{theme} ); $output .= qq( data-type="$self->{type}") if( defined $self->{type} ); $output .= "></div>"; if( $self->{noscript} ) { $output .= sprintf( qq(<noscript> <div style="width: 302px; height: 352px;"> <div style="width: 302px; height: 352px; position: relative;"> <div style="width: 302px; height: 352px; position: absolute;"> <iframe src="%s?k=%s" frameborder="0" scrolling="no" style="width: 302px; height:352px; border-style: none;"> </iframe> </div> <div style="width: 250px; height: 80px; position: absolute; border-style: none; bottom: 21px; left: 25px; margin: 0px; padding: 0px; right: 25px;"> <textarea id="g-recaptcha-response" name="g-recaptcha-response" class="g-recaptcha-response" style="width: 250px; height: 80px; border: 1px solid #c1c1c1; margin: 0px; padding: 0px; resize: none;" value=""> </textarea> </div> </div> </div> </noscript>), FBAPI, $self->{sitekey} ); } return $output; } # Verify the user response (normally in g-recaptcha-response parameter) # Supply the response and the IP address of the browser. # # Returns undef if unable to communicate with captcha server # Returns true if captcha validates, false otherwise sub check_answer { my $self = shift; my( $response, $remoteip ) = @_; croak "Bad argument to " . __PACKAGE__ . "::check_answer" unless( defined $remoteip && length $remoteip ); my $valid = get( sprintf( VFYAPI, $self->{secret}, (defined $response? $response : ''), $remoteip ) ); unless( defined $valid ) { carp "Unable to validate captcha"; return undef; } my $js = decode_json($valid); return 1 if( defined $js->{success} && $js->{success} eq 'true' ); $self->{error} = $js->{'error-codes'}; return 0; } # Return error(s) detected by check_answer # Will be one or more strings. # In scalar context: # Reference to an array of strings # undef if none # In array context: # Returns a list of strings # # These are currently error codes as defined in https://developers.google.com/recaptcha/docs/verify # However ,they should be translated to local language for display. sub get_error { my $self = shift; if( wantarray ) { return () unless( defined $self->{error} ); return @{$self->{error}}; } return $self->{error}; } 1;
Try Captcha::noCAPTCHA, just released this weekend.
Subject: Re: [rt.cpan.org #100714] Doesn't support new API
Date: Wed, 28 Jan 2015 01:24:55 -0500
To: bug-Captcha-reCAPTCHA [...] rt.cpan.org
From: tlhackque <tlhackque [...] yahoo.com>
On 11-Jan-15 11:39, Chuck Larson via RT wrote: Show quoted text
> <URL: https://rt.cpan.org/Ticket/Display.html?id=100714 > > > Try Captcha::noCAPTCHA, just released this weekend.
Thanks! That seems to work. It still has the problem of not including error strings corresponding to the error codes. Seems silly for all users to have to do that. And it doesn't expose language selection. It also forces the script for the Captcha into the <body>; it belongs in <head>, which is why I separated that in my quick port. So I'm not quite ready to retire my code :-( But I'm glad that you got something onto CPAN. -- This communication may not represent my employer's views, if any, on the matters discussed.
Any chance and getting this updated? Sponsorship?
Implemented new API