recaptcha 5.12.0 → 5.17.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4696b1987122715318c6ea1ce3ce1930dfe1cf9aad40913e74617f746db4176b
4
- data.tar.gz: ab251d09e9ad5f9596dc8a8a0d70d9f108dbfbafaaff92fbfe72758877f84354
3
+ metadata.gz: 52997b101110f7111f307af5bc5a66ce28d71cc74af339a267d55f8fe4bdeb1d
4
+ data.tar.gz: 5b62b2bf9740563b8f4e8edc9e3fdd90303daa4e8ea205cdb94e39a842dba770
5
5
  SHA512:
6
- metadata.gz: 764ffc3bad21f61f1b6d87212af60fcfa2533fe643de904a127f4ae47227aec45965a9d118429ea262e638e9021b62387716e8e96c3748ba71cb21cf96a7edc0
7
- data.tar.gz: 5a61522e047c0a2fe8da6a6facdd4228dbd322904144f15646bf5a8ea7adbff51fbf6ce7b880a406a01192fc3adf9128a875611307b352a19f2501d72ff309a9
6
+ metadata.gz: 6fe87d18b768bcdd4bf50f6a8ba5248856bcf54d7dd5afb5c8f8f9da4003902f7078782c8f75c685874f4d1427deb1348c48d6fe001bd78aa733af0acf24060e
7
+ data.tar.gz: a0190cbff7d1e7f0d8b312ad2d6fc9e0a88336db8f8d2dea8ac9a7d678fd35faac9ec3ca7ba029f22b5b1d48614797caef9b56443e10837af1a2d5106fe7fccb
data/CHANGELOG.md CHANGED
@@ -1,8 +1,42 @@
1
1
  ## Next
2
+ * Add key setup to v3 example in README
3
+ * Remove unnecessary id from textarea - This was unused and may cause accessability concerns if there is more than one recaptcha on the page due to multiple elements with the same id
4
+ * Update to latest version of rubocop
5
+ * Drop support for Ruby 2.7; add Ruby 3.3
6
+ * Add i18n: de, es, it, pt, pt-BR
2
7
 
3
- * Added Dutch locale
8
+ ## 5.16.0
9
+ * Allow usage of `options[:turbo]` as well as `options[:turbolinks]` for `recaptcha_v3`
10
+
11
+ ## 5.15.0
12
+ * Add 3.2 to the list of Ruby CI versions
13
+ * Add ability to submit verify_recaptcha via POST with JSON Body with `options[:json] = true`
14
+
15
+ ## 5.14.0
16
+ * drop json dependency
17
+
18
+ ## 5.13.1
19
+ * Permit actions as symbol
20
+
21
+ ## 5.13.0
22
+ * Added option to ignore_no_element.
23
+
24
+ ## 5.12.3
25
+ * Remove score fallback for enterprise
26
+ * Update enterprise tests to v1 assessment schema
27
+
28
+ ## 5.12.2
29
+ * Fix minimum score for enterprise
30
+
31
+ ## 5.12.1
32
+ * Fix Japanese locale
33
+
34
+ ## 5.12.0
4
35
  * Added Japanese locale
5
36
 
37
+ ## 5.11.0
38
+ * Added Dutch locale
39
+
6
40
  ## 5.10.1
7
41
  * Fix enterprise_verify_url #415
8
42
 
data/README.md CHANGED
@@ -78,6 +78,10 @@ export RECAPTCHA_ENTERPRISE_API_KEY = 'AIzvFyE3TU-g4K_Kozr9F1smEzZSGBVOfLKyup
78
78
  export RECAPTCHA_ENTERPRISE_PROJECT_ID = 'my-project'
79
79
  ```
80
80
 
81
+ _note:_ you'll still have to provide `RECAPTCHA_SITE_KEY`, which will hold the value of your enterprise recaptcha key id. You will not need to provide a `RECAPTCHA_SECRET_KEY`, however.
82
+
83
+ `RECAPTCHA_ENTERPRISE_API_KEY` is the enterprise key of your Google Cloud Project, which you can generate here: https://console.cloud.google.com/apis/credentials.
84
+
81
85
  Add `recaptcha_tags` to the forms you want to protect:
82
86
 
83
87
  ```erb
@@ -181,6 +185,7 @@ Some of the options available:
181
185
  | `:response` | Custom response parameter. (default: `params['g-recaptcha-response-data']`)
182
186
  | `: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
187
  | `:env` | Current environment. The request to verify will be skipped if the environment is specified in configuration under `skip_verify_env`
188
+ | `:json` | Boolean; defaults to false; if true, will submit the verification request by POST with the request data in JSON
184
189
 
185
190
 
186
191
  ### `invisible_recaptcha_tags`
@@ -304,6 +309,14 @@ With v3, you can let all users log in without any intervention at all if their s
304
309
  threshold, and only show a v2 checkbox recaptcha challenge (fall back to v2) if it is below the
305
310
  threshold:
306
311
 
312
+ This example sets v2 keys through environment variables. For more information on how to set up keys, please refer to the [documentation here](#alternative-api-key-setup).
313
+
314
+ ```bash
315
+ # .env
316
+ RECAPTCHA_SITE_KEY=6Lc6BAAAAAAAAChqRbQZcn_yyyyyyyyyyyyyyyyy
317
+ RECAPTCHA_SECRET_KEY=6Lc6BAAAAAAAAKN3DRm6VA_xxxxxxxxxxxxxxxxx
318
+ ```
319
+
307
320
  ```erb
308
321
 
309
322
  <% if @show_checkbox_recaptcha %>
@@ -418,7 +431,7 @@ but only accepts the following options:
418
431
  | Option | Description |
419
432
  |---------------------|-------------|
420
433
  | `:site_key` | Override site API key |
421
- | `:action` | The name of the [reCAPTCHA action](https://developers.google.com/recaptcha/docs/v3#actions). Actions may only contain alphanumeric characters and slashes, and must not be user-specific. |
434
+ | `:action` | The name of the [reCAPTCHA action](https://developers.google.com/recaptcha/docs/v3#actions). Actions are not case-sensitive and may only contain alphanumeric characters, slashes, and underscores, and must not be user-specific. |
422
435
  | `:nonce` | Optional. Sets nonce attribute for script. Can be generated via `SecureRandom.base64(32)`. (default: `nil`) |
423
436
  | `:callback` | Name of callback function to call with the token. When `element` is `:input`, this defaults to a function named `setInputWithRecaptchaResponseTokenFor#{sanitize_action(action)}` that sets the value of the hidden input to the token. |
424
437
  | `:id` | Specify a unique `id` attribute for the `<input>` element if using `element: :input`. (default: `"g-recaptcha-response-data-"` + `action`) |
@@ -426,7 +439,9 @@ but only accepts the following options:
426
439
  | `:script` | Same as setting both `:inline_script` and `:external_script`. (default: `true`). |
427
440
  | `:inline_script` | If `true`, adds an inline script tag that calls `grecaptcha.execute` for the given `site_key` and `action` and calls the `callback` with the resulting response token. Pass `false` if you want to handle calling `grecaptcha.execute` yourself. (default: `true`) |
428
441
  | `:element` | The element to render, if any (default: `:input`)<br/>`:input`: Renders a hidden `<input type="hidden">` tag. The value of this will be set to the response token by the default `setInputWithRecaptchaResponseTokenFor{action}` callback.<br/>`false`: Doesn't render any tag. You'll have to add a custom callback that does something with the token. |
429
- | `:turbolinks` | If `true`, calls the js function which executes reCAPTCHA after all the dependencies have been loaded. This cannot be used with the js param `:onload`. This makes reCAPTCHAv3 usable with turbolinks. |
442
+ | `:turbo` | If `true`, calls the js function which executes reCAPTCHA after all the dependencies have been loaded. This cannot be used with the js param `:onload`. This makes reCAPTCHAv3 usable with turbo. |
443
+ | `:turbolinks` | Alias of `:turbo`. Will be deprecated soon. |
444
+ | `:ignore_no_element` | If `true`, adds null element checker for forms that can be removed from the page by javascript like modals with forms. (default: true) |
430
445
 
431
446
  [JavaScript resource (api.js) parameters](https://developers.google.com/recaptcha/docs/invisible#js_param):
432
447
 
@@ -12,10 +12,11 @@ module Recaptcha
12
12
  action = options.delete(:action) || raise(Recaptcha::RecaptchaError, 'action is required')
13
13
  id = options.delete(:id) || "g-recaptcha-response-data-#{dasherize_action(action)}"
14
14
  name = options.delete(:name) || "g-recaptcha-response-data[#{action}]"
15
- turbolinks = options.delete(:turbolinks)
15
+ turbo = options.delete(:turbo) || options.delete(:turbolinks)
16
16
  options[:render] = site_key
17
17
  options[:script_async] ||= false
18
18
  options[:script_defer] ||= false
19
+ options[:ignore_no_element] = options.key?(:ignore_no_element) ? options[:ignore_no_element] : true
19
20
  element = options.delete(:element)
20
21
  element = element == false ? false : :input
21
22
  if element == :input
@@ -23,11 +24,11 @@ module Recaptcha
23
24
  end
24
25
  options[:class] = "g-recaptcha-response #{options[:class]}"
25
26
 
26
- if turbolinks
27
+ if turbo
27
28
  options[:onload] = recaptcha_v3_execute_function_name(action)
28
29
  end
29
30
  html, tag_attributes = components(options)
30
- if turbolinks
31
+ if turbo
31
32
  html << recaptcha_v3_onload_script(site_key, action, callback, id, options)
32
33
  elsif recaptcha_v3_inline_script?(options)
33
34
  html << recaptcha_v3_inline_script(site_key, action, callback, id, options)
@@ -73,7 +74,7 @@ module Recaptcha
73
74
  <div style="width: 300px; height: 60px; border-style: none;
74
75
  bottom: 12px; left: 25px; margin: 0px; padding: 0px; right: 25px;
75
76
  background: #f9f9f9; border: 1px solid #c1c1c1; border-radius: 3px;">
76
- <textarea id="g-recaptcha-response" name="g-recaptcha-response"
77
+ <textarea name="g-recaptcha-response"
77
78
  class="g-recaptcha-response"
78
79
  style="width: 250px; height: 40px; border: 1px solid #c1c1c1;
79
80
  margin: 10px 25px; padding: 0px; resize: none;">
@@ -138,6 +139,7 @@ module Recaptcha
138
139
  nonce = options.delete(:nonce)
139
140
  skip_script = (options.delete(:script) == false) || (options.delete(:external_script) == false)
140
141
  ui = options.delete(:ui)
142
+ options.delete(:ignore_no_element)
141
143
 
142
144
  data_attribute_keys = [:badge, :theme, :type, :callback, :expired_callback, :error_callback, :size]
143
145
  data_attribute_keys << :tabindex unless ui == :button
@@ -206,7 +208,7 @@ module Recaptcha
206
208
  })
207
209
  };
208
210
 
209
- #{recaptcha_v3_define_default_callback(callback) if recaptcha_v3_define_default_callback?(callback, action, options)}
211
+ #{recaptcha_v3_define_default_callback(callback, options) if recaptcha_v3_define_default_callback?(callback, action, options)}
210
212
  </script>
211
213
  HTML
212
214
  end
@@ -224,7 +226,7 @@ module Recaptcha
224
226
  });
225
227
  });
226
228
  };
227
- #{recaptcha_v3_define_default_callback(callback) if recaptcha_v3_define_default_callback?(callback, action, options)}
229
+ #{recaptcha_v3_define_default_callback(callback, options) if recaptcha_v3_define_default_callback?(callback, action, options)}
228
230
  </script>
229
231
  HTML
230
232
  end
@@ -235,12 +237,12 @@ module Recaptcha
235
237
  options[:inline_script] != false
236
238
  end
237
239
 
238
- private_class_method def self.recaptcha_v3_define_default_callback(callback)
240
+ private_class_method def self.recaptcha_v3_define_default_callback(callback, options)
239
241
  <<-HTML
240
- var #{callback} = function(id, token) {
241
- var element = document.getElementById(id);
242
- element.value = token;
243
- }
242
+ var #{callback} = function(id, token) {
243
+ var element = document.getElementById(id);
244
+ #{element_check_condition(options)} element.value = token;
245
+ }
244
246
  HTML
245
247
  end
246
248
 
@@ -328,5 +330,9 @@ module Recaptcha
328
330
  private_class_method def self.hash_to_query(hash)
329
331
  hash.delete_if { |_, val| val.nil? || val.empty? }.to_a.map { |pair| pair.join('=') }.join('&')
330
332
  end
333
+
334
+ private_class_method def self.element_check_condition(options)
335
+ options[:ignore_no_element] ? "if (element !== null)" : ""
336
+ end
331
337
  end
332
338
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Recaptcha
4
- VERSION = '5.12.0'
4
+ VERSION = '5.17.0'
5
5
  end
data/lib/recaptcha.rb CHANGED
@@ -77,13 +77,14 @@ module Recaptcha
77
77
  body['event']['userIpAddress'] = options[:remote_ip] if options.key?(:remote_ip)
78
78
 
79
79
  reply = api_verification_enterprise(query_params, body, project_id, timeout: options[:timeout])
80
+ score = reply.dig('riskAnalysis', 'score')
80
81
  token_properties = reply['tokenProperties']
81
82
  success = !token_properties.nil? &&
82
83
  token_properties['valid'].to_s == 'true' &&
83
84
  hostname_valid?(token_properties['hostname'], options[:hostname]) &&
84
85
  action_valid?(token_properties['action'], options[:action]) &&
85
- score_above_threshold?(reply['score'], options[:minimum_score]) &&
86
- score_below_threshold?(reply['score'], options[:maximum_score])
86
+ score_above_threshold?(score, options[:minimum_score]) &&
87
+ score_below_threshold?(score, options[:maximum_score])
87
88
 
88
89
  if options[:with_reply] == true
89
90
  [success, reply]
@@ -97,7 +98,7 @@ module Recaptcha
97
98
  verify_hash = { 'secret' => secret_key, 'response' => response }
98
99
  verify_hash['remoteip'] = options[:remote_ip] if options.key?(:remote_ip)
99
100
 
100
- reply = api_verification_free(verify_hash, timeout: options[:timeout])
101
+ reply = api_verification_free(verify_hash, timeout: options[:timeout], json: options[:json])
101
102
  success = reply['success'].to_s == 'true' &&
102
103
  hostname_valid?(reply['hostname'], options[:hostname]) &&
103
104
  action_valid?(reply['action'], options[:action]) &&
@@ -124,7 +125,7 @@ module Recaptcha
124
125
  def self.action_valid?(action, expected_action)
125
126
  case expected_action
126
127
  when nil, FalseClass then true
127
- else action == expected_action
128
+ else action == expected_action.to_s
128
129
  end
129
130
  end
130
131
 
@@ -151,11 +152,18 @@ module Recaptcha
151
152
  instance
152
153
  end
153
154
 
154
- def self.api_verification_free(verify_hash, timeout: nil)
155
- query = URI.encode_www_form(verify_hash)
156
- uri = URI.parse("#{configuration.verify_url}?#{query}")
155
+ def self.api_verification_free(verify_hash, timeout: nil, json: false)
156
+ if json
157
+ uri = URI.parse(configuration.verify_url)
158
+ request = Net::HTTP::Post.new(uri.request_uri)
159
+ request['Content-Type'] = 'application/json; charset=utf-8'
160
+ request.body = JSON.generate(verify_hash)
161
+ else
162
+ query = URI.encode_www_form(verify_hash)
163
+ uri = URI.parse("#{configuration.verify_url}?#{query}")
164
+ request = Net::HTTP::Get.new(uri.request_uri)
165
+ end
157
166
  http_instance = http_client_for(uri: uri, timeout: timeout)
158
- request = Net::HTTP::Get.new(uri.request_uri)
159
167
  JSON.parse(http_instance.request(request).body)
160
168
  end
161
169
 
@@ -0,0 +1,5 @@
1
+ de:
2
+ recaptcha:
3
+ errors:
4
+ verification_failed: Die reCAPTCHA-Überprüfung ist fehlgeschlagen, bitte versuchen Sie es erneut.
5
+ recaptcha_unreachable: Oops, wir konnten Ihre reCAPTCHA-Antwort nicht validieren. Bitte versuchen Sie es erneut.
@@ -0,0 +1,5 @@
1
+ es:
2
+ recaptcha:
3
+ errors:
4
+ verification_failed: La verificación de reCAPTCHA falló, por favor intente de nuevo.
5
+ recaptcha_unreachable: Ups, no pudimos validar su respuesta de reCAPTCHA. Por favor intente de nuevo.
@@ -0,0 +1,5 @@
1
+ it:
2
+ recaptcha:
3
+ errors:
4
+ verification_failed: La verifica reCAPTCHA non è riuscita, si prega di riprovare.
5
+ recaptcha_unreachable: Ops, non siamo riusciti a convalidare la tua risposta reCAPTCHA. Per favore riprova.
data/rails/locales/ja.yml CHANGED
@@ -1,4 +1,4 @@
1
- en:
1
+ ja:
2
2
  recaptcha:
3
3
  errors:
4
4
  verification_failed: reCAPTCHA認証に失敗しました。もう一度お試しください。
@@ -0,0 +1,5 @@
1
+ pt-BR:
2
+ recaptcha:
3
+ errors:
4
+ verification_failed: A verificação do reCAPTCHA falhou, por favor, tente novamente.
5
+ recaptcha_unreachable: Oops, não conseguimos validar sua resposta do reCAPTCHA. Por favor, tente novamente.
@@ -0,0 +1,5 @@
1
+ pt:
2
+ recaptcha:
3
+ errors:
4
+ verification_failed: A verificação do reCAPTCHA falhou, por favor, tente novamente.
5
+ recaptcha_unreachable: Oops, não conseguimos validar sua resposta do reCAPTCHA. Por favor, tente novamente.
metadata CHANGED
@@ -1,29 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: recaptcha
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.12.0
4
+ version: 5.17.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jason L Perry
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-08-28 00:00:00.000000000 Z
11
+ date: 2024-06-09 00:00:00.000000000 Z
12
12
  dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: json
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - ">="
18
- - !ruby/object:Gem::Version
19
- version: '0'
20
- type: :runtime
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - ">="
25
- - !ruby/object:Gem::Version
26
- version: '0'
27
13
  - !ruby/object:Gem::Dependency
28
14
  name: mocha
29
15
  requirement: !ruby/object:Gem::Requirement
@@ -154,10 +140,15 @@ files:
154
140
  - lib/recaptcha/rails.rb
155
141
  - lib/recaptcha/railtie.rb
156
142
  - lib/recaptcha/version.rb
143
+ - rails/locales/de.yml
157
144
  - rails/locales/en.yml
145
+ - rails/locales/es.yml
158
146
  - rails/locales/fr.yml
147
+ - rails/locales/it.yml
159
148
  - rails/locales/ja.yml
160
149
  - rails/locales/nl.yml
150
+ - rails/locales/pt-BR.yml
151
+ - rails/locales/pt.yml
161
152
  homepage: http://github.com/ambethia/recaptcha
162
153
  licenses:
163
154
  - MIT
@@ -171,14 +162,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
171
162
  requirements:
172
163
  - - ">="
173
164
  - !ruby/object:Gem::Version
174
- version: 2.7.0
165
+ version: 3.0.0
175
166
  required_rubygems_version: !ruby/object:Gem::Requirement
176
167
  requirements:
177
168
  - - ">="
178
169
  - !ruby/object:Gem::Version
179
170
  version: '0'
180
171
  requirements: []
181
- rubygems_version: 3.3.3
172
+ rubygems_version: 3.4.10
182
173
  signing_key:
183
174
  specification_version: 4
184
175
  summary: Helpers for the reCAPTCHA API