├── .gitignore ├── MANIFEST ├── MANIFEST.SKIP ├── Makefile.PL ├── README ├── LICENSE ├── example └── fastcgi.pl └── lib └── Captcha └── NocaptchaMailru.pm /.gitignore: -------------------------------------------------------------------------------- 1 | *.tar.gz 2 | *.bak 3 | *.old 4 | /Makefile 5 | /blib 6 | /pm_to_blib 7 | /MYMETA.json 8 | /MYMETA.yml 9 | -------------------------------------------------------------------------------- /MANIFEST: -------------------------------------------------------------------------------- 1 | lib/Captcha/NocaptchaMailru.pm 2 | LICENSE 3 | Makefile.PL 4 | MANIFEST This list of files 5 | README 6 | -------------------------------------------------------------------------------- /MANIFEST.SKIP: -------------------------------------------------------------------------------- 1 | ^blib/ 2 | .tar.gz$ 3 | ^Makefile$ 4 | ^Makefile.old$ 5 | ^MYMETA.* 6 | ^pm_to_blib$ 7 | ^\.git 8 | ^example/ 9 | .bak$ 10 | ^MANIFEST.SKIP$ 11 | -------------------------------------------------------------------------------- /Makefile.PL: -------------------------------------------------------------------------------- 1 | use 5.010001; 2 | use ExtUtils::MakeMaker; 3 | WriteMakefile( 4 | NAME => 'Captcha::NocaptchaMailru', 5 | VERSION_FROM => 'lib/Captcha/NocaptchaMailru.pm', 6 | PREREQ_PM => { 7 | LWP::UserAgent => 5, 8 | JSON => 2, 9 | URI::Escape => 3, 10 | }, 11 | LICENSE => 'mit', 12 | ($] >= 5.005 ? ## Add these new keywords supported since 5.005 13 | (ABSTRACT_FROM => 'lib/Captcha/NocaptchaMailru.pm', # retrieve abstract from module 14 | AUTHOR => 'Oleg Kovalev ') : ()), 15 | ); 16 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | Captcha-Nocaptcha 2 | ================= 3 | 4 | Nocaptcha is an intelligent CAPTCHA service that can deliver a majority of real 5 | users from solving a CAPTCHA riddle with the same protection level from spam 6 | scripts. The service has been successfully used in our internal projects and on 7 | sites unrelated to Mail.Ru. 8 | 9 | This module is Perl implementation of Nocaptcha Mail.Ru service API. 10 | 11 | INSTALLATION 12 | 13 | To install this module type the following: 14 | 15 | perl Makefile.PL 16 | make 17 | make install 18 | 19 | SUPPORT AND DOCUMENTATION 20 | 21 | After installing, you can find documentation for this module with the 22 | perldoc command. 23 | 24 | perldoc Captcha::Nocaptcha 25 | 26 | You can also look for information at: 27 | 28 | Official site 29 | https://nocaptcha.mail.ru 30 | 31 | Documentation 32 | https://nocaptcha.mail.ru/docs 33 | 34 | PHP module 35 | https://github.com/mailru/nocaptcha-php 36 | 37 | Python module 38 | https://github.com/mailru/nocaptcha-python 39 | 40 | Use this email for feedback: nocaptcha@corp.mail.ru 41 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Mail.Ru 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /example/fastcgi.pl: -------------------------------------------------------------------------------- 1 | use Captcha::Nocaptcha; 2 | use FCGI; 3 | use Data::Dumper; 4 | use URI::Escape; 5 | 6 | use constant PUBLIC_KEY => 'e5238532bf56e4c24bd5489d463ac2a0'; 7 | use constant PRIVATE_KEY => '3cf11185476394b85bcec3fbf16c69a4'; 8 | 9 | sub unpack_params { 10 | my ($buf, %params); 11 | read(STDIN, $buf, $ENV{'CONTENT_LENGTH'}); 12 | my @pairs = split(/&/, $buf); 13 | foreach my $pair (@pairs) { 14 | my ($key, $val) = split(/=/, $pair); 15 | $key = uri_unescape($key); 16 | $val = uri_unescape($val); 17 | $params{$key} = $val; 18 | } 19 | return \%params; 20 | } 21 | 22 | my $sock = FCGI::OpenSocket(":9000", 5); 23 | my $req = FCGI::Request(\*STDIN, \*STDOUT, \*STDOUT, \%ENV, $sock); 24 | 25 | while ($req->Accept() >= 0) { 26 | if ($ENV{REQUEST_METHOD} eq "POST") { 27 | my $params = unpack_params(); 28 | my $res = Dumper(nocaptcha_check_detailed(PRIVATE_KEY, $params->{captcha_id}, $params->{captcha_value})); 29 | print("Content-Type: text/html\r\n\r\n"); 30 | print <<" END"; 31 | 32 | 33 | 34 |

result: '$res', try again

35 | 36 | 37 | END 38 | } 39 | else { 40 | my $script = nocaptcha_generate_captcha_tag(PUBLIC_KEY); 41 | print("Content-Type: text/html\r\n\r\n"); 42 | print <<" END"; 43 | 44 | 45 | $script 46 | 47 | 48 |
49 |

text

50 |

51 |

52 |
53 | 54 | 55 | END 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /lib/Captcha/NocaptchaMailru.pm: -------------------------------------------------------------------------------- 1 | package Captcha::NocaptchaMailru; 2 | 3 | use strict; 4 | use warnings; 5 | use LWP::UserAgent; 6 | use JSON; 7 | use URI::Escape; 8 | require Exporter; 9 | 10 | our @ISA = qw(Exporter); 11 | our @EXPORT = qw( 12 | nocaptcha_generate_captcha_url 13 | nocaptcha_generate_captcha_tag 14 | nocaptcha_check 15 | nocaptcha_check_detailed 16 | ); 17 | use version 0.77; our $VERSION = version->declare('v1.0.0'); 18 | 19 | use constant API_SERVER => 'https://api-nocaptcha.mail.ru'; 20 | 21 | sub _is_check_response_correct { 22 | my ($resp) = @_; 23 | return 0 unless exists($resp->{status}); 24 | if ($resp->{status} eq 'ok') { 25 | return 0 unless exists($resp->{is_correct}); 26 | return 1; 27 | } 28 | return unless exists($resp->{desc}) and exists($resp->{code}); 29 | return 1; 30 | } 31 | 32 | sub _get_json_by_url { 33 | my $agent = LWP::UserAgent->new(); 34 | my $resp = $agent->get($_[0]); 35 | return 'request failed' unless $resp->is_success; 36 | my $json = eval { 37 | decode_json($resp->decoded_content); 38 | }; 39 | return 'JSON parsing failed' if $@; 40 | return $json; 41 | } 42 | 43 | sub _pack_params { 44 | my ($hash) = @_; 45 | my @pairs; 46 | for my $key (keys %$hash) { 47 | push @pairs, join('=', map { uri_escape($_) } $key, $hash->{$key}); 48 | } 49 | return join('&', @pairs); 50 | } 51 | 52 | sub _generate_check_url { 53 | my ($key, $id, $val) = @_; 54 | return API_SERVER . '/check?' . _pack_params({'private_key' => $key, 55 | 'captcha_id' => $id, 56 | 'captcha_value' => $val}); 57 | } 58 | 59 | sub check_detailed { 60 | my ($key, $id, $val) = @_; 61 | my $url = _generate_check_url($key, $id, $val); 62 | my $resp = _get_json_by_url($url); 63 | return {is_ok => 0, error => $resp} unless ref($resp) eq 'HASH'; 64 | return {is_ok => 0, error => 'invalid response'} unless _is_check_response_correct($resp); 65 | return {is_ok => 0, error => "$resp->{status}: $resp->{desc}"} unless $resp->{status} eq 'ok'; 66 | return {is_ok => 1, is_correct => ($resp->{is_correct} ? 1 : 0)}; 67 | } 68 | 69 | sub check { 70 | my $res = check_detailed(@_); 71 | return 1 if $res->{is_ok} and $res->{is_correct}; 72 | return 0; 73 | } 74 | 75 | sub generate_captcha_url { 76 | return API_SERVER . '/captcha?' . _pack_params({'public_key' => $_[0]}); 77 | } 78 | 79 | sub generate_captcha_tag { 80 | return ''; 82 | } 83 | 84 | sub nocaptcha_generate_captcha_url { 85 | return generate_captcha_url(@_); 86 | } 87 | 88 | sub nocaptcha_generate_captcha_tag { 89 | return generate_captcha_tag(@_); 90 | } 91 | 92 | sub nocaptcha_check { 93 | return check(@_); 94 | } 95 | 96 | sub nocaptcha_check_detailed { 97 | return check_detailed(@_); 98 | } 99 | 100 | 1; 101 | __END__ 102 | 103 | =head1 NAME 104 | 105 | Captcha::NocaptchaMailru - Module for working with Nocaptcha Mail.Ru service 106 | 107 | 108 | 109 | =head1 SYNOPSIS 110 | 111 | use Captcha::NocaptchaMailru; 112 | 113 | use constant PUBLIC_KEY => 'e5238532bf56e4c24bd5489d463ac2a0'; 114 | use constant PRIVATE_KEY => '3cf11185476394b85bcec3fbf16c69a4'; 115 | 116 | my $script = nocaptcha_generate_captcha_tag(PUBLIC_KEY); 117 | 118 | if (nocaptcha_check(PRIVATE_KEY, $form_params->{captcha_id}, $form_params->{captcha_value})) { 119 | print('OK'); 120 | } 121 | else { 122 | print('ERROR'); 123 | } 124 | 125 | 126 | 127 | =head1 DESCRIPTION 128 | 129 | Nocaptcha is an intelligent CAPTCHA service that can deliver a majority of real 130 | users from solving a CAPTCHA riddle with the same protection level from spam 131 | scripts. The service has been successfully used in our internal projects and on 132 | sites unrelated to Mail.Ru. 133 | 134 | This module is Perl implementation of Nocaptcha Mail.Ru service API. 135 | 136 | Use this email for feedback: nocaptcha@corp.mail.ru 137 | 138 | =head2 EXPORT 139 | 140 | =over 141 | 142 | =item nocaptcha_generate_captcha_url 143 | 144 | Same as C. 145 | 146 | =item nocaptcha_generate_captcha_tag 147 | 148 | Same as C. 149 | 150 | =item nocaptcha_check 151 | 152 | Same as C. 153 | 154 | =item nocaptcha_check_detailed 155 | 156 | Same as C. 157 | 158 | =back 159 | 160 | 161 | 162 | =head1 METHODS 163 | 164 | =head2 generate_captcha_url 165 | 166 | Generate URL for Nocaptcha script. It should be placed in the page header. 167 | Take public key as parameter. 168 | 169 | =head2 generate_captcha_tag 170 | 171 | Generate HTML tag for Nocaptcha script. It should be placed in the page header. 172 | Take public key as parameter. 173 | 174 | =head2 check 175 | 176 | Check CAPTCHA value received from user. Parameters: private key, CAPTCHA ID, 177 | CAPTCHA value. Return 1 if value is correct or 0 in other case. 178 | 179 | =head2 check_detailed 180 | 181 | Check CAPTCHA value received from user. Parameters: private key, CAPTCHA ID, 182 | CAPTCHA value. Return reference to hash with keys: is_ok, is_correct, error. 183 | If error occur is_ok=0 and error contains error message. In other case 184 | is_ok=1 and is_correct contains result of check. 185 | 186 | 187 | 188 | =head1 SEE ALSO 189 | 190 | =over 191 | 192 | =item * Official site 193 | 194 | L 195 | 196 | =item * Documentation 197 | 198 | L 199 | 200 | =item * PHP module 201 | 202 | L 203 | 204 | =item * Python module 205 | 206 | L 207 | 208 | =back 209 | 210 | 211 | 212 | =head1 AUTHOR 213 | 214 | Oleg Kovalev, 215 | 216 | 217 | 218 | =head1 COPYRIGHT AND LICENSE 219 | 220 | =for html 221 | CC0
223 | 224 | =for text Public Domain CC0, http://creativecommons.org/publicdomain/zero/1.0/ 225 | 226 | To the extent possible under law, Mail.Ru has waived all copyright and related 227 | or neighboring rights to Perl module for working with Nocaptcha Mail.Ru 228 | service. This work is published from: Russian Federation. 229 | 230 | =cut 231 | --------------------------------------------------------------------------------