invisible_captcha 0.8.0 → 0.8.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.
Files changed (35) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +3 -1
  3. data/.rspec +2 -0
  4. data/README.md +28 -6
  5. data/lib/invisible_captcha.rb +34 -4
  6. data/lib/invisible_captcha/controller_ext.rb +24 -2
  7. data/lib/invisible_captcha/version.rb +1 -1
  8. data/lib/invisible_captcha/view_helpers.rb +3 -2
  9. data/spec/controllers_spec.rb +52 -11
  10. data/spec/dummy/app/controllers/topics_controller.rb +7 -1
  11. data/spec/dummy/bin/bundle +3 -0
  12. data/spec/dummy/bin/rails +4 -0
  13. data/spec/dummy/bin/rake +4 -0
  14. data/spec/dummy/bin/setup +29 -0
  15. data/spec/dummy/config/application.rb +16 -5
  16. data/spec/dummy/config/boot.rb +2 -4
  17. data/spec/dummy/config/environment.rb +3 -3
  18. data/spec/dummy/config/environments/development.rb +24 -13
  19. data/spec/dummy/config/environments/production.rb +46 -34
  20. data/spec/dummy/config/environments/test.rb +20 -12
  21. data/spec/dummy/config/initializers/assets.rb +11 -0
  22. data/spec/dummy/config/initializers/cookies_serializer.rb +3 -0
  23. data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  24. data/spec/dummy/config/initializers/inflections.rb +6 -5
  25. data/spec/dummy/config/initializers/mime_types.rb +0 -1
  26. data/spec/dummy/config/initializers/session_store.rb +1 -6
  27. data/spec/dummy/config/initializers/wrap_parameters.rb +7 -2
  28. data/spec/dummy/config/locales/en.yml +20 -2
  29. data/spec/dummy/config/routes.rb +1 -1
  30. data/spec/dummy/config/secrets.yml +22 -0
  31. data/spec/invisible_captcha_spec.rb +36 -1
  32. data/spec/spec_helper.rb +1 -1
  33. data/spec/validator_spec.rb +1 -1
  34. data/spec/view_helpers_spec.rb +8 -2
  35. metadata +19 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 03aab9758bfbaf12adb3913f5b37c8423d269c2e
4
- data.tar.gz: 18e136fc292c192126f7c08d5d60286a4c86ba6b
3
+ metadata.gz: b7eba6a0efa0ea67bedde6d91063e95c22d3ea6c
4
+ data.tar.gz: ea76244a1e88963ffe3ac27f492fb50d3ac63401
5
5
  SHA512:
6
- metadata.gz: c60cc1997f5748fef444f1eea60aa3a47b42ee6de60dffa8f320e346608e224594f4252efbe19d7df80edaf8c137729df4357162cb27f2e8b6c7fa1327aed94f
7
- data.tar.gz: b5b62112cf6ea24aab60e66f589a0756d06e7337c7564e43cdea6a838023334c43e22cba5e486c3c8b1278fe1ef4829a5c925fea3e4917ba919677bd10710049
6
+ metadata.gz: 23c1ba38041202c3007b8f8283f19204d3487d0f6e32be065dea68ee35a39dd9eb11f14af4891a55053b4914f790de6dbb352e2a26c2b1f013573db56cfa598a
7
+ data.tar.gz: 12799ae4924800e64ffff0b50492e646e4aef7375eac687af9170732fb04c8ec2f6b56e9fb50d0c34c37fffc95235e3e108f7f15a77e675b760d2a6e9044ebbd
data/.gitignore CHANGED
@@ -1,6 +1,8 @@
1
1
  .bundle
2
2
  pkg
3
3
  .rvmrc
4
+ .ruby-version
5
+ .ruby-gemset
4
6
  Gemfile.lock
5
7
  spec/dummy/log/*.log
6
- spec/dummy/tmp/
8
+ spec/dummy/tmp/
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format documentation
data/README.md CHANGED
@@ -115,19 +115,24 @@ This section contains a description of all plugin options and customizations.
115
115
 
116
116
  You can customize:
117
117
 
118
- * `sentence_for_humans`: text for real users if input field was visible.
119
- * `error_message`: error message thrown by model validation (only model implementation).
118
+ * `sentence_for_humans`: text for real users if input field was visible. By default, it uses I18n (see below)
119
+ * `error_message`: error message thrown by model validation (only model implementation - by default it uses I18n).
120
120
  * `honeypots`: collection of default honeypots, used by the view helper, called with no args, to generate the honeypot field name
121
121
  * `visual_honeypots`: make honeypots visible, also useful to test/debug your implementation.
122
+ * `timestamp_threshold`: fastest time (4 seconds by default) to expect a human to submit the form (see [original article by Yoav Aner](http://blog.gingerlime.com/2012/simple-detection-of-comment-spam-in-rails/) outlining the idea)
123
+ * `timestamp_error_message`: flash error message thrown when form submitted quicker than the `timestamp_threshold` value. It uses I18n by default.
122
124
 
123
125
  To change these defaults, add the following to an initializer (recommended `config/initializers/invisible_captcha.rb`):
124
126
 
125
127
  ```ruby
126
128
  InvisibleCaptcha.setup do |config|
127
- config.sentence_for_humans = 'If you are a human, ignore this field'
128
- config.error_message = 'You are a robot!'
129
- config.honeypots += 'fake_resource_title'
130
- config.visual_honeypots = false
129
+ config.honeypots += 'fake_resource_title'
130
+ config.visual_honeypots = false
131
+ config.timestamp_threshold = 4.seconds
132
+ # Leave these unset if you want to use I18n (see below)
133
+ # config.error_message = 'You are a robot!'
134
+ # config.sentence_for_humans = 'If you are a human, ignore this field'
135
+ # config.timestamp_error_message = 'Sorry, that was too quick! Please resubmit.'
131
136
  end
132
137
  ```
133
138
 
@@ -140,6 +145,7 @@ The `invisible_captcha` method accepts some options:
140
145
  * `honeypot`: name of honeypot.
141
146
  * `scope`: name of scope, ie: 'topic[subtitle]' -> 'topic' is the scope.
142
147
  * `on_spam`: custom callback to be called on spam detection.
148
+ * `on_timestamp_spam`: custom callback to be called when form submitted too quickly.
143
149
 
144
150
  ### View helpers options:
145
151
 
@@ -153,6 +159,22 @@ Using the view/form helper you can override some defaults for the given instance
153
159
  <% end %>
154
160
  ```
155
161
 
162
+ ### I18n
163
+
164
+ `invisible_captcha` tries to use I18n when it's available by default. The keys it looks for are the following:
165
+
166
+ ```yaml
167
+ en:
168
+ invisible_captcha:
169
+ sentence_for_humans: "If you are human, ignore this field"
170
+ error_message: "You are a robot!"
171
+ timestamp_error_message: "Sorry, that was too quick! Please resubmit."
172
+ ```
173
+
174
+ You can override the english ones in your own i18n config files as well as add new ones for other locales.
175
+
176
+ If you intend to use I18n with `invisible_captcha`, you _must not_ set `sentence_for_humans`, `error_message` or `timestamp_error_message` to strings in the setup phase.
177
+
156
178
  ## Contribute
157
179
 
158
180
  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).
@@ -7,22 +7,46 @@ require 'invisible_captcha/railtie'
7
7
 
8
8
  module InvisibleCaptcha
9
9
  class << self
10
- attr_accessor :sentence_for_humans, :error_message, :honeypots, :visual_honeypots
10
+ attr_writer :sentence_for_humans,
11
+ :timestamp_error_message,
12
+ :error_message
13
+
14
+ attr_accessor :honeypots,
15
+ :timestamp_threshold,
16
+ :visual_honeypots
11
17
 
12
18
  def init!
13
19
  # Default sentence for real users if text field was visible
14
- self.sentence_for_humans = 'If you are a human, ignore this field'
20
+ self.sentence_for_humans = -> { I18n.t('invisible_captcha.sentence_for_humans', default: 'If you are a human, ignore this field') }
15
21
 
16
22
  # Default error message for validator
17
- self.error_message = 'You are a robot!'
23
+ self.error_message = -> { I18n.t('invisible_captcha.error_message', default: 'You are a robot!') }
18
24
 
19
25
  # Default fake fields for controller based workflow
20
26
  self.honeypots = ['foo_id', 'bar_id', 'baz_id']
21
27
 
28
+ # Fastest time to expect a human to submit the form
29
+ self.timestamp_threshold = 4.seconds
30
+
31
+ # Default error message for validator when form submitted too quickly
32
+ self.timestamp_error_message = -> { I18n.t('invisible_captcha.timestamp_error_message', default: 'Sorry, that was too quick! Please resubmit.') }
33
+
22
34
  # Make honeypots visibles
23
35
  self.visual_honeypots = false
24
36
  end
25
37
 
38
+ def sentence_for_humans
39
+ call_lambda_or_return(@sentence_for_humans)
40
+ end
41
+
42
+ def error_message
43
+ call_lambda_or_return(@error_message)
44
+ end
45
+
46
+ def timestamp_error_message
47
+ call_lambda_or_return(@timestamp_error_message)
48
+ end
49
+
26
50
  def setup
27
51
  yield(self) if block_given?
28
52
  end
@@ -30,7 +54,13 @@ module InvisibleCaptcha
30
54
  def get_honeypot
31
55
  honeypots.sample
32
56
  end
57
+
58
+ private
59
+
60
+ def call_lambda_or_return(obj)
61
+ obj.respond_to?(:call) ? obj.call : obj
62
+ end
33
63
  end
34
64
  end
35
65
 
36
- InvisibleCaptcha.init!
66
+ InvisibleCaptcha.init!
@@ -9,11 +9,21 @@ module InvisibleCaptcha
9
9
  end
10
10
 
11
11
  def detect_spam(options = {})
12
- if invisible_captcha?(options)
12
+ if invisible_captcha_timestamp?(options)
13
+ on_timestamp_spam_action(options)
14
+ elsif invisible_captcha?(options)
13
15
  on_spam_action(options)
14
16
  end
15
17
  end
16
18
 
19
+ def on_timestamp_spam_action(options = {})
20
+ if action = options[:on_timestamp_spam]
21
+ send(action)
22
+ else
23
+ flash[:error] = InvisibleCaptcha.timestamp_error_message
24
+ end
25
+ end
26
+
17
27
  def on_spam_action(options = {})
18
28
  if action = options[:on_spam]
19
29
  send(action)
@@ -26,6 +36,18 @@ module InvisibleCaptcha
26
36
  head(200)
27
37
  end
28
38
 
39
+ def invisible_captcha_timestamp?(options = {})
40
+ timestamp = session[:invisible_captcha_timestamp]
41
+ time_to_submit = Time.zone.now - timestamp
42
+
43
+ # Consider as spam if form submitted too quickly
44
+ if timestamp && time_to_submit < InvisibleCaptcha.timestamp_threshold
45
+ logger.warn("Potential spam detected for IP #{request.env['REMOTE_ADDR']}. Invisible Captcha timestamp threshold not reached (took #{time_to_submit.to_i}s).")
46
+ return true
47
+ end
48
+ false
49
+ end
50
+
29
51
  def invisible_captcha?(options = {})
30
52
  honeypot = options[:honeypot]
31
53
  scope = options[:scope] || controller_name.singularize
@@ -45,4 +67,4 @@ module InvisibleCaptcha
45
67
  false
46
68
  end
47
69
  end
48
- end
70
+ end
@@ -1,3 +1,3 @@
1
1
  module InvisibleCaptcha
2
- VERSION = "0.8.0"
2
+ VERSION = "0.8.1"
3
3
  end
@@ -6,6 +6,7 @@ module InvisibleCaptcha
6
6
  # @param scope [Symbol] name of honeypot scope, ie: topic => input name: topic[subtitle]
7
7
  # @return [String] the generated html
8
8
  def invisible_captcha(honeypot = nil, scope = nil, options = {})
9
+ session[:invisible_captcha_timestamp] ||= Time.zone.now
9
10
  build_invisible_captcha(honeypot, scope, options)
10
11
  end
11
12
 
@@ -29,7 +30,7 @@ module InvisibleCaptcha
29
30
  end
30
31
 
31
32
  def generate_html_id(honeypot, scope = nil)
32
- "#{scope || honeypot}_#{Time.now.to_i}"
33
+ "#{scope || honeypot}_#{Time.zone.now.to_i}"
33
34
  end
34
35
 
35
36
  def visibility_css(container_id, options)
@@ -60,4 +61,4 @@ module InvisibleCaptcha
60
61
  end
61
62
  end
62
63
  end
63
- end
64
+ end
@@ -5,21 +5,62 @@ describe InvisibleCaptcha::ControllerExt, type: :controller do
5
5
 
6
6
  before { @controller = TopicsController.new }
7
7
 
8
- it 'with spam' do
9
- post :create, topic: { subtitle: 'foo' }
8
+ context 'submission timestamp_threshold' do
9
+ before do
10
+ session[:invisible_captcha_timestamp] = Time.zone.now
11
+ end
10
12
 
11
- expect(response.body).to be_blank
12
- end
13
+ it 'fails if submission before timestamp_threshold' do
14
+ post :create, topic: { title: 'foo' }
15
+
16
+ expect(response).to redirect_to(new_topic_path)
17
+ expect(flash[:error]).to eq(InvisibleCaptcha.timestamp_error_message)
18
+ end
19
+
20
+ it 'allow custom on_timestamp_spam callback', focus: true do
21
+ put :update, id: 1, topic: { title: 'bar' }
22
+
23
+ expect(response.body).to redirect_to(root_path)
24
+ end
25
+
26
+ context 'successful submissions' do
27
+ before do
28
+ # Wait for valid submission
29
+ sleep InvisibleCaptcha.timestamp_threshold
30
+ end
13
31
 
14
- it 'with no spam' do
15
- post :create, topic: { title: 'foo' }
32
+ it 'passes if submission on or after timestamp_threshold' do
33
+ post :create, topic: { title: 'foo' }
16
34
 
17
- expect(response.body).to be_present
35
+ expect(flash[:error]).not_to be_present
36
+ expect(response.body).to be_present
37
+ end
38
+ end
18
39
  end
19
40
 
20
- it 'allow custom on_spam callback' do
21
- put :update, id: 1, topic: { subtitle: 'foo' }
41
+ context 'form field' do
42
+ before do
43
+ session[:invisible_captcha_timestamp] = Time.zone.now
44
+ # Wait for valid submission
45
+ sleep InvisibleCaptcha.timestamp_threshold
46
+ end
47
+
48
+ it 'with spam' do
49
+ post :create, topic: { subtitle: 'foo' }
50
+
51
+ expect(response.body).to be_blank
52
+ end
53
+
54
+ it 'with no spam' do
55
+ post :create, topic: { title: 'foo' }
56
+
57
+ expect(response.body).to be_present
58
+ end
59
+
60
+ it 'allow custom on_spam callback' do
61
+ put :update, id: 1, topic: { subtitle: 'foo' }
22
62
 
23
- expect(response.body).to redirect_to(new_topic_path)
63
+ expect(response.body).to redirect_to(new_topic_path)
64
+ end
24
65
  end
25
- end
66
+ end
@@ -1,6 +1,8 @@
1
1
  class TopicsController < ApplicationController
2
2
  invisible_captcha honeypot: :subtitle, only: :create
3
- invisible_captcha honeypot: :subtitle, only: :update, on_spam: :custom_callback
3
+ invisible_captcha honeypot: :subtitle, only: :update,
4
+ on_spam: :custom_callback,
5
+ on_timestamp_spam: :custom_timestamp_callback
4
6
 
5
7
  def new
6
8
  @topic = Topic.new
@@ -24,4 +26,8 @@ class TopicsController < ApplicationController
24
26
  def custom_callback
25
27
  redirect_to new_topic_path
26
28
  end
29
+
30
+ def custom_timestamp_callback
31
+ redirect_to root_path
32
+ end
27
33
  end
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
3
+ load Gem.bin_path('bundler', 'bundle')
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+ APP_PATH = File.expand_path('../../config/application', __FILE__)
3
+ require_relative '../config/boot'
4
+ require 'rails/commands'
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+ require_relative '../config/boot'
3
+ require 'rake'
4
+ Rake.application.run
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env ruby
2
+ require 'pathname'
3
+
4
+ # path to your application root.
5
+ APP_ROOT = Pathname.new File.expand_path('../../', __FILE__)
6
+
7
+ Dir.chdir APP_ROOT do
8
+ # This script is a starting point to setup your application.
9
+ # Add necessary setup steps to this file:
10
+
11
+ puts "== Installing dependencies =="
12
+ system "gem install bundler --conservative"
13
+ system "bundle check || bundle install"
14
+
15
+ # puts "\n== Copying sample files =="
16
+ # unless File.exist?("config/database.yml")
17
+ # system "cp config/database.yml.sample config/database.yml"
18
+ # end
19
+
20
+ puts "\n== Preparing database =="
21
+ system "bin/rake db:setup"
22
+
23
+ puts "\n== Removing old logs and tempfiles =="
24
+ system "rm -f log/*"
25
+ system "rm -rf tmp/cache"
26
+
27
+ puts "\n== Restarting application server =="
28
+ system "touch tmp/restart.txt"
29
+ end
@@ -5,16 +5,27 @@ require 'action_view/railtie'
5
5
  require 'action_mailer/railtie'
6
6
  require 'active_model/railtie'
7
7
 
8
+ # Require the gems listed in Gemfile, including any gems
9
+ # you've limited to :test, :development, or :production.
8
10
  Bundler.require(*Rails.groups)
9
11
 
10
12
  require 'invisible_captcha'
11
13
 
12
14
  module Dummy
13
15
  class Application < Rails::Application
14
- config.encoding = 'utf-8'
15
- config.filter_parameters += [:password]
16
- config.assets.enabled = true
17
- config.assets.version = '1.0'
16
+ # Settings in config/environments/* take precedence over those specified here.
17
+ # Application configuration should go into files in config/initializers
18
+ # -- all .rb files in that directory are automatically loaded.
19
+
20
+ # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
21
+ # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.
22
+ # config.time_zone = 'Central Time (US & Canada)'
23
+
24
+ # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
25
+ # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s]
26
+ # config.i18n.default_locale = :de
27
+
28
+ # Do not swallow errors in after_commit/after_rollback callbacks.
29
+ # config.active_record.raise_in_transactional_callbacks = true
18
30
  end
19
31
  end
20
-
@@ -1,5 +1,3 @@
1
- # Set up gems listed in the Gemfile.
2
- ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../../../Gemfile', __FILE__)
1
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
3
2
 
4
- require 'bundler/setup' if File.exists?(ENV['BUNDLE_GEMFILE'])
5
- $LOAD_PATH.unshift File.expand_path('../../../../lib', __FILE__)
3
+ require 'bundler/setup' # Set up gems listed in the Gemfile.
@@ -1,5 +1,5 @@
1
- # Load the rails application
1
+ # Load the Rails application.
2
2
  require File.expand_path('../application', __FILE__)
3
3
 
4
- # Initialize the rails application
5
- Dummy::Application.initialize!
4
+ # Initialize the Rails application.
5
+ Rails.application.initialize!
@@ -1,30 +1,41 @@
1
- Dummy::Application.configure do
2
- # Settings specified here will take precedence over those in config/application.rb
1
+ Rails.application.configure do
2
+ # Settings specified here will take precedence over those in config/application.rb.
3
3
 
4
4
  # In the development environment your application's code is reloaded on
5
5
  # every request. This slows down response time but is perfect for development
6
6
  # since you don't have to restart the web server when you make code changes.
7
7
  config.cache_classes = false
8
8
 
9
- # Log error messages when you accidentally call methods on nil.
10
- config.whiny_nils = true
9
+ # Do not eager load code on boot.
10
+ config.eager_load = false
11
11
 
12
- # Show full error reports and disable caching
12
+ # Show full error reports and disable caching.
13
13
  config.consider_all_requests_local = true
14
14
  config.action_controller.perform_caching = false
15
15
 
16
- # Don't care if the mailer can't send
16
+ # Don't care if the mailer can't send.
17
17
  config.action_mailer.raise_delivery_errors = false
18
18
 
19
- # Print deprecation notices to the Rails logger
19
+ # Print deprecation notices to the Rails logger.
20
20
  config.active_support.deprecation = :log
21
21
 
22
- # Only use best-standards-support built into browsers
23
- config.action_dispatch.best_standards_support = :builtin
22
+ # Raise an error on page load if there are pending migrations.
23
+ # config.active_record.migration_error = :page_load
24
24
 
25
- # Do not compress assets
26
- config.assets.compress = false
27
-
28
- # Expands the lines which load the assets
25
+ # Debug mode disables concatenation and preprocessing of assets.
26
+ # This option may cause significant delays in view rendering with a large
27
+ # number of complex assets.
29
28
  config.assets.debug = true
29
+
30
+ # Asset digests allow you to set far-future HTTP expiration dates on all assets,
31
+ # yet still be able to expire them through the digest params.
32
+ config.assets.digest = true
33
+
34
+ # Adds additional error checking when serving assets at runtime.
35
+ # Checks for improperly declared sprockets dependencies.
36
+ # Raises helpful error messages.
37
+ config.assets.raise_runtime_errors = true
38
+
39
+ # Raises error for missing translations
40
+ # config.action_view.raise_on_missing_translations = true
30
41
  end
@@ -1,67 +1,79 @@
1
- Dummy::Application.configure do
2
- # Settings specified here will take precedence over those in config/application.rb
1
+ Rails.application.configure do
2
+ # Settings specified here will take precedence over those in config/application.rb.
3
3
 
4
- # Code is not reloaded between requests
4
+ # Code is not reloaded between requests.
5
5
  config.cache_classes = true
6
6
 
7
- # Full error reports are disabled and caching is turned on
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.
8
14
  config.consider_all_requests_local = false
9
15
  config.action_controller.perform_caching = true
10
16
 
11
- # Disable Rails's static asset server (Apache or nginx will already do this)
12
- config.serve_static_assets = false
17
+ # Enable Rack::Cache to put a simple HTTP cache in front of your application
18
+ # Add `rack-cache` to your Gemfile before enabling this.
19
+ # For large-scale production use, consider using a caching reverse proxy like
20
+ # NGINX, varnish or squid.
21
+ # config.action_dispatch.rack_cache = true
22
+
23
+ # Disable serving static files from the `/public` folder by default since
24
+ # Apache or NGINX already handles this.
25
+ config.serve_static_files = ENV['RAILS_SERVE_STATIC_FILES'].present?
13
26
 
14
- # Compress JavaScripts and CSS
15
- config.assets.compress = true
27
+ # Compress JavaScripts and CSS.
28
+ config.assets.js_compressor = :uglifier
29
+ # config.assets.css_compressor = :sass
16
30
 
17
- # Don't fallback to assets pipeline if a precompiled asset is missed
31
+ # Do not fallback to assets pipeline if a precompiled asset is missed.
18
32
  config.assets.compile = false
19
33
 
20
- # Generate digests for assets URLs
34
+ # Asset digests allow you to set far-future HTTP expiration dates on all assets,
35
+ # yet still be able to expire them through the digest params.
21
36
  config.assets.digest = true
22
37
 
23
- # Defaults to nil and saved in location specified by config.assets.prefix
24
- # config.assets.manifest = YOUR_PATH
38
+ # `config.assets.precompile` and `config.assets.version` have moved to config/initializers/assets.rb
25
39
 
26
- # Specifies the header that your server uses for sending files
27
- # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for apache
28
- # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for nginx
40
+ # Specifies the header that your server uses for sending files.
41
+ # config.action_dispatch.x_sendfile_header = 'X-Sendfile' # for Apache
42
+ # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for NGINX
29
43
 
30
44
  # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.
31
45
  # config.force_ssl = true
32
46
 
33
- # See everything in the log (default is :info)
34
- # config.log_level = :debug
47
+ # Use the lowest log level to ensure availability of diagnostic information
48
+ # when problems arise.
49
+ config.log_level = :debug
35
50
 
36
- # Prepend all log lines with the following tags
51
+ # Prepend all log lines with the following tags.
37
52
  # config.log_tags = [ :subdomain, :uuid ]
38
53
 
39
- # Use a different logger for distributed setups
54
+ # Use a different logger for distributed setups.
40
55
  # config.logger = ActiveSupport::TaggedLogging.new(SyslogLogger.new)
41
56
 
42
- # Use a different cache store in production
57
+ # Use a different cache store in production.
43
58
  # config.cache_store = :mem_cache_store
44
59
 
45
- # Enable serving of images, stylesheets, and JavaScripts from an asset server
46
- # config.action_controller.asset_host = "http://assets.example.com"
47
-
48
- # Precompile additional assets (application.js, application.css, and all non-JS/CSS are already added)
49
- # config.assets.precompile += %w( search.js )
60
+ # Enable serving of images, stylesheets, and JavaScripts from an asset server.
61
+ # config.action_controller.asset_host = 'http://assets.example.com'
50
62
 
51
- # Disable delivery errors, bad email addresses will be ignored
63
+ # Ignore bad email addresses and do not raise email delivery errors.
64
+ # Set this to true and configure the email server for immediate delivery to raise delivery errors.
52
65
  # config.action_mailer.raise_delivery_errors = false
53
66
 
54
- # Enable threaded mode
55
- # config.threadsafe!
56
-
57
67
  # Enable locale fallbacks for I18n (makes lookups for any locale fall back to
58
- # the I18n.default_locale when a translation can not be found)
68
+ # the I18n.default_locale when a translation cannot be found).
59
69
  config.i18n.fallbacks = true
60
70
 
61
- # Send deprecation notices to registered listeners
71
+ # Send deprecation notices to registered listeners.
62
72
  config.active_support.deprecation = :notify
63
73
 
64
- # Log the query plan for queries taking more than this (works
65
- # with SQLite, MySQL, and PostgreSQL)
66
- # config.active_record.auto_explain_threshold_in_seconds = 0.5
74
+ # Use default logging formatter so that PID and timestamp are not suppressed.
75
+ config.log_formatter = ::Logger::Formatter.new
76
+
77
+ # Do not dump schema after migrations.
78
+ # config.active_record.dump_schema_after_migration = false
67
79
  end
@@ -1,5 +1,5 @@
1
- Dummy::Application.configure do
2
- # Settings specified here will take precedence over those in config/application.rb
1
+ Rails.application.configure do
2
+ # Settings specified here will take precedence over those in config/application.rb.
3
3
 
4
4
  # The test environment is used exclusively to run your application's
5
5
  # test suite. You never need to work with it otherwise. Remember that
@@ -7,28 +7,36 @@ Dummy::Application.configure do
7
7
  # and recreated between test runs. Don't rely on the data there!
8
8
  config.cache_classes = true
9
9
 
10
- # Configure static asset server for tests with Cache-Control for performance
11
- config.serve_static_assets = true
12
- config.static_cache_control = "public, max-age=3600"
10
+ # Do not eager load code on boot. This avoids loading your whole application
11
+ # just for the purpose of running a single test. If you are using a tool that
12
+ # preloads Rails for running tests, you may have to set it to true.
13
+ config.eager_load = false
13
14
 
14
- # Log error messages when you accidentally call methods on nil
15
- config.whiny_nils = true
15
+ # Configure static file server for tests with Cache-Control for performance.
16
+ config.serve_static_files = true
17
+ config.static_cache_control = 'public, max-age=3600'
16
18
 
17
- # Show full error reports and disable caching
19
+ # Show full error reports and disable caching.
18
20
  config.consider_all_requests_local = true
19
21
  config.action_controller.perform_caching = false
20
22
 
21
- # Raise exceptions instead of rendering exception templates
23
+ # Raise exceptions instead of rendering exception templates.
22
24
  config.action_dispatch.show_exceptions = false
23
25
 
24
- # Disable request forgery protection in test environment
25
- config.action_controller.allow_forgery_protection = false
26
+ # Disable request forgery protection in test environment.
27
+ config.action_controller.allow_forgery_protection = false
26
28
 
27
29
  # Tell Action Mailer not to deliver emails to the real world.
28
30
  # The :test delivery method accumulates sent emails in the
29
31
  # ActionMailer::Base.deliveries array.
30
32
  config.action_mailer.delivery_method = :test
31
33
 
32
- # Print deprecation notices to the stderr
34
+ # Randomize the order test cases are executed.
35
+ config.active_support.test_order = :random
36
+
37
+ # Print deprecation notices to the stderr.
33
38
  config.active_support.deprecation = :stderr
39
+
40
+ # Raises error for missing translations
41
+ # config.action_view.raise_on_missing_translations = true
34
42
  end
@@ -0,0 +1,11 @@
1
+ # Be sure to restart your server when you modify this file.
2
+
3
+ # Version of your assets, change this if you want to expire all your assets.
4
+ Rails.application.config.assets.version = '1.0'
5
+
6
+ # Add additional assets to the asset load path
7
+ # Rails.application.config.assets.paths << Emoji.images_path
8
+
9
+ # Precompile additional assets.
10
+ # application.js, application.css, and all non-JS/CSS in app/assets folder are already added.
11
+ # Rails.application.config.assets.precompile += %w( search.js )
@@ -0,0 +1,3 @@
1
+ # Be sure to restart your server when you modify this file.
2
+
3
+ Rails.application.config.action_dispatch.cookies_serializer = :marshal
@@ -0,0 +1,4 @@
1
+ # Be sure to restart your server when you modify this file.
2
+
3
+ # Configure sensitive parameters which will be filtered from the log file.
4
+ Rails.application.config.filter_parameters += [:password]
@@ -1,15 +1,16 @@
1
1
  # Be sure to restart your server when you modify this file.
2
2
 
3
- # Add new inflection rules using the following format
4
- # (all these examples are active by default):
5
- # ActiveSupport::Inflector.inflections do |inflect|
3
+ # Add new inflection rules using the following format. Inflections
4
+ # are locale specific, and you may define rules for as many different
5
+ # locales as you wish. All of these examples are active by default:
6
+ # ActiveSupport::Inflector.inflections(:en) do |inflect|
6
7
  # inflect.plural /^(ox)$/i, '\1en'
7
8
  # inflect.singular /^(ox)en/i, '\1'
8
9
  # inflect.irregular 'person', 'people'
9
10
  # inflect.uncountable %w( fish sheep )
10
11
  # end
11
- #
12
+
12
13
  # These inflection rules are supported but not enabled by default:
13
- # ActiveSupport::Inflector.inflections do |inflect|
14
+ # ActiveSupport::Inflector.inflections(:en) do |inflect|
14
15
  # inflect.acronym 'RESTful'
15
16
  # end
@@ -2,4 +2,3 @@
2
2
 
3
3
  # Add new mime types for use in respond_to blocks:
4
4
  # Mime::Type.register "text/richtext", :rtf
5
- # Mime::Type.register_alias "text/html", :iphone
@@ -1,8 +1,3 @@
1
1
  # Be sure to restart your server when you modify this file.
2
2
 
3
- Dummy::Application.config.session_store :cookie_store, key: '_dummy_session'
4
-
5
- # Use the database for sessions instead of the cookie-based default,
6
- # which shouldn't be used to store highly confidential information
7
- # (create the session table with "rails generate session_migration")
8
- # Dummy::Application.config.session_store :active_record_store
3
+ Rails.application.config.session_store :cookie_store, key: '_dummy_session'
@@ -1,9 +1,14 @@
1
1
  # Be sure to restart your server when you modify this file.
2
- #
2
+
3
3
  # This file contains settings for ActionController::ParamsWrapper which
4
4
  # is enabled by default.
5
5
 
6
6
  # Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array.
7
7
  ActiveSupport.on_load(:action_controller) do
8
- wrap_parameters format: [:json]
8
+ wrap_parameters format: [:json] if respond_to?(:wrap_parameters)
9
9
  end
10
+
11
+ # To enable root element in JSON for ActiveRecord objects.
12
+ # ActiveSupport.on_load(:active_record) do
13
+ # self.include_root_in_json = true
14
+ # end
@@ -1,5 +1,23 @@
1
- # Sample localization file for English. Add more files in this directory for other locales.
2
- # See https://github.com/svenfuchs/rails-i18n/tree/master/rails%2Flocale for starting points.
1
+ # Files in the config/locales directory are used for internationalization
2
+ # and are automatically loaded by Rails. If you want to use locales other
3
+ # than English, add the necessary files in this directory.
4
+ #
5
+ # To use the locales, use `I18n.t`:
6
+ #
7
+ # I18n.t 'hello'
8
+ #
9
+ # In views, this is aliased to just `t`:
10
+ #
11
+ # <%= t('hello') %>
12
+ #
13
+ # To use a different locale, set it with `I18n.locale`:
14
+ #
15
+ # I18n.locale = :es
16
+ #
17
+ # This would use the information in config/locales/es.yml.
18
+ #
19
+ # To learn more, please read the Rails Internationalization guide
20
+ # available at http://guides.rubyonrails.org/i18n.html.
3
21
 
4
22
  en:
5
23
  hello: "Hello world"
@@ -1,4 +1,4 @@
1
- Dummy::Application.routes.draw do
1
+ Rails.application.routes.draw do
2
2
  resources :topics, only: [:new, :create, :update]
3
3
 
4
4
  root to: 'topics#new'
@@ -0,0 +1,22 @@
1
+ # Be sure to restart your server when you modify this file.
2
+
3
+ # Your secret key is used for verifying the integrity of signed cookies.
4
+ # If you change this key, all old signed cookies will become invalid!
5
+
6
+ # Make sure the secret is at least 30 characters and all random,
7
+ # no regular words or you'll be exposed to dictionary attacks.
8
+ # You can use `rake secret` to generate a secure secret key.
9
+
10
+ # Make sure the secrets in this file are kept private
11
+ # if you're sharing your code publicly.
12
+
13
+ development:
14
+ secret_key_base: d55ed9a6ec6fc0b93d2404994c8632220ab5835d77ccbd52760c6fc4b9e0c83f87d78d9c2b66d366a698933feeac81efc445b29bad22c9f267ebdadbc5aebbd4
15
+
16
+ test:
17
+ secret_key_base: 5df5772ea2c76236d1444a2e7a491c9f99f9bc96770b6b52e995555ea7a70b2bd3a3d0a45bbe7d32bf1a0eb450db7e32a838e6aa17c494b464ff381bb4bf9910
18
+
19
+ # Do not keep production secrets in the repository,
20
+ # instead read values from the environment.
21
+ production:
22
+ secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
@@ -6,6 +6,8 @@ describe InvisibleCaptcha do
6
6
 
7
7
  expect(InvisibleCaptcha.sentence_for_humans).to eq('If you are a human, ignore this field')
8
8
  expect(InvisibleCaptcha.error_message).to eq('You are a robot!')
9
+ expect(InvisibleCaptcha.timestamp_threshold).to eq(4.seconds)
10
+ expect(InvisibleCaptcha.timestamp_error_message).to eq('Sorry, that was too quick! Please resubmit.')
9
11
  expect(InvisibleCaptcha.honeypots).to eq(['foo_id', 'bar_id', 'baz_id'])
10
12
  end
11
13
 
@@ -16,4 +18,37 @@ describe InvisibleCaptcha do
16
18
 
17
19
  expect(InvisibleCaptcha.sentence_for_humans).to eq('Another sentence')
18
20
  end
19
- end
21
+
22
+ it 'It uses I18n when available' do
23
+ InvisibleCaptcha.init!
24
+
25
+ I18n.available_locales = [:en, :fr]
26
+
27
+ I18n.backend.store_translations(:en,
28
+ 'invisible_captcha' => {
29
+ 'sentence_for_humans' => "Can't touch this",
30
+ 'error_message' => 'MR ROBOT',
31
+ 'timestamp_error_message' => 'Fast and furious' })
32
+
33
+ I18n.backend.store_translations(:fr,
34
+ 'invisible_captcha' => {
35
+ 'sentence_for_humans' => 'Ne touchez pas',
36
+ 'error_message' => 'Mon dieu, un robot!',
37
+ 'timestamp_error_message' => 'Plus doucement SVP' })
38
+
39
+ I18n.locale = :en
40
+ expect(InvisibleCaptcha.sentence_for_humans).to eq("Can't touch this")
41
+ expect(InvisibleCaptcha.error_message).to eq('MR ROBOT')
42
+ expect(InvisibleCaptcha.timestamp_error_message).to eq('Fast and furious')
43
+
44
+ I18n.locale = :fr
45
+ expect(InvisibleCaptcha.sentence_for_humans).to eq('Ne touchez pas')
46
+ expect(InvisibleCaptcha.error_message).to eq('Mon dieu, un robot!')
47
+ expect(InvisibleCaptcha.timestamp_error_message).to eq('Plus doucement SVP')
48
+
49
+ I18n.backend.reload!
50
+ expect(InvisibleCaptcha.sentence_for_humans).to eq('If you are a human, ignore this field')
51
+ expect(InvisibleCaptcha.error_message).to eq('You are a robot!')
52
+ expect(InvisibleCaptcha.timestamp_error_message).to eq('Sorry, that was too quick! Please resubmit.')
53
+ end
54
+ end
data/spec/spec_helper.rb CHANGED
@@ -13,4 +13,4 @@ RSpec.configure do |config|
13
13
  config.mock_with :rspec do |mocks|
14
14
  mocks.verify_partial_doubles = true
15
15
  end
16
- end
16
+ end
@@ -9,4 +9,4 @@ describe InvisibleCaptcha::InvisibleCaptchaValidator do
9
9
  expect(topic.valid?).to be false
10
10
  expect(topic.errors.messages[:base]).to eq [InvisibleCaptcha.error_message]
11
11
  end
12
- end
12
+ end
@@ -22,7 +22,7 @@ describe InvisibleCaptcha::ViewHelpers, type: :helper do
22
22
  end
23
23
 
24
24
  before do
25
- allow(Time).to receive(:now).and_return(Time.parse('Feb 19 1986'))
25
+ allow(Time.zone).to receive(:now).and_return(Time.zone.parse('Feb 19 1986'))
26
26
  InvisibleCaptcha.visual_honeypots = false
27
27
  end
28
28
 
@@ -60,4 +60,10 @@ describe InvisibleCaptcha::ViewHelpers, type: :helper do
60
60
  expect(invisible_captcha(visual_honeypots: false)).to eq(helper_output(nil, nil, visual_honeypots: false))
61
61
  end
62
62
  end
63
- end
63
+
64
+ it 'should set spam timestamp' do
65
+ InvisibleCaptcha.honeypots = [:foo_id]
66
+ invisible_captcha
67
+ expect(session[:invisible_captcha_timestamp]).to eq(Time.zone.now)
68
+ end
69
+ end
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: 0.8.0
4
+ version: 0.8.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Marc Anguera Insa
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-04-12 00:00:00.000000000 Z
11
+ date: 2016-04-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -47,6 +47,7 @@ extensions: []
47
47
  extra_rdoc_files: []
48
48
  files:
49
49
  - ".gitignore"
50
+ - ".rspec"
50
51
  - ".travis.yml"
51
52
  - Gemfile
52
53
  - LICENSE
@@ -73,6 +74,10 @@ files:
73
74
  - spec/dummy/app/models/topic.rb
74
75
  - spec/dummy/app/views/layouts/application.html.erb
75
76
  - spec/dummy/app/views/topics/new.html.erb
77
+ - spec/dummy/bin/bundle
78
+ - spec/dummy/bin/rails
79
+ - spec/dummy/bin/rake
80
+ - spec/dummy/bin/setup
76
81
  - spec/dummy/config.ru
77
82
  - spec/dummy/config/application.rb
78
83
  - spec/dummy/config/boot.rb
@@ -80,7 +85,10 @@ files:
80
85
  - spec/dummy/config/environments/development.rb
81
86
  - spec/dummy/config/environments/production.rb
82
87
  - spec/dummy/config/environments/test.rb
88
+ - spec/dummy/config/initializers/assets.rb
83
89
  - spec/dummy/config/initializers/backtrace_silencers.rb
90
+ - spec/dummy/config/initializers/cookies_serializer.rb
91
+ - spec/dummy/config/initializers/filter_parameter_logging.rb
84
92
  - spec/dummy/config/initializers/inflections.rb
85
93
  - spec/dummy/config/initializers/invisible_captcha.rb
86
94
  - spec/dummy/config/initializers/mime_types.rb
@@ -89,6 +97,7 @@ files:
89
97
  - spec/dummy/config/initializers/wrap_parameters.rb
90
98
  - spec/dummy/config/locales/en.yml
91
99
  - spec/dummy/config/routes.rb
100
+ - spec/dummy/config/secrets.yml
92
101
  - spec/dummy/lib/assets/.gitkeep
93
102
  - spec/dummy/log/.gitkeep
94
103
  - spec/dummy/public/404.html
@@ -138,6 +147,10 @@ test_files:
138
147
  - spec/dummy/app/models/topic.rb
139
148
  - spec/dummy/app/views/layouts/application.html.erb
140
149
  - spec/dummy/app/views/topics/new.html.erb
150
+ - spec/dummy/bin/bundle
151
+ - spec/dummy/bin/rails
152
+ - spec/dummy/bin/rake
153
+ - spec/dummy/bin/setup
141
154
  - spec/dummy/config.ru
142
155
  - spec/dummy/config/application.rb
143
156
  - spec/dummy/config/boot.rb
@@ -145,7 +158,10 @@ test_files:
145
158
  - spec/dummy/config/environments/development.rb
146
159
  - spec/dummy/config/environments/production.rb
147
160
  - spec/dummy/config/environments/test.rb
161
+ - spec/dummy/config/initializers/assets.rb
148
162
  - spec/dummy/config/initializers/backtrace_silencers.rb
163
+ - spec/dummy/config/initializers/cookies_serializer.rb
164
+ - spec/dummy/config/initializers/filter_parameter_logging.rb
149
165
  - spec/dummy/config/initializers/inflections.rb
150
166
  - spec/dummy/config/initializers/invisible_captcha.rb
151
167
  - spec/dummy/config/initializers/mime_types.rb
@@ -154,6 +170,7 @@ test_files:
154
170
  - spec/dummy/config/initializers/wrap_parameters.rb
155
171
  - spec/dummy/config/locales/en.yml
156
172
  - spec/dummy/config/routes.rb
173
+ - spec/dummy/config/secrets.yml
157
174
  - spec/dummy/lib/assets/.gitkeep
158
175
  - spec/dummy/log/.gitkeep
159
176
  - spec/dummy/public/404.html