validates_captcha 0.9.5 → 0.9.6
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.
- data/CHANGELOG.rdoc +6 -0
- data/Rakefile +9 -9
- data/lib/validates_captcha.rb +12 -12
- data/lib/validates_captcha/controller_validation.rb +11 -10
- data/lib/validates_captcha/form_builder.rb +2 -2
- data/lib/validates_captcha/form_helper.rb +11 -11
- data/lib/validates_captcha/image_generator/simple.rb +24 -23
- data/lib/validates_captcha/model_validation.rb +29 -13
- data/lib/validates_captcha/provider/dynamic_image.rb +50 -50
- data/lib/validates_captcha/provider/question.rb +28 -27
- data/lib/validates_captcha/provider/static_image.rb +62 -62
- data/lib/validates_captcha/string_generator/simple.rb +18 -17
- data/lib/validates_captcha/symmetric_encryptor/simple.rb +11 -10
- data/lib/validates_captcha/test_case.rb +1 -0
- data/lib/validates_captcha/version.rb +3 -2
- data/rails/init.rb +4 -4
- data/tasks/static_image_tasks.rake +7 -9
- data/test/cases/controller_validation_test.rb +42 -41
- data/test/cases/image_generator/simple_test.rb +8 -8
- data/test/cases/model_validation_test.rb +79 -64
- data/test/cases/provider/dynamic_image_test.rb +29 -28
- data/test/cases/provider/question_test.rb +11 -10
- data/test/cases/provider/static_image_test.rb +40 -39
- data/test/cases/string_generator/simple_test.rb +29 -29
- data/test/cases/symmetric_encryptor/simple_test.rb +6 -6
- data/test/cases/validates_captcha_test.rb +7 -6
- data/test/test_helper.rb +4 -0
- metadata +3 -3
@@ -5,7 +5,7 @@ module ValidatesCaptcha
|
|
5
5
|
# A question/answer captcha provider.
|
6
6
|
class Question
|
7
7
|
include ActionView::Helpers
|
8
|
-
|
8
|
+
|
9
9
|
DEFAULT_QUESTIONS_AND_ANSWERS = {
|
10
10
|
"What's the capital of France?" => "Paris",
|
11
11
|
"What's the capital of Germany?" => "Berlin",
|
@@ -19,27 +19,27 @@ module ValidatesCaptcha
|
|
19
19
|
"What day is today, if tomorrow is Tuesday?" => "Monday",
|
20
20
|
"What is the 2nd letter of the the third word in this question?" => "h",
|
21
21
|
"What color is the sky on a sunny day?" => "blue" }.freeze
|
22
|
-
|
22
|
+
|
23
23
|
@@questions_and_answers = DEFAULT_QUESTIONS_AND_ANSWERS
|
24
|
-
|
24
|
+
|
25
25
|
class << self
|
26
|
-
# Returns the current captcha questions/answers hash. Defaults to
|
26
|
+
# Returns the current captcha questions/answers hash. Defaults to
|
27
27
|
# DEFAULT_QUESTIONS_AND_ANSWERS.
|
28
28
|
def questions_and_answers
|
29
29
|
@@questions_and_answers
|
30
30
|
end
|
31
|
-
|
31
|
+
|
32
32
|
# Sets the current captcha questions/answers hash. Used to set a
|
33
33
|
# custom questions/answers hash.
|
34
34
|
def questions_and_answers=(qna)
|
35
35
|
@@questions_and_answers = qna
|
36
36
|
end
|
37
37
|
end
|
38
|
-
|
38
|
+
|
39
39
|
# This method is the one called by Rack.
|
40
|
-
#
|
41
|
-
# It returns HTTP status 404 if the path is not recognized. If the path is
|
42
|
-
# recognized, it returns HTTP status 200 and delivers a new challenge in
|
40
|
+
#
|
41
|
+
# It returns HTTP status 404 if the path is not recognized. If the path is
|
42
|
+
# recognized, it returns HTTP status 200 and delivers a new challenge in
|
43
43
|
# JSON format.
|
44
44
|
#
|
45
45
|
# Please take a look at the source code if you want to learn more.
|
@@ -47,64 +47,65 @@ module ValidatesCaptcha
|
|
47
47
|
if env['PATH_INFO'] == regenerate_path
|
48
48
|
captcha_challenge = generate_challenge
|
49
49
|
json = { :captcha_challenge => captcha_challenge }.to_json
|
50
|
-
|
50
|
+
|
51
51
|
[200, { 'Content-Type' => 'application/json' }, [json]]
|
52
52
|
else
|
53
53
|
[404, { 'Content-Type' => 'text/html' }, ['Not Found']]
|
54
54
|
end
|
55
55
|
end
|
56
|
-
|
56
|
+
|
57
57
|
# Returns a captcha question.
|
58
58
|
def generate_challenge
|
59
59
|
self.class.questions_and_answers.keys[rand(self.class.questions_and_answers.keys.size)]
|
60
60
|
end
|
61
|
-
|
62
|
-
# Returns true if the captcha was solved using the given +question+ and +answer+,
|
61
|
+
|
62
|
+
# Returns true if the captcha was solved using the given +question+ and +answer+,
|
63
63
|
# otherwise false.
|
64
64
|
def solved?(question, answer)
|
65
65
|
return false unless self.class.questions_and_answers.key?(question)
|
66
66
|
answers = Array.wrap(self.class.questions_and_answers[question]).map(&:downcase)
|
67
67
|
answers.include?(answer.downcase)
|
68
68
|
end
|
69
|
-
|
69
|
+
|
70
70
|
# Returns a span tag with the inner HTML set to the captcha question.
|
71
|
-
#
|
71
|
+
#
|
72
72
|
# Internally calls Rails' +content_tag+ helper method, passing the +options+ argument.
|
73
73
|
def render_challenge(sanitized_object_name, object, options = {})
|
74
74
|
options[:id] = "#{sanitized_object_name}_captcha_question"
|
75
|
-
|
75
|
+
|
76
76
|
content_tag :span, object.captcha_challenge, options
|
77
77
|
end
|
78
|
-
|
79
|
-
# Returns an anchor tag that makes an AJAX request to fetch a new question and updates
|
78
|
+
|
79
|
+
# Returns an anchor tag that makes an AJAX request to fetch a new question and updates
|
80
80
|
# the captcha challenge after the request is complete.
|
81
|
-
#
|
82
|
-
# Internally calls Rails' +link_to_remote+ helper method, passing the +options+ and
|
83
|
-
# +html_options+ arguments. So it relies on the Prototype javascript framework
|
81
|
+
#
|
82
|
+
# Internally calls Rails' +link_to_remote+ helper method, passing the +options+ and
|
83
|
+
# +html_options+ arguments. So it relies on the Prototype javascript framework
|
84
84
|
# to be available on the web page.
|
85
85
|
#
|
86
|
-
# The anchor text defaults to 'New question'. You can set this to a custom value
|
86
|
+
# The anchor text defaults to 'New question'. You can set this to a custom value
|
87
87
|
# providing a +:text+ key in the +options+ hash.
|
88
88
|
def render_regenerate_challenge_link(sanitized_object_name, object, options = {}, html_options = {})
|
89
89
|
text = options.delete(:text) || 'New question'
|
90
90
|
success = "var result = request.responseJSON; $('#{sanitized_object_name}_captcha_question').update(result.captcha_challenge); $('#{sanitized_object_name}_captcha_challenge').value = result.captcha_challenge; $('#{sanitized_object_name}_captcha_solution').value = '';"
|
91
|
-
|
91
|
+
|
92
92
|
link_to_remote text, options.reverse_merge(:url => regenerate_path, :method => :get, :success => success), html_options
|
93
93
|
end
|
94
|
-
|
95
|
-
private
|
94
|
+
|
95
|
+
private
|
96
96
|
def regenerate_path #:nodoc:
|
97
97
|
'/captchas/regenerate'
|
98
98
|
end
|
99
|
-
|
99
|
+
|
100
100
|
# This is needed by +link_to_remote+ called in +render_regenerate_link+.
|
101
101
|
def protect_against_forgery? #:nodoc:
|
102
102
|
false
|
103
103
|
end
|
104
|
-
|
104
|
+
|
105
105
|
def solve(challenge) #:nodoc:
|
106
106
|
Array.wrap(self.class.questions_and_answers[challenge]).first
|
107
107
|
end
|
108
108
|
end
|
109
109
|
end
|
110
110
|
end
|
111
|
+
|
@@ -9,121 +9,121 @@ module ValidatesCaptcha
|
|
9
9
|
#
|
10
10
|
# rake validates_captcha:create_static_images
|
11
11
|
#
|
12
|
-
# This will create 3 images in #filesystem_dir. To create a
|
12
|
+
# This will create 3 images in #filesystem_dir. To create a
|
13
13
|
# different number of images, provide a COUNT argument:
|
14
14
|
#
|
15
|
-
# rake validates_captcha:create_static_images COUNT=50
|
15
|
+
# rake validates_captcha:create_static_images COUNT=50
|
16
16
|
#
|
17
17
|
# This class contains the getters and setters for the backend classes:
|
18
|
-
# image generator and string generator. This allows you to replace them
|
19
|
-
# with your custom implementations. For more information on how to bring
|
20
|
-
# the image provider to use your own implementation instead of the default
|
18
|
+
# image generator and string generator. This allows you to replace them
|
19
|
+
# with your custom implementations. For more information on how to bring
|
20
|
+
# the image provider to use your own implementation instead of the default
|
21
21
|
# one, consult the documentation for the specific default class.
|
22
22
|
#
|
23
|
-
# The default captcha image generator uses ImageMagick's +convert+ command to
|
24
|
-
# create the captcha. So a recent and properly configured version of ImageMagick
|
25
|
-
# must be installed on the system. The version used while developing was 6.4.5.
|
26
|
-
# But you are not bound to ImageMagick. If you want to provide a custom image
|
27
|
-
# generator, take a look at the documentation for
|
23
|
+
# The default captcha image generator uses ImageMagick's +convert+ command to
|
24
|
+
# create the captcha. So a recent and properly configured version of ImageMagick
|
25
|
+
# must be installed on the system. The version used while developing was 6.4.5.
|
26
|
+
# But you are not bound to ImageMagick. If you want to provide a custom image
|
27
|
+
# generator, take a look at the documentation for
|
28
28
|
# ValidatesCaptcha::ImageGenerator::Simple on how to create your own.
|
29
29
|
class StaticImage
|
30
30
|
include ActionView::Helpers
|
31
|
-
|
31
|
+
|
32
32
|
SALT = "3f(61&831_fa0712d4a?b58-eb4b8$a2%.36378f".freeze
|
33
|
-
|
33
|
+
|
34
34
|
@@string_generator = nil
|
35
35
|
@@image_generator = nil
|
36
36
|
@@filesystem_dir = nil
|
37
37
|
@@web_dir = nil
|
38
38
|
@@salt = nil
|
39
|
-
|
39
|
+
|
40
40
|
class << self
|
41
41
|
# Returns the current captcha string generator. Defaults to an
|
42
42
|
# instance of the ValidatesCaptcha::StringGenerator::Simple class.
|
43
43
|
def string_generator
|
44
44
|
@@string_generator ||= ValidatesCaptcha::StringGenerator::Simple.new
|
45
45
|
end
|
46
|
-
|
46
|
+
|
47
47
|
# Sets the current captcha string generator. Used to set a
|
48
48
|
# custom string generator.
|
49
49
|
def string_generator=(generator)
|
50
50
|
@@string_generator = generator
|
51
51
|
end
|
52
|
-
|
52
|
+
|
53
53
|
# Returns the current captcha image generator. Defaults to an
|
54
54
|
# instance of the ValidatesCaptcha::ImageGenerator::Simple class.
|
55
55
|
def image_generator
|
56
56
|
@@image_generator ||= ValidatesCaptcha::ImageGenerator::Simple.new
|
57
57
|
end
|
58
|
-
|
58
|
+
|
59
59
|
# Sets the current captcha image generator. Used to set a custom
|
60
60
|
# image generator.
|
61
61
|
def image_generator=(generator)
|
62
62
|
@@image_generator = generator
|
63
63
|
end
|
64
|
-
|
65
|
-
# Returns the current captcha image file system directory. Defaults to
|
64
|
+
|
65
|
+
# Returns the current captcha image file system directory. Defaults to
|
66
66
|
# +RAILS_ROOT/public/images/captchas+.
|
67
67
|
def filesystem_dir
|
68
68
|
@@filesystem_dir ||= ::File.join(::Rails.public_path, 'images', 'captchas')
|
69
69
|
end
|
70
|
-
|
70
|
+
|
71
71
|
# Sets the current captcha image file system directory. Used to set a custom
|
72
72
|
# image directory.
|
73
73
|
def filesystem_dir=(dir)
|
74
74
|
@@filesystem_dir = dir
|
75
75
|
end
|
76
|
-
|
77
|
-
# Returns the current captcha image web directory. Defaults to
|
76
|
+
|
77
|
+
# Returns the current captcha image web directory. Defaults to
|
78
78
|
# +/images/captchas+.
|
79
79
|
def web_dir
|
80
80
|
@@web_dir ||= '/images/captchas'
|
81
81
|
end
|
82
|
-
|
82
|
+
|
83
83
|
# Sets the current captcha image web directory. Used to set a custom
|
84
84
|
# image directory.
|
85
85
|
def web_dir=(dir)
|
86
86
|
@@web_dir = dir
|
87
87
|
end
|
88
|
-
|
88
|
+
|
89
89
|
# Returns the current salt used for encryption.
|
90
90
|
def salt
|
91
91
|
@@salt ||= SALT
|
92
92
|
end
|
93
|
-
|
93
|
+
|
94
94
|
# Sets the current salt used for encryption. Used to set a custom
|
95
95
|
# salt.
|
96
96
|
def salt=(salt)
|
97
97
|
@@salt = salt
|
98
98
|
end
|
99
|
-
|
99
|
+
|
100
100
|
# Return the encryption of the +code+ using #salt.
|
101
101
|
def encrypt(code)
|
102
102
|
::Digest::SHA1.hexdigest "#{salt}--#{code}"
|
103
|
-
end
|
104
|
-
|
105
|
-
# Creates a captcha image in the #filesystem_dir and returns
|
103
|
+
end
|
104
|
+
|
105
|
+
# Creates a captcha image in the #filesystem_dir and returns
|
106
106
|
# the path to it and the code displayed on the image.
|
107
107
|
def create_image
|
108
108
|
code = string_generator.generate
|
109
109
|
encrypted_code = encrypt(code)
|
110
|
-
|
110
|
+
|
111
111
|
image_filename = "#{encrypted_code}#{image_generator.file_extension}"
|
112
112
|
image_path = File.join(filesystem_dir, image_filename)
|
113
113
|
image_bytes = image_generator.generate(code)
|
114
|
-
|
114
|
+
|
115
115
|
File.open image_path, 'w' do |os|
|
116
116
|
os.write image_bytes
|
117
117
|
end
|
118
|
-
|
118
|
+
|
119
119
|
return image_path, code
|
120
120
|
end
|
121
121
|
end
|
122
|
-
|
122
|
+
|
123
123
|
# This method is the one called by Rack.
|
124
|
-
#
|
125
|
-
# It returns HTTP status 404 if the path is not recognized. If the path is
|
126
|
-
# recognized, it returns HTTP status 200 and delivers a new challenge in
|
124
|
+
#
|
125
|
+
# It returns HTTP status 404 if the path is not recognized. If the path is
|
126
|
+
# recognized, it returns HTTP status 200 and delivers a new challenge in
|
127
127
|
# JSON format.
|
128
128
|
#
|
129
129
|
# Please take a look at the source code if you want to learn more.
|
@@ -131,89 +131,89 @@ module ValidatesCaptcha
|
|
131
131
|
if env['PATH_INFO'] == regenerate_path
|
132
132
|
captcha_challenge = generate_challenge
|
133
133
|
json = { :captcha_challenge => captcha_challenge, :captcha_image_path => image_path(captcha_challenge) }.to_json
|
134
|
-
|
134
|
+
|
135
135
|
[200, { 'Content-Type' => 'application/json' }, [json]]
|
136
136
|
else
|
137
137
|
[404, { 'Content-Type' => 'text/html' }, ['Not Found']]
|
138
138
|
end
|
139
139
|
end
|
140
|
-
|
140
|
+
|
141
141
|
# Returns an array containing the paths to the available captcha images.
|
142
142
|
def images
|
143
143
|
@images ||= Dir[File.join(filesystem_dir, "*#{image_file_extension}")]
|
144
144
|
end
|
145
|
-
|
145
|
+
|
146
146
|
# Returns an array containing the available challenges (encrypted captcha codes).
|
147
147
|
def challenges
|
148
148
|
@challenges ||= images.map { |path| File.basename(path, image_file_extension) }
|
149
149
|
end
|
150
|
-
|
150
|
+
|
151
151
|
# Returns a captcha challenge.
|
152
152
|
def generate_challenge
|
153
153
|
raise("no captcha images found in #{filesystem_dir}") if challenges.empty?
|
154
|
-
|
154
|
+
|
155
155
|
challenges[rand(challenges.size)]
|
156
156
|
end
|
157
|
-
|
158
|
-
# Returns true if the captcha was solved using the given +challenge+ and +solution+,
|
157
|
+
|
158
|
+
# Returns true if the captcha was solved using the given +challenge+ and +solution+,
|
159
159
|
# otherwise false.
|
160
160
|
def solved?(challenge, solution)
|
161
161
|
challenge == encrypt(solution)
|
162
162
|
end
|
163
|
-
|
163
|
+
|
164
164
|
# Returns an image tag with the source set to the url of the captcha image.
|
165
|
-
#
|
165
|
+
#
|
166
166
|
# Internally calls Rails' +image_tag+ helper method, passing the +options+ argument.
|
167
167
|
def render_challenge(sanitized_object_name, object, options = {})
|
168
168
|
src = image_path(object.captcha_challenge)
|
169
|
-
|
169
|
+
|
170
170
|
options[:alt] ||= 'CAPTCHA'
|
171
171
|
options[:id] = "#{sanitized_object_name}_captcha_image"
|
172
|
-
|
172
|
+
|
173
173
|
image_tag src, options
|
174
174
|
end
|
175
|
-
|
176
|
-
# Returns an anchor tag that makes an AJAX request to fetch a new captcha code and updates
|
175
|
+
|
176
|
+
# Returns an anchor tag that makes an AJAX request to fetch a new captcha code and updates
|
177
177
|
# the captcha image after the request is complete.
|
178
|
-
#
|
179
|
-
# Internally calls Rails' +link_to_remote+ helper method, passing the +options+ and
|
180
|
-
# +html_options+ arguments. So it relies on the Prototype javascript framework
|
178
|
+
#
|
179
|
+
# Internally calls Rails' +link_to_remote+ helper method, passing the +options+ and
|
180
|
+
# +html_options+ arguments. So it relies on the Prototype javascript framework
|
181
181
|
# to be available on the web page.
|
182
182
|
#
|
183
|
-
# The anchor text defaults to 'Regenerate Captcha'. You can set this to a custom value
|
183
|
+
# The anchor text defaults to 'Regenerate Captcha'. You can set this to a custom value
|
184
184
|
# providing a +:text+ key in the +options+ hash.
|
185
185
|
def render_regenerate_challenge_link(sanitized_object_name, object, options = {}, html_options = {})
|
186
186
|
text = options.delete(:text) || 'Regenerate Captcha'
|
187
187
|
success = "var result = request.responseJSON; $('#{sanitized_object_name}_captcha_image').src = result.captcha_image_path; $('#{sanitized_object_name}_captcha_challenge').value = result.captcha_challenge; $('#{sanitized_object_name}_captcha_solution').value = '';"
|
188
|
-
|
188
|
+
|
189
189
|
link_to_remote text, options.reverse_merge(:url => regenerate_path, :method => :get, :success => success), html_options
|
190
190
|
end
|
191
|
-
|
192
|
-
private
|
191
|
+
|
192
|
+
private
|
193
193
|
def regenerate_path #:nodoc:
|
194
194
|
'/captchas/regenerate'
|
195
195
|
end
|
196
|
-
|
196
|
+
|
197
197
|
def image_file_extension #:nodoc:
|
198
198
|
self.class.image_generator.file_extension
|
199
199
|
end
|
200
|
-
|
200
|
+
|
201
201
|
def image_path(encrypted_code) #:nodoc:
|
202
202
|
File.join(web_dir, "#{encrypted_code}#{image_file_extension}")
|
203
203
|
end
|
204
|
-
|
204
|
+
|
205
205
|
def encrypt(code) #:nodoc:
|
206
206
|
self.class.encrypt code
|
207
207
|
end
|
208
|
-
|
208
|
+
|
209
209
|
def filesystem_dir #:nodoc:
|
210
210
|
self.class.filesystem_dir
|
211
211
|
end
|
212
|
-
|
212
|
+
|
213
213
|
def web_dir #:nodoc:
|
214
214
|
self.class.web_dir
|
215
215
|
end
|
216
|
-
|
216
|
+
|
217
217
|
# This is needed by +link_to_remote+ called in +render_regenerate_link+.
|
218
218
|
def protect_against_forgery? #:nodoc:
|
219
219
|
false
|
@@ -221,4 +221,4 @@ module ValidatesCaptcha
|
|
221
221
|
end
|
222
222
|
end
|
223
223
|
end
|
224
|
-
|
224
|
+
|
@@ -1,23 +1,23 @@
|
|
1
1
|
module ValidatesCaptcha
|
2
2
|
module StringGenerator
|
3
|
-
# This class is responsible for generating the codes that are displayed
|
4
|
-
# on the captcha images. It does so by randomly selecting a number of
|
5
|
-
# characters from a predefined alphabet constisting of visually distinguishable
|
3
|
+
# This class is responsible for generating the codes that are displayed
|
4
|
+
# on the captcha images. It does so by randomly selecting a number of
|
5
|
+
# characters from a predefined alphabet constisting of visually distinguishable
|
6
6
|
# letters and digits.
|
7
7
|
#
|
8
|
-
# The number of characters and the alphabet used when generating strings can
|
8
|
+
# The number of characters and the alphabet used when generating strings can
|
9
9
|
# be customized. See the #alphabet= and #length= methods for details.
|
10
10
|
#
|
11
|
-
# You can implement your own string generator by creating a
|
12
|
-
# class that conforms to the method definitions of the example below and
|
13
|
-
# assign an instance of it to
|
11
|
+
# You can implement your own string generator by creating a
|
12
|
+
# class that conforms to the method definitions of the example below and
|
13
|
+
# assign an instance of it to
|
14
14
|
# ValidatesCaptcha::Provider::DynamicImage#string_generator=.
|
15
15
|
#
|
16
16
|
# Example for a custom string generator:
|
17
17
|
#
|
18
18
|
# class DictionaryGenerator
|
19
19
|
# DICTIONARY = ['foo', 'bar', 'baz', ...]
|
20
|
-
#
|
20
|
+
#
|
21
21
|
# def generate
|
22
22
|
# return DICTIONARY[rand(DICTIONARY.size)]
|
23
23
|
# end
|
@@ -27,21 +27,21 @@ module ValidatesCaptcha
|
|
27
27
|
# ValidatesCaptcha.provider = ValidatesCaptcha::Provider::DynamicImage.new
|
28
28
|
#
|
29
29
|
# You can also assign it to ValidatesCaptcha::Provider::StaticImage#string_generator=.
|
30
|
-
#
|
30
|
+
#
|
31
31
|
class Simple
|
32
32
|
@@alphabet = 'abdefghjkmnqrtABDEFGHJKLMNQRT234678923467892346789'
|
33
33
|
@@length = 6
|
34
|
-
|
34
|
+
|
35
35
|
class << self
|
36
|
-
# Returns a string holding the chars used when randomly generating the text that
|
37
|
-
# is displayed on a captcha image. Defaults to a string of visually distinguishable
|
36
|
+
# Returns a string holding the chars used when randomly generating the text that
|
37
|
+
# is displayed on a captcha image. Defaults to a string of visually distinguishable
|
38
38
|
# letters and digits.
|
39
39
|
def alphabet
|
40
40
|
@@alphabet
|
41
41
|
end
|
42
42
|
|
43
|
-
# Sets the string to use as alphabet when randomly generating the text displayed
|
44
|
-
# on a captcha image. To increase the probability of appearing in the image, some
|
43
|
+
# Sets the string to use as alphabet when randomly generating the text displayed
|
44
|
+
# on a captcha image. To increase the probability of appearing in the image, some
|
45
45
|
# characters might appear more than once in the string.
|
46
46
|
#
|
47
47
|
# You can set this to a custom alphabet within a Rails initializer:
|
@@ -50,10 +50,10 @@ module ValidatesCaptcha
|
|
50
50
|
def alphabet=(alphabet)
|
51
51
|
alphabet = alphabet.to_s.gsub(/\s/, '')
|
52
52
|
raise('alphabet cannot be blank') if alphabet.blank?
|
53
|
-
|
53
|
+
|
54
54
|
@@alphabet = alphabet
|
55
55
|
end
|
56
|
-
|
56
|
+
|
57
57
|
# Returns the length to use when generating captcha codes. Defaults to 6.
|
58
58
|
def length
|
59
59
|
@@length
|
@@ -68,7 +68,7 @@ module ValidatesCaptcha
|
|
68
68
|
@@length = length.to_i
|
69
69
|
end
|
70
70
|
end
|
71
|
-
|
71
|
+
|
72
72
|
# Randomly generates a string to be used as the code displayed on captcha images.
|
73
73
|
def generate
|
74
74
|
alphabet_chars = self.class.alphabet.split(//)
|
@@ -79,3 +79,4 @@ module ValidatesCaptcha
|
|
79
79
|
end
|
80
80
|
end
|
81
81
|
end
|
82
|
+
|