recaptcha 5.19.0 → 5.20.1

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: 61fa7316f287cfcec8e2b06d36481f1fa596d1b629810a784fae509c55255b2f
4
- data.tar.gz: 7cf82254973204d7ac47b6bba428ff394e24c9ec5dbbb5669657b4c10b30c16b
3
+ metadata.gz: 2da8cd22c6894e6e63203ccd675457744566353eec7b26e936631d96165fe9a0
4
+ data.tar.gz: 9dcaa544b2b142aedda52b4d90c6356d3fbf9079c5bae7bd663a94b7a93a70ec
5
5
  SHA512:
6
- metadata.gz: 572402b7af72a67f76a1952cb7e5739a7cf4073ba0b510f55f8f74bc59a6e6116bad1be5ece41e20a43cb2d3c36c7ab2bca072b8a4c27b5a1db16d1007846284
7
- data.tar.gz: 021a0fa67e25aee448c66c43ae5fd3295d1472329bccdcfe4a5acf2c6fe90fd83c9cdcf8963db29816919fb6383d49c8303d41032e1af8abde3dcafbdeacc36a
6
+ metadata.gz: 300ad0687a6bbdc9fa23b11fe0843c30d0ad23c04c04398ad2c4a770aff3a24cf8ba6dd0ed29f84e1eefd4c55fb6cb6be5d1a1c3b8fd11d8d7ede2f15310f083
7
+ data.tar.gz: 102bb49ccaaf8a69a89640cb83e3a40a3f85115c0f874a6dd58d757695503ea80fff809f5d7ba271802fe2d1d961c667c42bbfa6b860848f160103f06fa97684
data/CHANGELOG.md CHANGED
@@ -1,6 +1,7 @@
1
1
  ## Next
2
2
 
3
-
3
+ ## 5.20.0
4
+ * turn recpatch reply into a object with logic
4
5
 
5
6
  ## 5.19.0
6
7
  * require a minimum lenght of 100 for responses, configured via response_minimum
@@ -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
 
@@ -0,0 +1,118 @@
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 [](key)
11
+ @raw_reply[key.to_s]
12
+ end
13
+
14
+ def success?(options = {})
15
+ success.to_s == 'true' &&
16
+ hostname_valid?(options[:hostname]) &&
17
+ action_valid?(options[:action]) &&
18
+ score_above_threshold?(options[:minimum_score]) &&
19
+ score_below_threshold?(options[:maximum_score])
20
+ end
21
+
22
+ def token_properties
23
+ @raw_reply['tokenProperties'] if enterprise?
24
+ end
25
+
26
+ def success
27
+ if enterprise?
28
+ token_properties&.dig('valid')
29
+ else
30
+ @raw_reply['success']
31
+ end
32
+ end
33
+
34
+ def hostname
35
+ if enterprise?
36
+ token_properties&.dig('hostname')
37
+ else
38
+ @raw_reply['hostname']
39
+ end
40
+ end
41
+
42
+ def action
43
+ if enterprise?
44
+ token_properties&.dig('action')
45
+ else
46
+ @raw_reply['action']
47
+ end
48
+ end
49
+
50
+ def score
51
+ if enterprise?
52
+ @raw_reply.dig('riskAnalysis', 'score')
53
+ else
54
+ @raw_reply['score'] unless enterprise?
55
+ end
56
+ end
57
+
58
+ def error_codes
59
+ if enterprise?
60
+ []
61
+ else
62
+ @raw_reply['error-codes'] || []
63
+ end
64
+ end
65
+
66
+ def challenge_ts
67
+ return @raw_reply['challenge_ts'] unless enterprise?
68
+
69
+ token_properties&.dig('createTime')
70
+ end
71
+
72
+ def hostname_valid?(validation)
73
+ validation ||= Recaptcha.configuration.hostname
74
+
75
+ case validation
76
+ when nil, FalseClass
77
+ true
78
+ when String
79
+ validation == hostname
80
+ else
81
+ validation.call(hostname)
82
+ end
83
+ end
84
+
85
+ def action_valid?(expected_action)
86
+ case expected_action
87
+ when nil, FalseClass
88
+ true
89
+ else
90
+ action == expected_action.to_s
91
+ end
92
+ end
93
+
94
+ def score_above_threshold?(minimum_score)
95
+ !minimum_score || (score && score >= minimum_score)
96
+ end
97
+
98
+ def score_below_threshold?(maximum_score)
99
+ !maximum_score || (score && score <= maximum_score)
100
+ end
101
+
102
+ def enterprise?
103
+ @enterprise
104
+ end
105
+
106
+ def to_h
107
+ @raw_reply
108
+ end
109
+
110
+ def to_s
111
+ @raw_reply.to_s
112
+ end
113
+
114
+ def to_json(*args)
115
+ @raw_reply.to_json(*args)
116
+ end
117
+ end
118
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Recaptcha
4
- VERSION = '5.19.0'
4
+ VERSION = '5.20.1'
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)
@@ -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.19.0
4
+ version: 5.20.1
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: 2025-01-14 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