new_google_recaptcha_turbo 1.2.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 3c5cd7372d8cb66ef663b5d79f4c252e949189f9f60be5ea0a5d32691f5a8aa0
4
+ data.tar.gz: cc6f097e61eb5be159f6ac0e165f2f037e2ef94ac9e0a3e549532a7d743ba880
5
+ SHA512:
6
+ metadata.gz: e0ce6734d58c2e7f9b4d9c53a24fd9754b6aeb09b0688bc657989aceacd5c1ce76638b967367148cde449bd2ff7af8ef1e6770963d7d51b7291b20c0f1394f2b
7
+ data.tar.gz: 84570ddaeb15737ab5f3c2645ea1cd9e32a5c54d09ff378df6a3f2606a285297a56fb77fe37bb16e42bee837a592100240b8f1523da23687e60ee713cef03610
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2018 Igor Kasyanchuk
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,237 @@
1
+ # Google Recaptcha v3 + Rails
2
+
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
+
6
+ Integrate Google Recaptcha v3 with Rails app.
7
+
8
+ Google Recaptcha console: https://www.google.com/recaptcha/admin#list
9
+
10
+ Recaptcha v3 documentation: https://developers.google.com/recaptcha/docs/v3
11
+
12
+ ## Usage
13
+
14
+ - Open https://www.google.com/recaptcha/admin#list
15
+ - register a new site
16
+ - copy `site_key` and `secret_key` and put into config/initializers/new_google_recaptcha.rb
17
+ - optionally, change the `minimum_score` in the initializer to a preferred float value (from 0.0 to 1.0)
18
+ - in layout:
19
+ ```erb
20
+ <head>
21
+ ...
22
+ <%= yield :recaptcha_js %>
23
+ </head>
24
+ ```
25
+ - in view where you for example you have a form:
26
+ ```erb
27
+ <%= content_for :recaptcha_js do %>
28
+ <%= include_recaptcha_js %>
29
+ <% end %>
30
+ <form ...>
31
+ <%#= 'checkout' is action name to be verified later %>
32
+ <%= recaptcha_action('checkout') %>
33
+ </form>
34
+ ```
35
+ - in controller:
36
+ ```ruby
37
+ def create
38
+ @post = Post.new(post_params)
39
+ if NewGoogleRecaptcha.human?(
40
+ params[:new_google_recaptcha_token],
41
+ "checkout",
42
+ NewGoogleRecaptcha.minimum_score,
43
+ @post
44
+ ) && @post.save
45
+ redirect_to @post, notice: 'Post was successfully created.'
46
+ else
47
+ render :new
48
+ end
49
+ end
50
+
51
+
52
+ # or
53
+ # if you need to capture a humanity `score` from Google
54
+ # before you need to add a column for example `humanity_score` (type: float) where this score will be saved.
55
+
56
+
57
+ def create
58
+ @post = Post.new(post_params)
59
+ humanity_details =
60
+ NewGoogleRecaptcha.get_humanity_detailed(
61
+ params[:new_google_recaptcha_token],
62
+ "checkout",
63
+ NewGoogleRecaptcha.minimum_score,
64
+ @post
65
+ )
66
+
67
+ @post.humanity_score = humanity_details[:score]
68
+
69
+ if humanity_details[:is_human] && @post.save
70
+ redirect_to @post, notice: 'Post was successfully created.'
71
+ else
72
+ render :new
73
+ end
74
+ end
75
+ ```
76
+
77
+ There are two mandatory arguments for `human?` method:
78
+
79
+ - `token` - token valid for your site
80
+ - `action` - the action name for this request
81
+ (the gem checks if it is the same as the name used with the token,
82
+ otherwise a hacker could replace it on frontend to some another action used,
83
+ but with lower score requirement and thus pass the verification)
84
+
85
+ You can verify recaptcha without using these arguments:
86
+
87
+ - `minimum_score` - defaults to value set in the initializer
88
+ (reCAPTCHA recommends using 0.5 as default)
89
+ - `model` - defaults to `nil` which will result in not adding an error to model;
90
+ any custom failure handling is applicable here
91
+
92
+ like this:
93
+
94
+ ```ruby
95
+ NewGoogleRecaptcha.human?(params[:new_google_recaptcha_token], "checkout")
96
+ ```
97
+
98
+ ### Saving humanity score from Google in your model
99
+
100
+ `get_humanity_detailed` method acts like `human?` method, the only difference is that it returns following hash with three key-value pairs:
101
+
102
+ - `is_human` - whether actor is a human or not (same as result of `human?` method)
103
+ - `score` - actual humanity score from recaptcha response
104
+ - `model` - model which you trying to save
105
+
106
+ 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.
107
+
108
+ Add to your navigation links `data-turbolinks="false"` to make it works with `turbolinks`.
109
+
110
+ ## Installation
111
+
112
+ ```ruby
113
+ gem 'new_google_recaptcha'
114
+ ```
115
+
116
+ And then execute:
117
+ ```bash
118
+ $ bundle
119
+ ```
120
+
121
+ And then run:
122
+
123
+ ```bash
124
+ $ rails generate new_google_recaptcha initializer
125
+ ```
126
+
127
+ And edit new_google_recaptcha.rb and enter your site_key and secret_key.
128
+
129
+ ## API
130
+
131
+ `NewGoogleRecaptcha.human?(token, model)` or `NewGoogleRecaptcha.get_humanity_detailed(token, model)` in contoller
132
+
133
+ - token is received from google, must be sent to backend
134
+ - model optional parameter. if you want to add error to model.
135
+
136
+ `<%= include_recaptcha_js %>` in layout (by using yield)
137
+
138
+ Include Google Recaptcha v3 JS into your Rails app. In head, right before `</head>`.
139
+
140
+ `<%= recaptcha_action(action_name) %>` in view
141
+
142
+ 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.
143
+
144
+ ## How to add to the Devise
145
+
146
+ Generate Devise controllers and views, and edit "create" method.
147
+
148
+ ```ruby
149
+ class Users::RegistrationsController < Devise::RegistrationsController
150
+ ...
151
+ def create
152
+ build_resource(sign_up_params)
153
+
154
+ NewGoogleRecaptcha.human?(
155
+ params[:new_google_recaptcha_token],
156
+ "user",
157
+ NewGoogleRecaptcha.minimum_score,
158
+ resource) && resource.save
159
+
160
+ yield resource if block_given?
161
+ if resource.persisted?
162
+ if resource.active_for_authentication?
163
+ set_flash_message! :notice, :signed_up
164
+ sign_up(resource_name, resource)
165
+ respond_with resource, location: after_sign_up_path_for(resource)
166
+ else
167
+ set_flash_message! :notice, :"signed_up_but_#{resource.inactive_message}"
168
+ expire_data_after_sign_in!
169
+ respond_with resource, location: after_inactive_sign_up_path_for(resource)
170
+ end
171
+ else
172
+ clean_up_passwords resource
173
+ set_minimum_password_length
174
+ respond_with resource
175
+ end
176
+ end
177
+ ```
178
+
179
+ ## How to use in test or specs
180
+
181
+ At the end of the spec/rails_helper.rb put:
182
+
183
+ ```ruby
184
+ module NewGoogleRecaptcha
185
+ def self.human?(*attrs)
186
+ true
187
+ end
188
+ end
189
+ ```
190
+
191
+ Tests are located in `specs` folder and `test/dummy/tests` folder.
192
+
193
+
194
+ ## I18n support
195
+
196
+ reCAPTCHA passes one types of error explanation to a linked model. It will use the I18n gem
197
+ to translate the default error message if I18n is available. To customize the messages to your locale,
198
+ add these keys to your I18n backend:
199
+
200
+ `new_google_recaptcha.errors.verification_human` error message displayed when it is something like a robot, or a suspicious action
201
+
202
+ Also you can translate API response errors to human friendly by adding translations to the locale (`config/locales/en.yml`):
203
+
204
+ ```Yaml
205
+ en:
206
+ new_google_recaptcha:
207
+ errors:
208
+ verification_human: 'Fail'
209
+ ```
210
+
211
+ ## TODO
212
+
213
+ - check everything works with turbolinks
214
+ - allow custom ID for input
215
+ - more tests
216
+ - handle exceptions with timeouts, json is not parsed
217
+ - add support for non-Rails apps
218
+ - add support for older Rails (should be easy since code is very simple)
219
+
220
+ ## Contributors
221
+
222
+ You are welcome to contribute.
223
+
224
+ * [Igor Kasyanchuk](https://github.com/igorkasyanchuk) (maintainer)
225
+ * [gilcierweb](https://github.com/gilcierweb)
226
+ * [RoRElessar](https://github.com/RoRElessar)
227
+ * [rubyconvict](https://github.com/rubyconvict)
228
+ * [adelnabiullin](https://github.com/adelnabiullin)
229
+ * [jhill](https://github.com/jhill)
230
+
231
+ ## License
232
+
233
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
234
+
235
+
236
+ [<img src="https://github.com/igorkasyanchuk/rails_time_travel/blob/main/docs/more_gems.png?raw=true"
237
+ />](https://www.railsjazz.com/)
data/Rakefile ADDED
@@ -0,0 +1,27 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ require 'rdoc/task'
8
+
9
+ RDoc::Task.new(:rdoc) do |rdoc|
10
+ rdoc.rdoc_dir = 'rdoc'
11
+ rdoc.title = 'NewGoogleRecaptcha'
12
+ rdoc.options << '--line-numbers'
13
+ rdoc.rdoc_files.include('README.md')
14
+ rdoc.rdoc_files.include('lib/**/*.rb')
15
+ end
16
+
17
+ require 'bundler/gem_tasks'
18
+
19
+ require 'rake/testtask'
20
+
21
+ Rake::TestTask.new(:test) do |t|
22
+ t.libs << 'test'
23
+ t.pattern = 'test/**/*_test.rb'
24
+ t.verbose = false
25
+ end
26
+
27
+ task default: :test
@@ -0,0 +1,8 @@
1
+ Description:
2
+ Generate configuration file.
3
+
4
+ Example:
5
+ rails generate new_google_recaptcha initializer
6
+
7
+ This will create:
8
+ config/new_google_recaptcha.rb
@@ -0,0 +1,6 @@
1
+ class NewGoogleRecaptchaGenerator < Rails::Generators::NamedBase
2
+ source_root File.expand_path('../templates', __FILE__)
3
+ def copy_initializer
4
+ template 'new_google_recaptcha.rb', 'config/initializers/new_google_recaptcha.rb'
5
+ end
6
+ end
@@ -0,0 +1,7 @@
1
+ if Object.const_defined?('NewGoogleRecaptcha')
2
+ NewGoogleRecaptcha.setup do |config|
3
+ config.site_key = "SITE_KEY"
4
+ config.secret_key = "SECRET_KEY"
5
+ config.minimum_score = 0.5
6
+ end
7
+ end
@@ -0,0 +1,61 @@
1
+ require "new_google_recaptcha/railtie"
2
+
3
+ module NewGoogleRecaptcha
4
+ mattr_accessor :site_key
5
+ mattr_accessor :secret_key
6
+ mattr_accessor :minimum_score
7
+
8
+ def self.setup
9
+ yield(self)
10
+ end
11
+
12
+ def self.human?(token, action, minimum_score = self.minimum_score, model = nil)
13
+ is_valid =
14
+ NewGoogleRecaptcha::Validator.new(
15
+ token: token,
16
+ action: action,
17
+ minimum_score: minimum_score
18
+ ).call
19
+
20
+ if model && !is_valid
21
+ model.errors.add(:base, self.i18n("new_google_recaptcha.errors.verification_human", "Looks like you are not a human"))
22
+ end
23
+
24
+ is_valid
25
+ end
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
+
44
+ def self.i18n(key, default)
45
+ if defined?(I18n)
46
+ I18n.translate(key, default: default)
47
+ else
48
+ default
49
+ end
50
+ end
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
58
+ end
59
+
60
+ require_relative "new_google_recaptcha/view_ext"
61
+ require_relative "new_google_recaptcha/validator"
@@ -0,0 +1,9 @@
1
+ module NewGoogleRecaptcha
2
+ class Railtie < ::Rails::Railtie
3
+ initializer 'new_google_recaptcha.helpers' do
4
+ ActiveSupport.on_load :action_view do
5
+ ActionView::Base.send :include, NewGoogleRecaptcha::ViewExt
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,30 @@
1
+ require 'net/http'
2
+
3
+ module NewGoogleRecaptcha
4
+ class Validator
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
+
23
+ conditions = []
24
+ conditions << !!result['success']
25
+ conditions << (result['score'].to_f >= minimum_score)
26
+ conditions << (result['action'].to_s == action.to_s)
27
+ conditions.none?(&:!)
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,3 @@
1
+ module NewGoogleRecaptcha
2
+ VERSION = '1.2.1'
3
+ end
@@ -0,0 +1,41 @@
1
+ module NewGoogleRecaptcha
2
+ module ViewExt
3
+ include ActionView::Helpers::TagHelper
4
+
5
+ def include_recaptcha_js
6
+ generate_recaptcha_callback + javascript_include_tag("https://www.google.com/recaptcha/api.js?render=#{NewGoogleRecaptcha.site_key}&onload=newGoogleRecaptchaCallback", defer: true, 'data-turbolinks-track': "reload")
7
+ end
8
+
9
+ def recaptcha_action(action)
10
+ id = "new_google_recaptcha_token_#{SecureRandom.hex(10)}"
11
+ hidden_field_tag(
12
+ "new_recaptcha_token",
13
+ nil,
14
+ :readonly => true,
15
+ "data-google-recaptcha-action" => action,
16
+ :id => id
17
+ )
18
+ end
19
+
20
+ private
21
+
22
+ def generate_recaptcha_callback
23
+ javascript_tag %(
24
+ function newGoogleRecaptchaCallback () {
25
+ grecaptcha.ready(function () {
26
+ var elements = document.querySelectorAll('[data-google-recaptcha-action]')
27
+ Array.prototype.slice.call(elements).forEach(function (el) {
28
+ var action = el.dataset.googleRecaptchaAction
29
+ if (!action) return
30
+ grecaptcha
31
+ .execute("#{NewGoogleRecaptcha.site_key}", { action: action })
32
+ .then(function (token) {
33
+ el.value = token
34
+ })
35
+ })
36
+ })
37
+ }
38
+ )
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :new_google_recaptcha do
3
+ # # Task goes here
4
+ # end
metadata ADDED
@@ -0,0 +1,168 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: new_google_recaptcha_turbo
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.2.1
5
+ platform: ruby
6
+ authors:
7
+ - Igor Kasyanchuk
8
+ - rubyconvict
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2021-02-01 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rails
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - ">="
19
+ - !ruby/object:Gem::Version
20
+ version: 4.2.0
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ version: 4.2.0
28
+ - !ruby/object:Gem::Dependency
29
+ name: sqlite3
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - ">="
33
+ - !ruby/object:Gem::Version
34
+ version: '1.3'
35
+ type: :development
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ version: '1.3'
42
+ - !ruby/object:Gem::Dependency
43
+ name: byebug
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ version: '10.0'
49
+ type: :development
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: '10.0'
56
+ - !ruby/object:Gem::Dependency
57
+ name: webmock
58
+ requirement: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: '3.5'
63
+ type: :development
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ version: '3.5'
70
+ - !ruby/object:Gem::Dependency
71
+ name: mocha
72
+ requirement: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - "~>"
75
+ - !ruby/object:Gem::Version
76
+ version: 0.14.0
77
+ type: :development
78
+ prerelease: false
79
+ version_requirements: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - "~>"
82
+ - !ruby/object:Gem::Version
83
+ version: 0.14.0
84
+ - !ruby/object:Gem::Dependency
85
+ name: redis-store-testing
86
+ requirement: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ version: '0'
91
+ type: :development
92
+ prerelease: false
93
+ version_requirements: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - ">="
96
+ - !ruby/object:Gem::Version
97
+ version: '0'
98
+ - !ruby/object:Gem::Dependency
99
+ name: connection_pool
100
+ requirement: !ruby/object:Gem::Requirement
101
+ requirements:
102
+ - - "~>"
103
+ - !ruby/object:Gem::Version
104
+ version: 1.2.0
105
+ type: :development
106
+ prerelease: false
107
+ version_requirements: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - "~>"
110
+ - !ruby/object:Gem::Version
111
+ version: 1.2.0
112
+ - !ruby/object:Gem::Dependency
113
+ name: appraisal
114
+ requirement: !ruby/object:Gem::Requirement
115
+ requirements:
116
+ - - ">="
117
+ - !ruby/object:Gem::Version
118
+ version: '0'
119
+ type: :development
120
+ prerelease: false
121
+ version_requirements: !ruby/object:Gem::Requirement
122
+ requirements:
123
+ - - ">="
124
+ - !ruby/object:Gem::Version
125
+ version: '0'
126
+ description: Google reCAPTCHA v3 + Rails (integration)
127
+ email:
128
+ - igorkasyanchuk@gmail.com
129
+ executables: []
130
+ extensions: []
131
+ extra_rdoc_files: []
132
+ files:
133
+ - MIT-LICENSE
134
+ - README.md
135
+ - Rakefile
136
+ - lib/generators/USAGE
137
+ - lib/generators/new_google_recaptcha_generator.rb
138
+ - lib/generators/templates/new_google_recaptcha.rb
139
+ - lib/new_google_recaptcha.rb
140
+ - lib/new_google_recaptcha/railtie.rb
141
+ - lib/new_google_recaptcha/validator.rb
142
+ - lib/new_google_recaptcha/version.rb
143
+ - lib/new_google_recaptcha/view_ext.rb
144
+ - lib/tasks/new_google_recaptcha_tasks.rake
145
+ homepage: https://github.com/igorkasyanchuk/new_google_recaptcha
146
+ licenses:
147
+ - MIT
148
+ metadata: {}
149
+ post_install_message:
150
+ rdoc_options: []
151
+ require_paths:
152
+ - lib
153
+ required_ruby_version: !ruby/object:Gem::Requirement
154
+ requirements:
155
+ - - ">="
156
+ - !ruby/object:Gem::Version
157
+ version: '0'
158
+ required_rubygems_version: !ruby/object:Gem::Requirement
159
+ requirements:
160
+ - - ">="
161
+ - !ruby/object:Gem::Version
162
+ version: '0'
163
+ requirements: []
164
+ rubygems_version: 3.1.4
165
+ signing_key:
166
+ specification_version: 4
167
+ summary: Google reCAPTCHA v3 + Rails
168
+ test_files: []