validates_captcha 0.9.2 → 0.9.3

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG.rdoc CHANGED
@@ -1,3 +1,8 @@
1
- == 0.9.1 (September 27, 2009)
1
+ == 0.9.3 (September 29, 2009)
2
+
3
+ * Change API, include new Question provider, make it the default one
4
+
5
+
6
+ == 0.9.2 (September 27, 2009)
2
7
 
3
8
  * Initial version
data/README.rdoc CHANGED
@@ -1,12 +1,15 @@
1
1
  = Validates Captcha
2
2
 
3
- An image captcha verification approach for Rails apps, directly integrated into
3
+ A captcha verification approach for Rails apps, directly integrated into
4
4
  ActiveRecord's validation mechanism and providing helpers for ActionController
5
5
  and ActionView.
6
6
 
7
7
  RDoc documentation (including this README as start page) can be found at
8
8
  http://m4n.github.com/validates_captcha
9
9
 
10
+ Validates Captcha uses question/answer captchas by default. But you can
11
+ also use the built-in image captcha provider -- or implement your own.
12
+
10
13
 
11
14
 
12
15
  == Basic Usage
@@ -15,7 +18,7 @@ Validates Captcha extends ActiveRecord, ActionController and ActionView with
15
18
  helper methods that make it a snap to integrate captcha verification in your
16
19
  Rails application.
17
20
 
18
- Step #1: Extend the form of your view with the necessary captcha code display
21
+ <b>Step #1:</b> Extend the form of your view with the necessary captcha display
19
22
  and input logic.
20
23
 
21
24
  # app/views/comments/new.html.erb
@@ -32,8 +35,8 @@ and input logic.
32
35
  <!-- now something new: -->
33
36
  <p>
34
37
  <%= f.label :captcha %><br />
35
- <%= f.captcha_image %>
36
- <%= f.captcha_field %>
38
+ <%= f.captcha_challenge # displays the question or image %>
39
+ <%= f.captcha_field # displays the input field %>
37
40
  </p>
38
41
 
39
42
  <p>
@@ -41,7 +44,7 @@ and input logic.
41
44
  </p>
42
45
  <% end %>
43
46
 
44
- Step #2: Tell the controller that you want to validate
47
+ <b>Step #2:</b> Tell the controller that you want to validate
45
48
  captchas.
46
49
 
47
50
  class CommentsController < ApplicationController
@@ -57,11 +60,11 @@ captchas.
57
60
  This activates captcha validation in every action of the controller
58
61
  whenever an instance of class +Comment+ is saved.
59
62
 
60
- Step #3: There's no step three!
63
+ <b>Step #3:</b> There's no step three!
61
64
 
62
65
  To summarize: Put the following in your view.
63
66
 
64
- <%= f.captcha_image %>
67
+ <%= f.captcha_challenge %>
65
68
  <%= f.captcha_field %>
66
69
 
67
70
  And what you see below in the corresponding controller.
@@ -91,48 +94,39 @@ You can customize the validated class using the +validates_captcha_of+ method.
91
94
  end
92
95
 
93
96
  Two kinds of errors are added to the model if captcha validation fails:
94
- +:blank+ if no captcha code is submitted and +:invalid+ if a captcha code
95
- is submitted but does not match the code displayed on the captcha image.
96
- You can localize the error messages for the captcha as you usually do
97
- for the other attributes.
97
+ +:blank+ if no captcha solution is submitted and +:invalid+ if a captcha
98
+ solution is submitted but does not solve the captcha's challenge. You can
99
+ localize the error messages for the captcha as you usually do for the
100
+ other attributes.
98
101
 
99
102
  models:
100
103
  comment:
101
104
  attributes:
102
- captcha:
105
+ captcha_solution:
103
106
  blank: 'must not be empty'
104
107
  invalid: 'does not match the code displayed on the image'
105
108
 
106
- What if the captcha's text is unreadable? There's also a form helper
107
- method for captcha regeneration available. You can call it like this.
109
+ What if the image captcha's text is unreadable or a user does not know the
110
+ correct answer to the captcha question? There's also a form helper method
111
+ for captcha regeneration available. You can call it like this.
108
112
 
109
113
  <p>
110
- Captcha code unreadable? <%= f.regenerate_captcha_link %>
114
+ Don't know the answer? <%= f.regenerate_captcha_challenge_link %>
111
115
  </p>
112
116
 
113
- This generates an anchor tag that, when clicked, generates a new
114
- captcha and updates the image. It makes an AJAX request to fetch a
115
- new captcha code and updates the captcha image after the request is complete.
117
+ This generates an anchor tag that, when clicked, generates a new captcha
118
+ challenge and updates the display. It makes an AJAX request to fetch a
119
+ new challenge and updates the question/image after the request is complete.
116
120
 
117
- +regenerate_captcha_link+ internally calls Rails' #link_to_remote helper
118
- method. So it relies on the Prototype javascript framework to be available
119
- on the page.
121
+ +regenerate_captcha_challenge_link+ internally calls Rails' +link_to_remote+
122
+ helper method. So it relies on the Prototype javascript framework to be
123
+ available on the page.
120
124
 
121
- The anchor's text defaults to 'Regenerate Captcha'. You can set this to
125
+ The anchor's text defaults to 'New question' (question challenge) and
126
+ 'Regenerate Captcha' (image challenge) respectively. You can set this to
122
127
  a custom value by providing a +:text+ key in the options hash.
123
128
 
124
- <%= f.regenerate_captcha_link :text => 'Another captcha, please' %>
125
-
126
- By default, captchas have a length of 6 characters and the text displayed
127
- on the captcha image is created by randomly selecting characters from a
128
- predefined alphabet constisting of visually distinguishable letters and digits.
129
-
130
- The number of characters and the alphabet used when generating strings can
131
- be customized. Just put the following in a Rails initializer and adjust the
132
- values to your needs.
133
-
134
- ValidatesCaptcha::StringGenerator::Simple.alphabet = '01'
135
- ValidatesCaptcha::StringGenerator::Simple.length = 8
129
+ <%= f.regenerate_captcha_challenge_link :text => 'Another captcha, please' %>
136
130
 
137
131
  Apart from controllers, you can activate captcha validation for a model
138
132
  using the class level +with_captcha_validation+ method added to
@@ -146,28 +140,67 @@ ActiveRecord::Base.
146
140
  This activates captcha validation on entering the block and deactivates it
147
141
  on leaving the block.
148
142
 
149
- Two new attribute like methods are added to ActiveRecord: +captcha+ and
150
- +encrypted_captcha+. Those are made +attr_accessible+. The latter is
151
- initialized to a randomly generated and encrypted captcha code on
152
- instantation.
143
+ Two new attribute-like methods are added to ActiveRecord: +captcha_challenge+
144
+ and +captcha_solution+. Those are made +attr_accessible+. The former is
145
+ initialized to a randomly generated captcha challenge on instantiation.
146
+
147
+ For a record to be valid, the value assigned to +captcha_solution=+ must
148
+ solve the return value of +captcha_challenge+. Within a +with_captcha_validation+
149
+ block, calling +valid?+ (as is done by +save+, +update_attributes+, etc.)
150
+ will also validate the value of +captcha_solution+ against +captcha_challenge+.
151
+ Outside +with_captcha_validation+, no captcha validation is performed.
152
+
153
+
154
+
155
+ == Question/answer challange captchas (default provider)
156
+
157
+ You can set the captcha provider to use question/answer challenges with
158
+ the code below. It is best to put this in a Rails initializer.
159
+
160
+ ValidatesCaptcha.provider = ValidatesCaptcha::Provider::Question.new # this is the default
161
+
162
+ If you want to replace the few default questions and answers, here's how
163
+ to do it.
153
164
 
154
- For a record to be valid, the value assigned to +captcha=+ must match the
155
- decryption of the return value of +encrypted_captcha+. Within a
156
- +with_captcha_validation+ block, calling +valid?+ (as is done by +save+,
157
- +update_attributes+, etc.) will also validate the value of +captcha+
158
- against the +encrypted_captcha+. Outside +with_captcha_validation+, no
159
- captcha validation is performed.
165
+ ValidatesCaptcha::Provider::Question.questions_and_answers = {
166
+ "What's the opposite of bad?" => "good",
167
+ "What are the initials of the creator of Rails?" => "DHH",
168
+ "What's the sum of 3 and four?" => ["7", "seven"],
169
+ ... }
170
+
171
+
172
+
173
+ == Image challenge captchas
174
+
175
+ You can set the captcha provider to use image challenges with
176
+ the code below. It is best to put this in a Rails initializer.
177
+
178
+ ValidatesCaptcha.provider = ValidatesCaptcha::Provider::Image.new
179
+
180
+ By default, image captchas have a length of 6 characters and the text displayed
181
+ on the captcha image is created by randomly selecting characters from a
182
+ predefined alphabet constisting of visually distinguishable letters and digits.
183
+
184
+ The number of characters and the alphabet used when generating strings can
185
+ be customized. Just put the following in a Rails initializer and adjust the
186
+ values to your needs.
187
+
188
+ ValidatesCaptcha::StringGenerator::Simple.alphabet = '01'
189
+ ValidatesCaptcha::StringGenerator::Simple.length = 8
160
190
 
161
191
 
162
192
 
163
193
  == Extensibility
164
194
 
195
+ Don't like the built-in challenges? It's easy to extend them or to implement
196
+ your own.
197
+
165
198
  Validates Captcha delegates tasks like string and image generation,
166
199
  encryption/decryption of captcha codes, and responding to captcha requests
167
200
  to dedicated backend classes.
168
201
 
169
- Those classes can easily be replaced by your custom implementations. So
170
- you can achieve stronger encryption, can use a word list as captcha text
202
+ Those classes can easily be replaced with your custom implementations. So
203
+ you can achieve stronger encryption, can use a word list as image captcha text
171
204
  generation source, or can replace the captcha image generator with one
172
205
  that creates images that are harder to crack.
173
206
 
@@ -176,7 +209,10 @@ Please see the documentation of the following classes for further information.
176
209
  * ValidatesCaptcha::StringGenerator::Simple
177
210
  * ValidatesCaptcha::ReversibleEncrypter::Simple
178
211
  * ValidatesCaptcha::ImageGenerator::Simple
179
- * ValidatesCaptcha::Middleware::Simple
212
+
213
+ Or you can implement a custom captcha challenge provider and assign it to
214
+ ValidatesCaptcha#provider=. See the documentation on ValidatesCaptcha::Provider
215
+ for an example.
180
216
 
181
217
 
182
218
 
@@ -185,8 +221,8 @@ Please see the documentation of the following classes for further information.
185
221
  Using a Rack middleware to speed up the request/response cycle when fetching
186
222
  captcha images, Validates Captcha requires Rails version 2.3 or greater.
187
223
 
188
- The default captcha image generator uses ImageMagick's +convert+ command to
189
- create the captcha. So a recent and properly configured version of ImageMagick
224
+ The image captcha provider uses ImageMagick's +convert+ command to create
225
+ the captcha. So a recent and properly configured version of ImageMagick
190
226
  must be installed on the system. The version used while developing was 6.4.5.
191
227
  But you are not bound to ImageMagick. If you want to provide a custom image
192
228
  generator, take a look at the documentation for
@@ -22,17 +22,11 @@
22
22
  #++
23
23
 
24
24
 
25
- # This module contains the getters and setters for the backend classes:
26
- # image/string generator, reversible encrypter, and Rack middleware. This
27
- # allows you to replace them with your custom implementations. For more
25
+ # This module contains the getter and setter for the captcha provider.
26
+ # This allows you to replace it with your custom implementation. For more
28
27
  # information on how to bring Validates Captcha to use your own
29
28
  # implementation instead of the default one, consult the documentation
30
- # for the specific default class.
31
- #
32
- # This module also contains convenience wrapper methods for all the
33
- # methods provided by the configured backend classes. These wrapper
34
- # methods form the API that is visible to the outside world and that
35
- # all backend classes use for internal communication.
29
+ # for the default provider.
36
30
  module ValidatesCaptcha
37
31
  autoload :ModelValidation, 'validates_captcha/model_validation'
38
32
  autoload :ControllerValidation, 'validates_captcha/controller_validation'
@@ -41,8 +35,9 @@ module ValidatesCaptcha
41
35
  autoload :TestCase, 'validates_captcha/test_case'
42
36
  autoload :VERSION, 'validates_captcha/version'
43
37
 
44
- module ImageGenerator
45
- autoload :Simple, 'validates_captcha/image_generator/simple'
38
+ module Provider
39
+ autoload :Question, 'validates_captcha/provider/question'
40
+ autoload :Image, 'validates_captcha/provider/image'
46
41
  end
47
42
 
48
43
  module StringGenerator
@@ -53,117 +48,27 @@ module ValidatesCaptcha
53
48
  autoload :Simple, 'validates_captcha/reversible_encrypter/simple'
54
49
  end
55
50
 
56
- module Middleware
57
- autoload :Simple, 'validates_captcha/middleware/simple'
58
- end
51
+ module ImageGenerator
52
+ autoload :Simple, 'validates_captcha/image_generator/simple'
53
+ end
59
54
 
60
- @@image_generator = nil
61
- @@string_generator = nil
62
- @@reversible_encrypter = nil
63
- @@middleware = nil
55
+ @@provider = nil
64
56
 
65
57
  class << self
66
- # Returns ValidatesCaptcha's current version number.
58
+ # Returns Validates Captcha's current version number.
67
59
  def version
68
60
  ValidatesCaptcha::VERSION::STRING
69
61
  end
70
62
 
71
- # Returns the current captcha image generator. Defaults to an
72
- # instance of the ValidatesCaptcha::ImageGenerator::Simple class.
73
- def image_generator
74
- @@image_generator ||= ImageGenerator::Simple.new
75
- end
76
-
77
- # Sets the current captcha image generator. Used to set a custom
78
- # image generator.
79
- def image_generator=(generator)
80
- @@image_generator = generator
81
- end
82
-
83
- # Returns the current captcha string generator. Defaults to an
84
- # instance of the ValidatesCaptcha::StringGenerator::Simple class.
85
- def string_generator
86
- @@string_generator ||= StringGenerator::Simple.new
87
- end
88
-
89
- # Sets the current captcha string generator. Used to set a
90
- # custom string generator.
91
- def string_generator=(generator)
92
- @@string_generator = generator
93
- end
94
-
95
- # Returns the current captcha reversible encrypter. Defaults to an
96
- # instance of the ValidatesCaptcha::ReversibleEncrypter::Simple class.
97
- def reversible_encrypter
98
- @@reversible_encrypter ||= ReversibleEncrypter::Simple.new
99
- end
100
-
101
- # Sets the current captcha reversible encrypter. Used to set a
102
- # custom reversible encrypter.
103
- def reversible_encrypter=(encrypter)
104
- @@reversible_encrypter = encrypter
105
- end
106
-
107
- # Returns the current captcha middleware. Defaults to the
108
- # ValidatesCaptcha::Middleware::Simple class.
109
- def middleware
110
- @@middleware ||= Middleware::Simple.new
63
+ # Returns the current captcha challenge provider. Defaults to an instance of
64
+ # the ValidatesCaptcha::Provider::Question class.
65
+ def provider
66
+ @@provider ||= Provider::Question.new
111
67
  end
112
68
 
113
- # Sets the current captcha middleware. Used to set a custom
114
- # middleware.
115
- def middleware=(middleware)
116
- @@middleware = middleware
117
- end
118
-
119
- # Randomly generates a string which can be used as the code
120
- # displayed on captcha images. This method internally calls
121
- # +string_generator.generate+.
122
- def generate_captcha_code
123
- string_generator.generate
124
- end
125
-
126
- # Returns the image data of the generated captcha image. This
127
- # method internally calls +image_generator.generate+.
128
- def generate_captcha_image(code)
129
- image_generator.generate(code)
130
- end
131
-
132
- # Returns the image file extension of the captcha images. This
133
- # method internally calls +image_generator.image_file_extension+.
134
- def captcha_image_file_extension
135
- image_generator.image_file_extension
136
- end
137
-
138
- # Returns the image mime type of the captcha images. This
139
- # method internally calls +image_generator.image_mime_type+.
140
- def captcha_image_mime_type
141
- image_generator.image_mime_type
142
- end
143
-
144
- # Returns the encryption of a cleartext captcha code. This
145
- # method internally calls +reversible_encrypter.encrypt+.
146
- def encrypt_captcha_code(code)
147
- reversible_encrypter.encrypt(code)
148
- end
149
-
150
- # Returns the decryption of an encrypted captcha code. This
151
- # method internally calls +reversible_encrypter.decrypt+.
152
- def decrypt_captcha_code(encrypted_code)
153
- reversible_encrypter.decrypt(encrypted_code)
154
- end
155
-
156
- # Returns the captcha image path for a given encrypted code. This
157
- # method internally calls +middleware.image_path+.
158
- def captcha_image_path(encrypted_code)
159
- middleware.image_path(encrypted_code)
160
- end
161
-
162
- # Returns the path that is used when requesting the regeneration
163
- # of a captcha image. This method internally calls
164
- # +middleware.regenerate_path+.
165
- def regenerate_captcha_path
166
- middleware.regenerate_path
69
+ # Sets the current captcha challenge provider. Used to set a custom provider.
70
+ def provider=(provider)
71
+ @@provider = provider
167
72
  end
168
73
  end
169
74
  end
@@ -1,15 +1,15 @@
1
1
  module ValidatesCaptcha
2
2
  module FormBuilder #:nodoc:
3
- def captcha_image(options = {}) #:nodoc:
4
- @template.captcha_image @object_name, options.merge(:object => @object)
3
+ def captcha_challenge(options = {}) #:nodoc:
4
+ @template.captcha_challenge @object_name, options.merge(:object => @object)
5
5
  end
6
6
 
7
7
  def captcha_field(options = {}) #:nodoc:
8
8
  @template.captcha_field @object_name, options.merge(:object => @object)
9
9
  end
10
10
 
11
- def regenerate_captcha_link(options = {}, html_options = {}) #:nodoc:
12
- @template.regenerate_captcha_link @object_name, options.merge(:object => @object), html_options
11
+ def regenerate_captcha_challenge_link(options = {}, html_options = {}) #:nodoc:
12
+ @template.regenerate_captcha_challenge_link @object_name, options.merge(:object => @object), html_options
13
13
  end
14
14
  end
15
15
  end
@@ -1,50 +1,38 @@
1
1
  module ValidatesCaptcha
2
2
  module FormHelper
3
- # Returns an img tag with the src attribute pointing to the captcha image url.
3
+ # Returns the captcha challenge.
4
4
  #
5
- # Internally calls Rails' #image_tag helper method, passing the +options+
6
- # argument.
7
- def captcha_image(object_name, options = {})
5
+ # Internally calls the +render_challenge+ method of ValidatesCaptcha#provider.
6
+ def captcha_challenge(object_name, options = {})
7
+ options.symbolize_keys!
8
+
8
9
  object = options.delete(:object)
9
- src = ValidatesCaptcha.captcha_image_path(object.encrypted_captcha)
10
10
  sanitized_object_name = object_name.to_s.gsub(/\]\[|[^-a-zA-Z0-9:.]/, "_").sub(/_$/, "")
11
11
 
12
- options[:alt] ||= 'CAPTCHA'
13
- options[:id] = "#{sanitized_object_name}_captcha_image"
14
-
15
- image_tag src, options
12
+ ValidatesCaptcha.provider.render_challenge sanitized_object_name, object, options
16
13
  end
17
14
 
18
- # Returns an input tag of the "text" type tailored for entering the captcha code.
15
+ # Returns an input tag of the "text" type tailored for entering the captcha solution.
19
16
  #
20
17
  # Internally calls Rails' #text_field helper method, passing the +object_name+ and
21
18
  # +options+ arguments.
22
19
  def captcha_field(object_name, options = {})
23
20
  options.delete(:id)
24
21
 
25
- hidden_field(object_name, :encrypted_captcha, options) + text_field(object_name, :captcha, options)
22
+ hidden_field(object_name, :captcha_challenge, options) + text_field(object_name, :captcha_solution, options)
26
23
  end
27
24
 
28
- # Returns an anchor tag that makes an AJAX request to fetch a new captcha code and updates
29
- # the captcha image after the request is complete.
25
+ # By default, returns an anchor tag that makes an AJAX request to fetch a new captcha challenge and updates
26
+ # the current challenge after the request is complete.
30
27
  #
31
- # Internally calls Rails' #link_to_remote helper method, passing the +options+ and
32
- # +html_options+ arguments. So it relies on the Prototype javascript framework
33
- # to be available on the web page.
34
- #
35
- # The anchor text defaults to 'Regenerate Captcha'. You can set this to a custom value
36
- # providing a +:text+ key in the +options+ hash.
37
- def regenerate_captcha_link(object_name, options = {}, html_options = {})
28
+ # Internally calls +render_regenerate_challenge_link+ method of ValidatesCaptcha#provider.
29
+ def regenerate_captcha_challenge_link(object_name, options = {}, html_options = {})
38
30
  options.symbolize_keys!
39
31
 
40
32
  object = options.delete(:object)
41
- text = options.delete(:text) || 'Regenerate Captcha'
42
33
  sanitized_object_name = object_name.to_s.gsub(/\]\[|[^-a-zA-Z0-9:.]/, "_").sub(/_$/, "")
43
34
 
44
- url = ValidatesCaptcha.regenerate_captcha_path
45
- success = "var result = request.responseJSON; $('#{sanitized_object_name}_captcha_image').src = result.captcha_image_path; $('#{sanitized_object_name}_encrypted_captcha').value = result.encrypted_captcha_code;"
46
-
47
- link_to_remote text, options.reverse_merge(:url => url, :method => :get, :success => success), html_options
35
+ ValidatesCaptcha.provider.render_regenerate_challenge_link sanitized_object_name, object, options, html_options
48
36
  end
49
37
  end
50
38
  end