cm-graphql 0.0.12 → 0.0.14
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/Gemfile +4 -0
- data/Gemfile.lock +18 -6
- data/app/graphql/cm_graphql/extensions/recaptcha_extension.rb +9 -17
- data/app/services/recaptcha_verifier.rb +62 -16
- data/cm-graphql.gemspec +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f96a2b69bc022c0d1c34f17f3446eeb9e568675a3311085850673299f538dc5d
|
|
4
|
+
data.tar.gz: 1312ee2a215b9bf4a3f8506105c41dd9a05f66b70624bbaf5f9a74aab2366030
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 3934404241a4ddb217799a54dee2da3c019941a1ee61c3313391e9cd768d836bd46d382cc01fa95b673ef12f5554a8e5cc37460f604f15e8eea52fad7c132035
|
|
7
|
+
data.tar.gz: 3e564a39769a51646162853f7ad72c7331ea86f5a079450480a1e168ceee4276c1d91aa68f1cb41cfe2dfb704af1a96f266c6ec20864ee2e25aba97ad4f6c1aa
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
cm-graphql (0.0.
|
|
4
|
+
cm-graphql (0.0.14)
|
|
5
5
|
graphiql-rails (>= 1.9)
|
|
6
6
|
graphql (>= 2.2.5)
|
|
7
7
|
graphql-rails_logger (>= 1.2.4)
|
|
@@ -53,6 +53,7 @@ GEM
|
|
|
53
53
|
connection_pool (2.5.2)
|
|
54
54
|
crass (1.0.6)
|
|
55
55
|
date (3.4.1)
|
|
56
|
+
diff-lcs (1.6.2)
|
|
56
57
|
drb (2.2.1)
|
|
57
58
|
erubi (1.13.1)
|
|
58
59
|
fiber-storage (1.0.1)
|
|
@@ -90,11 +91,7 @@ GEM
|
|
|
90
91
|
loofah (2.24.0)
|
|
91
92
|
crass (~> 1.0.2)
|
|
92
93
|
nokogiri (>= 1.12.0)
|
|
93
|
-
mini_portile2 (2.8.8)
|
|
94
94
|
minitest (5.25.5)
|
|
95
|
-
nokogiri (1.18.8)
|
|
96
|
-
mini_portile2 (~> 2.8.2)
|
|
97
|
-
racc (~> 1.4)
|
|
98
95
|
nokogiri (1.18.8-arm64-darwin)
|
|
99
96
|
racc (~> 1.4)
|
|
100
97
|
pp (0.6.2)
|
|
@@ -133,6 +130,19 @@ GEM
|
|
|
133
130
|
reline (0.6.1)
|
|
134
131
|
io-console (~> 0.5)
|
|
135
132
|
rouge (4.5.1)
|
|
133
|
+
rspec (3.13.2)
|
|
134
|
+
rspec-core (~> 3.13.0)
|
|
135
|
+
rspec-expectations (~> 3.13.0)
|
|
136
|
+
rspec-mocks (~> 3.13.0)
|
|
137
|
+
rspec-core (3.13.6)
|
|
138
|
+
rspec-support (~> 3.13.0)
|
|
139
|
+
rspec-expectations (3.13.5)
|
|
140
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
|
141
|
+
rspec-support (~> 3.13.0)
|
|
142
|
+
rspec-mocks (3.13.7)
|
|
143
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
|
144
|
+
rspec-support (~> 3.13.0)
|
|
145
|
+
rspec-support (3.13.7)
|
|
136
146
|
securerandom (0.4.1)
|
|
137
147
|
stringio (3.1.7)
|
|
138
148
|
thor (1.3.2)
|
|
@@ -146,10 +156,12 @@ GEM
|
|
|
146
156
|
PLATFORMS
|
|
147
157
|
arm64-darwin-20
|
|
148
158
|
arm64-darwin-22
|
|
149
|
-
|
|
159
|
+
arm64-darwin-23
|
|
160
|
+
arm64-darwin-24
|
|
150
161
|
|
|
151
162
|
DEPENDENCIES
|
|
152
163
|
cm-graphql!
|
|
164
|
+
rspec (~> 3.12)
|
|
153
165
|
|
|
154
166
|
BUNDLED WITH
|
|
155
167
|
2.6.8
|
|
@@ -2,18 +2,15 @@ module CmGraphql
|
|
|
2
2
|
module Extensions
|
|
3
3
|
class RecaptchaExtension < GraphQL::Schema::FieldExtension
|
|
4
4
|
def apply
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
field.argument(:recaptcha_token, String, required: true)
|
|
9
|
-
end
|
|
5
|
+
input_arg = field.arguments["input"]
|
|
6
|
+
input_type = input_arg.type.unwrap
|
|
7
|
+
input_type.argument(:recaptcha_token, String, required: true)
|
|
10
8
|
end
|
|
11
|
-
|
|
12
|
-
def resolve(object:, arguments:, context:)
|
|
13
|
-
args_hash = arguments.to_h
|
|
14
|
-
input_hash = args_hash[:input].respond_to?(:to_h) ? args_hash[:input].to_h : nil
|
|
15
9
|
|
|
16
|
-
|
|
10
|
+
def resolve(object:, arguments:, context:, **_rest)
|
|
11
|
+
args_hash = arguments.to_h
|
|
12
|
+
input_hash = args_hash[:input].to_h
|
|
13
|
+
recaptcha_token = input_hash[:recaptcha_token]
|
|
17
14
|
|
|
18
15
|
RecaptchaVerifier.verify_v3!(
|
|
19
16
|
token: recaptcha_token,
|
|
@@ -22,13 +19,8 @@ module CmGraphql
|
|
|
22
19
|
minimum_score: options[:minimum_score] || RECAPTCHA_MINIMUM_SCORE
|
|
23
20
|
)
|
|
24
21
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
next_input.delete(:recaptcha_token)
|
|
28
|
-
yield(object, args_hash.merge(input: next_input))
|
|
29
|
-
else
|
|
30
|
-
yield(object, arguments.except(:recaptcha_token))
|
|
31
|
-
end
|
|
22
|
+
next_input = input_hash.except(:recaptcha_token)
|
|
23
|
+
yield(object, args_hash.except(:input).merge(input: next_input), nil)
|
|
32
24
|
end
|
|
33
25
|
end
|
|
34
26
|
end
|
|
@@ -2,19 +2,39 @@ require 'net/http'
|
|
|
2
2
|
require 'json'
|
|
3
3
|
|
|
4
4
|
class RecaptchaVerifier
|
|
5
|
-
|
|
5
|
+
API_HOST = 'recaptchaenterprise.googleapis.com'
|
|
6
6
|
|
|
7
7
|
def self.verify_v3(token:, action:, remote_ip: nil, minimum_score: 0.5)
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
project_id = Rails.application.credentials.dig(:gcp, :recaptcha_enterprise_project_id)
|
|
9
|
+
site_key = Rails.application.credentials.dig(:gcp, :recaptcha_site_key)
|
|
10
|
+
api_key = Rails.application.credentials.dig(:gcp, :recaptcha_api_key)
|
|
10
11
|
|
|
11
|
-
|
|
12
|
-
|
|
12
|
+
if project_id.blank? || site_key.blank? || api_key.blank?
|
|
13
|
+
raise RecaptchaVerificationFailed,
|
|
14
|
+
'Please configure recaptcha enterprise credentials at Rails.application.credentials.dig(:gcp, :recaptcha_enterprise_project_id), :recaptcha_site_key, :recaptcha_api_key.'
|
|
15
|
+
end
|
|
13
16
|
|
|
14
|
-
raise RecaptchaVerificationFailed,
|
|
15
|
-
raise RecaptchaVerificationFailed, "Recaptcha action mismatch" if response['action'].present? && response['action'] != action
|
|
17
|
+
raise RecaptchaVerificationFailed, 'Recaptcha token missing' if token.blank?
|
|
16
18
|
|
|
17
|
-
|
|
19
|
+
response = create_assessment(project_id:, site_key:, api_key:, token:, action:, remote_ip:)
|
|
20
|
+
raise RecaptchaVerificationFailed, 'Invalid response from recaptcha' unless response.is_a?(Hash)
|
|
21
|
+
|
|
22
|
+
token_props = response['tokenProperties']
|
|
23
|
+
unless token_props.is_a?(Hash)
|
|
24
|
+
raise RecaptchaVerificationFailed, 'Invalid response from recaptcha'
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
unless token_props['valid'] == true
|
|
28
|
+
reason = token_props['invalidReason']
|
|
29
|
+
raise RecaptchaVerificationFailed, reason.present? ? "Recaptcha invalid token: #{reason}" : 'Recaptcha invalid token'
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
if token_props['action'].present? && token_props['action'] != action
|
|
33
|
+
raise RecaptchaVerificationFailed, 'Recaptcha action mismatch'
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
risk = response['riskAnalysis']
|
|
37
|
+
score = risk.is_a?(Hash) ? risk['score'] : nil
|
|
18
38
|
return true if score.nil?
|
|
19
39
|
|
|
20
40
|
score.to_f >= minimum_score.to_f
|
|
@@ -27,18 +47,44 @@ class RecaptchaVerifier
|
|
|
27
47
|
true
|
|
28
48
|
end
|
|
29
49
|
|
|
30
|
-
def self.
|
|
31
|
-
|
|
32
|
-
|
|
50
|
+
def self.create_assessment(project_id:, site_key:, api_key:, token:, action:, remote_ip: nil)
|
|
51
|
+
uri = URI::HTTPS.build(
|
|
52
|
+
host: API_HOST,
|
|
53
|
+
path: "/v1/projects/#{project_id}/assessments",
|
|
54
|
+
query: URI.encode_www_form(key: api_key)
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
event = {
|
|
58
|
+
token: token,
|
|
59
|
+
siteKey: site_key,
|
|
60
|
+
expectedAction: action
|
|
61
|
+
}
|
|
62
|
+
event[:userIpAddress] = remote_ip if remote_ip.present?
|
|
33
63
|
|
|
34
|
-
|
|
64
|
+
request = Net::HTTP::Post.new(uri)
|
|
65
|
+
request['Content-Type'] = 'application/json'
|
|
66
|
+
request.body = JSON.generate({ event: event })
|
|
67
|
+
|
|
68
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
|
35
69
|
http.use_ssl = true
|
|
36
70
|
|
|
37
71
|
raw_response = http.request(request)
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
72
|
+
body = raw_response.body.to_s
|
|
73
|
+
|
|
74
|
+
parsed_body = JSON.parse(body)
|
|
75
|
+
|
|
76
|
+
unless raw_response.is_a?(Net::HTTPSuccess)
|
|
77
|
+
error_message = parsed_body.dig('error', 'message')
|
|
78
|
+
raise RecaptchaVerificationFailed,
|
|
79
|
+
"Recaptcha enterprise HTTP #{raw_response.code}: #{error_message.presence || raw_response.message}"
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
parsed_body
|
|
83
|
+
rescue JSON::ParserError
|
|
84
|
+
raise RecaptchaVerificationFailed, "Recaptcha enterprise returned invalid JSON"
|
|
85
|
+
rescue SocketError, Timeout::Error, Errno::ECONNRESET, Errno::ECONNREFUSED
|
|
86
|
+
raise RecaptchaVerificationFailed, 'Recaptcha enterprise request failed'
|
|
41
87
|
end
|
|
42
88
|
|
|
43
|
-
private_class_method :
|
|
89
|
+
private_class_method :create_assessment
|
|
44
90
|
end
|
data/cm-graphql.gemspec
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Gem::Specification.new do |spec|
|
|
4
4
|
spec.name = 'cm-graphql'
|
|
5
|
-
spec.version = '0.0.
|
|
5
|
+
spec.version = '0.0.14'
|
|
6
6
|
spec.date = '2022-09-14'
|
|
7
7
|
spec.summary = 'A gem to setup grapqhl basics like pagination, file upload'
|
|
8
8
|
spec.description = 'A gem to setup grapqhl basics like pagination, file upload'
|