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.
@@ -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
+