invisible_captcha 1.1.0 → 2.1.0

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.
@@ -3,39 +3,25 @@
3
3
  RSpec.describe InvisibleCaptcha::ControllerExt, type: :controller do
4
4
  render_views
5
5
 
6
- def switchable_post(action, params = {})
7
- if Rails.version > '5'
8
- post action, params: params
9
- else
10
- post action, params
11
- end
12
- end
13
-
14
- def switchable_put(action, params = {})
15
- if Rails.version > '5'
16
- put action, params: params
17
- else
18
- put action, params
19
- end
20
- end
21
-
22
6
  before(:each) do
23
7
  @controller = TopicsController.new
24
8
  request.env['HTTP_REFERER'] = 'http://test.host/topics'
9
+
25
10
  InvisibleCaptcha.init!
26
11
  InvisibleCaptcha.timestamp_threshold = 1
12
+ InvisibleCaptcha.spinner_enabled = false
27
13
  end
28
14
 
29
15
  context 'without invisible_captcha_timestamp in session' do
30
16
  it 'fails like if it was submitted too fast' do
31
- switchable_post :create, topic: { title: 'foo' }
17
+ post :create, params: { topic: { title: 'foo' } }
32
18
 
33
19
  expect(response).to redirect_to 'http://test.host/topics'
34
20
  expect(flash[:error]).to eq(InvisibleCaptcha.timestamp_error_message)
35
21
  end
36
22
 
37
23
  it 'passes if disabled at action level' do
38
- switchable_post :copy, topic: { title: 'foo' }
24
+ post :copy, params: { topic: { title: 'foo' } }
39
25
 
40
26
  expect(flash[:error]).not_to be_present
41
27
  expect(response.body).to be_present
@@ -43,7 +29,8 @@ RSpec.describe InvisibleCaptcha::ControllerExt, type: :controller do
43
29
 
44
30
  it 'passes if disabled at app level' do
45
31
  InvisibleCaptcha.timestamp_enabled = false
46
- switchable_post :create, topic: { title: 'foo' }
32
+
33
+ post :create, params: { topic: { title: 'foo' } }
47
34
 
48
35
  expect(flash[:error]).not_to be_present
49
36
  expect(response.body).to be_present
@@ -56,7 +43,7 @@ RSpec.describe InvisibleCaptcha::ControllerExt, type: :controller do
56
43
  end
57
44
 
58
45
  it 'fails if submission before timestamp_threshold' do
59
- switchable_post :create, topic: { title: 'foo' }
46
+ post :create, params: { topic: { title: 'foo' } }
60
47
 
61
48
  expect(response).to redirect_to 'http://test.host/topics'
62
49
  expect(flash[:error]).to eq(InvisibleCaptcha.timestamp_error_message)
@@ -66,7 +53,7 @@ RSpec.describe InvisibleCaptcha::ControllerExt, type: :controller do
66
53
  end
67
54
 
68
55
  it 'allows a custom on_timestamp_spam callback' do
69
- switchable_put :update, id: 1, topic: { title: 'bar' }
56
+ put :update, params: { id: 1, topic: { title: 'bar' } }
70
57
 
71
58
  expect(response.status).to eq(204)
72
59
  end
@@ -79,7 +66,7 @@ RSpec.describe InvisibleCaptcha::ControllerExt, type: :controller do
79
66
  end
80
67
  end
81
68
 
82
- expect { switchable_put :update, id: 1, topic: { title: 'bar' } }
69
+ expect { put :update, params: { id: 1, topic: { title: 'bar' } } }
83
70
  .to change { session[:invisible_captcha_timestamp] }
84
71
  .to be_present
85
72
  end
@@ -88,10 +75,12 @@ RSpec.describe InvisibleCaptcha::ControllerExt, type: :controller do
88
75
  it 'passes if submission on or after timestamp_threshold' do
89
76
  sleep InvisibleCaptcha.timestamp_threshold
90
77
 
91
- switchable_post :create, topic: {
92
- title: 'foobar',
93
- author: 'author',
94
- body: 'body that passes validation'
78
+ post :create, params: {
79
+ topic: {
80
+ title: 'foobar',
81
+ author: 'author',
82
+ body: 'body that passes validation'
83
+ }
95
84
  }
96
85
 
97
86
  expect(flash[:error]).not_to be_present
@@ -104,7 +93,7 @@ RSpec.describe InvisibleCaptcha::ControllerExt, type: :controller do
104
93
  it 'allow to set a custom timestamp_threshold per action' do
105
94
  sleep 2 # custom threshold
106
95
 
107
- switchable_post :publish, id: 1
96
+ post :publish, params: { id: 1 }
108
97
 
109
98
  expect(flash[:error]).not_to be_present
110
99
  expect(response.body).to be_present
@@ -115,30 +104,75 @@ RSpec.describe InvisibleCaptcha::ControllerExt, type: :controller do
115
104
  context 'honeypot attribute' do
116
105
  before(:each) do
117
106
  session[:invisible_captcha_timestamp] = Time.zone.now.iso8601
107
+
118
108
  # Wait for valid submission
119
109
  sleep InvisibleCaptcha.timestamp_threshold
120
110
  end
121
111
 
122
112
  it 'fails with spam' do
123
- switchable_post :create, topic: { subtitle: 'foo' }
113
+ post :create, params: { topic: { subtitle: 'foo' } }
124
114
 
125
115
  expect(response.body).to be_blank
126
116
  end
127
117
 
128
118
  it 'passes with no spam' do
129
- switchable_post :create, topic: { title: 'foo' }
119
+ post :create, params: { topic: { title: 'foo' } }
130
120
 
131
121
  expect(response.body).to be_present
132
122
  end
133
123
 
124
+ context 'with random honeypot' do
125
+ context 'auto-scoped' do
126
+ it 'passes with no spam' do
127
+ post :categorize, params: { topic: { title: 'foo' } }
128
+
129
+ expect(response.body).to be_present
130
+ end
131
+
132
+ it 'fails with spam' do
133
+ post :categorize, params: { topic: { "#{InvisibleCaptcha.honeypots.sample}": 'foo' } }
134
+
135
+ expect(response.body).to be_blank
136
+ end
137
+ end
138
+
139
+ context 'with no scope' do
140
+ it 'passes with no spam' do
141
+ post :categorize
142
+
143
+ expect(response.body).to be_present
144
+ end
145
+
146
+ it 'fails with spam' do
147
+ post :categorize, params: { "#{InvisibleCaptcha.honeypots.sample}": 'foo' }
148
+
149
+ expect(response.body).to be_blank
150
+ end
151
+ end
152
+
153
+ context 'with scope' do
154
+ it 'fails with spam' do
155
+ post :rename, params: { topic: { "#{InvisibleCaptcha.honeypots.sample}": 'foo' } }
156
+
157
+ expect(response.body).to be_blank
158
+ end
159
+
160
+ it 'passes with no spam' do
161
+ post :rename, params: { topic: { title: 'foo' } }
162
+
163
+ expect(response.body).to be_blank
164
+ end
165
+ end
166
+ end
167
+
134
168
  it 'allow a custom on_spam callback' do
135
- switchable_put :update, id: 1, topic: { subtitle: 'foo' }
169
+ put :update, params: { id: 1, topic: { subtitle: 'foo' } }
136
170
 
137
171
  expect(response.body).to redirect_to(new_topic_path)
138
172
  end
139
173
 
140
174
  it 'honeypot is removed from params if you use a custom honeypot' do
141
- switchable_post :create, topic: { title: 'foo', subtitle: '' }
175
+ post :create, params: { topic: { title: 'foo', subtitle: '' } }
142
176
 
143
177
  expect(flash[:error]).not_to be_present
144
178
  expect(@controller.params[:topic].key?(:subtitle)).to eq(false)
@@ -155,31 +189,49 @@ RSpec.describe InvisibleCaptcha::ControllerExt, type: :controller do
155
189
  subscriber
156
190
  end
157
191
 
158
- after { ActiveSupport::Notifications.unsubscribe(subscriber) }
192
+ after { ActiveSupport::Notifications.unsubscribe(subscriber) }
159
193
 
160
194
  it 'dispatches an `invisible_captcha.spam_detected` event' do
161
- # Skip the `with` matcher for Rails < 5 due to issues comparing arguments passed to / recived by the dummy event handler.
162
- # https://github.com/markets/invisible_captcha/pull/62#issuecomment-552218501
163
- if Rails.version > '5'
164
- expect(dummy_handler).to receive(:handle_event).once.with(
165
- message: "Invisible Captcha honeypot param 'subtitle' was present.",
166
- remote_ip: '0.0.0.0',
167
- user_agent: 'Rails Testing',
195
+ expect(dummy_handler).to receive(:handle_event).once.with({
196
+ message: "[Invisible Captcha] Potential spam detected for IP 0.0.0.0. Honeypot param 'subtitle' was present.",
197
+ remote_ip: '0.0.0.0',
198
+ user_agent: 'Rails Testing',
199
+ controller: 'topics',
200
+ action: 'create',
201
+ url: 'http://test.host/topics',
202
+ params: {
203
+ topic: { subtitle: "foo"},
168
204
  controller: 'topics',
169
- action: 'create',
170
- url: 'http://test.host/topics',
171
- params: {
172
- topic: { subtitle: "foo"},
173
- controller: 'topics',
174
- action: 'create'
175
- }
176
- )
177
- else
178
- expect(dummy_handler).to receive(:handle_event).once
179
- end
205
+ action: 'create'
206
+ }
207
+ })
180
208
 
181
- switchable_post :create, topic: { subtitle: 'foo' }
209
+ post :create, params: { topic: { subtitle: 'foo' } }
182
210
  end
183
211
  end
184
212
  end
213
+
214
+ context 'spinner attribute' do
215
+ before(:each) do
216
+ InvisibleCaptcha.spinner_enabled = true
217
+ InvisibleCaptcha.secret = 'secret'
218
+ session[:invisible_captcha_timestamp] = Time.zone.now.iso8601
219
+ session[:invisible_captcha_spinner] = '32ab649161f9f6faeeb323746de1a25d'
220
+
221
+ # Wait for valid submission
222
+ sleep InvisibleCaptcha.timestamp_threshold
223
+ end
224
+
225
+ it 'fails with no spam, but mismatch of spinner' do
226
+ post :create, params: { topic: { title: 'foo' }, spinner: 'mismatch' }
227
+
228
+ expect(response.body).to be_blank
229
+ end
230
+
231
+ it 'passes with no spam and spinner match' do
232
+ post :create, params: { topic: { title: 'foo' }, spinner: '32ab649161f9f6faeeb323746de1a25d' }
233
+
234
+ expect(response.body).to be_present
235
+ end
236
+ end
185
237
  end
@@ -9,6 +9,10 @@ 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
+
12
16
  def index
13
17
  redirect_to new_topic_path
14
18
  end
@@ -28,6 +32,14 @@ class TopicsController < ApplicationController
28
32
  end
29
33
 
30
34
  def update
35
+ redirect_to new_topic_path
36
+ end
37
+
38
+ def rename
39
+ end
40
+
41
+ def categorize
42
+ redirect_to new_topic_path
31
43
  end
32
44
 
33
45
  def publish
@@ -2,8 +2,7 @@
2
2
  <html>
3
3
  <head>
4
4
  <title>Dummy</title>
5
- <%= stylesheet_link_tag "application", :media => "all" %>
6
- <%= javascript_include_tag "application" %>
5
+ <%= stylesheet_link_tag "/styles.css" %>
7
6
  <%= csrf_meta_tags %>
8
7
  <%= invisible_captcha_styles %>
9
8
  </head>
@@ -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.
@@ -14,13 +14,8 @@ Dummy::Application.configure do
14
14
 
15
15
  # Disable serving static files from the `/public` folder by default since
16
16
  # Apache or NGINX already handles this.
17
- if Rails.version >= "5.0.0"
18
- config.public_file_server.enabled = true
19
- config.public_file_server.headers = {'Cache-Control' => 'public, max-age=3600'}
20
- else
21
- config.serve_static_files = true
22
- config.static_cache_control = "public, max-age=3600"
23
- end
17
+ config.public_file_server.enabled = true
18
+ config.public_file_server.headers = {'Cache-Control' => 'public, max-age=3600'}
24
19
 
25
20
  # Show full error reports and disable caching.
26
21
  config.consider_all_requests_local = true
@@ -35,7 +30,7 @@ Dummy::Application.configure do
35
30
  # Tell Action Mailer not to deliver emails to the real world.
36
31
  # The :test delivery method accumulates sent emails in the
37
32
  # ActionMailer::Base.deliveries array.
38
- config.action_mailer.delivery_method = :test
33
+ # config.action_mailer.delivery_method = :test
39
34
 
40
35
  # Print deprecation notices to the stderr.
41
36
  config.active_support.deprecation = :stderr
@@ -1,6 +1,8 @@
1
1
  Rails.application.routes.draw do
2
2
  resources :topics do
3
3
  post :publish, on: :member
4
+ post :rename, on: :collection
5
+ post :categorize, on: :collection
4
6
  post :copy, on: :collection
5
7
  end
6
8
 
@@ -8,8 +8,11 @@ h1 {
8
8
  border-bottom: 3px solid;
9
9
  }
10
10
 
11
- input,
12
- textarea {
11
+ a {
12
+ color: #000;
13
+ }
14
+
15
+ input, textarea {
13
16
  border: 0;
14
17
  margin-bottom: 1.5em;
15
18
  }
@@ -19,7 +22,9 @@ input {
19
22
  }
20
23
 
21
24
  button {
22
- background-color: #f0f0f0;
25
+ color: #fff;
26
+ background-color: #000;
27
+ border: none;
23
28
  border-radius: 0.25em;
24
29
  height: 3em;
25
30
  width: 10em;
@@ -28,4 +33,4 @@ button {
28
33
 
29
34
  .errors {
30
35
  color: darkred;
31
- }
36
+ }
data/spec/spec_helper.rb CHANGED
@@ -2,14 +2,19 @@
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'
8
15
 
9
16
  RSpec.configure do |config|
10
- if Rails.version >= '5.2'
11
- config.include ActionDispatch::ContentSecurityPolicy::Request, type: :helper
12
- end
17
+ config.include ActionDispatch::ContentSecurityPolicy::Request, type: :helper
13
18
  config.disable_monkey_patching!
14
19
  config.order = :random
15
20
  config.expect_with :rspec
@@ -17,17 +22,3 @@ RSpec.configure do |config|
17
22
  mocks.verify_partial_doubles = true
18
23
  end
19
24
  end
20
-
21
- # Rails 4.2 call `initialize` inside `recycle!`. However Ruby 2.6 doesn't allow calling `initialize` twice.
22
- # More info: https://github.com/rails/rails/issues/34790
23
- if RUBY_VERSION >= "2.6.0" && Rails.version < "5"
24
- module ActionController
25
- class TestResponse < ActionDispatch::TestResponse
26
- def recycle!
27
- @mon_mutex_owner_object_id = nil
28
- @mon_mutex = nil
29
- initialize
30
- end
31
- end
32
- end
33
- end
@@ -2,12 +2,8 @@
2
2
 
3
3
  RSpec.describe InvisibleCaptcha::ViewHelpers, type: :helper do
4
4
  before(:each) do
5
- allow(Time.zone).to receive(:now).and_return(Time.zone.parse('Feb 19 1986'))
6
5
  allow(InvisibleCaptcha).to receive(:css_strategy).and_return("display:none;")
7
-
8
- if Rails.version >= '5.2'
9
- allow_any_instance_of(ActionDispatch::ContentSecurityPolicy::Request).to receive(:content_security_policy_nonce).and_return('123')
10
- end
6
+ allow_any_instance_of(ActionDispatch::ContentSecurityPolicy::Request).to receive(:content_security_policy_nonce).and_return('123')
11
7
 
12
8
  # to test content_for and provide
13
9
  @view_flow = ActionView::OutputFlow.new
@@ -32,10 +28,8 @@ RSpec.describe InvisibleCaptcha::ViewHelpers, type: :helper do
32
28
  expect(invisible_captcha(:subtitle, :topic, { class: 'foo_class' })).to match(/class="foo_class"/)
33
29
  end
34
30
 
35
- if Rails.version >= '5.2'
36
- it 'with CSP nonce' do
37
- expect(invisible_captcha(:subtitle, :topic, { nonce: true })).to match(/nonce="123"/)
38
- end
31
+ it 'with CSP nonce' do
32
+ expect(invisible_captcha(:subtitle, :topic, { nonce: true })).to match(/nonce="123"/)
39
33
  end
40
34
 
41
35
  it 'generated html + styles' do
@@ -64,6 +58,18 @@ RSpec.describe InvisibleCaptcha::ViewHelpers, type: :helper do
64
58
  end
65
59
  end
66
60
 
61
+ context "should have spinner field" do
62
+ it 'that exists by default, spinner_enabled is true' do
63
+ InvisibleCaptcha.spinner_enabled = true
64
+ expect(invisible_captcha).to match(/spinner/)
65
+ end
66
+
67
+ it 'that does not exist if spinner_enabled is false' do
68
+ InvisibleCaptcha.spinner_enabled = false
69
+ expect(invisible_captcha).not_to match(/spinner/)
70
+ end
71
+ end
72
+
67
73
  it 'should set spam timestamp' do
68
74
  invisible_captcha
69
75
  expect(session[:invisible_captcha_timestamp]).to eq(Time.zone.now.iso8601)