custom_captcha 0.1.0
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/.gitignore +4 -0
- data/.rspec +1 -0
- data/CHANGELOG +4 -0
- data/Gemfile +4 -0
- data/Guardfile +22 -0
- data/README.markdown +107 -0
- data/Rakefile +2 -0
- data/app/controllers/custom_captcha/captcha_images_controller.rb +28 -0
- data/app/views/custom_captcha/captcha_images/change.html.erb +2 -0
- data/app/views/custom_captcha/captcha_images/change.js.erb +3 -0
- data/app/views/custom_captcha/captcha_images/show.html.erb +2 -0
- data/app/views/custom_captcha/captcha_styles/_default.html.erb +10 -0
- data/config/locales/custom_captcha.en.yml +6 -0
- data/config/routes.rb +9 -0
- data/custom_captcha.gemspec +31 -0
- data/lib/custom_captcha.rb +39 -0
- data/lib/custom_captcha/action_controller_extension.rb +42 -0
- data/lib/custom_captcha/action_view_extension.rb +56 -0
- data/lib/custom_captcha/active_record_extension.rb +51 -0
- data/lib/custom_captcha/common_methods.rb +13 -0
- data/lib/custom_captcha/configuration.rb +107 -0
- data/lib/custom_captcha/engine.rb +5 -0
- data/lib/custom_captcha/errors.rb +5 -0
- data/lib/custom_captcha/image.rb +86 -0
- data/lib/custom_captcha/railtie.rb +25 -0
- data/lib/custom_captcha/utils.rb +94 -0
- data/lib/custom_captcha/version.rb +4 -0
- data/lib/generators/custom_captcha/install/USAGE +8 -0
- data/lib/generators/custom_captcha/install/install_generator.rb +49 -0
- data/lib/generators/custom_captcha/install/templates/README +18 -0
- data/lib/generators/custom_captcha/uninstall/USAGE +8 -0
- data/lib/generators/custom_captcha/uninstall/templates/README +2 -0
- data/lib/generators/custom_captcha/uninstall/uninstall_generator.rb +38 -0
- data/lib/generators/custom_captcha/utils.rb +12 -0
- data/lib/tasks/.gitkeep +0 -0
- data/lib/tasks/custom_captcha_utils.rake +26 -0
- data/spec/configuration_spec.rb +19 -0
- data/spec/image_spec.rb +10 -0
- data/spec/spec_helper.rb +6 -0
- metadata +165 -0
data/.gitignore
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--colour
|
data/CHANGELOG
ADDED
data/Gemfile
ADDED
data/Guardfile
ADDED
@@ -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
|
+
|
data/README.markdown
ADDED
@@ -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
|
+
|
data/Rakefile
ADDED
@@ -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,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
|
+
|
data/config/routes.rb
ADDED
@@ -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,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,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,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
|
+
|
data/lib/tasks/.gitkeep
ADDED
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
|
+
|
data/spec/image_spec.rb
ADDED
data/spec/spec_helper.rb
ADDED
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:
|