recaptcha 5.5.0 → 5.12.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +48 -0
- data/README.md +93 -22
- data/lib/recaptcha/adapters/controller_methods.rb +5 -3
- data/lib/recaptcha/configuration.rb +24 -6
- data/lib/recaptcha/helpers.rb +24 -13
- data/lib/recaptcha/version.rb +1 -1
- data/lib/recaptcha.rb +66 -18
- data/rails/locales/fr.yml +5 -0
- data/rails/locales/ja.yml +5 -0
- data/rails/locales/nl.yml +5 -0
- metadata +10 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4052ca42cf536d84329b553a058de58f2c3579e0ac2ad1e08ba42fed8ce974b4
|
4
|
+
data.tar.gz: 90c873c15d0772690ca3da6cf2588669a05c159e4fbaa1d6bdf5d809ad05dfd0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 403d9de96d890bb3f75cfb83c5907f01944d8e88233248ec199fe014e04f7f1386c13cd867c9020a232cd5501faada986f6d3413d3a2369e5d38d9c56a0704b9
|
7
|
+
data.tar.gz: ce0d965054455acff094e60ccad808fbf836992666f9bd1233684b172e766440ba922a0f8d030803575b3a538945e3273d0ae237ce2527f9e0983b7b76671328
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,53 @@
|
|
1
1
|
## Next
|
2
2
|
|
3
|
+
## 5.12.3
|
4
|
+
* Remove score fallback for enterprise
|
5
|
+
* Update enterprise tests to v1 assessment schema
|
6
|
+
|
7
|
+
## 5.12.2
|
8
|
+
* Fix minimum score for enterprise
|
9
|
+
|
10
|
+
## 5.12.1
|
11
|
+
* Fix Japanese locale
|
12
|
+
|
13
|
+
## 5.12.0
|
14
|
+
* Added Japanese locale
|
15
|
+
|
16
|
+
## 5.11.0
|
17
|
+
* Added Dutch locale
|
18
|
+
|
19
|
+
## 5.10.1
|
20
|
+
* Fix enterprise_verify_url #415
|
21
|
+
|
22
|
+
## 5.10.0
|
23
|
+
* Drop ruby 2.4 2.5 2.6
|
24
|
+
* Add maxiumm score support for hcaptcha
|
25
|
+
|
26
|
+
## 5.9.0
|
27
|
+
* Gracefully handle invalid params
|
28
|
+
|
29
|
+
## 5.8.1
|
30
|
+
* Allow configuring response limit
|
31
|
+
|
32
|
+
## 5.8.0
|
33
|
+
* Add support for the enterprise API
|
34
|
+
|
35
|
+
## 5.7.0
|
36
|
+
* french locale
|
37
|
+
* drop ruby 2.3
|
38
|
+
|
39
|
+
## 5.6.0
|
40
|
+
* Allow multiple invisible recaptchas on a single page by setting custom selector
|
41
|
+
|
42
|
+
## 5.5.0
|
43
|
+
* add `recaptcha_reply` controller method for better debugging/inspection
|
44
|
+
|
45
|
+
## 5.4.1
|
46
|
+
* fix v2 vs 'data' postfix
|
47
|
+
|
48
|
+
## 5.4.0
|
49
|
+
* added 'data' postfix to g-recaptcha-response attribute name to avoid collisions
|
50
|
+
|
3
51
|
## 5.3.0
|
4
52
|
* turbolinks support
|
5
53
|
|
data/README.md
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
|
1
2
|
# reCAPTCHA
|
2
3
|
[](https://badge.fury.io/rb/recaptcha)
|
3
4
|
|
@@ -12,6 +13,23 @@ views you can use the `recaptcha_tags` method to embed the needed javascript, an
|
|
12
13
|
in your controllers with `verify_recaptcha` or `verify_recaptcha!`, which raises an error on
|
13
14
|
failure.
|
14
15
|
|
16
|
+
|
17
|
+
# Table of Contents
|
18
|
+
1. [Obtaining a key](#obtaining-a-key)
|
19
|
+
2. [Rails Installation](#rails-installation)
|
20
|
+
3. [Sinatra / Rack / Ruby Installation](#sinatra--rack--ruby-installation)
|
21
|
+
4. [reCAPTCHA V2 API & Usage](#recaptcha-v2-api-and-usage)
|
22
|
+
- [`recaptcha_tags`](#recaptcha_tags)
|
23
|
+
- [`verify_recaptcha`](#verify_recaptcha)
|
24
|
+
- [`invisible_recaptcha_tags`](#invisible_recaptcha_tags)
|
25
|
+
5. [reCAPTCHA V3 API & Usage](#recaptcha-v3-api-and-usage)
|
26
|
+
- [`recaptcha_v3`](#recaptcha_v3)
|
27
|
+
- [`verify_recaptcha` (use with v3)](#verify_recaptcha-use-with-v3)
|
28
|
+
- [`recaptcha_reply`](#recaptcha_reply)
|
29
|
+
6. [I18n Support](#i18n-support)
|
30
|
+
7. [Testing](#testing)
|
31
|
+
8. [Alternative API Key Setup](#alternative-api-key-setup)
|
32
|
+
|
15
33
|
## Obtaining a key
|
16
34
|
|
17
35
|
Go to the [reCAPTCHA admin console](https://www.google.com/recaptcha/admin) to obtain a reCAPTCHA API key.
|
@@ -32,6 +50,8 @@ Note: Enter `localhost` or `127.0.0.1` as the domain if using in development wit
|
|
32
50
|
|
33
51
|
## Rails Installation
|
34
52
|
|
53
|
+
**If you are having issues with Rails 7, Turbo, and Stimulus, make sure to check [this Wiki page](https://github.com/ambethia/recaptcha/wiki/Recaptcha-with-Turbo-and-Stimulus)!**
|
54
|
+
|
35
55
|
```ruby
|
36
56
|
gem "recaptcha"
|
37
57
|
```
|
@@ -50,6 +70,14 @@ export RECAPTCHA_SITE_KEY = '6Lc6BAAAAAAAAChqRbQZcn_yyyyyyyyyyyyyyyyy'
|
|
50
70
|
export RECAPTCHA_SECRET_KEY = '6Lc6BAAAAAAAAKN3DRm6VA_xxxxxxxxxxxxxxxxx'
|
51
71
|
```
|
52
72
|
|
73
|
+
If you have an Enterprise API key:
|
74
|
+
|
75
|
+
```shell
|
76
|
+
export RECAPTCHA_ENTERPRISE = 'true'
|
77
|
+
export RECAPTCHA_ENTERPRISE_API_KEY = 'AIzvFyE3TU-g4K_Kozr9F1smEzZSGBVOfLKyupA'
|
78
|
+
export RECAPTCHA_ENTERPRISE_PROJECT_ID = 'my-project'
|
79
|
+
```
|
80
|
+
|
53
81
|
Add `recaptcha_tags` to the forms you want to protect:
|
54
82
|
|
55
83
|
```erb
|
@@ -71,6 +99,7 @@ else
|
|
71
99
|
render 'new'
|
72
100
|
end
|
73
101
|
```
|
102
|
+
Please note that this setup uses [`reCAPTCHA_v2`](#recaptcha-v2-api-and-usage). For a `recaptcha_v3` use, please refer to [`reCAPTCHA_v3 setup`](#examples).
|
74
103
|
|
75
104
|
## Sinatra / Rack / Ruby installation
|
76
105
|
|
@@ -119,7 +148,7 @@ The following options are available:
|
|
119
148
|
Any unrecognized options will be added as attributes on the generated tag.
|
120
149
|
|
121
150
|
You can also override the html attributes for the sizes of the generated `textarea` and `iframe`
|
122
|
-
elements, if CSS isn't your thing. Inspect the [source of `recaptcha_tags`](https://github.com/ambethia/recaptcha/blob/master/lib/recaptcha/
|
151
|
+
elements, if CSS isn't your thing. Inspect the [source of `recaptcha_tags`](https://github.com/ambethia/recaptcha/blob/master/lib/recaptcha/helpers.rb)
|
123
152
|
to see these options.
|
124
153
|
|
125
154
|
Note that you cannot submit/verify the same response token more than once or you will get a
|
@@ -140,16 +169,18 @@ you like.
|
|
140
169
|
|
141
170
|
Some of the options available:
|
142
171
|
|
143
|
-
| Option
|
144
|
-
|
145
|
-
| `:model`
|
146
|
-
| `:attribute`
|
147
|
-
| `:message`
|
148
|
-
| `:secret_key`
|
149
|
-
| `:
|
150
|
-
| `:
|
151
|
-
| `:
|
152
|
-
| `:
|
172
|
+
| Option | Description |
|
173
|
+
|---------------------------|-------------|
|
174
|
+
| `:model` | Model to set errors.
|
175
|
+
| `:attribute` | Model attribute to receive errors. (default: `:base`)
|
176
|
+
| `:message` | Custom error message.
|
177
|
+
| `:secret_key` | Override the secret API key from the configuration.
|
178
|
+
| `:enterprise_api_key` | Override the Enterprise API key from the configuration.
|
179
|
+
| `:enterprise_project_id ` | Override the Enterprise project ID from the configuration.
|
180
|
+
| `:timeout` | The number of seconds to wait for reCAPTCHA servers before give up. (default: `3`)
|
181
|
+
| `:response` | Custom response parameter. (default: `params['g-recaptcha-response-data']`)
|
182
|
+
| `:hostname` | Expected hostname or a callable that validates the hostname, see [domain validation](https://developers.google.com/recaptcha/docs/domain_validation) and [hostname](https://developers.google.com/recaptcha/docs/verify#api-response) docs. (default: `nil`, but can be changed by setting `config.hostname`)
|
183
|
+
| `:env` | Current environment. The request to verify will be skipped if the environment is specified in configuration under `skip_verify_env`
|
153
184
|
|
154
185
|
|
155
186
|
### `invisible_recaptcha_tags`
|
@@ -278,7 +309,7 @@ threshold:
|
|
278
309
|
<% if @show_checkbox_recaptcha %>
|
279
310
|
<%= recaptcha_tags %>
|
280
311
|
<% else %>
|
281
|
-
<%= recaptcha_v3(action: 'login') %>
|
312
|
+
<%= recaptcha_v3(action: 'login', site_key: ENV['RECAPTCHA_SITE_KEY_V3']) %>
|
282
313
|
<% end %>
|
283
314
|
…
|
284
315
|
```
|
@@ -286,7 +317,7 @@ threshold:
|
|
286
317
|
```ruby
|
287
318
|
# app/controllers/sessions_controller.rb
|
288
319
|
def create
|
289
|
-
success = verify_recaptcha(action: 'login', minimum_score: 0.5)
|
320
|
+
success = verify_recaptcha(action: 'login', minimum_score: 0.5, secret_key: ENV['RECAPTCHA_SECRET_KEY_V3'])
|
290
321
|
checkbox_success = verify_recaptcha unless success
|
291
322
|
if success || checkbox_success
|
292
323
|
# Perform action
|
@@ -357,17 +388,19 @@ then you can either:
|
|
357
388
|
2. write and specify a custom `callback` function. You may also want to pass `element: false` if you
|
358
389
|
don't have a use for the hidden input element.
|
359
390
|
|
360
|
-
Note that you cannot submit/verify the same response token more than once or you
|
361
|
-
`timeout-or-duplicate` error code. If you need reset the captcha and
|
362
|
-
then you need to call `grecaptcha.execute(…)`
|
363
|
-
|
364
|
-
|
365
|
-
|
391
|
+
Note that you cannot submit/verify the same response token more than once or you
|
392
|
+
will get a `timeout-or-duplicate` error code. If you need reset the captcha and
|
393
|
+
generate a new response token, then you need to call `grecaptcha.execute(…)` or
|
394
|
+
`grecaptcha.enterprise.execute(…)` again. This helper provides a JavaScript
|
395
|
+
method (for each action) named `executeRecaptchaFor{action}` to make this
|
396
|
+
easier. That is the same method that is invoked immediately. It simply calls
|
397
|
+
`grecaptcha.execute` or `grecaptcha.enterprise.execute` again and then calls the
|
398
|
+
`callback` function with the response token.
|
366
399
|
|
367
400
|
You will also get a `timeout-or-duplicate` error if too much time has passed between getting the
|
368
401
|
response token and verifying it. This can easily happen with large forms that take the user a couple
|
369
402
|
minutes to complete. Unlike v2, where you can use the `expired-callback` to be notified when the
|
370
|
-
response
|
403
|
+
response expires, v3 appears to provide no such callback. See also
|
371
404
|
[1](https://github.com/google/recaptcha/issues/281) and
|
372
405
|
[2](https://stackoverflow.com/questions/54437745/recaptcha-v3-how-to-deal-with-expired-token-after-idle).
|
373
406
|
|
@@ -427,7 +460,7 @@ According to https://developers.google.com/recaptcha/docs/v3#placement,
|
|
427
460
|
|
428
461
|
> Note: You can execute reCAPTCHA as many times as you'd like with different actions on the same page.
|
429
462
|
|
430
|
-
You will need to verify each action individually with separate call to `verify_recaptcha`.
|
463
|
+
You will need to verify each action individually with a separate call to `verify_recaptcha`.
|
431
464
|
|
432
465
|
```ruby
|
433
466
|
result_a = verify_recaptcha(action: 'a')
|
@@ -487,14 +520,20 @@ Recaptcha.configuration.skip_verify_env.delete("test")
|
|
487
520
|
Recaptcha.configure do |config|
|
488
521
|
config.site_key = '6Lc6BAAAAAAAAChqRbQZcn_yyyyyyyyyyyyyyyyy'
|
489
522
|
config.secret_key = '6Lc6BAAAAAAAAKN3DRm6VA_xxxxxxxxxxxxxxxxx'
|
523
|
+
|
490
524
|
# Uncomment the following line if you are using a proxy server:
|
491
525
|
# config.proxy = 'http://myproxy.com.au:8080'
|
526
|
+
|
527
|
+
# Uncomment the following lines if you are using the Enterprise API:
|
528
|
+
# config.enterprise = true
|
529
|
+
# config.enterprise_api_key = 'AIzvFyE3TU-g4K_Kozr9F1smEzZSGBVOfLKyupA'
|
530
|
+
# config.enterprise_project_id = 'my-project'
|
492
531
|
end
|
493
532
|
```
|
494
533
|
|
495
534
|
### Recaptcha.with_configuration
|
496
535
|
|
497
|
-
For temporary overwrites (not thread
|
536
|
+
For temporary overwrites (not thread-safe).
|
498
537
|
|
499
538
|
```ruby
|
500
539
|
Recaptcha.with_configuration(site_key: '12345') do
|
@@ -514,6 +553,38 @@ recaptcha_tags site_key: '6Lc6BAAAAAAAAChqRbQZcn_yyyyyyyyyyyyyyyyy'
|
|
514
553
|
verify_recaptcha secret_key: '6Lc6BAAAAAAAAKN3DRm6VA_xxxxxxxxxxxxxxxxx'
|
515
554
|
```
|
516
555
|
|
556
|
+
|
557
|
+
## hCaptcha support
|
558
|
+
|
559
|
+
[hCaptcha](https://hcaptcha.com) is an alternative service providing reCAPTCHA API.
|
560
|
+
|
561
|
+
To use hCaptcha:
|
562
|
+
1. Set a site and a secret key as usual
|
563
|
+
2. Set two options in `verify_url` and `api_service_url` pointing to hCaptcha API endpoints.
|
564
|
+
3. Disable a response limit check by setting a `response_limit` to the large enough value (reCAPTCHA is limited by 4000 characters).
|
565
|
+
4. It is not required to change a parameter name as [official docs suggest](https://docs.hcaptcha.com/switch) because API handles standard `g-recaptcha` for compatibility.
|
566
|
+
|
567
|
+
```ruby
|
568
|
+
# config/initializers/recaptcha.rb
|
569
|
+
Recaptcha.configure do |config|
|
570
|
+
config.site_key = '6Lc6BAAAAAAAAChqRbQZcn_yyyyyyyyyyyyyyyyy'
|
571
|
+
config.secret_key = '6Lc6BAAAAAAAAKN3DRm6VA_xxxxxxxxxxxxxxxxx'
|
572
|
+
config.verify_url = 'https://hcaptcha.com/siteverify'
|
573
|
+
config.api_server_url = 'https://hcaptcha.com/1/api.js'
|
574
|
+
config.response_limit = 100000
|
575
|
+
end
|
576
|
+
```
|
577
|
+
|
578
|
+
hCaptcha uses a scoring system (higher number more likely to be a bot) which is inverse of the reCaptcha scoring system (lower number more likely to be a bot). As such, a `maximum_score` attribute is provided for use with hCaptcha.
|
579
|
+
|
580
|
+
```ruby
|
581
|
+
result = verify_recaptcha(maximum_score: 0.7)
|
582
|
+
```
|
583
|
+
|
584
|
+
| Option | Description |
|
585
|
+
|------------------|-------------|
|
586
|
+
| `:maximum_score` | Provide a threshold to meet or fall below. Threshold should be a float between 0 and 1 which will be tested as `score <= maximum_score`. (Default: `nil`) |
|
587
|
+
|
517
588
|
## Misc
|
518
589
|
- Check out the [wiki](https://github.com/ambethia/recaptcha/wiki) and leave whatever you found valuable there.
|
519
590
|
- [Add multiple widgets to the same page](https://github.com/ambethia/recaptcha/wiki/Add-multiple-widgets-to-the-same-page)
|
@@ -83,10 +83,12 @@ module Recaptcha
|
|
83
83
|
# @return [String] A response token if one was passed in the params; otherwise, `''`
|
84
84
|
def recaptcha_response_token(action = nil)
|
85
85
|
response_param = params['g-recaptcha-response-data'] || params['g-recaptcha-response']
|
86
|
-
if response_param
|
87
|
-
|
86
|
+
response_param = response_param[action] if action && response_param.respond_to?(:key?)
|
87
|
+
|
88
|
+
if response_param.is_a?(String)
|
89
|
+
response_param
|
88
90
|
else
|
89
|
-
|
91
|
+
''
|
90
92
|
end
|
91
93
|
end
|
92
94
|
end
|
@@ -31,22 +31,32 @@ module Recaptcha
|
|
31
31
|
#
|
32
32
|
class Configuration
|
33
33
|
DEFAULTS = {
|
34
|
-
'
|
35
|
-
'
|
34
|
+
'free_server_url' => 'https://www.recaptcha.net/recaptcha/api.js',
|
35
|
+
'enterprise_server_url' => 'https://www.recaptcha.net/recaptcha/enterprise.js',
|
36
|
+
'free_verify_url' => 'https://www.recaptcha.net/recaptcha/api/siteverify',
|
37
|
+
'enterprise_verify_url' => 'https://recaptchaenterprise.googleapis.com/v1/projects'
|
36
38
|
}.freeze
|
37
39
|
|
38
|
-
attr_accessor :default_env, :skip_verify_env, :
|
40
|
+
attr_accessor :default_env, :skip_verify_env, :proxy, :secret_key, :site_key, :handle_timeouts_gracefully,
|
41
|
+
:hostname, :enterprise, :enterprise_api_key, :enterprise_project_id, :response_limit
|
39
42
|
attr_writer :api_server_url, :verify_url
|
40
43
|
|
41
|
-
def initialize
|
44
|
+
def initialize # :nodoc:
|
42
45
|
@default_env = ENV['RAILS_ENV'] || ENV['RACK_ENV'] || (Rails.env if defined? Rails.env)
|
43
46
|
@skip_verify_env = %w[test cucumber]
|
44
47
|
@handle_timeouts_gracefully = true
|
45
48
|
|
46
49
|
@secret_key = ENV['RECAPTCHA_SECRET_KEY']
|
47
50
|
@site_key = ENV['RECAPTCHA_SITE_KEY']
|
51
|
+
|
52
|
+
@enterprise = ENV['RECAPTCHA_ENTERPRISE'] == 'true'
|
53
|
+
@enterprise_api_key = ENV['RECAPTCHA_ENTERPRISE_API_KEY']
|
54
|
+
@enterprise_project_id = ENV['RECAPTCHA_ENTERPRISE_PROJECT_ID']
|
55
|
+
|
48
56
|
@verify_url = nil
|
49
57
|
@api_server_url = nil
|
58
|
+
|
59
|
+
@response_limit = 4000
|
50
60
|
end
|
51
61
|
|
52
62
|
def secret_key!
|
@@ -57,12 +67,20 @@ module Recaptcha
|
|
57
67
|
site_key || raise(RecaptchaError, "No site key specified.")
|
58
68
|
end
|
59
69
|
|
70
|
+
def enterprise_api_key!
|
71
|
+
enterprise_api_key || raise(RecaptchaError, "No Enterprise API key specified.")
|
72
|
+
end
|
73
|
+
|
74
|
+
def enterprise_project_id!
|
75
|
+
enterprise_project_id || raise(RecaptchaError, "No Enterprise project ID specified.")
|
76
|
+
end
|
77
|
+
|
60
78
|
def api_server_url
|
61
|
-
@api_server_url || DEFAULTS.fetch('
|
79
|
+
@api_server_url || (enterprise ? DEFAULTS.fetch('enterprise_server_url') : DEFAULTS.fetch('free_server_url'))
|
62
80
|
end
|
63
81
|
|
64
82
|
def verify_url
|
65
|
-
@verify_url || DEFAULTS.fetch('
|
83
|
+
@verify_url || (enterprise ? DEFAULTS.fetch('enterprise_verify_url') : DEFAULTS.fetch('free_verify_url'))
|
66
84
|
end
|
67
85
|
end
|
68
86
|
end
|
data/lib/recaptcha/helpers.rb
CHANGED
@@ -10,7 +10,7 @@ module Recaptcha
|
|
10
10
|
def self.recaptcha_v3(options = {})
|
11
11
|
site_key = options[:site_key] ||= Recaptcha.configuration.site_key!
|
12
12
|
action = options.delete(:action) || raise(Recaptcha::RecaptchaError, 'action is required')
|
13
|
-
id = options.delete(:id) || "g-recaptcha-response-data
|
13
|
+
id = options.delete(:id) || "g-recaptcha-response-data-#{dasherize_action(action)}"
|
14
14
|
name = options.delete(:name) || "g-recaptcha-response-data[#{action}]"
|
15
15
|
turbolinks = options.delete(:turbolinks)
|
16
16
|
options[:render] = site_key
|
@@ -174,7 +174,8 @@ module Recaptcha
|
|
174
174
|
|
175
175
|
# v3
|
176
176
|
|
177
|
-
# Renders a script that calls `grecaptcha.execute`
|
177
|
+
# Renders a script that calls `grecaptcha.execute` or
|
178
|
+
# `grecaptcha.enterprise.execute` for the given `site_key` and `action` and
|
178
179
|
# calls the `callback` with the resulting response token.
|
179
180
|
private_class_method def self.recaptcha_v3_inline_script(site_key, action, callback, id, options = {})
|
180
181
|
nonce = options[:nonce]
|
@@ -185,8 +186,8 @@ module Recaptcha
|
|
185
186
|
// Define function so that we can call it again later if we need to reset it
|
186
187
|
// This executes reCAPTCHA and then calls our callback.
|
187
188
|
function #{recaptcha_v3_execute_function_name(action)}() {
|
188
|
-
|
189
|
-
|
189
|
+
#{recaptcha_ready_method_name}(function() {
|
190
|
+
#{recaptcha_execute_method_name}('#{site_key}', {action: '#{action}'}).then(function(token) {
|
190
191
|
#{callback}('#{id}', token)
|
191
192
|
});
|
192
193
|
});
|
@@ -199,8 +200,8 @@ module Recaptcha
|
|
199
200
|
// Returns a Promise that resolves with the response token.
|
200
201
|
async function #{recaptcha_v3_async_execute_function_name(action)}() {
|
201
202
|
return new Promise((resolve, reject) => {
|
202
|
-
|
203
|
-
resolve(await
|
203
|
+
#{recaptcha_ready_method_name}(async function() {
|
204
|
+
resolve(await #{recaptcha_execute_method_name}('#{site_key}', {action: '#{action}'}))
|
204
205
|
});
|
205
206
|
})
|
206
207
|
};
|
@@ -217,8 +218,8 @@ module Recaptcha
|
|
217
218
|
<<-HTML
|
218
219
|
<script#{nonce_attr}>
|
219
220
|
function #{recaptcha_v3_execute_function_name(action)}() {
|
220
|
-
|
221
|
-
|
221
|
+
#{recaptcha_ready_method_name}(function() {
|
222
|
+
#{recaptcha_execute_method_name}('#{site_key}', {action: '#{action}'}).then(function(token) {
|
222
223
|
#{callback}('#{id}', token)
|
223
224
|
});
|
224
225
|
});
|
@@ -251,8 +252,9 @@ module Recaptcha
|
|
251
252
|
recaptcha_v3_inline_script?(options)
|
252
253
|
end
|
253
254
|
|
254
|
-
# Returns the name of the JavaScript function that actually executes the
|
255
|
-
# grecaptcha.execute
|
255
|
+
# Returns the name of the JavaScript function that actually executes the
|
256
|
+
# reCAPTCHA code (calls `grecaptcha.execute` or
|
257
|
+
# `grecaptcha.enterprise.execute`). You can call it again later to reset it.
|
256
258
|
def self.recaptcha_v3_execute_function_name(action)
|
257
259
|
"executeRecaptchaFor#{sanitize_action_for_js(action)}"
|
258
260
|
end
|
@@ -271,6 +273,7 @@ module Recaptcha
|
|
271
273
|
private_class_method def self.default_callback(options = {})
|
272
274
|
nonce = options[:nonce]
|
273
275
|
nonce_attr = " nonce='#{nonce}'" if nonce
|
276
|
+
selector_attr = options[:id] ? "##{options[:id]}" : ".g-recaptcha"
|
274
277
|
|
275
278
|
<<-HTML
|
276
279
|
<script#{nonce_attr}>
|
@@ -283,9 +286,9 @@ module Recaptcha
|
|
283
286
|
return curEle.nodeName === 'FORM' ? curEle : null
|
284
287
|
};
|
285
288
|
|
286
|
-
var
|
287
|
-
if (
|
288
|
-
var form = closestForm(
|
289
|
+
var el = document.querySelector("#{selector_attr}")
|
290
|
+
if (!!el) {
|
291
|
+
var form = closestForm(el);
|
289
292
|
if (form) {
|
290
293
|
form.submit();
|
291
294
|
}
|
@@ -295,6 +298,14 @@ module Recaptcha
|
|
295
298
|
HTML
|
296
299
|
end
|
297
300
|
|
301
|
+
def self.recaptcha_execute_method_name
|
302
|
+
Recaptcha.configuration.enterprise ? "grecaptcha.enterprise.execute" : "grecaptcha.execute"
|
303
|
+
end
|
304
|
+
|
305
|
+
def self.recaptcha_ready_method_name
|
306
|
+
Recaptcha.configuration.enterprise ? "grecaptcha.enterprise.ready" : "grecaptcha.ready"
|
307
|
+
end
|
308
|
+
|
298
309
|
private_class_method def self.default_callback_required?(options)
|
299
310
|
options[:callback] == 'invisibleRecaptchaSubmit' &&
|
300
311
|
!Recaptcha.skip_env?(options[:env]) &&
|
data/lib/recaptcha/version.rb
CHANGED
data/lib/recaptcha.rb
CHANGED
@@ -14,7 +14,6 @@ end
|
|
14
14
|
|
15
15
|
module Recaptcha
|
16
16
|
DEFAULT_TIMEOUT = 3
|
17
|
-
RESPONSE_LIMIT = 4000
|
18
17
|
|
19
18
|
class RecaptchaError < StandardError
|
20
19
|
end
|
@@ -56,24 +55,60 @@ module Recaptcha
|
|
56
55
|
end
|
57
56
|
|
58
57
|
def self.invalid_response?(resp)
|
59
|
-
resp.empty? || resp.length >
|
58
|
+
resp.empty? || resp.length > configuration.response_limit
|
60
59
|
end
|
61
60
|
|
62
61
|
def self.verify_via_api_call(response, options)
|
62
|
+
if Recaptcha.configuration.enterprise
|
63
|
+
verify_via_api_call_enterprise(response, options)
|
64
|
+
else
|
65
|
+
verify_via_api_call_free(response, options)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def self.verify_via_api_call_enterprise(response, options)
|
70
|
+
site_key = options.fetch(:site_key) { configuration.site_key! }
|
71
|
+
api_key = options.fetch(:enterprise_api_key) { configuration.enterprise_api_key! }
|
72
|
+
project_id = options.fetch(:enterprise_project_id) { configuration.enterprise_project_id! }
|
73
|
+
|
74
|
+
query_params = { 'key' => api_key }
|
75
|
+
body = { 'event' => { 'token' => response, 'siteKey' => site_key } }
|
76
|
+
body['event']['expectedAction'] = options[:action] if options.key?(:action)
|
77
|
+
body['event']['userIpAddress'] = options[:remote_ip] if options.key?(:remote_ip)
|
78
|
+
|
79
|
+
reply = api_verification_enterprise(query_params, body, project_id, timeout: options[:timeout])
|
80
|
+
score = reply.dig('riskAnalysis', 'score')
|
81
|
+
token_properties = reply['tokenProperties']
|
82
|
+
success = !token_properties.nil? &&
|
83
|
+
token_properties['valid'].to_s == 'true' &&
|
84
|
+
hostname_valid?(token_properties['hostname'], options[:hostname]) &&
|
85
|
+
action_valid?(token_properties['action'], options[:action]) &&
|
86
|
+
score_above_threshold?(score, options[:minimum_score]) &&
|
87
|
+
score_below_threshold?(score, options[:maximum_score])
|
88
|
+
|
89
|
+
if options[:with_reply] == true
|
90
|
+
[success, reply]
|
91
|
+
else
|
92
|
+
success
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def self.verify_via_api_call_free(response, options)
|
63
97
|
secret_key = options.fetch(:secret_key) { configuration.secret_key! }
|
64
98
|
verify_hash = { 'secret' => secret_key, 'response' => response }
|
65
99
|
verify_hash['remoteip'] = options[:remote_ip] if options.key?(:remote_ip)
|
66
100
|
|
67
|
-
reply =
|
101
|
+
reply = api_verification_free(verify_hash, timeout: options[:timeout])
|
68
102
|
success = reply['success'].to_s == 'true' &&
|
69
103
|
hostname_valid?(reply['hostname'], options[:hostname]) &&
|
70
104
|
action_valid?(reply['action'], options[:action]) &&
|
71
|
-
score_above_threshold?(reply['score'], options[:minimum_score])
|
105
|
+
score_above_threshold?(reply['score'], options[:minimum_score]) &&
|
106
|
+
score_below_threshold?(reply['score'], options[:maximum_score])
|
72
107
|
|
73
108
|
if options[:with_reply] == true
|
74
|
-
|
109
|
+
[success, reply]
|
75
110
|
else
|
76
|
-
|
111
|
+
success
|
77
112
|
end
|
78
113
|
end
|
79
114
|
|
@@ -94,18 +129,15 @@ module Recaptcha
|
|
94
129
|
end
|
95
130
|
end
|
96
131
|
|
97
|
-
# Returns true iff score is greater or equal to (>=) minimum_score, or if no minimum_score was specified
|
98
132
|
def self.score_above_threshold?(score, minimum_score)
|
99
|
-
|
100
|
-
|
133
|
+
!minimum_score || (score && score >= minimum_score)
|
134
|
+
end
|
101
135
|
|
102
|
-
|
103
|
-
|
104
|
-
else score >= minimum_score
|
105
|
-
end
|
136
|
+
def self.score_below_threshold?(score, maximum_score)
|
137
|
+
!maximum_score || (score && score <= maximum_score)
|
106
138
|
end
|
107
139
|
|
108
|
-
def self.
|
140
|
+
def self.http_client_for(uri:, timeout: nil)
|
109
141
|
timeout ||= DEFAULT_TIMEOUT
|
110
142
|
http = if configuration.proxy
|
111
143
|
proxy_server = URI.parse(configuration.proxy)
|
@@ -113,12 +145,28 @@ module Recaptcha
|
|
113
145
|
else
|
114
146
|
Net::HTTP
|
115
147
|
end
|
148
|
+
instance = http.new(uri.host, uri.port)
|
149
|
+
instance.read_timeout = instance.open_timeout = timeout
|
150
|
+
instance.use_ssl = true if uri.port == 443
|
151
|
+
|
152
|
+
instance
|
153
|
+
end
|
154
|
+
|
155
|
+
def self.api_verification_free(verify_hash, timeout: nil)
|
116
156
|
query = URI.encode_www_form(verify_hash)
|
117
|
-
uri = URI.parse(configuration.verify_url
|
118
|
-
http_instance =
|
119
|
-
http_instance.read_timeout = http_instance.open_timeout = timeout
|
120
|
-
http_instance.use_ssl = true if uri.port == 443
|
157
|
+
uri = URI.parse("#{configuration.verify_url}?#{query}")
|
158
|
+
http_instance = http_client_for(uri: uri, timeout: timeout)
|
121
159
|
request = Net::HTTP::Get.new(uri.request_uri)
|
122
160
|
JSON.parse(http_instance.request(request).body)
|
123
161
|
end
|
162
|
+
|
163
|
+
def self.api_verification_enterprise(query_params, body, project_id, timeout: nil)
|
164
|
+
query = URI.encode_www_form(query_params)
|
165
|
+
uri = URI.parse("#{configuration.verify_url}/#{project_id}/assessments?#{query}")
|
166
|
+
http_instance = http_client_for(uri: uri, timeout: timeout)
|
167
|
+
request = Net::HTTP::Post.new(uri.request_uri)
|
168
|
+
request['Content-Type'] = 'application/json; charset=utf-8'
|
169
|
+
request.body = JSON.generate(body)
|
170
|
+
JSON.parse(http_instance.request(request).body)
|
171
|
+
end
|
124
172
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: recaptcha
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 5.
|
4
|
+
version: 5.12.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jason L Perry
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2022-09-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: json
|
@@ -155,12 +155,15 @@ files:
|
|
155
155
|
- lib/recaptcha/railtie.rb
|
156
156
|
- lib/recaptcha/version.rb
|
157
157
|
- rails/locales/en.yml
|
158
|
+
- rails/locales/fr.yml
|
159
|
+
- rails/locales/ja.yml
|
160
|
+
- rails/locales/nl.yml
|
158
161
|
homepage: http://github.com/ambethia/recaptcha
|
159
162
|
licenses:
|
160
163
|
- MIT
|
161
164
|
metadata:
|
162
165
|
source_code_uri: https://github.com/ambethia/recaptcha
|
163
|
-
post_install_message:
|
166
|
+
post_install_message:
|
164
167
|
rdoc_options: []
|
165
168
|
require_paths:
|
166
169
|
- lib
|
@@ -168,15 +171,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
168
171
|
requirements:
|
169
172
|
- - ">="
|
170
173
|
- !ruby/object:Gem::Version
|
171
|
-
version: 2.
|
174
|
+
version: 2.7.0
|
172
175
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
173
176
|
requirements:
|
174
177
|
- - ">="
|
175
178
|
- !ruby/object:Gem::Version
|
176
179
|
version: '0'
|
177
180
|
requirements: []
|
178
|
-
rubygems_version: 3.
|
179
|
-
signing_key:
|
181
|
+
rubygems_version: 3.3.3
|
182
|
+
signing_key:
|
180
183
|
specification_version: 4
|
181
184
|
summary: Helpers for the reCAPTCHA API
|
182
185
|
test_files: []
|