recaptcha 5.18.0 → 5.20.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: 41990aba0d4786ebf87da392ac025d8725d5ca5f30c9e1018b0cf2197f8efada
4
- data.tar.gz: 34b8d6b1dc5e34d9349c64f3a2d2c77f0cc67b2570077788e9e128d2a855a927
3
+ metadata.gz: 995e891c595981b495f6911abe80bdc9de1df1f2d445e12cc9129f4fcc5d523d
4
+ data.tar.gz: b160af36ee62814a45c2c3e96a0e6e268521b6f0eacc7dee2bcc130068384dd9
5
5
  SHA512:
6
- metadata.gz: b3d440a27b41351c81ca9ad94368ea5485d1a1bed05092c011bbfe358cb8c829e89bc295a52a0e323333fc1a3135384149bd3ec13f0cd4c6a8fcc09184a3d4d4
7
- data.tar.gz: f176ce1beb9764f342dedc8c36cbc40b248ae230c758f2df3053c891c5616b4898e435fde8251da03ff5e690b535bef64bdc7e2257aadc8755f7f0e4efbddbfd
6
+ metadata.gz: fa21ffc606ec9e389970f607aaab34449a21454c4ce5044092ae773dab3a2f622b097504969dd4ec3e532222bed29b8185936f4def1ec17886201ff1869106cd
7
+ data.tar.gz: 7dfe2542b8cda9555c578c4c9c1977d5ddc6ac6a8955b19f0b5abb96e5946cb4d7b25627a107f8bd2aa60984cb6babd0594fc1ae6e856f66ca500265f92be484
data/CHANGELOG.md CHANGED
@@ -1,4 +1,12 @@
1
1
  ## Next
2
+
3
+ ## 5.20.0
4
+ * turn recpatch reply into a object with logic
5
+
6
+ ## 5.19.0
7
+ * require a minimum lenght of 100 for responses, configured via response_minimum
8
+
9
+ ## 5.18.0
2
10
  * Add key setup to v3 example in README
3
11
  * 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
12
  * Update to latest version of rubocop
data/README.md CHANGED
@@ -589,6 +589,7 @@ Recaptcha.configure do |config|
589
589
  config.verify_url = 'https://hcaptcha.com/siteverify'
590
590
  config.api_server_url = 'https://hcaptcha.com/1/api.js'
591
591
  config.response_limit = 100000
592
+ config.response_minimum = 100
592
593
  end
593
594
  ```
594
595
 
@@ -31,16 +31,18 @@ module Recaptcha
31
31
 
32
32
  success, @_recaptcha_reply =
33
33
  Recaptcha.verify_via_api_call(recaptcha_response, options.merge(with_reply: true))
34
+
34
35
  unless success
35
- @_recaptcha_failure_reason = if @_recaptcha_reply["score"] &&
36
- @_recaptcha_reply["score"].to_f < options[:minimum_score].to_f
37
- "Recaptcha score didn't exceed the minimum: #{@_recaptcha_reply["score"]} < #{options[:minimum_score]}."
38
- elsif @_recaptcha_reply['error-codes']
39
- "Recaptcha api call returned with error-codes: #{@_recaptcha_reply['error-codes']}."
40
- else
41
- "Recaptcha failure after api call. Api reply: #{@_recaptcha_reply}."
42
- end
36
+ @_recaptcha_failure_reason =
37
+ if @_recaptcha_reply.score && @_recaptcha_reply.score.to_f < options[:minimum_score].to_f
38
+ "Recaptcha score didn't exceed the minimum: #{@_recaptcha_reply.score} < #{options[:minimum_score]}."
39
+ elsif @_recaptcha_reply.error_codes.any?
40
+ "Recaptcha api call returned with error-codes: #{@_recaptcha_reply.error_codes}."
41
+ else
42
+ "Recaptcha failure after api call. Api reply: #{@_recaptcha_reply}."
43
+ end
43
44
  end
45
+
44
46
  success
45
47
  end
46
48
 
@@ -37,8 +37,10 @@ module Recaptcha
37
37
  'enterprise_verify_url' => 'https://recaptchaenterprise.googleapis.com/v1/projects'
38
38
  }.freeze
39
39
 
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
40
+ attr_accessor(
41
+ :default_env, :skip_verify_env, :proxy, :secret_key, :site_key, :handle_timeouts_gracefully,
42
+ :hostname, :enterprise, :enterprise_api_key, :enterprise_project_id, :response_limit, :response_minimum
43
+ )
42
44
  attr_writer :api_server_url, :verify_url
43
45
 
44
46
  def initialize # :nodoc:
@@ -57,6 +59,7 @@ module Recaptcha
57
59
  @api_server_url = nil
58
60
 
59
61
  @response_limit = 4000
62
+ @response_minimum = 100
60
63
  end
61
64
 
62
65
  def secret_key!
@@ -0,0 +1,114 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Recaptcha
4
+ class Reply
5
+ def initialize(raw_reply, enterprise:)
6
+ @raw_reply = raw_reply
7
+ @enterprise = enterprise
8
+ end
9
+
10
+ def success?(options = {})
11
+ success.to_s == 'true' &&
12
+ hostname_valid?(options[:hostname]) &&
13
+ action_valid?(options[:action]) &&
14
+ score_above_threshold?(options[:minimum_score]) &&
15
+ score_below_threshold?(options[:maximum_score])
16
+ end
17
+
18
+ def token_properties
19
+ @raw_reply['tokenProperties'] if enterprise?
20
+ end
21
+
22
+ def success
23
+ if enterprise?
24
+ token_properties&.dig('valid')
25
+ else
26
+ @raw_reply['success']
27
+ end
28
+ end
29
+
30
+ def hostname
31
+ if enterprise?
32
+ token_properties&.dig('hostname')
33
+ else
34
+ @raw_reply['hostname']
35
+ end
36
+ end
37
+
38
+ def action
39
+ if enterprise?
40
+ token_properties&.dig('action')
41
+ else
42
+ @raw_reply['action']
43
+ end
44
+ end
45
+
46
+ def score
47
+ if enterprise?
48
+ @raw_reply.dig('riskAnalysis', 'score')
49
+ else
50
+ @raw_reply['score'] unless enterprise?
51
+ end
52
+ end
53
+
54
+ def error_codes
55
+ if enterprise?
56
+ []
57
+ else
58
+ @raw_reply['error-codes'] || []
59
+ end
60
+ end
61
+
62
+ def challenge_ts
63
+ return @raw_reply['challenge_ts'] unless enterprise?
64
+
65
+ token_properties&.dig('createTime')
66
+ end
67
+
68
+ def hostname_valid?(validation)
69
+ validation ||= Recaptcha.configuration.hostname
70
+
71
+ case validation
72
+ when nil, FalseClass
73
+ true
74
+ when String
75
+ validation == hostname
76
+ else
77
+ validation.call(hostname)
78
+ end
79
+ end
80
+
81
+ def action_valid?(expected_action)
82
+ case expected_action
83
+ when nil, FalseClass
84
+ true
85
+ else
86
+ action == expected_action.to_s
87
+ end
88
+ end
89
+
90
+ def score_above_threshold?(minimum_score)
91
+ !minimum_score || (score && score >= minimum_score)
92
+ end
93
+
94
+ def score_below_threshold?(maximum_score)
95
+ !maximum_score || (score && score <= maximum_score)
96
+ end
97
+
98
+ def enterprise?
99
+ @enterprise
100
+ end
101
+
102
+ def to_h
103
+ @raw_reply
104
+ end
105
+
106
+ def to_s
107
+ @raw_reply.to_s
108
+ end
109
+
110
+ def to_json(*args)
111
+ @raw_reply.to_json(*args)
112
+ end
113
+ end
114
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Recaptcha
4
- VERSION = '5.18.0'
4
+ VERSION = '5.20.0'
5
5
  end
data/lib/recaptcha.rb CHANGED
@@ -6,6 +6,7 @@ require 'uri'
6
6
 
7
7
  require 'recaptcha/configuration'
8
8
  require 'recaptcha/helpers'
9
+ require 'recaptcha/reply'
9
10
  require 'recaptcha/adapters/controller_methods'
10
11
  require 'recaptcha/adapters/view_methods'
11
12
  if defined?(Rails)
@@ -55,7 +56,7 @@ module Recaptcha
55
56
  end
56
57
 
57
58
  def self.invalid_response?(resp)
58
- resp.empty? || resp.length > configuration.response_limit
59
+ resp.empty? || resp.length > configuration.response_limit || resp.length < configuration.response_minimum
59
60
  end
60
61
 
61
62
  def self.verify_via_api_call(response, options)
@@ -76,21 +77,10 @@ module Recaptcha
76
77
  body['event']['expectedAction'] = options[:action] if options.key?(:action)
77
78
  body['event']['userIpAddress'] = options[:remote_ip] if options.key?(:remote_ip)
78
79
 
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
80
+ raw_reply = api_verification_enterprise(query_params, body, project_id, timeout: options[:timeout])
81
+ reply = Reply.new(raw_reply, enterprise: true)
82
+ result = reply.success?(options)
83
+ options[:with_reply] == true ? [result, reply] : result
94
84
  end
95
85
 
96
86
  def self.verify_via_api_call_free(response, options)
@@ -98,43 +88,10 @@ module Recaptcha
98
88
  verify_hash = { 'secret' => secret_key, 'response' => response }
99
89
  verify_hash['remoteip'] = options[:remote_ip] if options.key?(:remote_ip)
100
90
 
101
- reply = api_verification_free(verify_hash, timeout: options[:timeout], json: options[:json])
102
- success = reply['success'].to_s == 'true' &&
103
- hostname_valid?(reply['hostname'], options[:hostname]) &&
104
- action_valid?(reply['action'], options[:action]) &&
105
- score_above_threshold?(reply['score'], options[:minimum_score]) &&
106
- score_below_threshold?(reply['score'], options[:maximum_score])
107
-
108
- if options[:with_reply] == true
109
- [success, reply]
110
- else
111
- success
112
- end
113
- end
114
-
115
- def self.hostname_valid?(hostname, validation)
116
- validation ||= configuration.hostname
117
-
118
- case validation
119
- when nil, FalseClass then true
120
- when String then validation == hostname
121
- else validation.call(hostname)
122
- end
123
- end
124
-
125
- def self.action_valid?(action, expected_action)
126
- case expected_action
127
- when nil, FalseClass then true
128
- else action == expected_action.to_s
129
- end
130
- end
131
-
132
- def self.score_above_threshold?(score, minimum_score)
133
- !minimum_score || (score && score >= minimum_score)
134
- end
135
-
136
- def self.score_below_threshold?(score, maximum_score)
137
- !maximum_score || (score && score <= maximum_score)
91
+ raw_reply = api_verification_free(verify_hash, timeout: options[:timeout], json: options[:json])
92
+ reply = Reply.new(raw_reply, enterprise: false)
93
+ result = reply.success?(options)
94
+ options[:with_reply] == true ? [result, reply] : result
138
95
  end
139
96
 
140
97
  def self.http_client_for(uri:, timeout: nil)
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.18.0
4
+ version: 5.20.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: 2024-12-08 00:00:00.000000000 Z
11
+ date: 2025-07-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: mocha
@@ -139,6 +139,7 @@ files:
139
139
  - lib/recaptcha/helpers.rb
140
140
  - lib/recaptcha/rails.rb
141
141
  - lib/recaptcha/railtie.rb
142
+ - lib/recaptcha/reply.rb
142
143
  - lib/recaptcha/version.rb
143
144
  - rails/locales/de.yml
144
145
  - rails/locales/en.yml