Class: ValidatesCaptcha::Provider::DynamicImage

Inherits:
Object
  • Object
show all
Includes:
ActionView::Helpers
Defined in:
lib/validates_captcha/provider/dynamic_image.rb

Overview

An image captcha provider.

This class contains the getters and setters for the backend classes: image generator, string generator, and symmetric encryptor. This allows you to replace them with your custom implementations. For more information on how to bring the image provider to use your own implementation instead of the default one, consult the documentation for the specific default class.

The default captcha image generator uses ImageMagick’s convert command to create the captcha. So a recent and properly configured version of ImageMagick must be installed on the system. The version used while developing was 6.4.5. But you are not bound to ImageMagick. If you want to provide a custom image generator, take a look at the documentation for ValidatesCaptcha::ImageGenerator::Simple on how to create your own.

Constant Summary collapse

@@string_generator =
nil
@@symmetric_encryptor =
nil
@@image_generator =
nil

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.image_generatorObject

Returns the current captcha image generator. Defaults to an instance of the ValidatesCaptcha::ImageGenerator::Simple class.



112
113
114
# File 'lib/validates_captcha/provider/dynamic_image.rb', line 112

def image_generator
  @@image_generator ||= ValidatesCaptcha::ImageGenerator::Simple.new
end

.image_generator=(generator) ⇒ Object

Sets the current captcha image generator. Used to set a custom image generator.



118
119
120
# File 'lib/validates_captcha/provider/dynamic_image.rb', line 118

def image_generator=(generator)
  @@image_generator = generator
end

.string_generatorObject

Returns the current captcha string generator. Defaults to an instance of the ValidatesCaptcha::StringGenerator::Simple class.



88
89
90
# File 'lib/validates_captcha/provider/dynamic_image.rb', line 88

def string_generator
  @@string_generator ||= ValidatesCaptcha::StringGenerator::Simple.new
end

.string_generator=(generator) ⇒ Object

Sets the current captcha string generator. Used to set a custom string generator.



94
95
96
# File 'lib/validates_captcha/provider/dynamic_image.rb', line 94

def string_generator=(generator)
  @@string_generator = generator
end

.symmetric_encryptorObject

Returns the current captcha symmetric encryptor. Defaults to an instance of the ValidatesCaptcha::SymmetricEncryptor::Simple class.



100
101
102
# File 'lib/validates_captcha/provider/dynamic_image.rb', line 100

def symmetric_encryptor
  @@symmetric_encryptor ||= ValidatesCaptcha::SymmetricEncryptor::Simple.new
end

.symmetric_encryptor=(encryptor) ⇒ Object

Sets the current captcha symmetric encryptor. Used to set a custom symmetric encryptor.



106
107
108
# File 'lib/validates_captcha/provider/dynamic_image.rb', line 106

def symmetric_encryptor=(encryptor)
  @@symmetric_encryptor = encryptor
end

Instance Method Details

#call(env) ⇒ Object

This method is the one called by Rack.

It returns HTTP status 404 if the path is not recognized. If the path is recognized, it returns HTTP status 200 and delivers the image if it could successfully decrypt the captcha code, otherwise HTTP status 422.

Please take a look at the source code if you want to learn more.



130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
# File 'lib/validates_captcha/provider/dynamic_image.rb', line 130

def call(env)
  if env['PATH_INFO'] =~ /^\/captchas\/([^\.]+)/
    if $1 == 'regenerate'
      captcha_challenge = generate_challenge
      json = { :captcha_challenge => captcha_challenge, :captcha_image_path => image_path(captcha_challenge) }.to_json

      [200, { 'Content-Type' => 'application/json' }, [json]]
    else
      decrypted_code = decrypt($1)

      if decrypted_code.nil?
        [422, { 'Content-Type' => 'text/html' }, ['Unprocessable Entity']]
      else
        image_data = generate_image(decrypted_code)

        response_headers = {
          'Content-Length'            => image_data.bytesize.to_s,
          'Content-Type'              => image_mime_type,
          'Content-Disposition'       => 'inline',
          'Content-Transfer-Encoding' => 'binary',
          'Cache-Control'             => 'private'
        }

        [200, response_headers, [image_data]]
      end
    end
  else
    [404, { 'Content-Type' => 'text/html' }, ['Not Found']]
  end
end

#generate_challengeObject

Returns a captcha challenge.



162
163
164
# File 'lib/validates_captcha/provider/dynamic_image.rb', line 162

def generate_challenge
  encrypt(generate_code)
end

#render_challenge(sanitized_object_name, object, options = {}) ⇒ Object

Returns an image tag with the source set to the url of the captcha image.

Internally calls Rails’ image_tag helper method, passing the options argument.



175
176
177
178
179
180
181
182
# File 'lib/validates_captcha/provider/dynamic_image.rb', line 175

def render_challenge(sanitized_object_name, object, options = {})
  src = image_path(object.captcha_challenge)

  options[:alt] ||= 'CAPTCHA'
  options[:id] = "#{sanitized_object_name}_captcha_image"

  image_tag src, options
end

Returns an anchor tag that makes an AJAX request to fetch a new captcha code and updates the captcha image after the request is complete.

Internally calls Rails’ link_to_remote helper method, passing the options and html_options arguments. So it relies on the Prototype javascript framework to be available on the web page. As of version 0.9.8 you can pass :jquery => true as an option to render Javascript that’s based on jQuery.

The anchor text defaults to ‘Regenerate Captcha’. You can set this to a custom value providing a :text key in the options hash.



194
195
196
197
198
199
200
201
202
203
# File 'lib/validates_captcha/provider/dynamic_image.rb', line 194

def render_regenerate_challenge_link(sanitized_object_name, object, options = {}, html_options = {})
  text = options.delete(:text) || 'Regenerate Captcha'
  if options.delete(:jquery)
    onclick = "jQuery.getJSON('#{regenerate_path}', function(result){jQuery('##{sanitized_object_name}_captcha_image').attr('src',result.captcha_image_path); jQuery('##{sanitized_object_name}_captcha_challenge').val(result.captcha_challenge); jQuery('##{sanitized_object_name}_captcha_solution').val('');});return false;"
    link_to text, "#", options.reverse_merge(:onclick => onclick), html_options
  else
    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 = '';"
    link_to_remote text, options.reverse_merge(:url => regenerate_path, :method => :get, :success => success), html_options
  end
end

#solved?(challenge, solution) ⇒ Boolean

Returns true if the captcha was solved using the given challenge and solution, otherwise false.

Returns:

  • (Boolean)


168
169
170
# File 'lib/validates_captcha/provider/dynamic_image.rb', line 168

def solved?(challenge, solution)
  decrypt(challenge) == solution
end