acts_as_textcaptcha 4.5.1 → 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.
- checksums.yaml +4 -4
- data/.rubocop.yml +1165 -0
- data/.simplecov +4 -2
- data/.travis.yml +14 -18
- data/Appraisals +3 -8
- data/CHANGELOG.md +9 -1
- data/Gemfile +3 -1
- data/README.md +18 -7
- data/Rakefile +18 -9
- data/acts_as_textcaptcha.gemspec +31 -26
- data/gemfiles/rails_4.gemfile +1 -1
- data/gemfiles/rails_5.gemfile +1 -1
- data/gemfiles/rails_6.gemfile +1 -1
- data/lib/acts_as_textcaptcha.rb +7 -7
- data/lib/acts_as_textcaptcha/railtie.rb +2 -2
- data/lib/acts_as_textcaptcha/tasks/textcaptcha.rake +6 -5
- data/lib/acts_as_textcaptcha/textcaptcha.rb +89 -95
- data/lib/acts_as_textcaptcha/textcaptcha_api.rb +34 -37
- data/lib/acts_as_textcaptcha/textcaptcha_cache.rb +6 -9
- data/lib/acts_as_textcaptcha/textcaptcha_config.rb +35 -36
- data/lib/acts_as_textcaptcha/textcaptcha_helper.rb +10 -13
- data/lib/acts_as_textcaptcha/version.rb +1 -1
- metadata +38 -23
@@ -1,21 +1,20 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require "json"
|
4
4
|
|
5
5
|
module ActsAsTextcaptcha
|
6
6
|
class TextcaptchaApi
|
7
|
-
|
8
|
-
BASE_URL = 'http://textcaptcha.com'
|
7
|
+
BASE_URL = "http://textcaptcha.com"
|
9
8
|
|
10
9
|
def initialize(api_key: nil, api_endpoint: nil, raise_errors: false)
|
11
|
-
if api_endpoint
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
10
|
+
self.uri = if api_endpoint
|
11
|
+
URI(api_endpoint)
|
12
|
+
else
|
13
|
+
URI("#{BASE_URL}/#{api_key}.json")
|
14
|
+
end
|
16
15
|
self.raise_errors = raise_errors || false
|
17
|
-
rescue URI::InvalidURIError =>
|
18
|
-
raise ApiKeyError.new(api_key,
|
16
|
+
rescue URI::InvalidURIError => e
|
17
|
+
raise ApiKeyError.new(api_key, e)
|
19
18
|
end
|
20
19
|
|
21
20
|
def fetch
|
@@ -24,35 +23,33 @@ module ActsAsTextcaptcha
|
|
24
23
|
|
25
24
|
private
|
26
25
|
|
27
|
-
|
28
|
-
|
29
|
-
def get
|
30
|
-
response = Net::HTTP.new(uri.host, uri.port).get(uri.path)
|
31
|
-
if response.code == '200'
|
32
|
-
response.body
|
33
|
-
else
|
34
|
-
handle_error ResponseError.new(uri, "status: #{response.code}")
|
35
|
-
end
|
36
|
-
rescue SocketError, Timeout::Error, Errno::EINVAL, Errno::ECONNRESET,
|
37
|
-
Errno::EHOSTUNREACH, EOFError, Errno::ECONNREFUSED, Errno::ETIMEDOUT,
|
38
|
-
Net::HTTPBadResponse, Net::HTTPHeaderSyntaxError,
|
39
|
-
Net::ProtocolError => exception
|
40
|
-
handle_error ResponseError.new(uri, exception)
|
41
|
-
end
|
26
|
+
attr_accessor :uri, :raise_errors
|
42
27
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
28
|
+
def get
|
29
|
+
response = Net::HTTP.new(uri.host, uri.port).get(uri.path)
|
30
|
+
if response.code == "200"
|
31
|
+
response.body
|
32
|
+
else
|
33
|
+
handle_error ResponseError.new(uri, "status: #{response.code}")
|
47
34
|
end
|
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)
|
40
|
+
end
|
48
41
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
42
|
+
def parse(response)
|
43
|
+
JSON.parse(response) unless response.empty?
|
44
|
+
rescue JSON::ParserError
|
45
|
+
handle_error ParseError.new(uri)
|
46
|
+
end
|
47
|
+
|
48
|
+
def handle_error(error)
|
49
|
+
raise error if raise_errors
|
50
|
+
|
51
|
+
Rails.logger.error("#{error.class} #{error.message}")
|
52
|
+
nil
|
53
|
+
end
|
57
54
|
end
|
58
55
|
end
|
@@ -1,18 +1,15 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
# A simple cache for storing Textcaptcha answers, Rails.cache is used as the
|
4
|
-
# backend (ActiveSupport::Cache)
|
4
|
+
# backend (ActiveSupport::Cache). This must not be set as a `:null_store`.
|
5
5
|
|
6
6
|
module ActsAsTextcaptcha
|
7
7
|
class TextcaptchaCache
|
8
|
-
|
9
|
-
KEY_PREFIX = 'acts_as_textcaptcha-'
|
8
|
+
KEY_PREFIX = "acts_as_textcaptcha-"
|
10
9
|
DEFAULT_EXPIRY_MINUTES = 10
|
11
10
|
|
12
11
|
def write(key, value, options = {})
|
13
|
-
unless options.has_key?(:expires_in)
|
14
|
-
options[:expires_in] = DEFAULT_EXPIRY_MINUTES.minutes
|
15
|
-
end
|
12
|
+
options[:expires_in] = DEFAULT_EXPIRY_MINUTES.minutes unless options.has_key?(:expires_in)
|
16
13
|
Rails.cache.write(cache_key(key), value, options)
|
17
14
|
end
|
18
15
|
|
@@ -26,8 +23,8 @@ module ActsAsTextcaptcha
|
|
26
23
|
|
27
24
|
private
|
28
25
|
|
29
|
-
|
30
|
-
|
31
|
-
|
26
|
+
def cache_key(key)
|
27
|
+
"#{KEY_PREFIX}#{key}"
|
28
|
+
end
|
32
29
|
end
|
33
30
|
end
|
@@ -2,47 +2,46 @@
|
|
2
2
|
|
3
3
|
module ActsAsTextcaptcha
|
4
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)
|
5
11
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
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'
|
12
33
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
- question: 'what color is an orange?'
|
17
|
-
answers: 'orange'
|
18
|
-
- question: 'what is two plus 3?'
|
19
|
-
answers: '5,five'
|
20
|
-
- question: 'what is 5 times two?'
|
21
|
-
answers: '10,ten'
|
22
|
-
- question: 'How many colors in the list, green, brown, foot and blue?'
|
23
|
-
answers: '3,three'
|
24
|
-
- question: 'what is Georges name?'
|
25
|
-
answers: 'george'
|
26
|
-
- question: '11 minus 1?'
|
27
|
-
answers: '10,ten'
|
28
|
-
- question: 'is boiling water hot or cold?'
|
29
|
-
answers: 'hot'
|
30
|
-
- question: 'what color is my blue shirt today?'
|
31
|
-
answers: 'blue'
|
32
|
-
- question: 'what is 16 plus 4?'
|
33
|
-
answers: '20,twenty'
|
34
|
+
test:
|
35
|
+
<<: *common_settings
|
36
|
+
api_key: 'TEST_TEXTCAPTCHA_API_IDENT'
|
34
37
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
+
production:
|
39
|
+
<<: *common_settings
|
40
|
+
CONFIG
|
38
41
|
|
39
|
-
|
40
|
-
<<: *common_settings
|
41
|
-
CONFIG
|
42
|
-
|
43
|
-
def self.create(path: './config/textcaptcha.yml')
|
42
|
+
def self.create(path: "./config/textcaptcha.yml")
|
44
43
|
FileUtils.mkdir_p(File.dirname(path))
|
45
|
-
File.open(path,
|
44
|
+
File.open(path, "w") { |f| f.write(YAML) }
|
46
45
|
end
|
47
46
|
end
|
48
47
|
end
|
@@ -2,23 +2,20 @@
|
|
2
2
|
|
3
3
|
module ActsAsTextcaptcha
|
4
4
|
module TextcaptchaHelper
|
5
|
-
|
6
|
-
|
7
|
-
if f.object.perform_textcaptcha? && f.object.textcaptcha_key
|
8
|
-
build_textcaptcha_form_elements(f, &block)
|
9
|
-
end
|
5
|
+
def textcaptcha_fields(form, &block)
|
6
|
+
build_textcaptcha_form_elements(form, &block) if form.object.perform_textcaptcha? && form.object.textcaptcha_key
|
10
7
|
end
|
11
8
|
|
12
9
|
private
|
13
10
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
end
|
21
|
-
captcha_html.html_safe
|
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)
|
22
17
|
end
|
18
|
+
captcha_html.html_safe
|
19
|
+
end
|
23
20
|
end
|
24
21
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: acts_as_textcaptcha
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 4.5.
|
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:
|
11
|
+
date: 2021-01-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -25,7 +25,7 @@ dependencies:
|
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
|
-
name:
|
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:
|
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:
|
56
|
+
name: rubocop
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
59
|
- - ">="
|
@@ -67,21 +67,21 @@ dependencies:
|
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '0'
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
|
-
name:
|
70
|
+
name: rdoc
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
72
72
|
requirements:
|
73
|
-
- - "
|
73
|
+
- - ">="
|
74
74
|
- !ruby/object:Gem::Version
|
75
|
-
version:
|
75
|
+
version: '0'
|
76
76
|
type: :development
|
77
77
|
prerelease: false
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
79
79
|
requirements:
|
80
|
-
- - "
|
80
|
+
- - ">="
|
81
81
|
- !ruby/object:Gem::Version
|
82
|
-
version:
|
82
|
+
version: '0'
|
83
83
|
- !ruby/object:Gem::Dependency
|
84
|
-
name:
|
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:
|
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:
|
112
|
+
name: rails
|
113
113
|
requirement: !ruby/object:Gem::Requirement
|
114
114
|
requirements:
|
115
|
-
- - "
|
115
|
+
- - "~>"
|
116
116
|
- !ruby/object:Gem::Version
|
117
|
-
version:
|
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:
|
124
|
+
version: 6.0.3.4
|
125
125
|
- !ruby/object:Gem::Dependency
|
126
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:
|
154
|
+
name: webmock
|
141
155
|
requirement: !ruby/object:Gem::Requirement
|
142
156
|
requirements:
|
143
157
|
- - ">="
|
@@ -164,6 +178,7 @@ extra_rdoc_files:
|
|
164
178
|
- LICENSE
|
165
179
|
files:
|
166
180
|
- ".gitignore"
|
181
|
+
- ".rubocop.yml"
|
167
182
|
- ".simplecov"
|
168
183
|
- ".travis.yml"
|
169
184
|
- Appraisals
|
@@ -202,7 +217,7 @@ metadata:
|
|
202
217
|
source_code_uri: https://github.com/matthutchinson/acts_as_textcaptcha
|
203
218
|
bug_tracker_uri: https://github.com/matthutchinson/acts_as_textcaptcha/issues
|
204
219
|
allowed_push_host: https://rubygems.org
|
205
|
-
post_install_message:
|
220
|
+
post_install_message:
|
206
221
|
rdoc_options:
|
207
222
|
- "--title"
|
208
223
|
- ActAsTextcaptcha
|
@@ -215,15 +230,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
215
230
|
requirements:
|
216
231
|
- - ">="
|
217
232
|
- !ruby/object:Gem::Version
|
218
|
-
version: '2.
|
233
|
+
version: '2.5'
|
219
234
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
220
235
|
requirements:
|
221
236
|
- - ">="
|
222
237
|
- !ruby/object:Gem::Version
|
223
238
|
version: '0'
|
224
239
|
requirements: []
|
225
|
-
rubygems_version: 3.
|
226
|
-
signing_key:
|
240
|
+
rubygems_version: 3.2.3
|
241
|
+
signing_key:
|
227
242
|
specification_version: 4
|
228
243
|
summary: A text-based logic question captcha for Rails
|
229
244
|
test_files: []
|