invisible_captcha 0.10.0 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.gitignore +1 -0
- data/.rspec +3 -0
- data/.travis.yml +10 -23
- data/Appraisals +6 -14
- data/CHANGELOG.md +151 -0
- data/Gemfile +2 -0
- data/LICENSE +1 -1
- data/README.md +178 -40
- data/Rakefile +2 -0
- data/gemfiles/{rails_3.2.gemfile → rails_5.2.gemfile} +2 -2
- data/gemfiles/{rails_4.1.gemfile → rails_6.0.gemfile} +2 -2
- data/gemfiles/{rails_5.1.gemfile → rails_6.1.gemfile} +2 -2
- data/invisible_captcha.gemspec +4 -7
- data/lib/invisible_captcha/controller_ext.rb +40 -14
- data/lib/invisible_captcha/form_helpers.rb +3 -1
- data/lib/invisible_captcha/railtie.rb +2 -0
- data/lib/invisible_captcha/version.rb +3 -1
- data/lib/invisible_captcha/view_helpers.rb +27 -4
- data/lib/invisible_captcha.rb +17 -3
- data/spec/controllers_spec.rb +99 -30
- data/spec/dummy/app/assets/config/manifest.js +2 -0
- data/spec/dummy/config/environments/test.rb +3 -8
- data/spec/invisible_captcha_spec.rb +2 -2
- data/spec/spec_helper.rb +6 -1
- data/spec/view_helpers_spec.rb +22 -6
- metadata +15 -42
- data/gemfiles/rails_4.2.gemfile +0 -7
- data/gemfiles/rails_5.0.gemfile +0 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 86acfe71e903568702c63c261bfd32a066dbc947d1c2fa2b4956178a7de591db
|
4
|
+
data.tar.gz: a9a8768c5bcfb9a7656e0638dde4bf40e169719385bf947dace7fa4d34f03656
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ec1ed1b9f7bef2e753f7b736dbce8124b5cd4c699e4075cbd15fdade99e6f332025e3088f0754315b18f8bde48b7e883c3470f840a535a3631f2e5c659c415df
|
7
|
+
data.tar.gz: 3698ed54f31c8f87730dcd92e14c2076e10aaa98a14a765e7d3be8bfd0e259385572b5d3252b8328fb4a539634bb8e086270b2e7e34117ab76a15ab4f42c095b
|
data/.gitignore
CHANGED
data/.rspec
ADDED
data/.travis.yml
CHANGED
@@ -1,31 +1,18 @@
|
|
1
1
|
language: ruby
|
2
2
|
cache: bundler
|
3
|
-
sudo: false
|
4
3
|
rvm:
|
5
4
|
- ruby-head
|
6
|
-
-
|
7
|
-
- 2.
|
8
|
-
- 2.
|
9
|
-
- 2.
|
5
|
+
- 3.0.0
|
6
|
+
- 2.7.2
|
7
|
+
- 2.6.5
|
8
|
+
- 2.5.8
|
10
9
|
gemfile:
|
11
|
-
- gemfiles/
|
12
|
-
- gemfiles/
|
13
|
-
- gemfiles/
|
14
|
-
- gemfiles/rails_4.1.gemfile
|
15
|
-
- gemfiles/rails_3.2.gemfile
|
10
|
+
- gemfiles/rails_6.1.gemfile
|
11
|
+
- gemfiles/rails_6.0.gemfile
|
12
|
+
- gemfiles/rails_5.2.gemfile
|
16
13
|
matrix:
|
17
14
|
exclude:
|
18
|
-
- rvm:
|
19
|
-
gemfile: gemfiles/rails_5.
|
20
|
-
- rvm: 2.1.10
|
21
|
-
gemfile: gemfiles/rails_5.1.gemfile
|
22
|
-
- rvm: 2.4.2
|
23
|
-
gemfile: gemfiles/rails_4.1.gemfile
|
24
|
-
- rvm: 2.4.2
|
25
|
-
gemfile: gemfiles/rails_3.2.gemfile
|
26
|
-
- rvm: ruby-head
|
27
|
-
gemfile: gemfiles/rails_4.1.gemfile
|
28
|
-
- rvm: ruby-head
|
29
|
-
gemfile: gemfiles/rails_3.2.gemfile
|
15
|
+
- rvm: 3.0.0
|
16
|
+
gemfile: gemfiles/rails_5.2.gemfile
|
30
17
|
allow_failures:
|
31
|
-
- rvm: ruby-head
|
18
|
+
- rvm: ruby-head
|
data/Appraisals
CHANGED
@@ -1,19 +1,11 @@
|
|
1
|
-
appraise "rails-
|
2
|
-
gem "rails", "~>
|
1
|
+
appraise "rails-6.1" do
|
2
|
+
gem "rails", "~> 6.1.0"
|
3
3
|
end
|
4
4
|
|
5
|
-
appraise "rails-
|
6
|
-
gem "rails", "~>
|
5
|
+
appraise "rails-6.0" do
|
6
|
+
gem "rails", "~> 6.0.0"
|
7
7
|
end
|
8
8
|
|
9
|
-
appraise "rails-
|
10
|
-
gem "rails",
|
9
|
+
appraise "rails-5.2" do
|
10
|
+
gem "rails", "~> 5.2.0"
|
11
11
|
end
|
12
|
-
|
13
|
-
appraise "rails-4.1" do
|
14
|
-
gem "rails", "~> 4.1.0"
|
15
|
-
end
|
16
|
-
|
17
|
-
appraise "rails-3.2" do
|
18
|
-
gem "rails", "~> 3.2.0"
|
19
|
-
end
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,151 @@
|
|
1
|
+
# Changelog
|
2
|
+
|
3
|
+
All notable changes to this project will be documented in this file.
|
4
|
+
|
5
|
+
## [2.0.0]
|
6
|
+
|
7
|
+
- New spinner, IP based, validation check (#89)
|
8
|
+
- Drop official support for unmaintained Rails versions: 5.1, 5.0 and 4.2 (#86)
|
9
|
+
- Drop official support for EOL Rubies: 2.4 and 2.3 (#86)
|
10
|
+
|
11
|
+
## [1.1.0]
|
12
|
+
|
13
|
+
- New option `prepend: true` for the controller macro (#77)
|
14
|
+
|
15
|
+
## [1.0.1]
|
16
|
+
|
17
|
+
- Fix naming issue with Ruby 2.7 (#65)
|
18
|
+
|
19
|
+
## [1.0.0]
|
20
|
+
|
21
|
+
- Remove Ruby 2.2 and Rails 3.2 support
|
22
|
+
- Add Instrumentation event (#62)
|
23
|
+
|
24
|
+
## [0.13.0]
|
25
|
+
|
26
|
+
- Add support for the Content Security Policy nonce (#61)
|
27
|
+
- Freeze all strings (#60)
|
28
|
+
|
29
|
+
## [0.12.2]
|
30
|
+
|
31
|
+
- Allow new timestamp to be set during `on_timestamp_spam` callback (#53)
|
32
|
+
|
33
|
+
## [0.12.1]
|
34
|
+
|
35
|
+
- Clear timestamp stored in `session[:invisible_captcha_timestamp]` (#50)
|
36
|
+
- Rails 6 support
|
37
|
+
|
38
|
+
## [0.12.0]
|
39
|
+
|
40
|
+
- Honeypot input with autocomplete="off" by default (#42)
|
41
|
+
|
42
|
+
## [0.11.0]
|
43
|
+
|
44
|
+
- Improve logging (#40, #41)
|
45
|
+
- Official Rails 5.2 support
|
46
|
+
- Drop Ruby 2.1 from CI
|
47
|
+
|
48
|
+
## [0.10.0]
|
49
|
+
|
50
|
+
- New timestamp on each request to avoid stale timestamps (#24)
|
51
|
+
- Allow to inject styles manually anywhere in the layout (#27)
|
52
|
+
- Allow to change threshold per action
|
53
|
+
- Dynamic css strategy to hide the honeypot
|
54
|
+
- Remove Ruby 1.9 support
|
55
|
+
- Random default honeypots on each restart
|
56
|
+
- Allow to pass html_options to honeypot input (#28)
|
57
|
+
- Improvements on demo application and tests
|
58
|
+
- Better strong parameters interaction (#30, #33)
|
59
|
+
|
60
|
+
## [0.9.3]
|
61
|
+
|
62
|
+
- Rails 5.1 support (#29)
|
63
|
+
- Modernize CI Rubies
|
64
|
+
|
65
|
+
## [0.9.2]
|
66
|
+
|
67
|
+
- Rails 5.0 official support (#23)
|
68
|
+
- Travis CI matrix improvements
|
69
|
+
|
70
|
+
## [0.9.1]
|
71
|
+
|
72
|
+
- Add option (`timestamp_enabled`) to disable timestamp check (#22)
|
73
|
+
|
74
|
+
## [0.9.0]
|
75
|
+
|
76
|
+
- Remove model style validations (#14)
|
77
|
+
- Consider as spam if timestamp not in session (#11)
|
78
|
+
- Allow to define a different threshold per action (#8)
|
79
|
+
- Appraisals integration (#8)
|
80
|
+
- CI improvements: use new Travis infrastructure (#8)
|
81
|
+
|
82
|
+
## [0.8.2]
|
83
|
+
|
84
|
+
- Default timestamp action redirects to back (#19)
|
85
|
+
- Stores timestamps as string in session (#17)
|
86
|
+
|
87
|
+
## [0.8.1]
|
88
|
+
|
89
|
+
- Time-sensitive form submissions (#7)
|
90
|
+
- I18n integration (#13)
|
91
|
+
|
92
|
+
## [0.8.0]
|
93
|
+
|
94
|
+
- Better Rails integration with `ActiveSupport.on_load` callbacks (#5)
|
95
|
+
- Allow to override settings via the view helper (#5)
|
96
|
+
|
97
|
+
## [0.7.0]
|
98
|
+
|
99
|
+
- Revamped code base to allow more customizations (#2)
|
100
|
+
- Added basic specs (#2)
|
101
|
+
- Travis integration (#2)
|
102
|
+
- Demo app (#2)
|
103
|
+
|
104
|
+
## [0.6.5]
|
105
|
+
|
106
|
+
- Stop using Jeweler
|
107
|
+
|
108
|
+
## [0.6.4]
|
109
|
+
|
110
|
+
- Docs! (#1)
|
111
|
+
|
112
|
+
## [0.6.3]
|
113
|
+
|
114
|
+
- Internal re-naming
|
115
|
+
|
116
|
+
## [0.6.2]
|
117
|
+
|
118
|
+
- Fix gem initialization
|
119
|
+
|
120
|
+
## [0.6.0]
|
121
|
+
|
122
|
+
- Allow to configure via `InvisibleCaptcha.setup` block
|
123
|
+
|
124
|
+
## [0.5.0]
|
125
|
+
|
126
|
+
- First version of controller filters
|
127
|
+
|
128
|
+
[2.0.0]: https://github.com/markets/invisible_captcha/compare/v1.1.0...v2.0.0
|
129
|
+
[1.1.0]: https://github.com/markets/invisible_captcha/compare/v1.0.1...v1.1.0
|
130
|
+
[1.0.1]: https://github.com/markets/invisible_captcha/compare/v1.0.0...v1.0.1
|
131
|
+
[1.0.0]: https://github.com/markets/invisible_captcha/compare/v0.13.0...v1.0.0
|
132
|
+
[0.13.0]: https://github.com/markets/invisible_captcha/compare/v0.12.2...v0.13.0
|
133
|
+
[0.12.2]: https://github.com/markets/invisible_captcha/compare/v0.12.1...v0.12.2
|
134
|
+
[0.12.1]: https://github.com/markets/invisible_captcha/compare/v0.12.0...v0.12.1
|
135
|
+
[0.12.0]: https://github.com/markets/invisible_captcha/compare/v0.11.0...v0.12.0
|
136
|
+
[0.11.0]: https://github.com/markets/invisible_captcha/compare/v0.10.0...v0.11.0
|
137
|
+
[0.10.0]: https://github.com/markets/invisible_captcha/compare/v0.9.3...v0.10.0
|
138
|
+
[0.9.3]: https://github.com/markets/invisible_captcha/compare/v0.9.2...v0.9.3
|
139
|
+
[0.9.2]: https://github.com/markets/invisible_captcha/compare/v0.9.1...v0.9.2
|
140
|
+
[0.9.1]: https://github.com/markets/invisible_captcha/compare/v0.9.0...v0.9.1
|
141
|
+
[0.9.0]: https://github.com/markets/invisible_captcha/compare/v0.8.2...v0.9.0
|
142
|
+
[0.8.2]: https://github.com/markets/invisible_captcha/compare/v0.8.1...v0.8.2
|
143
|
+
[0.8.1]: https://github.com/markets/invisible_captcha/compare/v0.8.0...v0.8.1
|
144
|
+
[0.8.0]: https://github.com/markets/invisible_captcha/compare/v0.7.0...v0.8.0
|
145
|
+
[0.7.0]: https://github.com/markets/invisible_captcha/compare/v0.6.5...v0.7.0
|
146
|
+
[0.6.5]: https://github.com/markets/invisible_captcha/compare/v0.6.4...v0.6.5
|
147
|
+
[0.6.4]: https://github.com/markets/invisible_captcha/compare/v0.6.3...v0.6.4
|
148
|
+
[0.6.3]: https://github.com/markets/invisible_captcha/compare/v0.6.2...v0.6.3
|
149
|
+
[0.6.2]: https://github.com/markets/invisible_captcha/compare/v0.6.0...v0.6.2
|
150
|
+
[0.6.0]: https://github.com/markets/invisible_captcha/compare/v0.5.0...v0.6.0
|
151
|
+
[0.5.0]: https://github.com/markets/invisible_captcha/compare/v0.4.1...v0.5.0
|
data/Gemfile
CHANGED
data/LICENSE
CHANGED
data/README.md
CHANGED
@@ -1,37 +1,34 @@
|
|
1
1
|
# Invisible Captcha
|
2
2
|
|
3
|
-
[![Gem
|
3
|
+
[![Gem](https://img.shields.io/gem/v/invisible_captcha.svg?style=flat-square)](https://rubygems.org/gems/invisible_captcha)
|
4
|
+
[![Build Status](https://travis-ci.com/markets/invisible_captcha.svg?branch=master)](https://travis-ci.com/markets/invisible_captcha)
|
4
5
|
|
5
|
-
>
|
6
|
+
> Complete and flexible spam protection solution for Rails applications.
|
6
7
|
|
7
8
|
Invisible Captcha provides different techniques to protect your application against spambots.
|
8
9
|
|
9
|
-
The main protection is a solution based on the `honeypot` principle, which provides a better user experience
|
10
|
+
The main protection is a solution based on the `honeypot` principle, which provides a better user experience since there are no extra steps for real users, only for the bots.
|
10
11
|
|
11
12
|
Essentially, the strategy consists on adding an input field :honey_pot: into the form that:
|
12
13
|
|
13
|
-
|
14
|
-
|
15
|
-
|
14
|
+
- shouldn't be visible by the real users
|
15
|
+
- should be left empty by the real users
|
16
|
+
- will most likely be filled by spam bots
|
16
17
|
|
17
|
-
It also comes with
|
18
|
+
It also comes with:
|
19
|
+
- a time-sensitive :hourglass: form submission
|
20
|
+
- an IP based :mag: spinner validation
|
18
21
|
|
19
22
|
## Installation
|
20
23
|
|
21
|
-
Invisible Captcha is tested against Rails `>=
|
24
|
+
Invisible Captcha is tested against Rails `>= 5.2` and Ruby `>= 2.5`.
|
22
25
|
|
23
|
-
Add this line to
|
26
|
+
Add this line to your Gemfile and then execute `bundle install`:
|
24
27
|
|
25
|
-
```
|
28
|
+
```ruby
|
26
29
|
gem 'invisible_captcha'
|
27
30
|
```
|
28
31
|
|
29
|
-
Or install the gem manually:
|
30
|
-
|
31
|
-
```
|
32
|
-
$ gem install invisible_captcha
|
33
|
-
```
|
34
|
-
|
35
32
|
## Usage
|
36
33
|
|
37
34
|
View code:
|
@@ -52,7 +49,7 @@ class TopicsController < ApplicationController
|
|
52
49
|
end
|
53
50
|
```
|
54
51
|
|
55
|
-
This method will act as a `before_action` that triggers when spam is detected (honeypot field has some value). By default it responds with no content (only headers: `head(200)`). This is a good default, since the bot will surely read the response code and will think that it has achieved to submit the form properly. But, anyway, you
|
52
|
+
This method will act as a `before_action` that triggers when spam is detected (honeypot field has some value). By default, it responds with no content (only headers: `head(200)`). This is a good default, since the bot will surely read the response code and will think that it has achieved to submit the form properly. But, anyway, you can define your own callback by passing a method to the `on_spam` option:
|
56
53
|
|
57
54
|
```ruby
|
58
55
|
class TopicsController < ApplicationController
|
@@ -66,7 +63,7 @@ class TopicsController < ApplicationController
|
|
66
63
|
end
|
67
64
|
```
|
68
65
|
|
69
|
-
Note that is not mandatory to specify a `honeypot` attribute (
|
66
|
+
Note that it is not mandatory to specify a `honeypot` attribute (neither in the view nor in the controller). In this case, the engine will take a random field from `InvisibleCaptcha.honeypots`. So, if you're integrating it following this path, in your form:
|
70
67
|
|
71
68
|
```erb
|
72
69
|
<%= form_tag(new_contact_path) do |f| %>
|
@@ -74,12 +71,32 @@ Note that is not mandatory to specify a `honeypot` attribute (nor in the view, n
|
|
74
71
|
<% end %>
|
75
72
|
```
|
76
73
|
|
77
|
-
In
|
74
|
+
In your controller:
|
78
75
|
|
79
76
|
```
|
80
77
|
invisible_captcha only: [:new_contact]
|
81
78
|
```
|
82
79
|
|
80
|
+
`invisible_captcha` sends all messages to `flash[:error]`. For messages to appear on your pages, add `<%= flash[:error] %>` to `app/views/layouts/application.html.erb` (somewhere near the top of your `<body>` element):
|
81
|
+
|
82
|
+
```erb
|
83
|
+
<!DOCTYPE html>
|
84
|
+
<html>
|
85
|
+
<head>
|
86
|
+
<title>Yet another Rails app</title>
|
87
|
+
<%= stylesheet_link_tag "application", media: "all" %>
|
88
|
+
<%= javascript_include_tag "application" %>
|
89
|
+
<%= csrf_meta_tags %>
|
90
|
+
</head>
|
91
|
+
<body>
|
92
|
+
<%= flash[:error] %>
|
93
|
+
<%= yield %>
|
94
|
+
</body>
|
95
|
+
</html>
|
96
|
+
```
|
97
|
+
|
98
|
+
You can place `<%= flash[:error] %>` next to `:alert` and `:notice` message types, if you have them in your `app/views/layouts/application.html.erb`.
|
99
|
+
|
83
100
|
## Options and customization
|
84
101
|
|
85
102
|
This section contains a description of all plugin options and customizations.
|
@@ -88,13 +105,15 @@ This section contains a description of all plugin options and customizations.
|
|
88
105
|
|
89
106
|
You can customize:
|
90
107
|
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
108
|
+
- `sentence_for_humans`: text for real users if input field was visible. By default, it uses I18n (see below).
|
109
|
+
- `honeypots`: collection of default honeypots. Used by the view helper, called with no args, to generate a random honeypot field name. By default, a random collection is already generated. As the random collection is stored in memory, it will not work if you are running multiple Rails instances behind a load balancer. See [Multiple Rails instances](#multiple-rails-instances).
|
110
|
+
- `visual_honeypots`: make honeypots visible, also useful to test/debug your implementation.
|
111
|
+
- `timestamp_threshold`: fastest time (in seconds) to expect a human to submit the form (see [original article by Yoav Aner](https://blog.gingerlime.com/2012/simple-detection-of-comment-spam-in-rails/) outlining the idea). By default, 4 seconds. **NOTE:** It's recommended to deactivate the autocomplete feature to avoid false positives (`autocomplete="off"`).
|
112
|
+
- `timestamp_enabled`: option to disable the time threshold check at application level. Could be useful, for example, on some testing scenarios. By default, true.
|
113
|
+
- `timestamp_error_message`: flash error message thrown when form submitted quicker than the `timestamp_threshold` value. It uses I18n by default.
|
114
|
+
- `injectable_styles`: if enabled, you should call anywhere in your layout the following helper `<%= invisible_captcha_styles %>`. This allows you to inject styles, for example, in `<head>`. False by default, styles are injected inline with the honeypot.
|
115
|
+
- `spinner_enabled`: option to disable the IP spinner validation.
|
116
|
+
- `secret`: customize the secret key to encode some internal values. By default, it reads the environment variable `ENV['INVISIBLE_CAPTCHA_SECRET']` and fallbacks to random value. Be careful, if you are running multiple Rails instances behind a load balancer, use always the same value via the environment variable.
|
98
117
|
|
99
118
|
To change these defaults, add the following to an initializer (recommended `config/initializers/invisible_captcha.rb`):
|
100
119
|
|
@@ -102,9 +121,10 @@ To change these defaults, add the following to an initializer (recommended `conf
|
|
102
121
|
InvisibleCaptcha.setup do |config|
|
103
122
|
# config.honeypots << ['more', 'fake', 'attribute', 'names']
|
104
123
|
# config.visual_honeypots = false
|
105
|
-
# config.timestamp_threshold =
|
124
|
+
# config.timestamp_threshold = 2
|
106
125
|
# config.timestamp_enabled = true
|
107
126
|
# config.injectable_styles = false
|
127
|
+
# config.spinner_enabled = true
|
108
128
|
|
109
129
|
# Leave these unset if you want to use I18n (see below)
|
110
130
|
# config.sentence_for_humans = 'If you are a human, ignore this field'
|
@@ -112,28 +132,52 @@ InvisibleCaptcha.setup do |config|
|
|
112
132
|
end
|
113
133
|
```
|
114
134
|
|
135
|
+
#### Multiple Rails instances
|
136
|
+
|
137
|
+
If you have multiple Rails instances running behind a load balancer, you have to share the same honeypots collection between the instances.
|
138
|
+
|
139
|
+
Either use a fixed collection or share them between the instances using `Rails.cache`:
|
140
|
+
|
141
|
+
```ruby
|
142
|
+
InvisibleCaptcha.setup do |config|
|
143
|
+
config.honeypots = Rails.cache.fetch('invisible_captcha_honeypots') do
|
144
|
+
(1..20).map { InvisibleCaptcha.generate_random_honeypot }
|
145
|
+
end
|
146
|
+
end
|
147
|
+
```
|
148
|
+
|
149
|
+
Be careful also with the `secret` setting. Since it will be stored in-memory, if you are running this setup, the best idea is to provide the environment variable (`ENV['INVISIBLE_CAPTCHA_SECRET']`) from your infrastructure.
|
150
|
+
|
115
151
|
### Controller method options:
|
116
152
|
|
117
153
|
The `invisible_captcha` method accepts some options:
|
118
154
|
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
155
|
+
- `only`: apply to given controller actions.
|
156
|
+
- `except`: exclude to given controller actions.
|
157
|
+
- `honeypot`: name of custom honeypot.
|
158
|
+
- `scope`: name of scope, ie: 'topic[subtitle]' -> 'topic' is the scope. By default, it's inferred from the `controller_name`.
|
159
|
+
- `on_spam`: custom callback to be called on spam detection.
|
160
|
+
- `timestamp_enabled`: enable/disable this technique at action level.
|
161
|
+
- `on_timestamp_spam`: custom callback to be called when form submitted too quickly. The default action redirects to `:back` printing a warning in `flash[:error]`.
|
162
|
+
- `timestamp_threshold`: custom threshold per controller/action. Overrides the global value for `InvisibleCaptcha.timestamp_threshold`.
|
163
|
+
- `prepend`: the spam detection will run in a `prepend_before_action` if `prepend: true`, otherwise will run in a `before_action`.
|
127
164
|
|
128
165
|
### View helpers options:
|
129
166
|
|
130
|
-
Using the view/form helper you can override some defaults for the given instance. Actually, it allows to change:
|
167
|
+
Using the view/form helper you can override some defaults for the given instance. Actually, it allows to change:
|
168
|
+
|
169
|
+
- `sentence_for_humans`
|
131
170
|
|
132
171
|
```erb
|
133
172
|
<%= form_for(@topic) do |f| %>
|
134
|
-
<%= f.invisible_captcha :subtitle,
|
135
|
-
|
136
|
-
|
173
|
+
<%= f.invisible_captcha :subtitle, sentence_for_humans: "hey! leave this input empty!" %>
|
174
|
+
<% end %>
|
175
|
+
```
|
176
|
+
- `visual_honeypots`
|
177
|
+
|
178
|
+
```erb
|
179
|
+
<%= form_for(@topic) do |f| %>
|
180
|
+
<%= f.invisible_captcha :subtitle, visual_honeypots: true %>
|
137
181
|
<% end %>
|
138
182
|
```
|
139
183
|
|
@@ -143,6 +187,71 @@ You can also pass html options to the input:
|
|
143
187
|
<%= invisible_captcha :subtitle, :topic, id: "your_id", class: "your_class" %>
|
144
188
|
```
|
145
189
|
|
190
|
+
### Spam detection notifications
|
191
|
+
|
192
|
+
In addition to the `on_spam` controller callback, you can use the [Active Support Instrumentation API](https://guides.rubyonrails.org/active_support_instrumentation.html) to set up a global event handler that fires whenever spam is detected. This is useful for advanced logging, background processing, etc.
|
193
|
+
|
194
|
+
To set up a global event handler, [subscribe](https://guides.rubyonrails.org/active_support_instrumentation.html#subscribing-to-an-event) to the `invisible_captcha.spam_detected` event in an initializer:
|
195
|
+
|
196
|
+
```ruby
|
197
|
+
# config/initializers/invisible_captcha.rb
|
198
|
+
|
199
|
+
ActiveSupport::Notifications.subscribe('invisible_captcha.spam_detected') do |*args, data|
|
200
|
+
AwesomeLogger.warn(data[:message], data) # Log to an external logging service.
|
201
|
+
SpamRequest.create(data) # Record the blocked request in your database.
|
202
|
+
end
|
203
|
+
```
|
204
|
+
|
205
|
+
The `data` passed to the subscriber is hash containing information about the request that was detected as spam. For example:
|
206
|
+
|
207
|
+
```ruby
|
208
|
+
{
|
209
|
+
message: "Invisible Captcha honeypot param 'subtitle' was present.",
|
210
|
+
remote_ip: '127.0.0.1',
|
211
|
+
user_agent: 'Chrome 77',
|
212
|
+
controller: 'users',
|
213
|
+
action: 'create',
|
214
|
+
url: 'http://example.com/users',
|
215
|
+
params: {
|
216
|
+
topic: { subtitle: 'foo' },
|
217
|
+
controller: 'users',
|
218
|
+
action: 'create'
|
219
|
+
}
|
220
|
+
}
|
221
|
+
```
|
222
|
+
|
223
|
+
_**Note:** `params` will be filtered according to your `Rails.application.config.filter_parameters` configuration, making them (probably) safe for logging. But always double-check that you're not inadvertently logging sensitive form data, like passwords and credit cards._
|
224
|
+
|
225
|
+
### Content Security Policy
|
226
|
+
|
227
|
+
If you're using a Content Security Policy (CSP) in your Rails app, you will need to generate a nonce on the server, and pass `nonce: true` attribute to the view helper. Uncomment the following lines in your `config/initializers/content_security_policy.rb` file:
|
228
|
+
|
229
|
+
```ruby
|
230
|
+
# Be sure to restart your server when you modify this file.
|
231
|
+
|
232
|
+
# If you are using UJS then enable automatic nonce generation
|
233
|
+
Rails.application.config.content_security_policy_nonce_generator = -> request { SecureRandom.base64(16) }
|
234
|
+
|
235
|
+
# Set the nonce only to specific directives
|
236
|
+
Rails.application.config.content_security_policy_nonce_directives = %w(style-src)
|
237
|
+
```
|
238
|
+
Note that if you are already generating nonce for scripts, you'd have to include `script-src` to `content_security_policy_nonce_directives` as well:
|
239
|
+
|
240
|
+
```ruby
|
241
|
+
Rails.application.config.content_security_policy_nonce_directives = %w(script-src style-src)
|
242
|
+
```
|
243
|
+
|
244
|
+
And in your view helper, you need to pass `nonce: true` to the `invisible_captcha` helper:
|
245
|
+
|
246
|
+
```erb
|
247
|
+
<%= invisible_captcha nonce: true %>
|
248
|
+
```
|
249
|
+
|
250
|
+
**WARNING:** Content Security Policy can break your site! If you already run a website with third-party scripts, styles, images, and fonts, it is highly recommended to enable CSP in report-only mode and observe warnings as they appear. Learn more at MDN:
|
251
|
+
|
252
|
+
* https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP
|
253
|
+
* https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy
|
254
|
+
|
146
255
|
### I18n
|
147
256
|
|
148
257
|
`invisible_captcha` tries to use I18n when it's available by default. The keys it looks for are the following:
|
@@ -154,10 +263,33 @@ en:
|
|
154
263
|
timestamp_error_message: "Sorry, that was too quick! Please resubmit."
|
155
264
|
```
|
156
265
|
|
157
|
-
You can override the
|
266
|
+
You can override the English ones in your i18n config files as well as add new ones for other locales.
|
158
267
|
|
159
268
|
If you intend to use I18n with `invisible_captcha`, you _must not_ set `sentence_for_humans` or `timestamp_error_message` to strings in the setup phase.
|
160
269
|
|
270
|
+
## Testing your controllers
|
271
|
+
|
272
|
+
If you're encountering unexpected behaviour while testing controllers that use the `invisible_captcha` action filter, you may want to disable timestamp check for the test environment. Add the following snippet to the `config/initializers/invisible_captcha.rb` file:
|
273
|
+
|
274
|
+
```ruby
|
275
|
+
# Be sure to restart your server when you modify this file.
|
276
|
+
|
277
|
+
InvisibleCaptcha.setup do |config|
|
278
|
+
config.timestamp_enabled = !Rails.env.test?
|
279
|
+
end
|
280
|
+
```
|
281
|
+
|
282
|
+
Another option is to wait for the timestamp check to be valid:
|
283
|
+
|
284
|
+
```ruby
|
285
|
+
# Maybe in a before block
|
286
|
+
InvisibleCaptcha.init!
|
287
|
+
InvisibleCaptcha.timestamp_threshold = 1
|
288
|
+
|
289
|
+
# Before testing your controller action
|
290
|
+
sleep InvisibleCaptcha.timestamp_threshold
|
291
|
+
```
|
292
|
+
|
161
293
|
## Contribute
|
162
294
|
|
163
295
|
Any kind of idea, feedback or bug report are welcome! Open an [issue](https://github.com/markets/invisible_captcha/issues) or send a [pull request](https://github.com/markets/invisible_captcha/pulls).
|
@@ -179,6 +311,12 @@ $ bundle exec appraisal install
|
|
179
311
|
$ bundle exec appraisal rspec
|
180
312
|
```
|
181
313
|
|
314
|
+
Run specs against specific version:
|
315
|
+
|
316
|
+
```
|
317
|
+
$ bundle exec appraisal rails-6.0 rspec
|
318
|
+
```
|
319
|
+
|
182
320
|
### Demo
|
183
321
|
|
184
322
|
Start a sample Rails app ([source code](spec/dummy)) with `InvisibleCaptcha` integrated:
|
data/Rakefile
CHANGED
data/invisible_captcha.gemspec
CHANGED
@@ -5,8 +5,8 @@ Gem::Specification.new do |spec|
|
|
5
5
|
spec.version = InvisibleCaptcha::VERSION
|
6
6
|
spec.authors = ["Marc Anguera Insa"]
|
7
7
|
spec.email = ["srmarc.ai@gmail.com"]
|
8
|
-
spec.description = "Unobtrusive, flexible and
|
9
|
-
spec.summary = "
|
8
|
+
spec.description = "Unobtrusive, flexible and complete spam protection for Rails applications using honeypot strategy for better user experience."
|
9
|
+
spec.summary = "Honeypot spam protection for Rails"
|
10
10
|
spec.homepage = "https://github.com/markets/invisible_captcha"
|
11
11
|
spec.license = "MIT"
|
12
12
|
|
@@ -15,11 +15,8 @@ Gem::Specification.new do |spec|
|
|
15
15
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
16
16
|
spec.require_paths = ["lib"]
|
17
17
|
|
18
|
-
spec.add_dependency 'rails', '>=
|
18
|
+
spec.add_dependency 'rails', '>= 5.0'
|
19
19
|
|
20
|
-
spec.add_development_dependency 'rspec-rails'
|
20
|
+
spec.add_development_dependency 'rspec-rails'
|
21
21
|
spec.add_development_dependency 'appraisal'
|
22
|
-
spec.add_development_dependency 'test-unit', '~> 3.0'
|
23
|
-
spec.add_development_dependency 'byebug'
|
24
22
|
end
|
25
|
-
|