new_google_recaptcha 1.0.0 → 1.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fa810b760940cf717035ca4440a7fdc6fa770cde651ff6b987c0e10d0a471718
4
- data.tar.gz: 41af27ec27a704388b0bc6e946fbf3ee595a261df8b90355720a9f6cb9742131
3
+ metadata.gz: a187e51b64407ccc6cae4186568b1f0deac59c601e6b095424dcb5aad7243edd
4
+ data.tar.gz: 5660c73c953982985bd3b926071e38040e64615cf9bfed9342cb71d2eed05ddf
5
5
  SHA512:
6
- metadata.gz: d378417f2010faed2b3bea508a54d17ddf66ca38766ba5d8c9ec3224a04742000c56a2121a1ec07217c86bfa59f2e36a7d84b680617cac2bb700093c0da39930
7
- data.tar.gz: 9a3dad7d9fb2236905e94a970e499935b52f2d9281e56a9612c3439ccc229aa545afc43fb8a3c0992de4c7faa0551a0047b89064be9fd9dfd8b1ee74f937bd73
6
+ metadata.gz: f4032d4cfa438d70622a2f7b49f4af670b52f6e67fe81638cbb50396fdf240fa356fc23a3417d8b57ba78d2e2fef294f59bcd62037352fcda7d801066837d712
7
+ data.tar.gz: bd804e4ace434e6dab65d07eef3988c9d6880671a69ee04d8fe081c964ca6b4b94818506165af14aa9a09ded729f0806e77ff0cd637cf36401f4268f4169971d
data/README.md CHANGED
@@ -1,6 +1,10 @@
1
1
  # Google Recaptcha v3 + Rails
2
2
 
3
- Integrate Google Recaptcha v3 with Rails app.
3
+ [![Build Status](https://travis-ci.org/igorkasyanchuk/new_google_recaptcha.svg?branch=master)](https://travis-ci.org/igorkasyanchuk/new_google_recaptcha)
4
+ [![RailsJazz](https://github.com/igorkasyanchuk/rails_time_travel/blob/main/docs/my_other.svg?raw=true)](https://www.railsjazz.com)
5
+ [![https://www.patreon.com/igorkasyanchuk](https://github.com/igorkasyanchuk/rails_time_travel/blob/main/docs/patron.svg?raw=true)](https://www.patreon.com/igorkasyanchuk)
6
+
7
+ Integrate Google Recaptcha v3 with Rails app.
4
8
 
5
9
  Google Recaptcha console: https://www.google.com/recaptcha/admin#list
6
10
 
@@ -44,6 +48,31 @@ Recaptcha v3 documentation: https://developers.google.com/recaptcha/docs/v3
44
48
  render :new
45
49
  end
46
50
  end
51
+
52
+
53
+ # or
54
+ # if you need to capture a humanity `score` from Google
55
+ # before you need to add a column for example `humanity_score` (type: float) where this score will be saved.
56
+
57
+
58
+ def create
59
+ @post = Post.new(post_params)
60
+ humanity_details =
61
+ NewGoogleRecaptcha.get_humanity_detailed(
62
+ params[:new_google_recaptcha_token],
63
+ "checkout",
64
+ NewGoogleRecaptcha.minimum_score,
65
+ @post
66
+ )
67
+
68
+ @post.humanity_score = humanity_details[:score]
69
+
70
+ if humanity_details[:is_human] && @post.save
71
+ redirect_to @post, notice: 'Post was successfully created.'
72
+ else
73
+ render :new
74
+ end
75
+ end
47
76
  ```
48
77
 
49
78
  There are two mandatory arguments for `human?` method:
@@ -67,6 +96,16 @@ like this:
67
96
  NewGoogleRecaptcha.human?(params[:new_google_recaptcha_token], "checkout")
68
97
  ```
69
98
 
99
+ ### Saving humanity score from Google in your model
100
+
101
+ `get_humanity_detailed` method acts like `human?` method, the only difference is that it returns following hash with three key-value pairs:
102
+
103
+ - `is_human` - whether actor is a human or not (same as result of `human?` method)
104
+ - `score` - actual humanity score from recaptcha response
105
+ - `model` - model which you trying to save
106
+
107
+ It could be handy if you want to store score in db or put it into logs or smth else. Real example is above in the code samples.
108
+
70
109
  Add to your navigation links `data-turbolinks="false"` to make it works with `turbolinks`.
71
110
 
72
111
  ## Installation
@@ -90,20 +129,71 @@ And edit new_google_recaptcha.rb and enter your site_key and secret_key.
90
129
 
91
130
  ## API
92
131
 
93
- **NewGoogleRecaptcha.human?(token, model)** in contoller
132
+ `NewGoogleRecaptcha.human?(token, model)` or `NewGoogleRecaptcha.get_humanity_detailed(token, model)` in contoller
94
133
 
95
134
  - token is received from google, must be sent to backend
96
135
  - model optional parameter. if you want to add error to model.
97
136
 
98
- **<%= include_recaptcha_js %>** in layout (by using yield)
137
+ `<%= include_recaptcha_js %>` in layout (by using yield)
99
138
 
100
139
  Include Google Recaptcha v3 JS into your Rails app. In head, right before `</head>`.
101
140
 
102
- **<%= recaptcha_action(action_name) %>** in view
141
+ `<%= recaptcha_action(action_name) %>` in view
103
142
 
104
143
  Action where recaptcha action was executed. Actions could be viewed in Admin console. More docs: https://developers.google.com/recaptcha/docs/v3. Action name could be "comments", "checkout", etc. Put any name and check scores in console.
105
144
 
145
+ ## How to add to the Devise
146
+
147
+ Generate Devise controllers and views, and edit "create" method.
148
+
149
+ ```ruby
150
+ class Users::RegistrationsController < Devise::RegistrationsController
151
+ ...
152
+ def create
153
+ build_resource(sign_up_params)
154
+
155
+ NewGoogleRecaptcha.human?(
156
+ params[:new_google_recaptcha_token],
157
+ "user",
158
+ NewGoogleRecaptcha.minimum_score,
159
+ resource) && resource.save
160
+
161
+ yield resource if block_given?
162
+ if resource.persisted?
163
+ if resource.active_for_authentication?
164
+ set_flash_message! :notice, :signed_up
165
+ sign_up(resource_name, resource)
166
+ respond_with resource, location: after_sign_up_path_for(resource)
167
+ else
168
+ set_flash_message! :notice, :"signed_up_but_#{resource.inactive_message}"
169
+ expire_data_after_sign_in!
170
+ respond_with resource, location: after_inactive_sign_up_path_for(resource)
171
+ end
172
+ else
173
+ clean_up_passwords resource
174
+ set_minimum_password_length
175
+ respond_with resource
176
+ end
177
+ end
178
+ ```
179
+
180
+ ## How to use in test or specs
181
+
182
+ At the end of the spec/rails_helper.rb put:
183
+
184
+ ```ruby
185
+ module NewGoogleRecaptcha
186
+ def self.human?(*attrs)
187
+ true
188
+ end
189
+ end
190
+ ```
191
+
192
+ Tests are located in `specs` folder and `test/dummy/tests` folder.
193
+
194
+
106
195
  ## I18n support
196
+
107
197
  reCAPTCHA passes one types of error explanation to a linked model. It will use the I18n gem
108
198
  to translate the default error message if I18n is available. To customize the messages to your locale,
109
199
  add these keys to your I18n backend:
@@ -119,11 +209,21 @@ en:
119
209
  verification_human: 'Fail'
120
210
  ```
121
211
 
212
+ ## Badge position
213
+
214
+ NewGoogleRecaptcha allows you to render badge in different positions
215
+
216
+ ```ruby
217
+ <%= include_recaptcha_js badge: "bottomleft" %>
218
+ ```
219
+
220
+ Three of existing `badge` values are `bottomright`, `bottomleft` and `inline`.
221
+ 'inline' lets you position it with CSS.
222
+
122
223
  ## TODO
123
224
 
124
225
  - check everything works with turbolinks
125
226
  - allow custom ID for input
126
- - return score ?
127
227
  - more tests
128
228
  - handle exceptions with timeouts, json is not parsed
129
229
  - add support for non-Rails apps
@@ -137,7 +237,15 @@ You are welcome to contribute.
137
237
  * [gilcierweb](https://github.com/gilcierweb)
138
238
  * [RoRElessar](https://github.com/RoRElessar)
139
239
  * [rubyconvict](https://github.com/rubyconvict)
240
+ * [adelnabiullin](https://github.com/adelnabiullin)
241
+ * [jhill](https://github.com/jhill)
242
+ * [dachinat](https://github.com/dachinat)
243
+ * [edugonch](https://github.com/edugonch)
140
244
 
141
245
  ## License
142
246
 
143
247
  The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
248
+
249
+
250
+ [<img src="https://github.com/igorkasyanchuk/rails_time_travel/blob/main/docs/more_gems.png?raw=true"
251
+ />](https://www.railsjazz.com/)
@@ -2,9 +2,24 @@ require 'net/http'
2
2
 
3
3
  module NewGoogleRecaptcha
4
4
  class Validator
5
- def self.valid?(token, action, minimum_score)
6
- uri = URI("https://www.google.com/recaptcha/api/siteverify?secret=#{NewGoogleRecaptcha.secret_key}&response=#{token}")
7
- result = JSON.parse(Net::HTTP.get(uri))
5
+ attr_reader :score
6
+ attr_reader :token, :action, :minimum_score
7
+
8
+ def initialize(token:, action:, minimum_score:)
9
+ @token = token
10
+ @action = action
11
+ @minimum_score = minimum_score
12
+ end
13
+
14
+ def call
15
+ uri = NewGoogleRecaptcha.compose_uri(token)
16
+
17
+ http = Net::HTTP.new(uri.host, uri.port)
18
+ http.use_ssl = true if uri.scheme == 'https'
19
+ result = JSON.parse(http.request(Net::HTTP::Get.new(uri)).body)
20
+
21
+ @score = result['score'].to_f
22
+
8
23
  conditions = []
9
24
  conditions << !!result['success']
10
25
  conditions << (result['score'].to_f >= minimum_score)
@@ -12,4 +27,4 @@ module NewGoogleRecaptcha
12
27
  conditions.none?(&:!)
13
28
  end
14
29
  end
15
- end
30
+ end
@@ -1,3 +1,3 @@
1
1
  module NewGoogleRecaptcha
2
- VERSION = '1.0.0'
2
+ VERSION = '1.4.0'
3
3
  end
@@ -2,24 +2,45 @@ module NewGoogleRecaptcha
2
2
  module ViewExt
3
3
  include ActionView::Helpers::TagHelper
4
4
 
5
- def include_recaptcha_js
6
- raw %Q{
7
- <script src="https://www.google.com/recaptcha/api.js?render=#{NewGoogleRecaptcha.site_key}"></script>
8
- }
5
+ def include_recaptcha_js(opts = {})
6
+ badge = opts[:badge] ? "&badge=#{opts[:badge]}" : ""
7
+ generate_recaptcha_callback +
8
+ javascript_include_tag(
9
+ "https://www.google.com/recaptcha/api.js?render=#{NewGoogleRecaptcha.site_key}&onload=newGoogleRecaptchaCallback#{badge}",
10
+ defer: true
11
+ )
9
12
  end
10
13
 
11
14
  def recaptcha_action(action)
12
15
  id = "new_google_recaptcha_token_#{SecureRandom.hex(10)}"
13
- raw %Q{
14
- <input name="new_google_recaptcha_token" type="hidden" id="#{id}"/>
15
- <script>
16
- grecaptcha.ready(function() {
17
- grecaptcha.execute("#{NewGoogleRecaptcha.site_key}", {action: "#{action}"}).then(function(token) {
18
- document.getElementById("#{id}").value = token;
19
- });
20
- });
21
- </script>
22
- }
16
+ hidden_field_tag(
17
+ 'new_google_recaptcha_token',
18
+ nil,
19
+ readonly: true,
20
+ 'data-google-recaptcha-action' => action,
21
+ id: id
22
+ )
23
+ end
24
+
25
+ private
26
+
27
+ def generate_recaptcha_callback
28
+ javascript_tag %(
29
+ function newGoogleRecaptchaCallback () {
30
+ grecaptcha.ready(function () {
31
+ var elements = document.querySelectorAll('[data-google-recaptcha-action]')
32
+ Array.prototype.slice.call(elements).forEach(function (el) {
33
+ var action = el.dataset.googleRecaptchaAction
34
+ if (!action) return
35
+ grecaptcha
36
+ .execute("#{NewGoogleRecaptcha.site_key}", { action: action })
37
+ .then(function (token) {
38
+ el.value = token
39
+ })
40
+ })
41
+ })
42
+ }
43
+ )
23
44
  end
24
45
  end
25
- end
46
+ end
@@ -10,13 +10,37 @@ module NewGoogleRecaptcha
10
10
  end
11
11
 
12
12
  def self.human?(token, action, minimum_score = self.minimum_score, model = nil)
13
- is_valid = NewGoogleRecaptcha::Validator.valid?(token, action, minimum_score)
13
+ is_valid =
14
+ NewGoogleRecaptcha::Validator.new(
15
+ token: token,
16
+ action: action,
17
+ minimum_score: minimum_score
18
+ ).call
19
+
14
20
  if model && !is_valid
15
21
  model.errors.add(:base, self.i18n("new_google_recaptcha.errors.verification_human", "Looks like you are not a human"))
16
22
  end
23
+
17
24
  is_valid
18
25
  end
19
26
 
27
+ def self.get_humanity_detailed(token, action, minimum_score = self.minimum_score, model = nil)
28
+ validator =
29
+ NewGoogleRecaptcha::Validator.new(
30
+ token: token,
31
+ action: action,
32
+ minimum_score: minimum_score
33
+ )
34
+
35
+ is_valid = validator.call
36
+
37
+ if model && !is_valid
38
+ model.errors.add(:base, self.i18n("new_google_recaptcha.errors.verification_human", "Looks like you are not a human"))
39
+ end
40
+
41
+ { is_human: is_valid, score: validator.score, model: model }
42
+ end
43
+
20
44
  def self.i18n(key, default)
21
45
  if defined?(I18n)
22
46
  I18n.translate(key, default: default)
@@ -25,7 +49,13 @@ module NewGoogleRecaptcha
25
49
  end
26
50
  end
27
51
 
52
+ def self.compose_uri(token)
53
+ URI(
54
+ "https://www.google.com/recaptcha/api/siteverify?"\
55
+ "secret=#{self.secret_key}&response=#{token}"
56
+ )
57
+ end
28
58
  end
29
59
 
30
60
  require_relative "new_google_recaptcha/view_ext"
31
- require_relative "new_google_recaptcha/validator"
61
+ require_relative "new_google_recaptcha/validator"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: new_google_recaptcha
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Igor Kasyanchuk
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2019-01-03 00:00:00.000000000 Z
12
+ date: 2022-01-23 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rails
@@ -123,7 +123,7 @@ dependencies:
123
123
  - - ">="
124
124
  - !ruby/object:Gem::Version
125
125
  version: '0'
126
- description: Google reCaptcha v3 + Rails (integration)
126
+ description: Google reCAPTCHA v3 + Rails (integration)
127
127
  email:
128
128
  - igorkasyanchuk@gmail.com
129
129
  executables: []
@@ -161,8 +161,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
161
161
  - !ruby/object:Gem::Version
162
162
  version: '0'
163
163
  requirements: []
164
- rubygems_version: 3.0.1
164
+ rubygems_version: 3.3.3
165
165
  signing_key:
166
166
  specification_version: 4
167
- summary: Google reCaptcha v3 + Rails
167
+ summary: Google reCAPTCHA v3 + Rails
168
168
  test_files: []