acts_as_textcaptcha 4.2.0 → 4.5.2

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 (44) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -1
  3. data/.rubocop.yml +1165 -0
  4. data/.simplecov +11 -0
  5. data/.travis.yml +30 -8
  6. data/Appraisals +9 -6
  7. data/CHANGELOG.md +94 -34
  8. data/CODE_OF_CONDUCT.md +54 -31
  9. data/CONTRIBUTING.md +14 -9
  10. data/Gemfile +2 -2
  11. data/LICENSE +165 -0
  12. data/PULL_REQUEST_TEMPLATE.md +16 -0
  13. data/README.md +206 -228
  14. data/Rakefile +26 -19
  15. data/acts_as_textcaptcha.gemspec +57 -41
  16. data/bin/console +2 -5
  17. data/bin/setup +7 -0
  18. data/gemfiles/rails_3.gemfile +1 -0
  19. data/gemfiles/rails_4.gemfile +2 -1
  20. data/gemfiles/rails_5.gemfile +2 -1
  21. data/gemfiles/rails_6.gemfile +8 -0
  22. data/lib/acts_as_textcaptcha.rb +9 -4
  23. data/lib/acts_as_textcaptcha/errors.rb +21 -0
  24. data/lib/acts_as_textcaptcha/framework/rails.rb +3 -1
  25. data/lib/acts_as_textcaptcha/railtie.rb +9 -0
  26. data/lib/acts_as_textcaptcha/tasks/textcaptcha.rake +17 -0
  27. data/lib/acts_as_textcaptcha/textcaptcha.rb +75 -72
  28. data/lib/acts_as_textcaptcha/textcaptcha_api.rb +39 -45
  29. data/lib/acts_as_textcaptcha/textcaptcha_cache.rb +12 -16
  30. data/lib/acts_as_textcaptcha/textcaptcha_config.rb +47 -0
  31. data/lib/acts_as_textcaptcha/textcaptcha_helper.rb +13 -14
  32. data/lib/acts_as_textcaptcha/version.rb +3 -1
  33. metadata +68 -46
  34. data/.coveralls.yml +0 -1
  35. data/LICENSE.txt +0 -21
  36. data/config/textcaptcha.yml +0 -34
  37. data/lib/tasks/textcaptcha.rake +0 -21
  38. data/test/schema.rb +0 -34
  39. data/test/test_helper.rb +0 -44
  40. data/test/test_models.rb +0 -69
  41. data/test/textcaptcha_api_test.rb +0 -46
  42. data/test/textcaptcha_cache_test.rb +0 -25
  43. data/test/textcaptcha_helper_test.rb +0 -68
  44. data/test/textcaptcha_test.rb +0 -198
@@ -1,61 +1,55 @@
1
- # simple wrapper for the textcaptcha.com API service
2
- # loads and parses captcha question and answers
1
+ # frozen_string_literal: true
3
2
 
4
- require 'rexml/document'
3
+ require "json"
5
4
 
6
5
  module ActsAsTextcaptcha
7
-
8
- # raised if an empty response is returned
9
- class EmptyResponseError < StandardError; end;
10
-
11
6
  class TextcaptchaApi
7
+ BASE_URL = "http://textcaptcha.com"
8
+
9
+ def initialize(api_key: nil, api_endpoint: nil, raise_errors: false)
10
+ self.uri = if api_endpoint
11
+ URI(api_endpoint)
12
+ else
13
+ URI("#{BASE_URL}/#{api_key}.json")
14
+ end
15
+ self.raise_errors = raise_errors || false
16
+ rescue URI::InvalidURIError => e
17
+ raise ApiKeyError.new(api_key, e)
18
+ end
12
19
 
13
- ENDPOINT = 'http://textcaptcha.com/api/'
14
-
15
- def self.fetch(api_key, options = {})
16
- begin
17
- url = uri_parser.parse("#{ENDPOINT}#{api_key}")
18
- http = Net::HTTP.new(url.host, url.port)
19
- if options[:http_open_timeout]
20
- http.open_timeout = options[:http_open_timeout]
21
- end
22
- if options[:http_read_timeout]
23
- http.read_timeout = options[:http_read_timeout]
24
- end
25
-
26
- response = http.get(url.path)
27
- if response.body.to_s.empty?
28
- raise ActsAsTextcaptcha::EmptyResponseError
29
- else
30
- return parse(response.body)
31
- end
32
- rescue SocketError, Timeout::Error, Errno::EINVAL, Errno::ECONNRESET,
33
- Errno::EHOSTUNREACH, EOFError, Errno::ECONNREFUSED, Errno::ETIMEDOUT,
34
- Net::HTTPBadResponse, Net::HTTPHeaderSyntaxError, Net::ProtocolError,
35
- URI::InvalidURIError, ActsAsTextcaptcha::EmptyResponseError,
36
- REXML::ParseException
37
- # rescue from these errors and continue
38
- end
20
+ def fetch
21
+ parse(get.to_s)
39
22
  end
40
23
 
41
- def self.parse(xml)
42
- parsed_xml = ActiveSupport::XmlMini.parse(xml)['captcha']
43
- question = parsed_xml['question']['__content__']
44
- if parsed_xml['answer'].is_a?(Array)
45
- answers = parsed_xml['answer'].collect { |a| a['__content__'] }
24
+ private
25
+
26
+ attr_accessor :uri, :raise_errors
27
+
28
+ def get
29
+ response = Net::HTTP.new(uri.host, uri.port).get(uri.path)
30
+ if response.code == "200"
31
+ response.body
46
32
  else
47
- answers = [parsed_xml['answer']['__content__']]
33
+ handle_error ResponseError.new(uri, "status: #{response.code}")
48
34
  end
49
-
50
- [question, answers]
35
+ rescue SocketError, Timeout::Error, Errno::EINVAL, Errno::ECONNRESET,
36
+ Errno::EHOSTUNREACH, EOFError, Errno::ECONNREFUSED, Errno::ETIMEDOUT,
37
+ Net::HTTPBadResponse, Net::HTTPHeaderSyntaxError,
38
+ Net::ProtocolError => e
39
+ handle_error ResponseError.new(uri, e)
51
40
  end
52
41
 
42
+ def parse(response)
43
+ JSON.parse(response) unless response.empty?
44
+ rescue JSON::ParserError
45
+ handle_error ParseError.new(uri)
46
+ end
53
47
 
54
- private
48
+ def handle_error(error)
49
+ raise error if raise_errors
55
50
 
56
- def self.uri_parser
57
- # URI.parse is deprecated in 1.9.2
58
- URI.const_defined?(:Parser) ? URI::Parser.new : URI
51
+ Rails.logger.error("#{error.class} #{error.message}")
52
+ nil
59
53
  end
60
54
  end
61
55
  end
@@ -1,34 +1,30 @@
1
- # A simple cache for storing Textcaptcha answers
2
- # by default the underlying cache implementation is
3
- # the standard Rails.cache (ActiveSupport::Cache)
1
+ # frozen_string_literal: true
2
+
3
+ # A simple cache for storing Textcaptcha answers, Rails.cache is used as the
4
+ # backend (ActiveSupport::Cache). This must not be set as a `:null_store`.
4
5
 
5
6
  module ActsAsTextcaptcha
6
7
  class TextcaptchaCache
7
-
8
- CACHE_KEY_PREFIX = 'acts_as_textcaptcha-'
9
- DEFAULT_CACHE_EXPIRY_MINUTES = 10
8
+ KEY_PREFIX = "acts_as_textcaptcha-"
9
+ DEFAULT_EXPIRY_MINUTES = 10
10
10
 
11
11
  def write(key, value, options = {})
12
- unless options.has_key?(:expires_in)
13
- options[:expires_in] = DEFAULT_CACHE_EXPIRY_MINUTES.minutes
14
- end
12
+ options[:expires_in] = DEFAULT_EXPIRY_MINUTES.minutes unless options.has_key?(:expires_in)
15
13
  Rails.cache.write(cache_key(key), value, options)
16
14
  end
17
15
 
18
- def read(key, options = nil)
19
- Rails.cache.read(cache_key(key), options)
16
+ def read(key)
17
+ Rails.cache.read(cache_key(key))
20
18
  end
21
19
 
22
- def delete(key, options = nil)
23
- Rails.cache.delete(cache_key(key), options)
20
+ def delete(key)
21
+ Rails.cache.delete(cache_key(key))
24
22
  end
25
23
 
26
24
  private
27
25
 
28
- # since this cache may be shared with other objects
29
- # a prefix is used in all cache keys
30
26
  def cache_key(key)
31
- "#{CACHE_KEY_PREFIX}#{key}"
27
+ "#{KEY_PREFIX}#{key}"
32
28
  end
33
29
  end
34
30
  end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActsAsTextcaptcha
4
+ class TextcaptchaConfig
5
+ YAML = <<~CONFIG
6
+ development: &common_settings
7
+ api_key: 'TEXTCAPTCHA_API_IDENT' # see https://textcaptcha.com for details
8
+ # api_endpoint: nil # Optional API URL to fetch questions and answers from
9
+ # raise_errors: false # Optional flag, if true errors will be raised if the API endpoint fails
10
+ # cache_expiry_minutes: 10 # Optional minutes for captcha answers to persist in the cache (default 10 minutes)
11
+
12
+ questions:
13
+ - question: 'Is ice hot or cold?'
14
+ answers: 'cold'
15
+ - question: 'what color is an orange?'
16
+ answers: 'orange'
17
+ - question: 'what is two plus 3?'
18
+ answers: '5,five'
19
+ - question: 'what is 5 times two?'
20
+ answers: '10,ten'
21
+ - question: 'How many colors in the list, green, brown, foot and blue?'
22
+ answers: '3,three'
23
+ - question: 'what is Georges name?'
24
+ answers: 'george'
25
+ - question: '11 minus 1?'
26
+ answers: '10,ten'
27
+ - question: 'is boiling water hot or cold?'
28
+ answers: 'hot'
29
+ - question: 'what color is my blue shirt today?'
30
+ answers: 'blue'
31
+ - question: 'what is 16 plus 4?'
32
+ answers: '20,twenty'
33
+
34
+ test:
35
+ <<: *common_settings
36
+ api_key: 'TEST_TEXTCAPTCHA_API_IDENT'
37
+
38
+ production:
39
+ <<: *common_settings
40
+ CONFIG
41
+
42
+ def self.create(path: "./config/textcaptcha.yml")
43
+ FileUtils.mkdir_p(File.dirname(path))
44
+ File.open(path, "w") { |f| f.write(YAML) }
45
+ end
46
+ end
47
+ end
@@ -1,21 +1,20 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActsAsTextcaptcha
2
4
  module TextcaptchaHelper
5
+ def textcaptcha_fields(form, &block)
6
+ build_textcaptcha_form_elements(form, &block) if form.object.perform_textcaptcha? && form.object.textcaptcha_key
7
+ end
3
8
 
4
- # builds html form fields for the textcaptcha
5
- def textcaptcha_fields(f, &block)
6
- model = f.object
7
- captcha_html = ''
8
- if model.perform_textcaptcha?
9
- if model.textcaptcha_key
10
- captcha_html += f.hidden_field(:textcaptcha_key)
11
- if model.textcaptcha_question
12
- captcha_html += capture(&block)
13
- elsif model.textcaptcha_answer
14
- captcha_html += f.hidden_field(:textcaptcha_answer)
15
- end
16
- end
17
- end
9
+ private
18
10
 
11
+ def build_textcaptcha_form_elements(form, &block)
12
+ captcha_html = form.hidden_field(:textcaptcha_key)
13
+ if form.object.textcaptcha_question
14
+ captcha_html += capture(&block)
15
+ elsif form.object.textcaptcha_answer
16
+ captcha_html += form.hidden_field(:textcaptcha_answer)
17
+ end
19
18
  captcha_html.html_safe
20
19
  end
21
20
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActsAsTextcaptcha
2
- VERSION = "4.2.0"
4
+ VERSION = "4.5.2"
3
5
  end
metadata CHANGED
@@ -1,31 +1,31 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: acts_as_textcaptcha
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.2.0
4
+ version: 4.5.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matthew Hutchinson
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-01-17 00:00:00.000000000 Z
11
+ date: 2021-01-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: rails
14
+ name: bundler
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - "~>"
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: 5.1.4
19
+ version: '0'
20
20
  type: :development
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.1.4
26
+ version: '0'
27
27
  - !ruby/object:Gem::Dependency
28
- name: mime-types
28
+ name: pry-byebug
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - ">="
@@ -39,7 +39,7 @@ dependencies:
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
41
  - !ruby/object:Gem::Dependency
42
- name: bundler
42
+ name: rake
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - ">="
@@ -53,7 +53,7 @@ dependencies:
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
55
  - !ruby/object:Gem::Dependency
56
- name: minitest
56
+ name: rubocop
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - ">="
@@ -67,7 +67,7 @@ dependencies:
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
69
  - !ruby/object:Gem::Dependency
70
- name: simplecov
70
+ name: rdoc
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
73
  - - ">="
@@ -81,7 +81,7 @@ dependencies:
81
81
  - !ruby/object:Gem::Version
82
82
  version: '0'
83
83
  - !ruby/object:Gem::Dependency
84
- name: rdoc
84
+ name: appraisal
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
87
  - - ">="
@@ -95,7 +95,7 @@ dependencies:
95
95
  - !ruby/object:Gem::Version
96
96
  version: '0'
97
97
  - !ruby/object:Gem::Dependency
98
- name: sqlite3
98
+ name: minitest
99
99
  requirement: !ruby/object:Gem::Requirement
100
100
  requirements:
101
101
  - - ">="
@@ -109,21 +109,35 @@ dependencies:
109
109
  - !ruby/object:Gem::Version
110
110
  version: '0'
111
111
  - !ruby/object:Gem::Dependency
112
- name: webmock
112
+ name: rails
113
113
  requirement: !ruby/object:Gem::Requirement
114
114
  requirements:
115
- - - ">="
115
+ - - "~>"
116
116
  - !ruby/object:Gem::Version
117
- version: '0'
117
+ version: 6.0.3.4
118
118
  type: :development
119
119
  prerelease: false
120
120
  version_requirements: !ruby/object:Gem::Requirement
121
121
  requirements:
122
- - - ">="
122
+ - - "~>"
123
123
  - !ruby/object:Gem::Version
124
- version: '0'
124
+ version: 6.0.3.4
125
125
  - !ruby/object:Gem::Dependency
126
- name: coveralls
126
+ name: simplecov
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: 0.19.1
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: 0.19.1
139
+ - !ruby/object:Gem::Dependency
140
+ name: sqlite3
127
141
  requirement: !ruby/object:Gem::Requirement
128
142
  requirements:
129
143
  - - ">="
@@ -137,7 +151,7 @@ dependencies:
137
151
  - !ruby/object:Gem::Version
138
152
  version: '0'
139
153
  - !ruby/object:Gem::Dependency
140
- name: appraisal
154
+ name: webmock
141
155
  requirement: !ruby/object:Gem::Requirement
142
156
  requirements:
143
157
  - - ">="
@@ -150,73 +164,81 @@ dependencies:
150
164
  - - ">="
151
165
  - !ruby/object:Gem::Version
152
166
  version: '0'
153
- description: |-
154
- Simple question/answer based spam protection for your Rails models.
155
- You can define your own logic questions and/or fetch questions from the textcaptcha.com API.
156
- The questions involve human logic and are tough for spam bots to crack.
157
- For more reasons on why logic questions are a good idea visit; http://textcaptcha.com/why
167
+ description: |2
168
+ ActsAsTextcaptcha provides spam protection for Rails models with text-based
169
+ logic question captchas. Questions are fetched from Rob Tuley's
170
+ textcaptcha.com They can be solved easily by humans but are tough for robots
171
+ to crack.
158
172
  email:
159
173
  - matt@hiddenloop.com
160
174
  executables: []
161
175
  extensions: []
162
- extra_rdoc_files: []
176
+ extra_rdoc_files:
177
+ - README.md
178
+ - LICENSE
163
179
  files:
164
- - ".coveralls.yml"
165
180
  - ".gitignore"
181
+ - ".rubocop.yml"
182
+ - ".simplecov"
166
183
  - ".travis.yml"
167
184
  - Appraisals
168
185
  - CHANGELOG.md
169
186
  - CODE_OF_CONDUCT.md
170
187
  - CONTRIBUTING.md
171
188
  - Gemfile
172
- - LICENSE.txt
189
+ - LICENSE
190
+ - PULL_REQUEST_TEMPLATE.md
173
191
  - README.md
174
192
  - Rakefile
175
193
  - acts_as_textcaptcha.gemspec
176
194
  - bin/console
177
- - config/textcaptcha.yml
195
+ - bin/setup
178
196
  - gemfiles/rails_3.gemfile
179
197
  - gemfiles/rails_4.gemfile
180
198
  - gemfiles/rails_5.gemfile
199
+ - gemfiles/rails_6.gemfile
181
200
  - lib/acts_as_textcaptcha.rb
201
+ - lib/acts_as_textcaptcha/errors.rb
182
202
  - lib/acts_as_textcaptcha/framework/rails.rb
203
+ - lib/acts_as_textcaptcha/railtie.rb
204
+ - lib/acts_as_textcaptcha/tasks/textcaptcha.rake
183
205
  - lib/acts_as_textcaptcha/textcaptcha.rb
184
206
  - lib/acts_as_textcaptcha/textcaptcha_api.rb
185
207
  - lib/acts_as_textcaptcha/textcaptcha_cache.rb
208
+ - lib/acts_as_textcaptcha/textcaptcha_config.rb
186
209
  - lib/acts_as_textcaptcha/textcaptcha_helper.rb
187
210
  - lib/acts_as_textcaptcha/version.rb
188
- - lib/tasks/textcaptcha.rake
189
- - test/schema.rb
190
- - test/test_helper.rb
191
- - test/test_models.rb
192
- - test/textcaptcha_api_test.rb
193
- - test/textcaptcha_cache_test.rb
194
- - test/textcaptcha_helper_test.rb
195
- - test/textcaptcha_test.rb
196
211
  homepage: http://github.com/matthutchinson/acts_as_textcaptcha
197
212
  licenses:
198
213
  - MIT
199
214
  metadata:
215
+ homepage_uri: https://github.com/matthutchinson/acts_as_textcaptcha
216
+ changelog_uri: https://github.com/matthutchinson/acts_as_textcaptcha/blob/master/CHANGELOG.md
217
+ source_code_uri: https://github.com/matthutchinson/acts_as_textcaptcha
218
+ bug_tracker_uri: https://github.com/matthutchinson/acts_as_textcaptcha/issues
200
219
  allowed_push_host: https://rubygems.org
201
- post_install_message:
202
- rdoc_options: []
220
+ post_install_message:
221
+ rdoc_options:
222
+ - "--title"
223
+ - ActAsTextcaptcha
224
+ - "--main"
225
+ - README.md
226
+ - "-ri"
203
227
  require_paths:
204
228
  - lib
205
229
  required_ruby_version: !ruby/object:Gem::Requirement
206
230
  requirements:
207
231
  - - ">="
208
232
  - !ruby/object:Gem::Version
209
- version: '0'
233
+ version: '2.5'
210
234
  required_rubygems_version: !ruby/object:Gem::Requirement
211
235
  requirements:
212
236
  - - ">="
213
237
  - !ruby/object:Gem::Version
214
238
  version: '0'
215
239
  requirements: []
216
- rubyforge_project:
217
- rubygems_version: 2.7.3
218
- signing_key:
240
+ rubygems_version: 3.2.3
241
+ signing_key:
219
242
  specification_version: 4
220
- summary: Spam protection for your models via logic questions and the textcaptcha.com
221
- API
243
+ summary: A text-based logic question captcha for Rails
222
244
  test_files: []