line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package HTML::FormHandlerX::Field::noCAPTCHA; |
2
|
|
|
|
|
|
|
|
3
|
8
|
|
|
8
|
|
304223
|
use Moose; |
|
8
|
|
|
|
|
21
|
|
|
8
|
|
|
|
|
74
|
|
4
|
8
|
|
|
8
|
|
53172
|
use Moose::Util::TypeConstraints; |
|
8
|
|
|
|
|
21
|
|
|
8
|
|
|
|
|
72
|
|
5
|
8
|
|
|
8
|
|
18980
|
use Captcha::noCAPTCHA; |
|
8
|
|
|
|
|
232832
|
|
|
8
|
|
|
|
|
263
|
|
6
|
8
|
|
|
8
|
|
59
|
use namespace::autoclean; |
|
8
|
|
|
|
|
19
|
|
|
8
|
|
|
|
|
91
|
|
7
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
our $VERSION = '0.12'; # VERSION |
9
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
extends 'HTML::FormHandler::Field'; |
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
has '+widget' => ( default => 'noCAPTCHA' ); |
13
|
|
|
|
|
|
|
has '+input_param' => ( default => 'g-recaptcha-response' ); |
14
|
|
|
|
|
|
|
has '+messages' => ( default => sub { {required => 'You must prove your Humanity!'} }); |
15
|
|
|
|
|
|
|
has '+required' => ( default => 1 ); |
16
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
has [qw/site_key secret_key/] => (is=>'rw', isa=>'Str', required => 1,lazy_build => 1); |
18
|
|
|
|
|
|
|
has 'theme' => (is=>'ro',isa=> enum([qw(dark light)]),default => 'light'); |
19
|
|
|
|
|
|
|
has 'noscript' => (is=>'ro',isa=> 'Bool',default => 0); |
20
|
|
|
|
|
|
|
has 'remote_address' => (is=>'ro', isa=>'Str', required => 1, lazy_build => 1); |
21
|
|
|
|
|
|
|
has 'api_url' => (is=>'ro', isa=>'Str', required => 1, lazy_build => 1); |
22
|
|
|
|
|
|
|
has 'api_timeout' => (is=>'ro', isa=>'Int', required => 1, lazy_build => 1); |
23
|
|
|
|
|
|
|
has 'g_captcha_message' => (is=>'ro', isa=>'Str', default=>'You\'ve failed to prove your Humanity!'); |
24
|
|
|
|
|
|
|
has 'g_captcha_failure_message' => (is=>'ro', isa=>'Str', default=>'We\'ve had trouble processing your request, please try again.'); |
25
|
|
|
|
|
|
|
has 'config_key' => (is=>'ro', isa=>'Str', default=> __PACKAGE__); |
26
|
|
|
|
|
|
|
has '_nocaptcha' => (is=>'ro', isa=>'Captcha::noCAPTCHA', lazy_build => 1); |
27
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
sub _build_remote_address { |
29
|
0
|
|
|
0
|
|
0
|
my ($self) = @_; |
30
|
0
|
0
|
|
|
|
0
|
return '' unless ($self->form->ctx); |
31
|
0
|
|
|
|
|
0
|
return $self->form->ctx->req->address; |
32
|
|
|
|
|
|
|
} |
33
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
sub _build_secret_key { |
35
|
0
|
|
|
0
|
|
0
|
my ($self) = @_; |
36
|
0
|
|
0
|
|
|
0
|
my $config = $self->_g_captcha_config || return; |
37
|
0
|
|
|
|
|
0
|
return $config->{secret_key}; |
38
|
|
|
|
|
|
|
} |
39
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
sub _build_site_key { |
41
|
0
|
|
|
0
|
|
0
|
my ($self) = @_; |
42
|
0
|
|
0
|
|
|
0
|
my $config = $self->_g_captcha_config || return; |
43
|
0
|
|
|
|
|
0
|
return $config->{site_key}; |
44
|
|
|
|
|
|
|
} |
45
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
sub _build_api_url { |
47
|
3
|
|
|
3
|
|
12
|
my ($self) = @_; |
48
|
3
|
|
|
|
|
20
|
my $config = $self->_g_captcha_config; |
49
|
3
|
50
|
33
|
|
|
307
|
return $config && $config->{api_url} ? $config->{api_url} : 'https://www.google.com/recaptcha/api/siteverify'; |
50
|
|
|
|
|
|
|
} |
51
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
sub _build_api_timeout { |
53
|
5
|
|
|
5
|
|
15
|
my ($self) = @_; |
54
|
5
|
|
|
|
|
23
|
my $config = $self->_g_captcha_config; |
55
|
5
|
50
|
33
|
|
|
423
|
return $config && exists $config->{api_timeout} ? $config->{api_timeout} : 10; |
56
|
|
|
|
|
|
|
} |
57
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
sub _g_captcha_config { |
59
|
8
|
|
|
8
|
|
20
|
my ($self) = @_; |
60
|
8
|
50
|
33
|
|
|
200
|
return unless ($self->form && $self->form->ctx && $self->form->ctx->config); |
|
|
|
33
|
|
|
|
|
61
|
0
|
|
|
|
|
0
|
return $self->form->ctx->config->{$self->config_key}; |
62
|
|
|
|
|
|
|
} |
63
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
sub _build__nocaptcha { |
65
|
5
|
|
|
5
|
|
15
|
my ($self) = @_; |
66
|
5
|
|
|
|
|
166
|
return Captcha::noCAPTCHA->new({ |
67
|
|
|
|
|
|
|
api_url => $self->api_url, |
68
|
|
|
|
|
|
|
api_timeout => $self->api_timeout, |
69
|
|
|
|
|
|
|
site_key => $self->site_key, |
70
|
|
|
|
|
|
|
secret_key => $self->secret_key, |
71
|
|
|
|
|
|
|
theme => $self->theme, |
72
|
|
|
|
|
|
|
noscript => $self->noscript, |
73
|
|
|
|
|
|
|
}); |
74
|
|
|
|
|
|
|
} |
75
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
sub validate { |
77
|
3
|
|
|
3
|
1
|
4393
|
my ($self) = @_; |
78
|
|
|
|
|
|
|
|
79
|
3
|
|
|
|
|
100
|
my $cap = $self->_nocaptcha; |
80
|
|
|
|
|
|
|
|
81
|
3
|
|
|
|
|
15
|
my $success = $cap->verify( $self->value, $self->remote_address ); |
82
|
|
|
|
|
|
|
|
83
|
3
|
100
|
|
|
|
451
|
if (not defined $success) { |
|
|
100
|
|
|
|
|
|
84
|
1
|
|
|
|
|
36
|
$self->add_error($self->g_captcha_failure_message); |
85
|
1
|
|
|
|
|
2630
|
return; |
86
|
|
|
|
|
|
|
} elsif (!$success) { |
87
|
1
|
|
|
|
|
34
|
$self->add_error($self->g_captcha_message); |
88
|
|
|
|
|
|
|
} |
89
|
|
|
|
|
|
|
|
90
|
2
|
|
|
|
|
759
|
return; |
91
|
|
|
|
|
|
|
} |
92
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
1; |
94
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
=head1 NAME |
96
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
HTML::FormHandlerX::Field::noCAPTCHA - Google's noCAPTCHA reCAPTCHA for HTML::FormHandler |
98
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
=head1 SYNOPSIS |
100
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
The following is example usage. |
102
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
In your L<HTML::FormHandler> subclass, "YourApp::HTML::Forms::YourForm": |
104
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
has_field 'nocaptcha' => ( |
106
|
|
|
|
|
|
|
type=>'noCAPTCHA', |
107
|
|
|
|
|
|
|
site_key=>'[YOUR SITE KEY]', |
108
|
|
|
|
|
|
|
secret_key=>'[YOUR SECRET KEY]', |
109
|
|
|
|
|
|
|
); |
110
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
Example L<Catalyst> controller: |
112
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
my $form = YourApp::HTML::Forms::YourForm->new({ctx => $c}); |
114
|
|
|
|
|
|
|
my $params = $c->request->body_parameters; |
115
|
|
|
|
|
|
|
if($form->process($c->req->body_parameters) { |
116
|
|
|
|
|
|
|
## Do something with the form. |
117
|
|
|
|
|
|
|
} else { |
118
|
|
|
|
|
|
|
## Redisplay form and ask to try again. |
119
|
|
|
|
|
|
|
} |
120
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
Example L<Catalyst> config: |
122
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
__PACKAGE__->config( |
124
|
|
|
|
|
|
|
'HTML::FormHandlerX::Field::noCAPTCHA' => { |
125
|
|
|
|
|
|
|
site_key => '[YOUR SITE KEY]', |
126
|
|
|
|
|
|
|
secret_key => '[YOUR SECRET KEY]', |
127
|
|
|
|
|
|
|
}, |
128
|
|
|
|
|
|
|
); |
129
|
|
|
|
|
|
|
|
130
|
|
|
|
|
|
|
=head1 FIELD OPTIONS |
131
|
|
|
|
|
|
|
|
132
|
|
|
|
|
|
|
Support for the following field options, over what is inherited from |
133
|
|
|
|
|
|
|
L<HTML::FormHandler::Field> |
134
|
|
|
|
|
|
|
|
135
|
|
|
|
|
|
|
=head2 site_key |
136
|
|
|
|
|
|
|
|
137
|
|
|
|
|
|
|
Required. The site key you get when you create an account on L<https://www.google.com/recaptcha/> |
138
|
|
|
|
|
|
|
|
139
|
|
|
|
|
|
|
=head2 secret_key |
140
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
Required. The secret key you get when you create an account on L<https://www.google.com/recaptcha/> |
142
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
=head2 theme |
144
|
|
|
|
|
|
|
|
145
|
|
|
|
|
|
|
Optional. The color theme of the widget. Options are 'light ' or 'dark' (Default: light) |
146
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
=head2 noscript |
148
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
Optional. When true, includes the <noscript> markup in the rendered html. (Default: false) |
150
|
|
|
|
|
|
|
|
151
|
|
|
|
|
|
|
=head2 remote_address |
152
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
Optional. The user's IP address. Google states this is optional. If you are using |
154
|
|
|
|
|
|
|
catalyst and pass the context to the form, noCAPTCHA will use it by default. |
155
|
|
|
|
|
|
|
|
156
|
|
|
|
|
|
|
=head2 api_url |
157
|
|
|
|
|
|
|
|
158
|
|
|
|
|
|
|
Optional. URL to the Google API. Defaults to https://www.google.com/recaptcha/api/siteverify |
159
|
|
|
|
|
|
|
|
160
|
|
|
|
|
|
|
=head2 api_timeout |
161
|
|
|
|
|
|
|
|
162
|
|
|
|
|
|
|
Optional. Seconds to wait for Google API to respond. Default is 10 seconds. |
163
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
=head2 g_captcha_message |
165
|
|
|
|
|
|
|
|
166
|
|
|
|
|
|
|
Optional. Message to display if user answers captcha incorrectly. |
167
|
|
|
|
|
|
|
Default is "You've failed to prove your Humanity!" |
168
|
|
|
|
|
|
|
|
169
|
|
|
|
|
|
|
=head2 g_captcha_failure_message |
170
|
|
|
|
|
|
|
|
171
|
|
|
|
|
|
|
Optional. Message to display if there was an issue with Google's API response. |
172
|
|
|
|
|
|
|
Default is "We've had trouble processing your request, please try again." |
173
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
=head2 config_key |
175
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
Optional. When passing catalyst context to L<HTML::FormHandler>, uses this values |
177
|
|
|
|
|
|
|
as the key to lookup configurations for this package. |
178
|
|
|
|
|
|
|
Default is HTML::FormHandlerX::Field::noCAPTCHA |
179
|
|
|
|
|
|
|
|
180
|
|
|
|
|
|
|
=head1 SEE ALSO |
181
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
The following modules or resources may be of interest. |
183
|
|
|
|
|
|
|
|
184
|
|
|
|
|
|
|
L<HTML::FormHandler> |
185
|
|
|
|
|
|
|
L<Captcha::noCAPTCHA> |
186
|
|
|
|
|
|
|
|
187
|
|
|
|
|
|
|
=head1 AUTHOR |
188
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
Chuck Larson C<< <clarson@cpan.org> >> |
190
|
|
|
|
|
|
|
|
191
|
|
|
|
|
|
|
=head1 COPYRIGHT & LICENSE |
192
|
|
|
|
|
|
|
|
193
|
|
|
|
|
|
|
Copyright 2017, Chuck Larson C<< <chuck+github@endcapsoftwware.com> >> |
194
|
|
|
|
|
|
|
|
195
|
|
|
|
|
|
|
This projects work sponsored by End Cap Software, LLC. |
196
|
|
|
|
|
|
|
L<http://www.endcapsoftware.com> |
197
|
|
|
|
|
|
|
|
198
|
|
|
|
|
|
|
Original work by John Napiorkowski C<< <jjnapiork@cpan.org> >> |
199
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify |
201
|
|
|
|
|
|
|
it under the same terms as Perl itself. |
202
|
|
|
|
|
|
|
|
203
|
|
|
|
|
|
|
=cut |