acts_as_textcaptcha 4.5.1 → 4.5.2

Sign up to get free protection for your applications and to get access to all the features.
data/.simplecov CHANGED
@@ -1,6 +1,8 @@
1
+ # frozen_string_literal: true
2
+
1
3
  SimpleCov.start do
2
- add_filter '/test/'
3
- add_filter '/vendor/'
4
+ add_filter "/test/"
5
+ add_filter "/vendor/"
4
6
  end
5
7
 
6
8
  SimpleCov.at_exit do
@@ -1,33 +1,31 @@
1
1
  sudo: false
2
2
  language: ruby
3
- script: 'bundle exec rake test'
4
3
  gemfile:
5
- - gemfiles/rails_3.gemfile
6
4
  - gemfiles/rails_4.gemfile
7
5
  - gemfiles/rails_5.gemfile
8
6
  - gemfiles/rails_6.gemfile
9
7
 
10
8
  rvm:
11
- - 2.4.9
12
- - 2.5.7
13
- - 2.6.5
14
- - 2.7.0
9
+ - 2.5.8
10
+ - 2.6.6
11
+ - 2.7.2
12
+ - 3.0.0
15
13
  - ruby-head
16
14
 
17
15
  matrix:
18
16
  allow_failures:
19
17
  - rvm: ruby-head
20
18
  exclude:
21
- - rvm: 2.4.9
22
- gemfile: gemfiles/rails_6.gemfile
23
- - rvm: 2.7.0
24
- gemfile: gemfiles/rails_3.gemfile
25
- - rvm: 2.7.0
19
+ - rvm: 2.7.2
26
20
  gemfile: gemfiles/rails_4.gemfile
27
- - rvm: ruby-head
28
- gemfile: gemfiles/rails_3.gemfile
21
+ - rvm: 3.0.0
22
+ gemfile: gemfiles/rails_4.gemfile
23
+ - rvm: 3.0.0
24
+ gemfile: gemfiles/rails_5.gemfile
29
25
  - rvm: ruby-head
30
26
  gemfile: gemfiles/rails_4.gemfile
27
+ - rvm: ruby-head
28
+ gemfile: gemfiles/rails_5.gemfile
31
29
 
32
30
  deploy:
33
31
  provider: rubygems
@@ -40,12 +38,10 @@ deploy:
40
38
  env:
41
39
  global:
42
40
  - CC_TEST_REPORTER_ID=3ff570478529bcdd11ef42d33229702118aa36b17a3de01c3f6d5a9c58fc7a4c
43
- before_install:
44
- - gem uninstall -v '>= 2' -i $(rvm gemdir)@global -ax bundler || true
45
- - gem install bundler -v '< 2'
41
+ - GIT_COMMITTED_AT=$(if [ "$TRAVIS_PULL_REQUEST" == "false" ]; then git log -1 --pretty=format:%ct; else git log -1 --skip 1 --pretty=format:%ct; fi)
46
42
  before_script:
47
43
  - curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
48
44
  - chmod +x ./cc-test-reporter
49
- - ./cc-test-reporter before-build
45
+ - ./cc-test-reporter before-build - GIT_COMMITTED_AT=$(if [ "$TRAVIS_PULL_REQUEST" == "false" ]; then git log -1 --pretty=format:%ct; else git log -1 --skip 1 --pretty=format:%ct; fi)
50
46
  after_script:
51
- - ./cc-test-reporter after-build
47
+ - ./cc-test-reporter after-build --exit-code $TRAVIS_TEST_RESULT -t simplecov
data/Appraisals CHANGED
@@ -1,19 +1,14 @@
1
- appraise "rails-3" do
2
- gem "rails", "3.2.22.5"
3
- gem "sqlite3", "~> 1.3.5"
4
- end
5
-
6
1
  appraise "rails-4" do
7
- gem "rails", "4.2.11.1"
2
+ gem "rails", "4.2.11.3"
8
3
  gem "sqlite3", "~> 1.3.5"
9
4
  end
10
5
 
11
6
  appraise "rails-5" do
12
- gem "rails", "5.2.4.1"
7
+ gem "rails", "5.2.4.4"
13
8
  gem "sqlite3", "~> 1.4.2"
14
9
  end
15
10
 
16
11
  appraise "rails-6" do
17
- gem "rails", "6.0.2.1"
12
+ gem "rails", "6.0.3.4"
18
13
  gem "sqlite3", "~> 1.4.2"
19
14
  end
@@ -9,6 +9,13 @@ adheres to [Semantic Versioning][Semver].
9
9
 
10
10
  - Your contribution here!
11
11
 
12
+ ## [4.5.2] - 2021-01-28
13
+ ### Changed
14
+ - CI covers Latest Rails version 6,5,4 and Ruby 3,2.7,2.6,2.5
15
+ ### Removed
16
+ - Support for Ruby < 2.5 (EOL versions not supported)
17
+ - No longer testing against Rails 3 in CI
18
+
12
19
  ## [4.5.1] - 2020-01-28
13
20
  ### Fixed
14
21
  - add Rails Railtie to fix rake task loading
@@ -88,7 +95,8 @@ adheres to [Semantic Versioning][Semver].
88
95
  - README updated.
89
96
  - Test coverage improved.
90
97
 
91
- [Unreleased]: https://github.com/matthutchinson/acts_as_textcaptcha/compare/v4.5.1...HEAD
98
+ [Unreleased]: https://github.com/matthutchinson/acts_as_textcaptcha/compare/v4.5.2...HEAD
99
+ [4.5.2]: https://github.com/matthutchinson/acts_as_textcaptcha/compare/v4.5.1...v4.5.2
92
100
  [4.5.1]: https://github.com/matthutchinson/acts_as_textcaptcha/compare/v4.5.0...v4.5.1
93
101
  [4.5.0]: https://github.com/matthutchinson/acts_as_textcaptcha/compare/v4.4.1...v4.5.0
94
102
  [4.4.1]: https://github.com/matthutchinson/acts_as_textcaptcha/compare/v4.3.0...v4.4.1
data/Gemfile CHANGED
@@ -1,2 +1,4 @@
1
- source 'https://rubygems.org'
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
2
4
  gemspec
data/README.md CHANGED
@@ -9,18 +9,18 @@
9
9
  ActsAsTextcaptcha provides spam protection for Rails models with text-based
10
10
  logic question captchas. Questions are fetched from [Rob
11
11
  Tuley's](https://twitter.com/robtuley)
12
- [textcaptcha.com](http://textcaptcha.com/). They can be solved easily by humans
12
+ [textcaptcha.com](https://textcaptcha.com/). They can be solved easily by humans
13
13
  but are tough for robots to crack.
14
14
 
15
15
  The gem can also be configured with your own questions; as an alternative, or as
16
16
  a fallback to handle any API issues. For reasons on why logic based captchas
17
- are a good idea visit [textcaptcha.com](http://textcaptcha.com).
17
+ are a good idea visit [textcaptcha.com](https://textcaptcha.com).
18
18
 
19
19
  ## Requirements
20
20
 
21
- * [Ruby](http://ruby-lang.org/) >= 2.4
22
- * [Rails](http://github.com/rails/rails) >= 3
23
- * [Rails.cache](http://guides.rubyonrails.org/caching_with_rails.html#cache-stores)
21
+ * [Ruby](http://ruby-lang.org/) >= 2.5
22
+ * [Rails](http://github.com/rails/rails) >= 4
23
+ * A valid [Rails.cache](http://guides.rubyonrails.org/caching_with_rails.html#cache-stores) (not `:null_store`)
24
24
 
25
25
  ## Demo
26
26
 
@@ -59,7 +59,7 @@ def new
59
59
  end
60
60
  ```
61
61
 
62
- Finally add the question and answer fields to your form using the
62
+ Add the question and answer fields to your form using the
63
63
  `textcaptcha_fields` helper. Arrange the HTML within this block as you like.
64
64
 
65
65
  ```ruby
@@ -75,6 +75,17 @@ If you'd prefer to construct your own form elements, take a look at the HTML
75
75
  produced
76
76
  [here](https://github.com/matthutchinson/acts_as_textcaptcha/blob/master/lib/acts_as_textcaptcha/textcaptcha_helper.rb).
77
77
 
78
+ Finally set a valid [cache
79
+ store](https://guides.rubyonrails.org/caching_with_rails.html#cache-stores) (not `:null_store`) for your environments:
80
+
81
+ ```ruby
82
+ # e.g. in each config/environments/*.rb
83
+ config.cache_store = :memory_store
84
+ ```
85
+
86
+ You can run `rails dev:cache` on a modern generated Rails app to enable
87
+ a memory store cache in the development environment.
88
+
78
89
  ## Configuration
79
90
 
80
91
  The following options are available (only `api_key` is required):
@@ -241,7 +252,7 @@ The code is available as open source under the terms of
241
252
  ## Who's who?
242
253
 
243
254
  * [ActsAsTextcaptcha](http://github.com/matthutchinson/acts_as_textcaptcha) and [little robot drawing](http://www.flickr.com/photos/hiddenloop/4541195635/) by [Matthew Hutchinson](http://matthewhutchinson.net)
244
- * [TextCaptcha](http://textcaptcha.com) API and service by [Rob Tuley](https://twitter.com/robtuley)
255
+ * [TextCaptcha](https://textcaptcha.com) API and service by [Rob Tuley](https://twitter.com/robtuley)
245
256
 
246
257
  ## Links
247
258
 
data/Rakefile CHANGED
@@ -1,13 +1,16 @@
1
- require 'bundler/gem_tasks'
2
- require 'rake/testtask'
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rake/testtask"
3
5
  require "rdoc/task"
6
+ require "rubocop/rake_task"
4
7
 
5
8
  # generate docs
6
9
  RDoc::Task.new do |rd|
7
- rd.main = "README.md"
8
- rd.title = 'ActsAsTextcaptcha'
9
- rd.rdoc_dir = 'doc'
10
- rd.options << "--all"
10
+ rd.main = "README.md"
11
+ rd.title = "ActsAsTextcaptcha"
12
+ rd.rdoc_dir = "doc"
13
+ rd.options << "--all"
11
14
  rd.rdoc_files.include("README.md", "LICENSE", "lib/**/*.rb")
12
15
  end
13
16
 
@@ -18,13 +21,19 @@ Rake::TestTask.new(:test) do |t|
18
21
  t.test_files = FileList["test/**/*_test.rb"]
19
22
  end
20
23
 
24
+ # run lint
25
+ RuboCop::RakeTask.new(:rubocop) do |t|
26
+ t.options = ["--display-cop-names"]
27
+ end
28
+
21
29
  # run tests with code coverage (default)
22
30
  namespace :test do
23
31
  desc "Run all tests and features and generate a code coverage report"
24
32
  task :coverage do
25
- ENV['COVERAGE'] = 'true'
26
- Rake::Task['test'].execute
33
+ ENV["COVERAGE"] = "true"
34
+ Rake::Task["test"].execute
35
+ Rake::Task["rubocop"].execute
27
36
  end
28
37
  end
29
38
 
30
- task :default => ['test:coverage']
39
+ task default: [:rubocop, "test:coverage"]
@@ -1,34 +1,36 @@
1
- lib = File.expand_path('../lib', __FILE__)
1
+ # frozen_string_literal: true
2
+
3
+ lib = File.expand_path("lib", __dir__)
2
4
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
5
  require "acts_as_textcaptcha/version"
4
6
 
5
7
  Gem::Specification.new do |spec|
6
- spec.name = "acts_as_textcaptcha"
7
- spec.version = ActsAsTextcaptcha::VERSION
8
- spec.authors = ["Matthew Hutchinson"]
9
- spec.email = ["matt@hiddenloop.com"]
8
+ spec.name = "acts_as_textcaptcha"
9
+ spec.version = ActsAsTextcaptcha::VERSION
10
+ spec.authors = ["Matthew Hutchinson"]
11
+ spec.email = ["matt@hiddenloop.com"]
10
12
  spec.homepage = "http://github.com/matthutchinson/acts_as_textcaptcha"
11
- spec.license = 'MIT'
12
- spec.summary = "A text-based logic question captcha for Rails"
13
+ spec.license = "MIT"
14
+ spec.summary = "A text-based logic question captcha for Rails"
13
15
 
14
- spec.description = <<-EOF
16
+ spec.description = <<-DESCRIPTION
15
17
  ActsAsTextcaptcha provides spam protection for Rails models with text-based
16
18
  logic question captchas. Questions are fetched from Rob Tuley's
17
19
  textcaptcha.com They can be solved easily by humans but are tough for robots
18
20
  to crack.
19
- EOF
21
+ DESCRIPTION
20
22
 
21
23
  spec.metadata = {
22
- "homepage_uri" => "https://github.com/matthutchinson/acts_as_textcaptcha",
23
- "changelog_uri" => "https://github.com/matthutchinson/acts_as_textcaptcha/blob/master/CHANGELOG.md",
24
- "source_code_uri" => "https://github.com/matthutchinson/acts_as_textcaptcha",
25
- "bug_tracker_uri" => "https://github.com/matthutchinson/acts_as_textcaptcha/issues",
24
+ "homepage_uri" => "https://github.com/matthutchinson/acts_as_textcaptcha",
25
+ "changelog_uri" => "https://github.com/matthutchinson/acts_as_textcaptcha/blob/master/CHANGELOG.md",
26
+ "source_code_uri" => "https://github.com/matthutchinson/acts_as_textcaptcha",
27
+ "bug_tracker_uri" => "https://github.com/matthutchinson/acts_as_textcaptcha/issues",
26
28
  "allowed_push_host" => "https://rubygems.org"
27
29
  }
28
30
 
29
- spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
30
- spec.test_files = `git ls-files -- {test}/*`.split("\n")
31
- spec.bindir = "bin"
31
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
32
+ spec.test_files = `git ls-files -- {test}/*`.split("\n")
33
+ spec.bindir = "bin"
32
34
  spec.require_paths = ["lib"]
33
35
 
34
36
  # documentation
@@ -36,21 +38,24 @@ Gem::Specification.new do |spec|
36
38
  spec.rdoc_options << "--title" << "ActAsTextcaptcha" << "--main" << "README.md" << "-ri"
37
39
 
38
40
  # non-gem dependecies
39
- spec.required_ruby_version = ">= 2.4"
41
+ spec.required_ruby_version = ">= 2.5"
40
42
 
41
43
  # dev gems
42
- spec.add_development_dependency('bundler')
44
+ spec.add_development_dependency("bundler")
45
+ spec.add_development_dependency("pry-byebug")
43
46
  spec.add_development_dependency "rake"
44
- spec.add_development_dependency('pry-byebug')
47
+
48
+ # Lint
49
+ spec.add_development_dependency("rubocop")
45
50
 
46
51
  # docs
47
- spec.add_development_dependency('rdoc')
52
+ spec.add_development_dependency("rdoc")
48
53
 
49
54
  # testing
50
- spec.add_development_dependency('rails', '~> 6.0.2.1')
51
- spec.add_development_dependency('minitest')
52
- spec.add_development_dependency('sqlite3')
53
- spec.add_development_dependency('webmock')
54
- spec.add_development_dependency('simplecov')
55
- spec.add_development_dependency('appraisal')
55
+ spec.add_development_dependency("appraisal")
56
+ spec.add_development_dependency("minitest")
57
+ spec.add_development_dependency("rails", "~> 6.0.3.4")
58
+ spec.add_development_dependency("simplecov", "~> 0.19.1")
59
+ spec.add_development_dependency("sqlite3")
60
+ spec.add_development_dependency("webmock")
56
61
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
- gem "rails", "4.2.11.1"
5
+ gem "rails", "4.2.11.3"
6
6
  gem "sqlite3", "~> 1.3.5"
7
7
 
8
8
  gemspec path: "../"
@@ -2,7 +2,7 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
- gem "rails", "5.2.4.1"
5
+ gem "rails", "5.2.4.4"
6
6
  gem "sqlite3", "~> 1.4.2"
7
7
 
8
8
  gemspec path: "../"
@@ -2,7 +2,7 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
- gem "rails", "6.0.2.1"
5
+ gem "rails", "6.1.1"
6
6
  gem "sqlite3", "~> 1.4.2"
7
7
 
8
8
  gemspec path: "../"
@@ -1,9 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'acts_as_textcaptcha/version'
4
- require 'acts_as_textcaptcha/errors'
5
- require 'acts_as_textcaptcha/textcaptcha'
6
- require 'acts_as_textcaptcha/textcaptcha_config'
7
- require 'acts_as_textcaptcha/textcaptcha_helper'
8
- require 'acts_as_textcaptcha/framework/rails'
9
- require 'acts_as_textcaptcha/railtie' if defined?(Rails::Railtie)
3
+ require "acts_as_textcaptcha/version"
4
+ require "acts_as_textcaptcha/errors"
5
+ require "acts_as_textcaptcha/textcaptcha"
6
+ require "acts_as_textcaptcha/textcaptcha_config"
7
+ require "acts_as_textcaptcha/textcaptcha_helper"
8
+ require "acts_as_textcaptcha/framework/rails"
9
+ require "acts_as_textcaptcha/railtie" if defined?(Rails::Railtie)
@@ -1,9 +1,9 @@
1
1
  # frozen_string_literal: true
2
- #
2
+
3
3
  module ActsAsTextcaptcha
4
4
  class Railtie < Rails::Railtie
5
5
  rake_tasks do
6
- Dir[File.join(File.dirname(__FILE__), '/tasks/*.rake')].each { |f| load f }
6
+ Dir[File.join(File.dirname(__FILE__), "/tasks/*.rake")].each { |f| load f }
7
7
  end
8
8
  end
9
9
  end
@@ -1,16 +1,17 @@
1
- require 'rails'
2
- require 'acts_as_textcaptcha/textcaptcha_config'
1
+ # frozen_string_literal: true
3
2
 
4
- namespace :textcaptcha do
3
+ require "rails"
4
+ require "acts_as_textcaptcha/textcaptcha_config"
5
5
 
6
+ namespace :textcaptcha do
6
7
  desc "Creates an example textcaptcha config at config/textcaptcha.yml"
7
8
  task :config do
8
- path = File.join((Rails.root ? Rails.root : '.'), 'config', 'textcaptcha.yml')
9
+ path = File.join((Rails.root || "."), "config", "textcaptcha.yml")
9
10
  if File.exist?(path)
10
11
  puts "Ooops, a textcaptcha config file at #{path} already exists ... aborting."
11
12
  else
12
13
  ActsAsTextcaptcha::TextcaptchaConfig.create(path: path)
13
- puts "Done, config generated at #{path}\nEdit this file to add your TextCaptcha API key (see http://textcaptcha.com)."
14
+ puts "Done, config generated at #{path}\nEdit this file to add your TextCaptcha API key (see https://textcaptcha.com)."
14
15
  end
15
16
  end
16
17
  end
@@ -1,22 +1,19 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'yaml'
4
- require 'net/http'
5
- require 'digest/md5'
6
- require 'acts_as_textcaptcha/textcaptcha_cache'
7
- require 'acts_as_textcaptcha/textcaptcha_api'
3
+ require "yaml"
4
+ require "net/http"
5
+ require "digest/md5"
6
+ require "acts_as_textcaptcha/textcaptcha_cache"
7
+ require "acts_as_textcaptcha/textcaptcha_api"
8
8
 
9
9
  module ActsAsTextcaptcha
10
10
  module Textcaptcha
11
-
12
11
  def acts_as_textcaptcha(options = nil)
13
12
  cattr_accessor :textcaptcha_config
14
13
  attr_accessor :textcaptcha_question, :textcaptcha_answer, :textcaptcha_key
15
14
 
16
15
  # ensure these attrs are accessible (Rails 3)
17
- if respond_to?(:accessible_attributes) && respond_to?(:attr_accessible)
18
- attr_accessible :textcaptcha_answer, :textcaptcha_key
19
- end
16
+ attr_accessible :textcaptcha_answer, :textcaptcha_key if respond_to?(:accessible_attributes) && respond_to?(:attr_accessible)
20
17
 
21
18
  self.textcaptcha_config = build_textcaptcha_config(options).symbolize_keys!
22
19
 
@@ -26,122 +23,119 @@ module ActsAsTextcaptcha
26
23
  end
27
24
 
28
25
  module InstanceMethods
29
-
30
26
  # override this method to toggle textcaptcha checking, by default this
31
27
  # will only allow new records to be protected with textcaptchas
32
28
  def perform_textcaptcha?
33
- (!respond_to?('new_record?') || new_record?)
29
+ (!respond_to?("new_record?") || new_record?)
34
30
  end
35
31
 
36
32
  def textcaptcha
37
- if perform_textcaptcha? && textcaptcha_config
38
- assign_textcaptcha(fetch_q_and_a || config_q_and_a)
39
- end
33
+ assign_textcaptcha(fetch_q_and_a || config_q_and_a) if perform_textcaptcha? && textcaptcha_config
40
34
  end
41
35
 
42
-
43
36
  private
44
37
 
45
- def fetch_q_and_a
46
- return unless should_fetch?
38
+ def fetch_q_and_a
39
+ return unless should_fetch?
47
40
 
48
- TextcaptchaApi.new(
49
- api_key: textcaptcha_config[:api_key],
50
- api_endpoint: textcaptcha_config[:api_endpoint],
51
- raise_errors: textcaptcha_config[:raise_errors]
52
- ).fetch
53
- end
41
+ TextcaptchaApi.new(
42
+ api_key: textcaptcha_config[:api_key],
43
+ api_endpoint: textcaptcha_config[:api_endpoint],
44
+ raise_errors: textcaptcha_config[:raise_errors]
45
+ ).fetch
46
+ end
54
47
 
55
- def should_fetch?
56
- textcaptcha_config[:api_key] || textcaptcha_config[:api_endpoint]
57
- end
48
+ def should_fetch?
49
+ textcaptcha_config[:api_key] || textcaptcha_config[:api_endpoint]
50
+ end
58
51
 
59
- def config_q_and_a
60
- if textcaptcha_config[:questions]
61
- random_question = textcaptcha_config[:questions][rand(textcaptcha_config[:questions].size)].symbolize_keys!
62
- answers = (random_question[:answers] || '').split(',').map!{ |answer| safe_md5(answer) }
63
- if random_question && answers.present?
64
- { 'q' => random_question[:question], 'a' => answers }
65
- end
66
- end
67
- end
52
+ def config_q_and_a
53
+ return unless textcaptcha_config[:questions]
68
54
 
69
- # check textcaptcha, if incorrect, generate a new textcaptcha
70
- def validate_textcaptcha
71
- valid_answers = textcaptcha_cache.read(textcaptcha_key) || []
72
- reset_textcaptcha
73
- if valid_answers.include?(safe_md5(textcaptcha_answer))
74
- # answer was valid, mutate the key again
75
- self.textcaptcha_key = textcaptcha_random_key
76
- textcaptcha_cache.write(textcaptcha_key, valid_answers, textcaptcha_cache_options)
77
- true
78
- else
79
- add_textcaptcha_error(too_slow: valid_answers.empty?)
80
- textcaptcha
81
- false
82
- end
83
- end
55
+ random_question = textcaptcha_config[:questions][rand(textcaptcha_config[:questions].size)].symbolize_keys!
56
+ answers = (random_question[:answers] || "").split(",").map { |answer| safe_md5(answer) }
57
+ { "q" => random_question[:question], "a" => answers } if random_question && answers.present?
58
+ end
84
59
 
85
- def add_textcaptcha_error(too_slow: false)
86
- if too_slow
87
- errors.add(:textcaptcha_answer, :expired, :message => 'was not submitted quickly enough, try another question instead')
88
- else
89
- errors.add(:textcaptcha_answer, :incorrect, :message => 'is incorrect, try another question instead')
90
- end
60
+ # check textcaptcha, if incorrect, generate a new textcaptcha
61
+ def validate_textcaptcha
62
+ valid_answers = textcaptcha_cache.read(textcaptcha_key) || []
63
+ reset_textcaptcha
64
+ if valid_answers.include?(safe_md5(textcaptcha_answer))
65
+ # answer was valid, mutate the key again
66
+ self.textcaptcha_key = textcaptcha_random_key
67
+ textcaptcha_cache.write(textcaptcha_key, valid_answers, textcaptcha_cache_options)
68
+ true
69
+ else
70
+ add_textcaptcha_error(too_slow: valid_answers.empty?)
71
+ textcaptcha
72
+ false
91
73
  end
74
+ end
92
75
 
93
- def reset_textcaptcha
94
- if textcaptcha_key
95
- textcaptcha_cache.delete(textcaptcha_key)
96
- self.textcaptcha_key = nil
97
- end
76
+ def add_textcaptcha_error(too_slow: false)
77
+ if too_slow
78
+ errors.add(:textcaptcha_answer, :expired, message: "was not submitted quickly enough, try another question instead")
79
+ else
80
+ errors.add(:textcaptcha_answer, :incorrect, message: "is incorrect, try another question instead")
98
81
  end
82
+ end
99
83
 
100
- def assign_textcaptcha(q_and_a)
101
- return unless q_and_a
102
- self.textcaptcha_question = q_and_a['q']
103
- self.textcaptcha_key = textcaptcha_random_key
104
- textcaptcha_cache.write(textcaptcha_key, q_and_a['a'], textcaptcha_cache_options)
84
+ def reset_textcaptcha
85
+ if textcaptcha_key
86
+ textcaptcha_cache.delete(textcaptcha_key)
87
+ self.textcaptcha_key = nil
105
88
  end
89
+ end
106
90
 
107
- # strip whitespace pass through mb_chars (a multibyte safe proxy for
108
- # strings) then downcase
109
- def safe_md5(answer)
110
- Digest::MD5.hexdigest(answer.to_s.strip.mb_chars.downcase)
111
- end
91
+ def assign_textcaptcha(q_and_a)
92
+ return unless q_and_a
112
93
 
113
- # a random cache key, time based, random
114
- def textcaptcha_random_key
115
- safe_md5(Time.now.to_i + rand(1_000_000))
116
- end
94
+ self.textcaptcha_question = q_and_a["q"]
95
+ self.textcaptcha_key = textcaptcha_random_key
96
+ textcaptcha_cache.write(textcaptcha_key, q_and_a["a"], textcaptcha_cache_options)
97
+ end
117
98
 
118
- def textcaptcha_cache_options
119
- if textcaptcha_config[:cache_expiry_minutes]
120
- { :expires_in => textcaptcha_config[:cache_expiry_minutes].to_f.minutes }
121
- else
122
- {}
123
- end
124
- end
99
+ # strip whitespace pass through mb_chars (a multibyte safe proxy for
100
+ # strings) then downcase
101
+ def safe_md5(answer)
102
+ Digest::MD5.hexdigest(answer.to_s.strip.mb_chars.downcase)
103
+ end
104
+
105
+ # a random cache key, time based, random
106
+ def textcaptcha_random_key
107
+ safe_md5(Time.now.to_i + rand(1_000_000))
108
+ end
125
109
 
126
- def textcaptcha_cache
127
- @@textcaptcha_cache ||= TextcaptchaCache.new
110
+ def textcaptcha_cache_options
111
+ if textcaptcha_config[:cache_expiry_minutes]
112
+ { expires_in: textcaptcha_config[:cache_expiry_minutes].to_f.minutes }
113
+ else
114
+ {}
128
115
  end
116
+ end
117
+
118
+ def textcaptcha_cache
119
+ @textcaptcha_cache ||= TextcaptchaCache.new
120
+ end
129
121
  end
130
122
 
131
123
  private
132
124
 
133
- def build_textcaptcha_config(options)
134
- if options.is_a?(Hash)
135
- options
136
- else
137
- YAML.load(ERB.new(read_textcaptcha_config).result)[Rails.env]
138
- end
139
- rescue
140
- raise ArgumentError.new('could not find any textcaptcha options, in config/textcaptcha.yml or model - run rake textcaptcha:config to generate a template config file')
125
+ # rubocop:disable Security/YAMLLoad
126
+ def build_textcaptcha_config(options)
127
+ if options.is_a?(Hash)
128
+ options
129
+ else
130
+ YAML.load(ERB.new(read_textcaptcha_config).result)[Rails.env]
141
131
  end
132
+ rescue StandardError
133
+ raise ArgumentError, "could not find any textcaptcha options, in config/textcaptcha.yml or model - run rake textcaptcha:config to generate a template config file"
134
+ end
135
+ # rubocop:enable Security/YAMLLoad
142
136
 
143
- def read_textcaptcha_config
144
- File.read("#{Rails.root ? Rails.root : '.'}/config/textcaptcha.yml")
145
- end
137
+ def read_textcaptcha_config
138
+ File.read("#{Rails.root || "."}/config/textcaptcha.yml")
139
+ end
146
140
  end
147
141
  end