custom_captcha 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. data/.gitignore +4 -0
  2. data/.rspec +1 -0
  3. data/CHANGELOG +4 -0
  4. data/Gemfile +4 -0
  5. data/Guardfile +22 -0
  6. data/README.markdown +107 -0
  7. data/Rakefile +2 -0
  8. data/app/controllers/custom_captcha/captcha_images_controller.rb +28 -0
  9. data/app/views/custom_captcha/captcha_images/change.html.erb +2 -0
  10. data/app/views/custom_captcha/captcha_images/change.js.erb +3 -0
  11. data/app/views/custom_captcha/captcha_images/show.html.erb +2 -0
  12. data/app/views/custom_captcha/captcha_styles/_default.html.erb +10 -0
  13. data/config/locales/custom_captcha.en.yml +6 -0
  14. data/config/routes.rb +9 -0
  15. data/custom_captcha.gemspec +31 -0
  16. data/lib/custom_captcha.rb +39 -0
  17. data/lib/custom_captcha/action_controller_extension.rb +42 -0
  18. data/lib/custom_captcha/action_view_extension.rb +56 -0
  19. data/lib/custom_captcha/active_record_extension.rb +51 -0
  20. data/lib/custom_captcha/common_methods.rb +13 -0
  21. data/lib/custom_captcha/configuration.rb +107 -0
  22. data/lib/custom_captcha/engine.rb +5 -0
  23. data/lib/custom_captcha/errors.rb +5 -0
  24. data/lib/custom_captcha/image.rb +86 -0
  25. data/lib/custom_captcha/railtie.rb +25 -0
  26. data/lib/custom_captcha/utils.rb +94 -0
  27. data/lib/custom_captcha/version.rb +4 -0
  28. data/lib/generators/custom_captcha/install/USAGE +8 -0
  29. data/lib/generators/custom_captcha/install/install_generator.rb +49 -0
  30. data/lib/generators/custom_captcha/install/templates/README +18 -0
  31. data/lib/generators/custom_captcha/uninstall/USAGE +8 -0
  32. data/lib/generators/custom_captcha/uninstall/templates/README +2 -0
  33. data/lib/generators/custom_captcha/uninstall/uninstall_generator.rb +38 -0
  34. data/lib/generators/custom_captcha/utils.rb +12 -0
  35. data/lib/tasks/.gitkeep +0 -0
  36. data/lib/tasks/custom_captcha_utils.rake +26 -0
  37. data/spec/configuration_spec.rb +19 -0
  38. data/spec/image_spec.rb +10 -0
  39. data/spec/spec_helper.rb +6 -0
  40. metadata +165 -0
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --colour
@@ -0,0 +1,4 @@
1
+ == 0.1.0
2
+
3
+ * First release
4
+
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ gemspec
4
+
@@ -0,0 +1,22 @@
1
+ # A sample Guardfile
2
+ # More info at https://github.com/guard/guard#readme
3
+
4
+ guard 'rspec', :version => 2 do
5
+ watch(%r{^spec/.+_spec\.rb$})
6
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
7
+ watch('spec/spec_helper.rb') { "spec" }
8
+
9
+ # Rails example
10
+ watch(%r{^spec/.+_spec\.rb$})
11
+ watch(%r{^app/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
12
+ watch(%r{^app/(.*)(\.erb|\.haml)$}) { |m| "spec/#{m[1]}#{m[2]}_spec.rb" }
13
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
14
+ watch(%r{^app/controllers/(.+)_(controller)\.rb$}) { |m| ["spec/routing/#{m[1]}_routing_spec.rb", "spec/#{m[2]}s/#{m[1]}_#{m[2]}_spec.rb", "spec/acceptance/#{m[1]}_spec.rb"] }
15
+ watch(%r{^spec/support/(.+)\.rb$}) { "spec" }
16
+ watch('spec/spec_helper.rb') { "spec" }
17
+ watch('config/routes.rb') { "spec/routing" }
18
+ watch('app/controllers/application_controller.rb') { "spec/controllers" }
19
+ # Capybara request specs
20
+ watch(%r{^app/views/(.+)/.*\.(erb|haml)$}) { |m| "spec/requests/#{m[1]}_spec.rb" }
21
+ end
22
+
@@ -0,0 +1,107 @@
1
+ == CustomCaptcha
2
+
3
+ CustomCaptcha is a simple and custom captcha plugin for Rails3.
4
+
5
+
6
+ == Supported versions
7
+
8
+ * Ruby 1.8.7, 1.9.2, 1.9.3
9
+
10
+ * Rails 3.0.x, 3.1
11
+
12
+ * ImageMagick should be installed on your machine to use this plugin.
13
+
14
+
15
+ == Installation
16
+
17
+ In your app's `Gemfile`, add:
18
+
19
+ gem "custom_captcha", :git => "git://github.com/vkill/custom_captcha.git"
20
+
21
+ Then run:
22
+
23
+ bundle
24
+ rails generate custom_captcha:install
25
+
26
+ If you want to modify default captcha images storage location, edit your `config/initializers/custom_captcha.rb`
27
+
28
+ Then run:
29
+
30
+ bundle exec rake custom_captcha:generate_images[100]
31
+
32
+
33
+ == Base Usage
34
+
35
+ === View helper
36
+
37
+ In the view file within the form tags add this code
38
+
39
+ <%= display_custom_captcha %>
40
+
41
+ and in the controller's action authenticate it as
42
+
43
+ if custom_captcha_valid?(params[:custom_captcha])
44
+ flash[:notice] = "captcha did match."
45
+ else
46
+ flash[:notice] = "captcha did not match."
47
+ end
48
+
49
+ === FormBuilder helper
50
+
51
+ In the model class add this code
52
+
53
+ class User < ActiveRecord::Basse
54
+ apply_custom_captcha
55
+ end
56
+
57
+ and in the view file within the form tags write this code
58
+
59
+ <%= form_for @user do |form| -%>
60
+ ...
61
+ <%= form.custom_captcha %>
62
+ ...
63
+ <% end -%>
64
+
65
+
66
+ == Usage your custom captcha area template
67
+
68
+ first, copy and modify your custom captcha area template
69
+
70
+ cd app/views/custom_captcha/captcha_styles/
71
+ cp _default.html.erb _mycaptcha.html.erb
72
+
73
+ and then in the view file your the use of
74
+
75
+ <%= display_custom_captcha(:template => :mycaptcha) %>
76
+
77
+
78
+ == Options & Examples
79
+
80
+ === Helper Options, View helper and FormBuilder helper
81
+
82
+ * *template* - use your custom template
83
+
84
+ * *label_text* - custom label text
85
+
86
+ * *key_id* - custom captcha hidden input key id
87
+
88
+ * *key_name* - custom captcha hidden input key name
89
+
90
+ * *field_name* - custom captcha input field name
91
+
92
+ * *img_id* - custom captcha img id
93
+
94
+ * *change_text* - custom change text
95
+
96
+ === Examples
97
+
98
+ <%= display_custom_captcha(:img_id => :captcha, :label_text => "captcha", :field_name => :captcha %>
99
+
100
+
101
+ == I18n supported
102
+
103
+
104
+ == Copyright
105
+
106
+ Copyright (c) 2011 vkill.net .
107
+
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
@@ -0,0 +1,28 @@
1
+ class CustomCaptcha::CaptchaImagesController < ApplicationController
2
+
3
+ respond_to :html, :js, :json
4
+
5
+ def show
6
+ @image_file_path = read_image_file_path(params[:key])
7
+ respond_to do |format|
8
+ format.html {
9
+ send_file(@image_file_path, :type => 'image/jpeg', :disposition => 'inline', :filename => 'custom_captcha.jpg')
10
+ }
11
+ format.json { render :json => {:image_file_path => @image_file_path} }
12
+ end
13
+ end
14
+
15
+ def change
16
+ @img_id = params[:img_id] || CustomCaptcha::DEFAULTVALUE[:img_id]
17
+ @key_id = params[:key_id] || CustomCaptcha::DEFAULTVALUE[:key_id]
18
+ @key = choice_image_file_path_and_write_session_cache()
19
+ @img_src = show_captcha_image_path(@key)
20
+
21
+ respond_to do |format|
22
+ format.js
23
+ format.json { render :json => {@img_id => @img_src, @key_id => @key} }
24
+ end
25
+ end
26
+
27
+ end
28
+
@@ -0,0 +1,2 @@
1
+ if you see this message, please mail to administrator!
2
+
@@ -0,0 +1,3 @@
1
+ $("img#<%= @img_id %>").attr("src", "<%= @img_src %>")
2
+ $("input#<%= @key_id %>").attr("value", "<%= @key %>")
3
+
@@ -0,0 +1,2 @@
1
+ if you see this message, please mail to administrator!
2
+
@@ -0,0 +1,10 @@
1
+ <br/>
2
+
3
+ <%= label_tag captcha[:label_text] %>
4
+ <%= text_field_tag captcha[:field_name] %>
5
+ <%= hidden_field_tag captcha[:key_name], captcha[:key], :id => captcha[:key_id] %>
6
+ <%= image_tag captcha[:img_src], :id => captcha[:img_id], :alt => captcha[:label_text] %>
7
+ <%= link_to captcha[:change_text], captcha[:change_url], :remote => true %>
8
+
9
+ <br/>
10
+
@@ -0,0 +1,6 @@
1
+ en:
2
+ custom_captcha:
3
+ label: "captcha"
4
+ change: "changing a picture"
5
+ message: "Secret Code did not match with the Image"
6
+
@@ -0,0 +1,9 @@
1
+ Rails.application.routes.draw do
2
+ match "captcha_images/change" => "custom_captcha/captcha_images#change",
3
+ :as => :change_captcha_images
4
+
5
+ match "captcha_images/:key" => "custom_captcha/captcha_images#show",
6
+ :as => :show_captcha_image,
7
+ :constraints => { :key => /[A-Za-z0-9]{32,40}/ }
8
+ end
9
+
@@ -0,0 +1,31 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "custom_captcha/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "custom_captcha"
7
+ s.version = CustomCaptcha::VERSION
8
+ s.date = Date.today
9
+ s.authors = ["vkill"]
10
+ s.email = ["vkill.net@gmail.com"]
11
+ s.homepage = "https://github.com/vkill/custom_captcha"
12
+ s.summary = "A simple and custom captcha for Rails3."
13
+ s.description = "A simple and custom captcha for Rails3."
14
+
15
+ s.rubyforge_project = "custom_captcha"
16
+
17
+ s.files = `git ls-files`.split("\n")
18
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
+ s.require_paths = ["lib"]
21
+
22
+ s.add_development_dependency 'bundler'
23
+ s.add_development_dependency "rake"
24
+ s.add_development_dependency "rspec"
25
+ s.add_development_dependency "guard-rspec"
26
+ s.add_dependency "rails", "~> 3.0"
27
+ s.add_dependency "rmagick", "~> 2.13.1"
28
+ s.add_dependency 'jquery-rails', "~> 1.0.16"
29
+
30
+ end
31
+
@@ -0,0 +1,39 @@
1
+ require "active_support/concern"
2
+ require "active_support/core_ext/object"
3
+ require "active_support/core_ext/class/attribute_accessors"
4
+ require "active_support/core_ext/module/attribute_accessors"
5
+ require "securerandom"
6
+ require "RMagick"
7
+ include Magick
8
+ require "tmpdir"
9
+ require "fileutils"
10
+ require "digest/md5"
11
+ require "find"
12
+
13
+ require 'custom_captcha/errors'
14
+ require 'custom_captcha/version'
15
+ require 'custom_captcha/configuration'
16
+ require 'custom_captcha/utils'
17
+ require 'custom_captcha/image'
18
+
19
+ require "rails"
20
+ require "custom_captcha/engine"
21
+ require "custom_captcha/railtie"
22
+
23
+ module CustomCaptcha
24
+ DEFAULTVALUE = {
25
+ :field_name => :custom_captcha,
26
+ :key_name => :custom_captcha_key,
27
+ :key_id => :custom_captcha_key,
28
+ :img_id => :custom_captcha_img,
29
+ :template => 'default'
30
+ }
31
+ class << self
32
+ def configure(&block)
33
+ CustomCaptcha::Configuration.configure(&block)
34
+ end
35
+ end
36
+ # init configuration
37
+ CustomCaptcha::Configuration.init_config()
38
+ end
39
+
@@ -0,0 +1,42 @@
1
+ module CustomCaptcha
2
+ module ActionControllerExtension
3
+ extend ActiveSupport::Concern
4
+ included do
5
+ include CustomCaptcha::CommonMethods
6
+ helper_method :choice_image_file_path_and_write_session_cache,
7
+ :read_captcha_digested, :read_image_file_path
8
+ end
9
+ module ClassMethods
10
+ end
11
+ module InstanceMethods
12
+ def custom_captcha_valid?(captcha_value=nil)
13
+ if CustomCaptcha::Configuration.disable? or Rails.env.test?
14
+ return true
15
+ end
16
+ captcha_value ||= params[CustomCaptcha::DEFAULTVALUE[:field_name]]
17
+ if captcha_value
18
+ CustomCaptcha::Utils.captcha_value_valid?(captcha_value, read_captcha_digested())
19
+ else
20
+ return false
21
+ end
22
+ end
23
+
24
+ def choice_image_file_path_and_write_session_cache
25
+ image_file_path, captcha_digested, key =
26
+ CustomCaptcha::Utils.choice_image_file_path_and_generate_captcha_digested_key
27
+ session[:captcha_digested] = captcha_digested
28
+ Rails.cache.write(key, [image_file_path, captcha_digested])
29
+ key
30
+ end
31
+
32
+ def read_captcha_digested
33
+ session[:captcha_digested]
34
+ end
35
+
36
+ def read_image_file_path(key)
37
+ Rails.cache.read(key)[0] rescue nil
38
+ end
39
+ end
40
+ end
41
+ end
42
+
@@ -0,0 +1,56 @@
1
+ module CustomCaptcha
2
+ module ActionViewExtension
3
+ module Base
4
+ extend ActiveSupport::Concern
5
+ included do
6
+ include CustomCaptcha::CommonMethods
7
+ end
8
+ module ClassMethods
9
+ end
10
+ module InstanceMethods
11
+ def display_custom_captcha(options={})
12
+ return "" if CustomCaptcha::Configuration.disable?
13
+ options[:key] = choice_image_file_path_and_write_session_cache
14
+
15
+ options[:field_name] ||= CustomCaptcha::DEFAULTVALUE[:field_name]
16
+ options[:key_name] ||= CustomCaptcha::DEFAULTVALUE[:key_name]
17
+ options[:key_id] ||= CustomCaptcha::DEFAULTVALUE[:key_id]
18
+ options[:img_id] ||= CustomCaptcha::DEFAULTVALUE[:img_id]
19
+
20
+ options[:img_src] = show_captcha_image_path(options[:key])
21
+ options[:template] ||= CustomCaptcha::DEFAULTVALUE[:template]
22
+ options[:label_text] ||= I18n.t('custom_captcha.label')
23
+ options[:change_text] ||= I18n.t('custom_captcha.change')
24
+ options[:change_url] = change_captcha_images_path(:img_id => options[:img_id], :key_id => options[:key_id])
25
+ render "custom_captcha/captcha_styles/#{options[:template].to_s}", :captcha => options
26
+ end
27
+ end
28
+ end
29
+
30
+ module Helpers
31
+ module FormBuilder
32
+ extend ActiveSupport::Concern
33
+ included do
34
+ include CustomCaptcha::CommonMethods
35
+ end
36
+ module ClassMethods
37
+ end
38
+ module InstanceMethods
39
+ def custom_captcha(options={})
40
+ return "" unless (@object.custom_captcha_key rescue nil)
41
+ options[:object_name] = @object_name.to_s
42
+ options[:key] = @object.custom_captcha_key
43
+
44
+ options[:field_name] = object_field_name options[:object_name], CustomCaptcha::DEFAULTVALUE[:field_name]
45
+ options[:key_name] = object_field_name options[:object_name], CustomCaptcha::DEFAULTVALUE[:key_name]
46
+ options[:key_id] = object_field_id options[:object_name], CustomCaptcha::DEFAULTVALUE[:key_id]
47
+ options[:img_id] = object_field_id options[:object_name], CustomCaptcha::DEFAULTVALUE[:img_id]
48
+
49
+ @template.display_custom_captcha(options)
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
56
+
@@ -0,0 +1,51 @@
1
+ module CustomCaptcha
2
+ module ActiveRecordExtension
3
+ extend ActiveSupport::Concern
4
+ included do
5
+ include CustomCaptcha::CommonMethods
6
+ extend ClassMethods
7
+ end
8
+ module ClassMethods
9
+ def apply_custom_captcha
10
+ attr_accessor :custom_captcha, :custom_captcha_key
11
+
12
+ after_initialize do
13
+ after_initialize if custom_captcha_need_valid?
14
+ end
15
+
16
+ validate :valid_custom_captcha, :if => :custom_captcha_need_valid?
17
+
18
+ include CustomCaptcha::ActiveRecordExtension::InstanceMethods
19
+ end
20
+ end
21
+ module InstanceMethods
22
+ def after_initialize
23
+ self.custom_captcha_key ||= choice_image_file_path_and_write_cache
24
+ end
25
+
26
+ def valid_custom_captcha
27
+ unless CustomCaptcha::Utils.captcha_value_valid?(custom_captcha, read_captcha_digested())
28
+ errors.add(:custom_captcha, I18n.t('custom_captcha.message'))
29
+ end
30
+ end
31
+
32
+ def custom_captcha_need_valid?
33
+ !CustomCaptcha::Configuration.disable? and !Rails.env.test?
34
+ end
35
+
36
+ private
37
+ def choice_image_file_path_and_write_cache
38
+ image_file_path, captcha_digested, key =
39
+ CustomCaptcha::Utils.choice_image_file_path_and_generate_captcha_digested_key
40
+ Rails.cache.write(key, [image_file_path, captcha_digested])
41
+ key
42
+ end
43
+
44
+ def read_captcha_digested
45
+ Rails.cache.read(self.custom_captcha_key)[1] rescue ""
46
+ end
47
+
48
+ end
49
+ end
50
+ end
51
+
@@ -0,0 +1,13 @@
1
+ module CustomCaptcha
2
+ module CommonMethods
3
+ private
4
+ def object_field_name(object_name, field_name)
5
+ object_name.to_s + "[" + field_name.to_s + "]"
6
+ end
7
+
8
+ def object_field_id(object_name, field_name)
9
+ object_name.to_s + "_" + field_name.to_s
10
+ end
11
+ end
12
+ end
13
+
@@ -0,0 +1,107 @@
1
+ module CustomCaptcha
2
+ module Configuration
3
+
4
+ mattr_accessor :image_columns,
5
+ :image_rows,
6
+ :image_style,
7
+ :text_range,
8
+ :text_length,
9
+ :images_path,
10
+ :enable,
11
+ :salt
12
+ mattr_reader :images_path_definite
13
+
14
+ class << self
15
+
16
+ def configure
17
+ yield self
18
+ # make inage files path and defined @@images_path_definite
19
+ make_and_define_images_path()
20
+ # reload all image files key
21
+ CustomCaptcha::Utils.reload_image_files_paths()
22
+ end
23
+
24
+ def reset_config
25
+ configure do |config|
26
+ config.image_columns = default_image_columns()
27
+ config.image_rows = default_image_rows()
28
+ config.image_style = CustomCaptcha::Image.image_style.keys.first
29
+ config.text_range = default_text_range()
30
+ config.text_length = default_text_length()
31
+ config.images_path = default_images_path()
32
+ config.enable = true
33
+ config.salt = SecureRandom.hex(10)
34
+ end
35
+ make_and_define_images_path()
36
+ end
37
+ alias_method :init_config, :reset_config
38
+
39
+ def disable?
40
+ !@@enable
41
+ end
42
+
43
+ #image columns setting
44
+ def default_image_columns
45
+ 120
46
+ end
47
+ def image_columns
48
+ image_columns = @@image_columns.to_i.blank? ? default_image_columns() : @@image_columns
49
+ end
50
+
51
+ #image rows setting
52
+ def default_image_rows
53
+ 40
54
+ end
55
+ def image_rows
56
+ image_rows = @@image_rows.to_i.blank? ? default_image_rows() : @@image_rows
57
+ end
58
+
59
+ #image style setting
60
+ def default_image_style
61
+
62
+ end
63
+
64
+ #image text range setting
65
+ def default_text_range
66
+ ('a'..'z').to_a + (0..9).to_a
67
+ end
68
+ def text_range
69
+ text_range = @@text_range.to_a.blank? ? default_text_range() : @@text_range
70
+ end
71
+
72
+ #image text length setting
73
+ def default_text_length
74
+ 5
75
+ end
76
+ def text_length
77
+ text_length = @@text_length.to_i.blank? ? default_text_length() : @@text_length
78
+ if 4 < text_length or text_length < 10
79
+ text_length
80
+ else
81
+ default_text_length()
82
+ end
83
+ end
84
+
85
+ #images path setting
86
+ def default_images_path
87
+ File.join(Dir::tmpdir, 'captcha_images')
88
+ end
89
+ def images_path
90
+ images_path = @@images_path.to_s.blank? ? default_images_path() : @@images_path
91
+ end
92
+
93
+ #images path make and define
94
+ def make_and_define_images_path
95
+ images_path = images_path()
96
+ begin
97
+ FileUtils.mkdir_p images_path
98
+ rescue
99
+ raise CustomCaptcha::MakeImagePathError
100
+ else
101
+ @@images_path_definite = images_path
102
+ end
103
+ end
104
+ end
105
+ end
106
+ end
107
+
@@ -0,0 +1,5 @@
1
+ module CustomCaptcha
2
+ class Engine < ::Rails::Engine
3
+ end
4
+ end
5
+
@@ -0,0 +1,5 @@
1
+ module CustomCaptcha
2
+ class MakeImagePathError < StandardError; end
3
+ class InitImageFilesKeyError < StandardError; end
4
+ end
5
+
@@ -0,0 +1,86 @@
1
+ module CustomCaptcha
2
+ module Image
3
+ mattr_reader :image_style
4
+ @@image_style = {
5
+ :simply_blue => {:background_color => :white, :text_fill => :darkblue, :text_font_family => :helvetica}
6
+ }
7
+ #image text length and image text font_size proportion
8
+ @@font_size = {
9
+ 4 => 46,
10
+ 5 => 41,
11
+ 6 => 36,
12
+ 7 => 31,
13
+ 8 => 26,
14
+ 9 => 21,
15
+ 10 => 16
16
+ }
17
+
18
+ class << self
19
+ def create(number=1, &block)
20
+ image_style_simply_blue = @@image_style[:simply_blue]
21
+ image_style = @@image_style[CustomCaptcha::Configuration.image_style] || image_style_simply_blue
22
+ options = {}
23
+ options[:background_color] = image_style[:background_color] || image_style_simply_blue[:background_color]
24
+ options[:text_fill] = image_style[:text_fill] || image_style_simply_blue[:text_fill]
25
+ options[:text_font_family] = image_style[:text_font_family] || image_style_simply_blue[:text_font_family]
26
+ image_files = create_image_files(number, options, &block)
27
+ end
28
+ end
29
+
30
+ private
31
+ class << self
32
+ def generate_image_text
33
+ text_range = CustomCaptcha::Configuration.text_range
34
+ text_length = CustomCaptcha::Configuration.text_length
35
+ text_range.to_a.sort_by!{rand()}.take(text_length).join()
36
+ end
37
+
38
+ def generate_image_file_path(text)
39
+ File.join(
40
+ CustomCaptcha::Utils.image_file_dirname(),
41
+ [
42
+ CustomCaptcha::Utils.image_file_basename(text),
43
+ CustomCaptcha::Utils.image_file_extname()
44
+ ].join()
45
+ )
46
+ end
47
+
48
+ def create_image_files(number, options={}, &block)
49
+ columns = CustomCaptcha::Configuration.image_columns
50
+ rows = CustomCaptcha::Configuration.image_rows
51
+
52
+ image_files = []
53
+ number.to_i.times do |n|
54
+ canvas = Magick::ImageList.new
55
+ canvas.new_image(columns, rows) {
56
+ self.background_color = options[:background_color].to_s
57
+ }
58
+ text = Magick::Draw.new
59
+ text.font_family = options[:text_font_family].to_s
60
+ text.fill = options[:text_fill].to_s
61
+ text.gravity = Magick::CenterGravity
62
+
63
+ image_text = generate_image_text()
64
+ text.annotate(canvas, 0,0,0,0, image_text) {
65
+ self.pointsize = @@font_size[image_text.length]
66
+ }
67
+ image_file = generate_image_file_path(image_text)
68
+ begin
69
+ canvas.write(image_file)
70
+ rescue
71
+ yield(number, n+1, "failed", image_file) if block
72
+ next
73
+ else
74
+ yield(number, n+1, "succeed", image_file) if block
75
+ image_files << image_file
76
+ ensure
77
+ canvas.clear
78
+ end
79
+ end
80
+ image_files
81
+ end
82
+
83
+ end
84
+ end
85
+ end
86
+
@@ -0,0 +1,25 @@
1
+ require 'custom_captcha/common_methods'
2
+ require 'custom_captcha/action_controller_extension'
3
+ require 'custom_captcha/action_view_extension'
4
+ require 'custom_captcha/active_record_extension'
5
+
6
+ module CustomCaptcha
7
+ class Railtie < ::Rails::Railtie
8
+ initializer 'custom_captcha' do |app|
9
+ ActiveSupport.on_load :action_controller do
10
+ ActionController::Base.send :include, CustomCaptcha::ActionControllerExtension
11
+ end
12
+
13
+ ActiveSupport.on_load :action_view do
14
+ ActionView::Base.send :include, CustomCaptcha::ActionViewExtension::Base
15
+ ActionView::Helpers::FormBuilder.send :include,
16
+ CustomCaptcha::ActionViewExtension::Helpers::FormBuilder
17
+ end
18
+
19
+ ActiveSupport.on_load :active_record do
20
+ include CustomCaptcha::ActiveRecordExtension
21
+ end
22
+ end
23
+ end
24
+ end
25
+
@@ -0,0 +1,94 @@
1
+ module CustomCaptcha
2
+ module Utils
3
+
4
+ mattr_reader :image_files_paths, :image_files_paths_choice_size
5
+ @@image_files_paths = []
6
+ @@image_files_paths_choice_size = @@image_files_paths.size
7
+
8
+ class << self
9
+
10
+ def generate_image_files(number=1, &block)
11
+ CustomCaptcha::Image.create(number, &block)
12
+ end
13
+
14
+ def clear_image_files
15
+ FileUtils.rm_r Dir[File.join(image_file_dirname(), "**", "*")]
16
+ end
17
+
18
+ def reload_image_files_paths
19
+ @@image_files_paths.clear
20
+ reset_image_files_paths()
21
+ end
22
+ alias_method :init_image_files_paths, :reload_image_files_paths
23
+
24
+
25
+ def choice_image_file_path_and_generate_captcha_digested_key
26
+ image_file_path = random_choice_image_file_path
27
+ captcha_digested = get_captcha_digested(image_file_path)
28
+ key = hexdigest_text([Time.now.to_i, SecureRandom.hex(10)].join())
29
+ [image_file_path, captcha_digested, key]
30
+ end
31
+
32
+ def captcha_value_valid?(captcha_value, captcha_digested)
33
+ image_file_basename_suffix(captcha_value) == captcha_digested
34
+ end
35
+
36
+ end
37
+
38
+ private
39
+ class << self
40
+ def hexdigest_text(text)
41
+ Digest::MD5.hexdigest([text.to_s.downcase, CustomCaptcha::Configuration.salt].join())
42
+ end
43
+
44
+ def image_file_dirname
45
+ CustomCaptcha::Configuration.images_path_definite
46
+ end
47
+
48
+ def image_file_basename_prefix
49
+ # ("a".."z").to_a.sort_by!{rand()}.take(8).join()
50
+ SecureRandom.hex(4)
51
+ end
52
+
53
+ def image_file_basename_suffix(text)
54
+ hexdigest_text(text)
55
+ end
56
+
57
+ def image_file_basename(text)
58
+ [image_file_basename_prefix, image_file_basename_suffix(text)].join()
59
+ end
60
+
61
+ def image_file_extname
62
+ ".gif"
63
+ end
64
+
65
+ # if image file path empty, then auto generating 3 image file.
66
+ def reset_image_files_paths
67
+ if @@image_files_paths.blank? or @@image_files_paths_choice_size == 0
68
+ n = 0
69
+ while true
70
+ @@image_files_paths = Dir[File.join(image_file_dirname(), ["[a-z0-9]*", image_file_extname()].join())]
71
+ break unless self.image_files_paths.blank?
72
+ generate_image_files(3)
73
+ raise InitImageFilesKeyError if n >= 3
74
+ n += 1
75
+ end
76
+ @@image_files_paths.sort_by!{rand()}
77
+ @@image_files_paths_choice_size = @@image_files_paths.size
78
+ end
79
+ end
80
+
81
+ def random_choice_image_file_path
82
+ reset_image_files_paths()
83
+ @@image_files_paths_choice_size -= 1
84
+ @@image_files_paths[@@image_files_paths_choice_size]
85
+ end
86
+
87
+ def get_captcha_digested(image_file_path)
88
+ image_file_basename = File.basename(image_file_path, image_file_extname())
89
+ image_file_basename[-32..-1]
90
+ end
91
+ end
92
+ end
93
+ end
94
+
@@ -0,0 +1,4 @@
1
+ module CustomCaptcha
2
+ VERSION = "0.1.0"
3
+ end
4
+
@@ -0,0 +1,8 @@
1
+ Description:
2
+ Explain the generator
3
+
4
+ Example:
5
+ rails generate install Thing
6
+
7
+ This will create:
8
+ what/will/it/create
@@ -0,0 +1,49 @@
1
+ require File.expand_path('../../utils', __FILE__)
2
+
3
+ class CustomCaptcha::InstallGenerator < Rails::Generators::Base
4
+
5
+ source_root File.expand_path('../templates', __FILE__)
6
+
7
+ include CustomCaptcha::Generators::Utils::InstanceMethods
8
+
9
+ desc "Creates CustomCaptcha initializer and copy locale files to your application."
10
+
11
+ def create_initializer
12
+ data_custom_captcha_rb = %Q/
13
+ CustomCaptcha.configure do |config|
14
+ config.image_columns = 120
15
+ config.image_rows = 40
16
+ config.image_style = "simply_blue"
17
+ config.text_range = ("a".."z").to_a
18
+ config.text_length = 5
19
+ config.images_path = Rails.root.join("public", "system", "captcha_images").to_s
20
+ config.enable = true
21
+ config.salt = "#{ SecureRandom.hex(20) }"
22
+ end
23
+ /
24
+ initializer "custom_captcha.rb", data_custom_captcha_rb
25
+ end
26
+
27
+ def create_locale
28
+ copy_file "../../../../../config/locales/custom_captcha.en.yml", "config/locales/custom_captcha.en.yml"
29
+ end
30
+
31
+ def create_views
32
+ filename_pattern = File.expand_path("../../../../../app/views/custom_captcha/captcha_styles/*", __FILE__)
33
+ Dir[filename_pattern].each do |f|
34
+ copy_file f, "app/views/custom_captcha/captcha_styles/#{File.basename f}"
35
+ end
36
+ end
37
+
38
+ def test_rakes
39
+ display "test generate and clear images..."
40
+ rake("custom_captcha:generate_images[1]")
41
+ rake("custom_captcha:clear_images")
42
+ end
43
+
44
+ def show_readme
45
+ display "Succeed! custom_captcha has been installed."
46
+ readme("README")
47
+ end
48
+ end
49
+
@@ -0,0 +1,18 @@
1
+ ===============================================================================
2
+
3
+ Some setup you must do manually:
4
+
5
+ 1. Modify captcha images directory in config/initializers/custom_captcha.rb.
6
+ For example:
7
+
8
+ config.images_path = Rails.root.join("public", "captcha_images").to_s
9
+
10
+ 2. Generate captcha images.
11
+
12
+ # bundle exec rake custom_captcha:generate_images[100]
13
+
14
+
15
+ Homepage: https://github.com/vkill/custom_captcha
16
+ by: vkill
17
+ ===============================================================================
18
+
@@ -0,0 +1,8 @@
1
+ Description:
2
+ Explain the generator
3
+
4
+ Example:
5
+ rails generate uninstall Thing
6
+
7
+ This will create:
8
+ what/will/it/create
@@ -0,0 +1,2 @@
1
+ Homepage: https://github.com/vkill/custom_captcha
2
+
@@ -0,0 +1,38 @@
1
+ require File.expand_path('../../utils', __FILE__)
2
+
3
+ class CustomCaptcha::UninstallGenerator < Rails::Generators::Base
4
+
5
+ source_root File.expand_path('../templates', __FILE__)
6
+
7
+ include CustomCaptcha::Generators::Utils::InstanceMethods
8
+
9
+ desc "Remove CustomCaptcha initializer and remove locale files from your application."
10
+
11
+ def clear_images
12
+ rake("custom_captcha:clear_images")
13
+ end
14
+
15
+ def destroy_initializer
16
+ remove_file "config/initializers/custom_captcha.rb"
17
+ end
18
+
19
+ def destroy_locale
20
+ remove_file "config/locales/custom_captcha.en.yml"
21
+ end
22
+
23
+ def destroy_views
24
+ # filename_pattern = File.expand_path("../../../../../app/views/custom_captcha/captcha_styles/*", __FILE__)
25
+ # Dir[filename_pattern].each do |f|
26
+ # copy_file f, "app/views/custom_captcha/captcha_styles/#{File.basename f}"
27
+ # end
28
+ Dir["app/views/custom_captcha/captcha_styles/*"].each do |f|
29
+ remove_file f
30
+ end
31
+ end
32
+
33
+ def show_readme
34
+ display "Done! custom_captcha has been uninstalled."
35
+ readme("README")
36
+ end
37
+ end
38
+
@@ -0,0 +1,12 @@
1
+ module CustomCaptcha
2
+ module Generators
3
+ module Utils
4
+ module InstanceMethods
5
+ def display(output, color = :green)
6
+ say(" - #{output}", color)
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
12
+
File without changes
@@ -0,0 +1,26 @@
1
+ #encoding: utf-8
2
+
3
+ require "rubygems"
4
+ require "bundler/setup"
5
+
6
+ require "custom_captcha"
7
+
8
+ namespace :custom_captcha do
9
+ desc "Generate {count} captcha images."
10
+ task :generate_images, [:count] => :environment do |t, args|
11
+ args.with_defaults(:count => 3)
12
+ count = args[:count].to_i
13
+ CustomCaptcha::Utils.generate_image_files(count) do |number, n, state, image_file|
14
+ puts " - [%s/%s] %s Generating %s" % [ n, number, state.capitalize!, image_file ]
15
+ end
16
+ end
17
+
18
+ desc "Clear captcha images."
19
+ task :clear_images => :environment do |t|
20
+ print "\r - Clearing captcha images..."
21
+ CustomCaptcha::Utils.clear_image_files()
22
+ print "done\n"
23
+ end
24
+
25
+ end
26
+
@@ -0,0 +1,19 @@
1
+ #encoding: utf-8
2
+ require "spec_helper"
3
+
4
+ describe CustomCaptcha::Configuration do
5
+
6
+ it "should set a configuration" do
7
+ CustomCaptcha::Configuration.text_length.should == 5
8
+ CustomCaptcha.configure do |config|
9
+ config.text_length = 6
10
+ end
11
+ CustomCaptcha::Configuration.text_length.should == 6
12
+ end
13
+
14
+ it "should define images path and create images path" do
15
+ CustomCaptcha::Configuration.make_and_define_images_path()
16
+ File.exist?(CustomCaptcha::Configuration.images_path_definite).should be_true
17
+ end
18
+ end
19
+
@@ -0,0 +1,10 @@
1
+ #encoding: utf-8
2
+ require "spec_helper"
3
+
4
+ describe CustomCaptcha::Image do
5
+
6
+ it "should create a image" do
7
+ CustomCaptcha::Image.create().should be_true
8
+ end
9
+ end
10
+
@@ -0,0 +1,6 @@
1
+ #encoding: utf-8
2
+
3
+ require "rubygems"
4
+ require "bundler/setup"
5
+ require "custom_captcha"
6
+
metadata ADDED
@@ -0,0 +1,165 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: custom_captcha
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - vkill
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-11-13 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: bundler
16
+ requirement: &70249600 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: *70249600
25
+ - !ruby/object:Gem::Dependency
26
+ name: rake
27
+ requirement: &70249330 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: *70249330
36
+ - !ruby/object:Gem::Dependency
37
+ name: rspec
38
+ requirement: &70249040 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ! '>='
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ type: :development
45
+ prerelease: false
46
+ version_requirements: *70249040
47
+ - !ruby/object:Gem::Dependency
48
+ name: guard-rspec
49
+ requirement: &70248730 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ type: :development
56
+ prerelease: false
57
+ version_requirements: *70248730
58
+ - !ruby/object:Gem::Dependency
59
+ name: rails
60
+ requirement: &70248350 !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ~>
64
+ - !ruby/object:Gem::Version
65
+ version: '3.0'
66
+ type: :runtime
67
+ prerelease: false
68
+ version_requirements: *70248350
69
+ - !ruby/object:Gem::Dependency
70
+ name: rmagick
71
+ requirement: &70248000 !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ~>
75
+ - !ruby/object:Gem::Version
76
+ version: 2.13.1
77
+ type: :runtime
78
+ prerelease: false
79
+ version_requirements: *70248000
80
+ - !ruby/object:Gem::Dependency
81
+ name: jquery-rails
82
+ requirement: &70247670 !ruby/object:Gem::Requirement
83
+ none: false
84
+ requirements:
85
+ - - ~>
86
+ - !ruby/object:Gem::Version
87
+ version: 1.0.16
88
+ type: :runtime
89
+ prerelease: false
90
+ version_requirements: *70247670
91
+ description: A simple and custom captcha for Rails3.
92
+ email:
93
+ - vkill.net@gmail.com
94
+ executables: []
95
+ extensions: []
96
+ extra_rdoc_files: []
97
+ files:
98
+ - .gitignore
99
+ - .rspec
100
+ - CHANGELOG
101
+ - Gemfile
102
+ - Guardfile
103
+ - README.markdown
104
+ - Rakefile
105
+ - app/controllers/custom_captcha/captcha_images_controller.rb
106
+ - app/views/custom_captcha/captcha_images/change.html.erb
107
+ - app/views/custom_captcha/captcha_images/change.js.erb
108
+ - app/views/custom_captcha/captcha_images/show.html.erb
109
+ - app/views/custom_captcha/captcha_styles/_default.html.erb
110
+ - config/locales/custom_captcha.en.yml
111
+ - config/routes.rb
112
+ - custom_captcha.gemspec
113
+ - lib/custom_captcha.rb
114
+ - lib/custom_captcha/action_controller_extension.rb
115
+ - lib/custom_captcha/action_view_extension.rb
116
+ - lib/custom_captcha/active_record_extension.rb
117
+ - lib/custom_captcha/common_methods.rb
118
+ - lib/custom_captcha/configuration.rb
119
+ - lib/custom_captcha/engine.rb
120
+ - lib/custom_captcha/errors.rb
121
+ - lib/custom_captcha/image.rb
122
+ - lib/custom_captcha/railtie.rb
123
+ - lib/custom_captcha/utils.rb
124
+ - lib/custom_captcha/version.rb
125
+ - lib/generators/custom_captcha/install/USAGE
126
+ - lib/generators/custom_captcha/install/install_generator.rb
127
+ - lib/generators/custom_captcha/install/templates/README
128
+ - lib/generators/custom_captcha/uninstall/USAGE
129
+ - lib/generators/custom_captcha/uninstall/templates/README
130
+ - lib/generators/custom_captcha/uninstall/uninstall_generator.rb
131
+ - lib/generators/custom_captcha/utils.rb
132
+ - lib/tasks/.gitkeep
133
+ - lib/tasks/custom_captcha_utils.rake
134
+ - spec/configuration_spec.rb
135
+ - spec/image_spec.rb
136
+ - spec/spec_helper.rb
137
+ homepage: https://github.com/vkill/custom_captcha
138
+ licenses: []
139
+ post_install_message:
140
+ rdoc_options: []
141
+ require_paths:
142
+ - lib
143
+ required_ruby_version: !ruby/object:Gem::Requirement
144
+ none: false
145
+ requirements:
146
+ - - ! '>='
147
+ - !ruby/object:Gem::Version
148
+ version: '0'
149
+ required_rubygems_version: !ruby/object:Gem::Requirement
150
+ none: false
151
+ requirements:
152
+ - - ! '>='
153
+ - !ruby/object:Gem::Version
154
+ version: '0'
155
+ requirements: []
156
+ rubyforge_project: custom_captcha
157
+ rubygems_version: 1.8.10
158
+ signing_key:
159
+ specification_version: 3
160
+ summary: A simple and custom captcha for Rails3.
161
+ test_files:
162
+ - spec/configuration_spec.rb
163
+ - spec/image_spec.rb
164
+ - spec/spec_helper.rb
165
+ has_rdoc: