invisible_captcha 2.0.0 → 2.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +35 -0
- data/Appraisals +10 -10
- data/CHANGELOG.md +19 -0
- data/LICENSE +1 -1
- data/README.md +33 -8
- data/Rakefile +1 -6
- data/gemfiles/rails_7.0.gemfile +7 -0
- data/gemfiles/rails_7.1.gemfile +7 -0
- data/invisible_captcha.gemspec +4 -1
- data/lib/invisible_captcha/controller_ext.rb +17 -11
- data/lib/invisible_captcha/form_helpers.rb +1 -1
- data/lib/invisible_captcha/version.rb +1 -1
- data/lib/invisible_captcha/view_helpers.rb +1 -1
- data/spec/controllers_spec.rb +61 -5
- data/spec/dummy/app/controllers/topics_controller.rb +28 -0
- data/spec/dummy/app/views/layouts/application.html.erb +8 -3
- data/spec/dummy/config/application.rb +0 -2
- data/spec/dummy/config/environments/development.rb +1 -4
- data/spec/dummy/config/environments/test.rb +1 -1
- data/spec/dummy/config/routes.rb +3 -0
- data/spec/dummy/{app/assets/stylesheets/application.css → public/styles.css} +18 -4
- data/spec/spec_helper.rb +7 -0
- metadata +55 -21
- data/.travis.yml +0 -18
- data/spec/dummy/app/assets/config/manifest.js +0 -2
- data/spec/dummy/app/assets/javascripts/application.js +0 -1
- data/spec/dummy/app/mailers/.gitkeep +0 -0
- data/spec/dummy/config/environments/production.rb +0 -86
- data/spec/dummy/lib/assets/.gitkeep +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8421f23e2c4ca4f1512efe6f0ac5b7d538c21fae25c94dae1eb12080bcc7bff2
|
4
|
+
data.tar.gz: d80bbba59b964e84f677620a2c24a5047744a95733805981583034e3629034a4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 94f28d33d89e5dcfa741d97c34c4a42645a5d3f668238653341cd402c1e1e3bfbf8d2c42f5bc6d9d8bda3815d3e7036c0dae13965691e7409ce5df1ff5763bee
|
7
|
+
data.tar.gz: 2a187357840766a3eae1c40f032015c38f07a2b12955c9bfc82f95251b81138a6eab8e69ccd0adbfb9e5f13c095a541e869f2b3d5672e29a75b893253702965e
|
@@ -0,0 +1,35 @@
|
|
1
|
+
name: CI
|
2
|
+
|
3
|
+
on: [push, pull_request]
|
4
|
+
|
5
|
+
jobs:
|
6
|
+
test:
|
7
|
+
name: CI
|
8
|
+
runs-on: ubuntu-latest
|
9
|
+
env:
|
10
|
+
BUNDLE_GEMFILE: ${{ github.workspace }}/gemfiles/${{ matrix.gemfile }}.gemfile
|
11
|
+
strategy:
|
12
|
+
fail-fast: false
|
13
|
+
matrix:
|
14
|
+
ruby: ["2.7", "3.0", "3.1", "3.2"]
|
15
|
+
gemfile: [rails_6.0, rails_6.1, rails_7.0, rails_7.1]
|
16
|
+
exclude:
|
17
|
+
- ruby: "3.1"
|
18
|
+
gemfile: rails_6.0
|
19
|
+
- ruby: "3.2"
|
20
|
+
gemfile: rails_6.0
|
21
|
+
include:
|
22
|
+
- ruby: "2.7"
|
23
|
+
gemfile: rails_5.2
|
24
|
+
- ruby: head
|
25
|
+
gemfile: rails_7.0
|
26
|
+
steps:
|
27
|
+
- uses: actions/checkout@v3
|
28
|
+
- uses: ruby/setup-ruby@v1
|
29
|
+
with:
|
30
|
+
ruby-version: ${{ matrix.ruby }}
|
31
|
+
bundler-cache: true
|
32
|
+
- run: bundle exec rspec
|
33
|
+
continue-on-error: ${{ endsWith(matrix.ruby, 'head') }}
|
34
|
+
- name: Upload coverage reports to Codecov
|
35
|
+
uses: codecov/codecov-action@v3
|
data/Appraisals
CHANGED
@@ -1,11 +1,11 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
1
|
+
%w(
|
2
|
+
7.1
|
3
|
+
7.0
|
4
|
+
6.1
|
5
|
+
6.0
|
6
|
+
5.2
|
7
|
+
).each do |version|
|
8
|
+
appraise "rails-#{version}" do
|
9
|
+
gem "rails", "~> #{version}.0"
|
10
|
+
end
|
11
11
|
end
|
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,22 @@
|
|
2
2
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
4
4
|
|
5
|
+
## [2.3.0]
|
6
|
+
|
7
|
+
- Run honeypot + spinner checks and their callback also if timestamp triggers but passes through (#132)
|
8
|
+
- Mark as spam requests with no spinner value (#134)
|
9
|
+
|
10
|
+
## [2.2.0]
|
11
|
+
|
12
|
+
- Official support for Rails 7.1
|
13
|
+
- Fix flash message for `on_timestamp_spam` callback (#125)
|
14
|
+
- Fix potential error when lookup the honeypot parameter using (#128)
|
15
|
+
|
16
|
+
## [2.1.0]
|
17
|
+
|
18
|
+
- Drop official support for EOL Rubies: 2.5 and 2.6
|
19
|
+
- Allow random honeypots to be scoped (#117)
|
20
|
+
|
5
21
|
## [2.0.0]
|
6
22
|
|
7
23
|
- New spinner, IP based, validation check (#89)
|
@@ -125,6 +141,9 @@ All notable changes to this project will be documented in this file.
|
|
125
141
|
|
126
142
|
- First version of controller filters
|
127
143
|
|
144
|
+
[2.3.0]: https://github.com/markets/invisible_captcha/compare/v2.2.0...v2.3.0
|
145
|
+
[2.2.0]: https://github.com/markets/invisible_captcha/compare/v2.1.0...v2.2.0
|
146
|
+
[2.1.0]: https://github.com/markets/invisible_captcha/compare/v2.0.0...v2.1.0
|
128
147
|
[2.0.0]: https://github.com/markets/invisible_captcha/compare/v1.1.0...v2.0.0
|
129
148
|
[1.1.0]: https://github.com/markets/invisible_captcha/compare/v1.0.1...v1.1.0
|
130
149
|
[1.0.1]: https://github.com/markets/invisible_captcha/compare/v1.0.0...v1.0.1
|
data/LICENSE
CHANGED
data/README.md
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
# Invisible Captcha
|
2
2
|
|
3
3
|
[![Gem](https://img.shields.io/gem/v/invisible_captcha.svg?style=flat-square)](https://rubygems.org/gems/invisible_captcha)
|
4
|
-
[![Build Status](https://
|
4
|
+
[![Build Status](https://github.com/markets/invisible_captcha/workflows/CI/badge.svg)](https://github.com/markets/invisible_captcha/actions)
|
5
|
+
[![codecov](https://codecov.io/gh/markets/invisible_captcha/branch/master/graph/badge.svg?token=nADSa6rbhM)](https://codecov.io/gh/markets/invisible_captcha)
|
5
6
|
|
6
7
|
> Complete and flexible spam protection solution for Rails applications.
|
7
8
|
|
@@ -21,7 +22,7 @@ It also comes with:
|
|
21
22
|
|
22
23
|
## Installation
|
23
24
|
|
24
|
-
Invisible Captcha is tested against Rails `>= 5.2` and Ruby `>= 2.
|
25
|
+
Invisible Captcha is tested against Rails `>= 5.2` and Ruby `>= 2.7`.
|
25
26
|
|
26
27
|
Add this line to your Gemfile and then execute `bundle install`:
|
27
28
|
|
@@ -63,6 +64,8 @@ class TopicsController < ApplicationController
|
|
63
64
|
end
|
64
65
|
```
|
65
66
|
|
67
|
+
You should _not_ name your method `on_spam`, as this will collide with an internal method of the same name.
|
68
|
+
|
66
69
|
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:
|
67
70
|
|
68
71
|
```erb
|
@@ -97,6 +100,8 @@ invisible_captcha only: [:new_contact]
|
|
97
100
|
|
98
101
|
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
102
|
|
103
|
+
**NOTE:** This gem relies on data set by the backend, so in order to properly work, your forms should be rendered by Rails. Forms generated via JavaScript are not going to work well.
|
104
|
+
|
100
105
|
## Options and customization
|
101
106
|
|
102
107
|
This section contains a description of all plugin options and customizations.
|
@@ -106,13 +111,13 @@ This section contains a description of all plugin options and customizations.
|
|
106
111
|
You can customize:
|
107
112
|
|
108
113
|
- `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
|
114
|
+
- `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)). Beware that Chrome may ignore `autocomplete="off"`. Thus, consider not to use field names, which would be autocompleted, like for example `name`, `country`.
|
110
115
|
- `visual_honeypots`: make honeypots visible, also useful to test/debug your implementation.
|
111
116
|
- `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
117
|
- `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
118
|
- `timestamp_error_message`: flash error message thrown when form submitted quicker than the `timestamp_threshold` value. It uses I18n by default.
|
114
119
|
- `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.
|
120
|
+
- `spinner_enabled`: option to disable the IP spinner validation. By default, true.
|
116
121
|
- `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.
|
117
122
|
|
118
123
|
To change these defaults, add the following to an initializer (recommended `config/initializers/invisible_captcha.rb`):
|
@@ -206,7 +211,7 @@ The `data` passed to the subscriber is hash containing information about the req
|
|
206
211
|
|
207
212
|
```ruby
|
208
213
|
{
|
209
|
-
message: "
|
214
|
+
message: "Honeypot param 'subtitle' was present.",
|
210
215
|
remote_ip: '127.0.0.1',
|
211
216
|
user_agent: 'Chrome 77',
|
212
217
|
controller: 'users',
|
@@ -220,7 +225,7 @@ The `data` passed to the subscriber is hash containing information about the req
|
|
220
225
|
}
|
221
226
|
```
|
222
227
|
|
223
|
-
|
228
|
+
**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
229
|
|
225
230
|
### Content Security Policy
|
226
231
|
|
@@ -247,7 +252,7 @@ And in your view helper, you need to pass `nonce: true` to the `invisible_captch
|
|
247
252
|
<%= invisible_captcha nonce: true %>
|
248
253
|
```
|
249
254
|
|
250
|
-
**
|
255
|
+
**NOTE:** 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
256
|
|
252
257
|
* https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP
|
253
258
|
* https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy
|
@@ -282,7 +287,7 @@ end
|
|
282
287
|
Another option is to wait for the timestamp check to be valid:
|
283
288
|
|
284
289
|
```ruby
|
285
|
-
# Maybe
|
290
|
+
# Maybe inside a before block
|
286
291
|
InvisibleCaptcha.init!
|
287
292
|
InvisibleCaptcha.timestamp_threshold = 1
|
288
293
|
|
@@ -290,6 +295,26 @@ InvisibleCaptcha.timestamp_threshold = 1
|
|
290
295
|
sleep InvisibleCaptcha.timestamp_threshold
|
291
296
|
```
|
292
297
|
|
298
|
+
If you're using the "random honeypot" approach, you may want to set a known honeypot:
|
299
|
+
|
300
|
+
```ruby
|
301
|
+
config.honeypots = ['my_honeypot_field'] if Rails.env.test?
|
302
|
+
```
|
303
|
+
|
304
|
+
And for the "spinner validation" check, you may want to disable it:
|
305
|
+
|
306
|
+
```ruby
|
307
|
+
config.spinner_enabled = !Rails.env.test?
|
308
|
+
```
|
309
|
+
|
310
|
+
Or alternativelly, you should send a valid spinner value along your requests:
|
311
|
+
|
312
|
+
```ruby
|
313
|
+
# RSpec example
|
314
|
+
session[:invisible_captcha_spinner] = '32ab649161f9f6faeeb323746de1a25d'
|
315
|
+
post :create, params: { topic: { title: 'foo' }, spinner: '32ab649161f9f6faeeb323746de1a25d' }
|
316
|
+
```
|
317
|
+
|
293
318
|
## Contribute
|
294
319
|
|
295
320
|
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).
|
data/Rakefile
CHANGED
@@ -1,11 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "bundler/gem_tasks"
|
4
|
-
require 'rspec/core/rake_task'
|
5
|
-
|
6
|
-
RSpec::Core::RakeTask.new(:spec)
|
7
|
-
|
8
|
-
task :default => :spec
|
9
4
|
|
10
5
|
desc 'Start development Rails app'
|
11
6
|
task :web do
|
@@ -16,4 +11,4 @@ task :web do
|
|
16
11
|
|
17
12
|
Dir.chdir(app_path)
|
18
13
|
exec("rails s -p #{port}")
|
19
|
-
end
|
14
|
+
end
|
data/invisible_captcha.gemspec
CHANGED
@@ -15,8 +15,11 @@ 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', '>= 5.
|
18
|
+
spec.add_dependency 'rails', '>= 5.2'
|
19
19
|
|
20
20
|
spec.add_development_dependency 'rspec-rails'
|
21
21
|
spec.add_development_dependency 'appraisal'
|
22
|
+
spec.add_development_dependency 'webrick'
|
23
|
+
spec.add_development_dependency 'simplecov'
|
24
|
+
spec.add_development_dependency 'simplecov-cobertura'
|
22
25
|
end
|
@@ -21,7 +21,10 @@ module InvisibleCaptcha
|
|
21
21
|
def detect_spam(options = {})
|
22
22
|
if timestamp_spam?(options)
|
23
23
|
on_timestamp_spam(options)
|
24
|
-
|
24
|
+
return if performed?
|
25
|
+
end
|
26
|
+
|
27
|
+
if honeypot_spam?(options) || spinner_spam?
|
25
28
|
on_spam(options)
|
26
29
|
end
|
27
30
|
end
|
@@ -30,7 +33,8 @@ module InvisibleCaptcha
|
|
30
33
|
if action = options[:on_timestamp_spam]
|
31
34
|
send(action)
|
32
35
|
else
|
33
|
-
|
36
|
+
flash[:error] = InvisibleCaptcha.timestamp_error_message
|
37
|
+
redirect_back(fallback_location: root_path)
|
34
38
|
end
|
35
39
|
end
|
36
40
|
|
@@ -55,7 +59,7 @@ module InvisibleCaptcha
|
|
55
59
|
|
56
60
|
# Consider as spam if timestamp not in session, cause that means the form was not fetched at all
|
57
61
|
unless timestamp
|
58
|
-
warn_spam("
|
62
|
+
warn_spam("Timestamp not found in session.")
|
59
63
|
return true
|
60
64
|
end
|
61
65
|
|
@@ -64,7 +68,7 @@ module InvisibleCaptcha
|
|
64
68
|
|
65
69
|
# Consider as spam if form submitted too quickly
|
66
70
|
if time_to_submit < threshold
|
67
|
-
warn_spam("
|
71
|
+
warn_spam("Timestamp threshold not reached (took #{time_to_submit.to_i}s).")
|
68
72
|
return true
|
69
73
|
end
|
70
74
|
|
@@ -72,8 +76,8 @@ module InvisibleCaptcha
|
|
72
76
|
end
|
73
77
|
|
74
78
|
def spinner_spam?
|
75
|
-
if InvisibleCaptcha.spinner_enabled && params[:spinner] != session[:invisible_captcha_spinner]
|
76
|
-
warn_spam("
|
79
|
+
if InvisibleCaptcha.spinner_enabled && (params[:spinner].blank? || params[:spinner] != session[:invisible_captcha_spinner])
|
80
|
+
warn_spam("Spinner value mismatch")
|
77
81
|
return true
|
78
82
|
end
|
79
83
|
|
@@ -88,8 +92,8 @@ module InvisibleCaptcha
|
|
88
92
|
# If honeypot is defined for this controller-action, search for:
|
89
93
|
# - honeypot: params[:subtitle]
|
90
94
|
# - honeypot with scope: params[:topic][:subtitle]
|
91
|
-
if params[honeypot].present? || params
|
92
|
-
warn_spam("
|
95
|
+
if params[honeypot].present? || (params[scope] && params[scope][honeypot].present?)
|
96
|
+
warn_spam("Honeypot param '#{honeypot}' was present.")
|
93
97
|
return true
|
94
98
|
else
|
95
99
|
# No honeypot spam detected, remove honeypot from params to avoid UnpermittedParameters exceptions
|
@@ -98,8 +102,8 @@ module InvisibleCaptcha
|
|
98
102
|
end
|
99
103
|
else
|
100
104
|
InvisibleCaptcha.honeypots.each do |default_honeypot|
|
101
|
-
if params[default_honeypot].present?
|
102
|
-
warn_spam("
|
105
|
+
if params[default_honeypot].present? || (params[scope] && params[scope][default_honeypot].present?)
|
106
|
+
warn_spam("Honeypot param '#{scope}.#{default_honeypot}' was present.")
|
103
107
|
return true
|
104
108
|
end
|
105
109
|
end
|
@@ -109,7 +113,9 @@ module InvisibleCaptcha
|
|
109
113
|
end
|
110
114
|
|
111
115
|
def warn_spam(message)
|
112
|
-
|
116
|
+
message = "[Invisible Captcha] Potential spam detected for IP #{request.remote_ip}. #{message}"
|
117
|
+
|
118
|
+
logger.warn(message)
|
113
119
|
|
114
120
|
ActiveSupport::Notifications.instrument(
|
115
121
|
'invisible_captcha.spam_detected',
|
@@ -57,7 +57,7 @@ module InvisibleCaptcha
|
|
57
57
|
concat label_tag(build_label_name(honeypot, scope), label)
|
58
58
|
concat text_field_tag(build_input_name(honeypot, scope), nil, default_honeypot_options.merge(options))
|
59
59
|
if InvisibleCaptcha.spinner_enabled
|
60
|
-
concat hidden_field_tag("spinner", session[:invisible_captcha_spinner])
|
60
|
+
concat hidden_field_tag("spinner", session[:invisible_captcha_spinner], id: nil)
|
61
61
|
end
|
62
62
|
end
|
63
63
|
end
|
data/spec/controllers_spec.rb
CHANGED
@@ -71,6 +71,12 @@ RSpec.describe InvisibleCaptcha::ControllerExt, type: :controller do
|
|
71
71
|
.to be_present
|
72
72
|
end
|
73
73
|
|
74
|
+
it 'runs on_spam callback if on_timestamp_spam callback is defined but passes' do
|
75
|
+
put :test_passthrough, params: { id: 1, topic: { title: 'bar', subtitle: 'foo' } }
|
76
|
+
|
77
|
+
expect(response.status).to eq(204)
|
78
|
+
end
|
79
|
+
|
74
80
|
context 'successful submissions' do
|
75
81
|
it 'passes if submission on or after timestamp_threshold' do
|
76
82
|
sleep InvisibleCaptcha.timestamp_threshold
|
@@ -84,7 +90,7 @@ RSpec.describe InvisibleCaptcha::ControllerExt, type: :controller do
|
|
84
90
|
}
|
85
91
|
|
86
92
|
expect(flash[:error]).not_to be_present
|
87
|
-
expect(response.body).to
|
93
|
+
expect(response.body).to redirect_to(new_topic_path)
|
88
94
|
|
89
95
|
# Make sure session is cleared
|
90
96
|
expect(session[:invisible_captcha_timestamp]).to be_nil
|
@@ -96,7 +102,13 @@ RSpec.describe InvisibleCaptcha::ControllerExt, type: :controller do
|
|
96
102
|
post :publish, params: { id: 1 }
|
97
103
|
|
98
104
|
expect(flash[:error]).not_to be_present
|
99
|
-
expect(response.body).to
|
105
|
+
expect(response.body).to redirect_to(new_topic_path)
|
106
|
+
end
|
107
|
+
|
108
|
+
it 'passes if on_timestamp_spam doesn\'t perform' do
|
109
|
+
put :test_passthrough, params: { id: 1, topic: { title: 'bar' } }
|
110
|
+
|
111
|
+
expect(response.body).to redirect_to(new_topic_path)
|
100
112
|
end
|
101
113
|
end
|
102
114
|
end
|
@@ -121,6 +133,50 @@ RSpec.describe InvisibleCaptcha::ControllerExt, type: :controller do
|
|
121
133
|
expect(response.body).to be_present
|
122
134
|
end
|
123
135
|
|
136
|
+
context 'with random honeypot' do
|
137
|
+
context 'auto-scoped' do
|
138
|
+
it 'passes with no spam' do
|
139
|
+
post :categorize, params: { topic: { title: 'foo' } }
|
140
|
+
|
141
|
+
expect(response.body).to redirect_to(new_topic_path)
|
142
|
+
end
|
143
|
+
|
144
|
+
it 'fails with spam' do
|
145
|
+
post :categorize, params: { topic: { "#{InvisibleCaptcha.honeypots.sample}": 'foo' } }
|
146
|
+
|
147
|
+
expect(response.body).not_to redirect_to(new_topic_path)
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
context 'with no scope' do
|
152
|
+
it 'passes with no spam' do
|
153
|
+
post :categorize
|
154
|
+
|
155
|
+
expect(response.body).to redirect_to(new_topic_path)
|
156
|
+
end
|
157
|
+
|
158
|
+
it 'fails with spam' do
|
159
|
+
post :categorize, params: { "#{InvisibleCaptcha.honeypots.sample}": 'foo' }
|
160
|
+
|
161
|
+
expect(response.body).not_to redirect_to(new_topic_path)
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
context 'with scope' do
|
166
|
+
it 'fails with spam' do
|
167
|
+
post :rename, params: { topic: { "#{InvisibleCaptcha.honeypots.sample}": 'foo' } }
|
168
|
+
|
169
|
+
expect(response.body).to be_blank
|
170
|
+
end
|
171
|
+
|
172
|
+
it 'passes with no spam' do
|
173
|
+
post :rename, params: { topic: { title: 'foo' } }
|
174
|
+
|
175
|
+
expect(response.body).to be_blank
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
124
180
|
it 'allow a custom on_spam callback' do
|
125
181
|
put :update, params: { id: 1, topic: { subtitle: 'foo' } }
|
126
182
|
|
@@ -148,8 +204,8 @@ RSpec.describe InvisibleCaptcha::ControllerExt, type: :controller do
|
|
148
204
|
after { ActiveSupport::Notifications.unsubscribe(subscriber) }
|
149
205
|
|
150
206
|
it 'dispatches an `invisible_captcha.spam_detected` event' do
|
151
|
-
expect(dummy_handler).to receive(:handle_event).once.with(
|
152
|
-
message: "Invisible Captcha
|
207
|
+
expect(dummy_handler).to receive(:handle_event).once.with({
|
208
|
+
message: "[Invisible Captcha] Potential spam detected for IP 0.0.0.0. Honeypot param 'subtitle' was present.",
|
153
209
|
remote_ip: '0.0.0.0',
|
154
210
|
user_agent: 'Rails Testing',
|
155
211
|
controller: 'topics',
|
@@ -160,7 +216,7 @@ RSpec.describe InvisibleCaptcha::ControllerExt, type: :controller do
|
|
160
216
|
controller: 'topics',
|
161
217
|
action: 'create'
|
162
218
|
}
|
163
|
-
)
|
219
|
+
})
|
164
220
|
|
165
221
|
post :create, params: { topic: { subtitle: 'foo' } }
|
166
222
|
end
|
@@ -9,6 +9,14 @@ class TopicsController < ApplicationController
|
|
9
9
|
|
10
10
|
invisible_captcha honeypot: :subtitle, only: :copy, timestamp_enabled: false
|
11
11
|
|
12
|
+
invisible_captcha scope: :topic, only: :rename
|
13
|
+
|
14
|
+
invisible_captcha only: :categorize
|
15
|
+
|
16
|
+
invisible_captcha honeypot: :subtitle, only: :test_passthrough,
|
17
|
+
on_spam: :catching_on_spam_callback,
|
18
|
+
on_timestamp_spam: :on_timestamp_spam_callback_with_passthrough
|
19
|
+
|
12
20
|
def index
|
13
21
|
redirect_to new_topic_path
|
14
22
|
end
|
@@ -28,6 +36,14 @@ class TopicsController < ApplicationController
|
|
28
36
|
end
|
29
37
|
|
30
38
|
def update
|
39
|
+
redirect_to new_topic_path
|
40
|
+
end
|
41
|
+
|
42
|
+
def rename
|
43
|
+
end
|
44
|
+
|
45
|
+
def categorize
|
46
|
+
redirect_to new_topic_path
|
31
47
|
end
|
32
48
|
|
33
49
|
def publish
|
@@ -44,6 +60,10 @@ class TopicsController < ApplicationController
|
|
44
60
|
end
|
45
61
|
end
|
46
62
|
|
63
|
+
def test_passthrough
|
64
|
+
redirect_to new_topic_path
|
65
|
+
end
|
66
|
+
|
47
67
|
private
|
48
68
|
|
49
69
|
def custom_callback
|
@@ -53,4 +73,12 @@ class TopicsController < ApplicationController
|
|
53
73
|
def custom_timestamp_callback
|
54
74
|
head(204)
|
55
75
|
end
|
76
|
+
|
77
|
+
def on_timestamp_spam_callback_with_passthrough
|
78
|
+
end
|
79
|
+
|
80
|
+
def catching_on_spam_callback
|
81
|
+
head(204)
|
82
|
+
end
|
83
|
+
|
56
84
|
end
|
@@ -1,9 +1,8 @@
|
|
1
1
|
<!DOCTYPE html>
|
2
2
|
<html>
|
3
3
|
<head>
|
4
|
-
<title>
|
5
|
-
<%= stylesheet_link_tag
|
6
|
-
<%= javascript_include_tag "application" %>
|
4
|
+
<title>InvisibleCaptcha Demo</title>
|
5
|
+
<%= stylesheet_link_tag "/styles.css" %>
|
7
6
|
<%= csrf_meta_tags %>
|
8
7
|
<%= invisible_captcha_styles %>
|
9
8
|
</head>
|
@@ -25,5 +24,11 @@
|
|
25
24
|
<% end %>
|
26
25
|
|
27
26
|
<%= yield %>
|
27
|
+
|
28
|
+
<footer>
|
29
|
+
Running on
|
30
|
+
<b>Ruby <%= RUBY_VERSION %></b> and
|
31
|
+
<b>Rails <%= Rails.version %></b>
|
32
|
+
</footer>
|
28
33
|
</body>
|
29
34
|
</html>
|
@@ -2,9 +2,7 @@ require File.expand_path('../boot', __FILE__)
|
|
2
2
|
|
3
3
|
require 'action_controller/railtie'
|
4
4
|
require 'action_view/railtie'
|
5
|
-
require 'action_mailer/railtie'
|
6
5
|
require 'active_model/railtie'
|
7
|
-
require 'sprockets/railtie'
|
8
6
|
|
9
7
|
# Require the gems listed in Gemfile, including any gems
|
10
8
|
# you've limited to :test, :development, or :production.
|
@@ -14,7 +14,7 @@ Dummy::Application.configure do
|
|
14
14
|
config.action_controller.perform_caching = false
|
15
15
|
|
16
16
|
# Don't care if the mailer can't send.
|
17
|
-
config.action_mailer.raise_delivery_errors = false
|
17
|
+
# config.action_mailer.raise_delivery_errors = false
|
18
18
|
|
19
19
|
# Print deprecation notices to the Rails logger.
|
20
20
|
config.active_support.deprecation = :log
|
@@ -31,9 +31,6 @@ Dummy::Application.configure do
|
|
31
31
|
# yet still be able to expire them through the digest params.
|
32
32
|
# config.assets.digest = true
|
33
33
|
|
34
|
-
# quiet assets
|
35
|
-
config.assets.quiet = true
|
36
|
-
|
37
34
|
# Adds additional error checking when serving assets at runtime.
|
38
35
|
# Checks for improperly declared sprockets dependencies.
|
39
36
|
# Raises helpful error messages.
|
@@ -30,7 +30,7 @@ Dummy::Application.configure do
|
|
30
30
|
# Tell Action Mailer not to deliver emails to the real world.
|
31
31
|
# The :test delivery method accumulates sent emails in the
|
32
32
|
# ActionMailer::Base.deliveries array.
|
33
|
-
config.action_mailer.delivery_method = :test
|
33
|
+
# config.action_mailer.delivery_method = :test
|
34
34
|
|
35
35
|
# Print deprecation notices to the stderr.
|
36
36
|
config.active_support.deprecation = :stderr
|
data/spec/dummy/config/routes.rb
CHANGED
@@ -8,8 +8,11 @@ h1 {
|
|
8
8
|
border-bottom: 3px solid;
|
9
9
|
}
|
10
10
|
|
11
|
-
|
12
|
-
|
11
|
+
a {
|
12
|
+
color: #000;
|
13
|
+
}
|
14
|
+
|
15
|
+
input, textarea {
|
13
16
|
border: 0;
|
14
17
|
margin-bottom: 1.5em;
|
15
18
|
}
|
@@ -19,13 +22,24 @@ input {
|
|
19
22
|
}
|
20
23
|
|
21
24
|
button {
|
22
|
-
|
25
|
+
color: #fff;
|
26
|
+
background-color: #000;
|
27
|
+
border: none;
|
23
28
|
border-radius: 0.25em;
|
24
29
|
height: 3em;
|
25
30
|
width: 10em;
|
26
31
|
font-size: 1em;
|
27
32
|
}
|
28
33
|
|
34
|
+
footer {
|
35
|
+
position: fixed;
|
36
|
+
bottom: 0;
|
37
|
+
width: 100%;
|
38
|
+
padding: 1em 0;
|
39
|
+
font-size: 0.8em;
|
40
|
+
background-color: #ccc;
|
41
|
+
}
|
42
|
+
|
29
43
|
.errors {
|
30
44
|
color: darkred;
|
31
|
-
}
|
45
|
+
}
|
data/spec/spec_helper.rb
CHANGED
@@ -2,6 +2,13 @@
|
|
2
2
|
|
3
3
|
ENV['RAILS_ENV'] = 'test'
|
4
4
|
|
5
|
+
require 'simplecov'
|
6
|
+
if ENV['CI']
|
7
|
+
require 'simplecov-cobertura'
|
8
|
+
SimpleCov.formatter = SimpleCov::Formatter::CoberturaFormatter
|
9
|
+
end
|
10
|
+
SimpleCov.start
|
11
|
+
|
5
12
|
require File.expand_path("../dummy/config/environment.rb", __FILE__)
|
6
13
|
require 'rspec/rails'
|
7
14
|
require 'invisible_captcha'
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: invisible_captcha
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Marc Anguera Insa
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2024-03-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '5.
|
19
|
+
version: '5.2'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '5.
|
26
|
+
version: '5.2'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: rspec-rails
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -52,6 +52,48 @@ dependencies:
|
|
52
52
|
- - ">="
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: webrick
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: simplecov
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: simplecov-cobertura
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
55
97
|
description: Unobtrusive, flexible and complete spam protection for Rails applications
|
56
98
|
using honeypot strategy for better user experience.
|
57
99
|
email:
|
@@ -60,9 +102,9 @@ executables: []
|
|
60
102
|
extensions: []
|
61
103
|
extra_rdoc_files: []
|
62
104
|
files:
|
105
|
+
- ".github/workflows/ci.yml"
|
63
106
|
- ".gitignore"
|
64
107
|
- ".rspec"
|
65
|
-
- ".travis.yml"
|
66
108
|
- Appraisals
|
67
109
|
- CHANGELOG.md
|
68
110
|
- Gemfile
|
@@ -72,6 +114,8 @@ files:
|
|
72
114
|
- gemfiles/rails_5.2.gemfile
|
73
115
|
- gemfiles/rails_6.0.gemfile
|
74
116
|
- gemfiles/rails_6.1.gemfile
|
117
|
+
- gemfiles/rails_7.0.gemfile
|
118
|
+
- gemfiles/rails_7.1.gemfile
|
75
119
|
- invisible_captcha.gemspec
|
76
120
|
- lib/invisible_captcha.rb
|
77
121
|
- lib/invisible_captcha/controller_ext.rb
|
@@ -82,13 +126,9 @@ files:
|
|
82
126
|
- spec/controllers_spec.rb
|
83
127
|
- spec/dummy/README.md
|
84
128
|
- spec/dummy/Rakefile
|
85
|
-
- spec/dummy/app/assets/config/manifest.js
|
86
|
-
- spec/dummy/app/assets/javascripts/application.js
|
87
|
-
- spec/dummy/app/assets/stylesheets/application.css
|
88
129
|
- spec/dummy/app/controllers/application_controller.rb
|
89
130
|
- spec/dummy/app/controllers/topics_controller.rb
|
90
131
|
- spec/dummy/app/helpers/application_helper.rb
|
91
|
-
- spec/dummy/app/mailers/.gitkeep
|
92
132
|
- spec/dummy/app/models/topic.rb
|
93
133
|
- spec/dummy/app/views/layouts/application.html.erb
|
94
134
|
- spec/dummy/app/views/topics/new.html.erb
|
@@ -101,7 +141,6 @@ files:
|
|
101
141
|
- spec/dummy/config/boot.rb
|
102
142
|
- spec/dummy/config/environment.rb
|
103
143
|
- spec/dummy/config/environments/development.rb
|
104
|
-
- spec/dummy/config/environments/production.rb
|
105
144
|
- spec/dummy/config/environments/test.rb
|
106
145
|
- spec/dummy/config/initializers/backtrace_silencers.rb
|
107
146
|
- spec/dummy/config/initializers/cookies_serializer.rb
|
@@ -114,12 +153,12 @@ files:
|
|
114
153
|
- spec/dummy/config/locales/en.yml
|
115
154
|
- spec/dummy/config/routes.rb
|
116
155
|
- spec/dummy/config/secrets.yml
|
117
|
-
- spec/dummy/lib/assets/.gitkeep
|
118
156
|
- spec/dummy/log/.gitkeep
|
119
157
|
- spec/dummy/public/404.html
|
120
158
|
- spec/dummy/public/422.html
|
121
159
|
- spec/dummy/public/500.html
|
122
160
|
- spec/dummy/public/favicon.ico
|
161
|
+
- spec/dummy/public/styles.css
|
123
162
|
- spec/invisible_captcha_spec.rb
|
124
163
|
- spec/spec_helper.rb
|
125
164
|
- spec/view_helpers_spec.rb
|
@@ -127,7 +166,7 @@ homepage: https://github.com/markets/invisible_captcha
|
|
127
166
|
licenses:
|
128
167
|
- MIT
|
129
168
|
metadata: {}
|
130
|
-
post_install_message:
|
169
|
+
post_install_message:
|
131
170
|
rdoc_options: []
|
132
171
|
require_paths:
|
133
172
|
- lib
|
@@ -142,21 +181,17 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
142
181
|
- !ruby/object:Gem::Version
|
143
182
|
version: '0'
|
144
183
|
requirements: []
|
145
|
-
rubygems_version: 3.
|
146
|
-
signing_key:
|
184
|
+
rubygems_version: 3.4.10
|
185
|
+
signing_key:
|
147
186
|
specification_version: 4
|
148
187
|
summary: Honeypot spam protection for Rails
|
149
188
|
test_files:
|
150
189
|
- spec/controllers_spec.rb
|
151
190
|
- spec/dummy/README.md
|
152
191
|
- spec/dummy/Rakefile
|
153
|
-
- spec/dummy/app/assets/config/manifest.js
|
154
|
-
- spec/dummy/app/assets/javascripts/application.js
|
155
|
-
- spec/dummy/app/assets/stylesheets/application.css
|
156
192
|
- spec/dummy/app/controllers/application_controller.rb
|
157
193
|
- spec/dummy/app/controllers/topics_controller.rb
|
158
194
|
- spec/dummy/app/helpers/application_helper.rb
|
159
|
-
- spec/dummy/app/mailers/.gitkeep
|
160
195
|
- spec/dummy/app/models/topic.rb
|
161
196
|
- spec/dummy/app/views/layouts/application.html.erb
|
162
197
|
- spec/dummy/app/views/topics/new.html.erb
|
@@ -169,7 +204,6 @@ test_files:
|
|
169
204
|
- spec/dummy/config/boot.rb
|
170
205
|
- spec/dummy/config/environment.rb
|
171
206
|
- spec/dummy/config/environments/development.rb
|
172
|
-
- spec/dummy/config/environments/production.rb
|
173
207
|
- spec/dummy/config/environments/test.rb
|
174
208
|
- spec/dummy/config/initializers/backtrace_silencers.rb
|
175
209
|
- spec/dummy/config/initializers/cookies_serializer.rb
|
@@ -182,12 +216,12 @@ test_files:
|
|
182
216
|
- spec/dummy/config/locales/en.yml
|
183
217
|
- spec/dummy/config/routes.rb
|
184
218
|
- spec/dummy/config/secrets.yml
|
185
|
-
- spec/dummy/lib/assets/.gitkeep
|
186
219
|
- spec/dummy/log/.gitkeep
|
187
220
|
- spec/dummy/public/404.html
|
188
221
|
- spec/dummy/public/422.html
|
189
222
|
- spec/dummy/public/500.html
|
190
223
|
- spec/dummy/public/favicon.ico
|
224
|
+
- spec/dummy/public/styles.css
|
191
225
|
- spec/invisible_captcha_spec.rb
|
192
226
|
- spec/spec_helper.rb
|
193
227
|
- spec/view_helpers_spec.rb
|
data/.travis.yml
DELETED
@@ -1,18 +0,0 @@
|
|
1
|
-
language: ruby
|
2
|
-
cache: bundler
|
3
|
-
rvm:
|
4
|
-
- ruby-head
|
5
|
-
- 3.0.0
|
6
|
-
- 2.7.2
|
7
|
-
- 2.6.5
|
8
|
-
- 2.5.8
|
9
|
-
gemfile:
|
10
|
-
- gemfiles/rails_6.1.gemfile
|
11
|
-
- gemfiles/rails_6.0.gemfile
|
12
|
-
- gemfiles/rails_5.2.gemfile
|
13
|
-
matrix:
|
14
|
-
exclude:
|
15
|
-
- rvm: 3.0.0
|
16
|
-
gemfile: gemfiles/rails_5.2.gemfile
|
17
|
-
allow_failures:
|
18
|
-
- rvm: ruby-head
|
@@ -1 +0,0 @@
|
|
1
|
-
console.log('Hi from Invisible Captcha!');
|
File without changes
|
@@ -1,86 +0,0 @@
|
|
1
|
-
Rails.application.configure do
|
2
|
-
# Settings specified here will take precedence over those in config/application.rb.
|
3
|
-
|
4
|
-
# Code is not reloaded between requests.
|
5
|
-
config.cache_classes = true
|
6
|
-
|
7
|
-
# Eager load code on boot. This eager loads most of Rails and
|
8
|
-
# your application in memory, allowing both threaded web servers
|
9
|
-
# and those relying on copy on write to perform better.
|
10
|
-
# Rake tasks automatically ignore this option for performance.
|
11
|
-
config.eager_load = true
|
12
|
-
|
13
|
-
# Full error reports are disabled and caching is turned on.
|
14
|
-
config.consider_all_requests_local = false
|
15
|
-
config.action_controller.perform_caching = true
|
16
|
-
|
17
|
-
# Disable serving static files from the `/public` folder by default since
|
18
|
-
# Apache or NGINX already handles this.
|
19
|
-
config.public_file_server.enabled = ENV['RAILS_SERVE_STATIC_FILES'].present?
|
20
|
-
|
21
|
-
# Compress JavaScripts and CSS.
|
22
|
-
config.assets.js_compressor = :uglifier
|
23
|
-
# config.assets.css_compressor = :sass
|
24
|
-
|
25
|
-
# Do not fallback to assets pipeline if a precompiled asset is missed.
|
26
|
-
config.assets.compile = false
|
27
|
-
|
28
|
-
# `config.assets.precompile` and `config.assets.version` have moved to config/initializers/assets.rb
|
29
|
-
|
30
|
-
# Enable serving of images, stylesheets, and JavaScripts from an asset server.
|
31
|
-
# config.action_controller.asset_host = 'http://assets.example.com'
|
32
|
-
|
33
|
-
# Specifies the header that your server uses for sending files.
|
34
|
-
# config.action_dispatch.x_sendfile_header = 'X-Sendfile' # for Apache
|
35
|
-
# config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for NGINX
|
36
|
-
|
37
|
-
# Mount Action Cable outside main process or domain
|
38
|
-
# config.action_cable.mount_path = nil
|
39
|
-
# config.action_cable.url = 'wss://example.com/cable'
|
40
|
-
# config.action_cable.allowed_request_origins = [ 'http://example.com', /http:\/\/example.*/ ]
|
41
|
-
|
42
|
-
# Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.
|
43
|
-
# config.force_ssl = true
|
44
|
-
|
45
|
-
# Use the lowest log level to ensure availability of diagnostic information
|
46
|
-
# when problems arise.
|
47
|
-
config.log_level = :debug
|
48
|
-
|
49
|
-
# Prepend all log lines with the following tags.
|
50
|
-
config.log_tags = [ :request_id ]
|
51
|
-
|
52
|
-
# Use a different cache store in production.
|
53
|
-
# config.cache_store = :mem_cache_store
|
54
|
-
|
55
|
-
# Use a real queuing backend for Active Job (and separate queues per environment)
|
56
|
-
# config.active_job.queue_adapter = :resque
|
57
|
-
# config.active_job.queue_name_prefix = "dummy_#{Rails.env}"
|
58
|
-
config.action_mailer.perform_caching = false
|
59
|
-
|
60
|
-
# Ignore bad email addresses and do not raise email delivery errors.
|
61
|
-
# Set this to true and configure the email server for immediate delivery to raise delivery errors.
|
62
|
-
# config.action_mailer.raise_delivery_errors = false
|
63
|
-
|
64
|
-
# Enable locale fallbacks for I18n (makes lookups for any locale fall back to
|
65
|
-
# the I18n.default_locale when a translation cannot be found).
|
66
|
-
config.i18n.fallbacks = true
|
67
|
-
|
68
|
-
# Send deprecation notices to registered listeners.
|
69
|
-
config.active_support.deprecation = :notify
|
70
|
-
|
71
|
-
# Use default logging formatter so that PID and timestamp are not suppressed.
|
72
|
-
config.log_formatter = ::Logger::Formatter.new
|
73
|
-
|
74
|
-
# Use a different logger for distributed setups.
|
75
|
-
# require 'syslog/logger'
|
76
|
-
# config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new 'app-name')
|
77
|
-
|
78
|
-
if ENV["RAILS_LOG_TO_STDOUT"].present?
|
79
|
-
logger = ActiveSupport::Logger.new(STDOUT)
|
80
|
-
logger.formatter = config.log_formatter
|
81
|
-
config.logger = ActiveSupport::TaggedLogging.new(logger)
|
82
|
-
end
|
83
|
-
|
84
|
-
# Do not dump schema after migrations.
|
85
|
-
config.active_record.dump_schema_after_migration = false
|
86
|
-
end
|
File without changes
|