new_google_recaptcha_turbo 1.2.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 +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +237 -0
- data/Rakefile +27 -0
- data/lib/generators/USAGE +8 -0
- data/lib/generators/new_google_recaptcha_generator.rb +6 -0
- data/lib/generators/templates/new_google_recaptcha.rb +7 -0
- data/lib/new_google_recaptcha.rb +61 -0
- data/lib/new_google_recaptcha/railtie.rb +9 -0
- data/lib/new_google_recaptcha/validator.rb +30 -0
- data/lib/new_google_recaptcha/version.rb +3 -0
- data/lib/new_google_recaptcha/view_ext.rb +41 -0
- data/lib/tasks/new_google_recaptcha_tasks.rake +4 -0
- metadata +168 -0
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
|
+
[](https://travis-ci.org/igorkasyanchuk/new_google_recaptcha)
|
4
|
+
[](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,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,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,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
|
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: []
|