winton-captcha 1.0.3 → 1.0.4
Sign up to get free protection for your applications and to get access to all the features.
- data/README.markdown +10 -10
- data/Rakefile +31 -0
- data/captcha.gemspec +37 -0
- data/init.rb +7 -1
- data/lib/captcha.rb +4 -59
- data/lib/captcha/action.rb +42 -0
- data/lib/captcha/config.rb +71 -0
- data/lib/captcha/generator.rb +29 -0
- data/lib/captcha/image.rb +46 -0
- data/resources/captcha.ttf +0 -0
- data/resources/captchas.rb +24 -0
- data/spec/lib/captcha_spec.rb +63 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +5 -0
- data/tasks/captcha.rake +55 -0
- metadata +18 -6
- data/lib/captcha/actions.rb +0 -26
data/README.markdown
CHANGED
@@ -1,23 +1,23 @@
|
|
1
1
|
captcha
|
2
2
|
=======
|
3
3
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
How it works
|
8
|
-
------------
|
9
|
-
|
10
|
-
If **public/images/captchas** does not exist, 100 captchas will be generated there when the application starts.
|
4
|
+
An Rmagick based, Google-style captcha generator for Rails.
|
11
5
|
|
12
6
|
|
13
7
|
Install
|
14
8
|
-------
|
15
9
|
|
16
|
-
|
10
|
+
script/plugin install git://github.com/winton/captcha.git
|
11
|
+
|
12
|
+
### Generate config/captcha.rb
|
13
|
+
|
14
|
+
rake captcha
|
17
15
|
|
18
|
-
|
16
|
+
Take a look at the config file.
|
19
17
|
|
20
|
-
|
18
|
+
### Generate captchas
|
19
|
+
|
20
|
+
rake captcha:generate
|
21
21
|
|
22
22
|
### Add to .gitignore
|
23
23
|
|
data/Rakefile
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'rake'
|
2
|
+
|
3
|
+
task :default => 'captcha.gemspec'
|
4
|
+
|
5
|
+
file 'captcha.gemspec' => FileList['{lib,spec}/**','Rakefile'] do |f|
|
6
|
+
# read spec file and split out manifest section
|
7
|
+
spec = File.read(f.name)
|
8
|
+
parts = spec.split(" # = MANIFEST =\n")
|
9
|
+
fail 'bad spec' if parts.length != 3
|
10
|
+
# determine file list from git ls-files
|
11
|
+
files = `git ls-files`.
|
12
|
+
split("\n").
|
13
|
+
sort.
|
14
|
+
reject{ |file| file =~ /^\./ }.
|
15
|
+
reject { |file| file =~ /^doc/ }.
|
16
|
+
map{ |file| " #{file}" }.
|
17
|
+
join("\n")
|
18
|
+
# piece file back together and write...
|
19
|
+
parts[1] = " s.files = %w[\n#{files}\n ]\n"
|
20
|
+
spec = parts.join(" # = MANIFEST =\n")
|
21
|
+
File.open(f.name, 'w') { |io| io.write(spec) }
|
22
|
+
puts "Updated #{f.name}"
|
23
|
+
end
|
24
|
+
|
25
|
+
# sudo rake install
|
26
|
+
task :install do
|
27
|
+
`sudo gem uninstall captcha -x`
|
28
|
+
`gem build captcha.gemspec`
|
29
|
+
`sudo gem install captcha*.gem`
|
30
|
+
`rm captcha*.gem`
|
31
|
+
end
|
data/captcha.gemspec
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = 'captcha'
|
3
|
+
s.version = '1.0.4'
|
4
|
+
s.date = '2009-03-23'
|
5
|
+
|
6
|
+
s.summary = "An Rmagick based, Google-style captcha generator"
|
7
|
+
s.description = "An Rmagick based, Google-style captcha generator"
|
8
|
+
|
9
|
+
s.author = 'Winton Welsh'
|
10
|
+
s.email = 'mail@wintoni.us'
|
11
|
+
s.homepage = 'http://github.com/winton/captcha'
|
12
|
+
|
13
|
+
s.has_rdoc = false
|
14
|
+
|
15
|
+
# = MANIFEST =
|
16
|
+
s.files = %w[
|
17
|
+
README.markdown
|
18
|
+
Rakefile
|
19
|
+
captcha.gemspec
|
20
|
+
init.rb
|
21
|
+
lib/captcha.rb
|
22
|
+
lib/captcha/action.rb
|
23
|
+
lib/captcha/actions.rb
|
24
|
+
lib/captcha/captcha.rb
|
25
|
+
lib/captcha/config.rb
|
26
|
+
lib/captcha/generator.rb
|
27
|
+
lib/captcha/image.rb
|
28
|
+
lib/captcha/routes.rb
|
29
|
+
resources/captcha.ttf
|
30
|
+
resources/captchas.rb
|
31
|
+
spec/lib/captcha_spec.rb
|
32
|
+
spec/spec.opts
|
33
|
+
spec/spec_helper.rb
|
34
|
+
tasks/captcha.rake
|
35
|
+
]
|
36
|
+
# = MANIFEST =
|
37
|
+
end
|
data/init.rb
CHANGED
data/lib/captcha.rb
CHANGED
@@ -1,59 +1,4 @@
|
|
1
|
-
require
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
end
|
6
|
-
|
7
|
-
class Captcha
|
8
|
-
|
9
|
-
include Magick
|
10
|
-
attr_reader :code, :code_image
|
11
|
-
|
12
|
-
JIGGLE = 15
|
13
|
-
WOBBLE = 25
|
14
|
-
|
15
|
-
def initialize(len)
|
16
|
-
chars = ('a'..'z').to_a - ['a','e','i','o','u','l','j']
|
17
|
-
code_array = []
|
18
|
-
1.upto(len) { code_array << chars[rand(chars.length)] }
|
19
|
-
granite = Magick::ImageList.new('granite:')
|
20
|
-
canvas = Magick::ImageList.new
|
21
|
-
canvas.new_image(32*len, 50, Magick::TextureFill.new(granite))
|
22
|
-
text = Magick::Draw.new
|
23
|
-
text.font = File.expand_path('vendor/plugins/captcha/resources/captcha.ttf')
|
24
|
-
text.pointsize = 40
|
25
|
-
cur = 10
|
26
|
-
|
27
|
-
code_array.each { |c|
|
28
|
-
rot = rand(10) > 5 ? rand(WOBBLE) : -rand(WOBBLE)
|
29
|
-
weight = rand(10) > 5 ? NormalWeight : BoldWeight
|
30
|
-
text.annotate(canvas,0,0,cur,30+rand(JIGGLE), c) {
|
31
|
-
self.rotation = rot
|
32
|
-
self.font_weight = weight
|
33
|
-
self.fill = '#98999B'
|
34
|
-
}
|
35
|
-
cur += 30
|
36
|
-
}
|
37
|
-
|
38
|
-
@code = code_array.to_s
|
39
|
-
@code_image = canvas.to_blob {
|
40
|
-
self.format = "JPG"
|
41
|
-
}
|
42
|
-
|
43
|
-
GC.start
|
44
|
-
end
|
45
|
-
|
46
|
-
end
|
47
|
-
|
48
|
-
to = "public/images/captchas"
|
49
|
-
unless File.exists?(to)
|
50
|
-
FileUtils.mkdir_p to
|
51
|
-
(0..99).each do |x|
|
52
|
-
c = Captcha.new(6)
|
53
|
-
File.open("#{to}/#{c.code}.jpg", 'w') do |f|
|
54
|
-
f << c.code_image
|
55
|
-
end
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
ActionController::Base.send :include, CaptchaActions
|
1
|
+
require File.dirname(__FILE__) + "/captcha/action.rb"
|
2
|
+
require File.dirname(__FILE__) + "/captcha/image.rb"
|
3
|
+
require File.dirname(__FILE__) + "/captcha/config.rb"
|
4
|
+
require File.dirname(__FILE__) + "/captcha/generator.rb"
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Captcha
|
2
|
+
module Action
|
3
|
+
|
4
|
+
def self.included(base)
|
5
|
+
base.extend ClassMethods
|
6
|
+
end
|
7
|
+
|
8
|
+
module ClassMethods
|
9
|
+
def acts_as_captcha
|
10
|
+
include Captcha::Action::InstanceMethods
|
11
|
+
self.around_filter CaptchaFilter.new
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
module InstanceMethods
|
16
|
+
def new
|
17
|
+
files = Dir["#{RAILS_ROOT}/#{CAPTCHAS.options[:destination]}/*.jpg"]
|
18
|
+
@captcha = File.basename(files[rand(files.length)], '.jpg')
|
19
|
+
show
|
20
|
+
end
|
21
|
+
|
22
|
+
def show
|
23
|
+
new unless @captcha
|
24
|
+
send_file "#{RAILS_ROOT}/#{CAPTCHAS.options[:destination]}/#{@captcha}.jpg", :type => 'image/jpeg', :disposition => 'inline'
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
class CaptchaFilter
|
31
|
+
def before(controller)
|
32
|
+
@captcha = session[:captcha]
|
33
|
+
end
|
34
|
+
def after(controller)
|
35
|
+
if session[:captcha] != @captcha
|
36
|
+
session[:captcha] = @captcha
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
module Captcha
|
2
|
+
class Config
|
3
|
+
def initialize(options={})
|
4
|
+
@@options = {
|
5
|
+
:colors => {
|
6
|
+
:background => '#1B1C20',
|
7
|
+
:font => '#7385C5'
|
8
|
+
},
|
9
|
+
# number of captcha images to generate
|
10
|
+
:count => 500,
|
11
|
+
:destination => File.expand_path(
|
12
|
+
(defined?(RAILS_ROOT) ? "#{RAILS_ROOT}/" : '') +
|
13
|
+
"public/images/captchas"
|
14
|
+
),
|
15
|
+
:dimensions => {
|
16
|
+
# canvas height (px)
|
17
|
+
:height => 31,
|
18
|
+
# canvas width (px)
|
19
|
+
:width => 90
|
20
|
+
},
|
21
|
+
:generate_every => 24 * 60 * 60,
|
22
|
+
# http://www.imagemagick.org/RMagick/doc/image2.html#implode
|
23
|
+
:implode => 0.2,
|
24
|
+
:letters => {
|
25
|
+
# text baseline (px)
|
26
|
+
:baseline => 24,
|
27
|
+
# number of letters in captcha
|
28
|
+
:count => 6,
|
29
|
+
:ignore => ['a','e','i','o','u','l','j','q'],
|
30
|
+
# font size (pts)
|
31
|
+
:points => 34,
|
32
|
+
# width of a character (used to decrease or increase space between characters) (px)
|
33
|
+
:width => 14
|
34
|
+
},
|
35
|
+
:ttf => File.expand_path("#{File.dirname(__FILE__)}/../../resources/captcha.ttf"),
|
36
|
+
# http://www.imagemagick.org/RMagick/doc/image3.html#wave
|
37
|
+
:wave => {
|
38
|
+
# range is used for randomness (px)
|
39
|
+
:wavelength => (20..70),
|
40
|
+
# distance between peak and valley of sin wave (px)
|
41
|
+
:amplitude => 3
|
42
|
+
}
|
43
|
+
}.merge(options)
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.captchas_ordered_by_modified
|
47
|
+
return unless @@options
|
48
|
+
files_modified = Dir["#{@@options[:destination]}/*.jpg"].collect do |file|
|
49
|
+
[ file, File.mtime(file) ]
|
50
|
+
end
|
51
|
+
# Youngest to oldest
|
52
|
+
files_modified.sort! { |a, b| b[1] <=> a[1] }
|
53
|
+
files_modified.collect { |f| f[0] }
|
54
|
+
end
|
55
|
+
|
56
|
+
def self.codes
|
57
|
+
self.captchas_ordered_by_modified.collect do |f|
|
58
|
+
File.basename f, '.jpg'
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def self.options
|
63
|
+
@@options
|
64
|
+
end
|
65
|
+
|
66
|
+
def self.last_modified
|
67
|
+
youngest = self.captchas_ordered_by_modified.first
|
68
|
+
youngest ? File.mtime(youngest) : nil
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Captcha
|
2
|
+
class Generator
|
3
|
+
def initialize
|
4
|
+
generate
|
5
|
+
end
|
6
|
+
|
7
|
+
def generate
|
8
|
+
return unless Config.options
|
9
|
+
return if Config.last_modified && Config.last_modified > Time.now - Config.options[:generate_every]
|
10
|
+
FileUtils.mkdir_p Config.options[:destination]
|
11
|
+
(1..Config.options[:count]).each do |x|
|
12
|
+
c = Image.new Config.options
|
13
|
+
File.open("#{Config.options[:destination]}/#{c.code}.jpg", 'w') do |f|
|
14
|
+
f << c.image
|
15
|
+
end
|
16
|
+
end
|
17
|
+
destroy_if_over_limit
|
18
|
+
GC.start
|
19
|
+
end
|
20
|
+
|
21
|
+
def destroy_if_over_limit
|
22
|
+
if Config.codes.length >= Config.options[:count] * 3
|
23
|
+
Config.captchas_ordered_by_modified[(Config.options[:count] * 2)..-1].each do |file|
|
24
|
+
FileUtils.rm_f(file)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'RMagick'
|
2
|
+
|
3
|
+
module Captcha
|
4
|
+
class Image
|
5
|
+
|
6
|
+
include Magick
|
7
|
+
attr_reader :code, :image
|
8
|
+
|
9
|
+
def initialize(o)
|
10
|
+
@code = generate_code o
|
11
|
+
|
12
|
+
canvas = Magick::ImageList.new
|
13
|
+
canvas.new_image(o[:dimensions][:width], o[:dimensions][:height]) {
|
14
|
+
self.background_color = o[:colors][:background]
|
15
|
+
}
|
16
|
+
|
17
|
+
text = Magick::Draw.new
|
18
|
+
text.font = File.expand_path o[:ttf]
|
19
|
+
text.pointsize = o[:letters][:points]
|
20
|
+
|
21
|
+
cur = 0
|
22
|
+
@code.each { |c|
|
23
|
+
text.annotate(canvas, 0, 0, cur, o[:letters][:baseline], c) {
|
24
|
+
self.fill = o[:colors][:font]
|
25
|
+
}
|
26
|
+
cur += o[:letters][:width]
|
27
|
+
}
|
28
|
+
|
29
|
+
w = o[:wave][:wavelength]
|
30
|
+
canvas = canvas.wave(o[:wave][:amplitude], rand(w.last - w.first) + w.first)
|
31
|
+
canvas = canvas.implode(o[:implode])
|
32
|
+
|
33
|
+
@code = @code.to_s
|
34
|
+
@image = canvas.to_blob { self.format = "JPG" }
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def generate_code(o)
|
40
|
+
chars = ('a'..'z').to_a - o[:letters][:ignore]
|
41
|
+
code_array = []
|
42
|
+
1.upto(o[:letters][:count]) { code_array << chars[rand(chars.length)] }
|
43
|
+
code_array
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
data/resources/captcha.ttf
CHANGED
Binary file
|
@@ -0,0 +1,24 @@
|
|
1
|
+
{
|
2
|
+
:count => 100, # number of captcha images to generate
|
3
|
+
:width => 90, # canvas width (px)
|
4
|
+
:height => 31, # canvas height (px)
|
5
|
+
:colors => {
|
6
|
+
:background => '#1B1C20',
|
7
|
+
:font => '#7385C5'
|
8
|
+
},
|
9
|
+
:letters => {
|
10
|
+
:baseline => 24,# text baseline (px)
|
11
|
+
:count => 6, # number of letters in captcha
|
12
|
+
:ignore => ['a','e','i','o','u','l','j','q'],
|
13
|
+
:points => 34, # font size (pts)
|
14
|
+
:width => 14, # width of a character (used to decrease or increase space between characters) (px)
|
15
|
+
},
|
16
|
+
:implode => 0.2, # http://www.imagemagick.org/RMagick/doc/image2.html#implode
|
17
|
+
:wave => { # http://www.imagemagick.org/RMagick/doc/image3.html#wave
|
18
|
+
:wavelength => (20..70), # range is used for randomness (px)
|
19
|
+
:amplitude => 3 # distance between peak and valley of sin wave (px)
|
20
|
+
},
|
21
|
+
:generate_on_startup => RAILS_ENV == 'production',
|
22
|
+
:destination => 'tmp/captchas',
|
23
|
+
:ttf => 'vendor/plugins/captcha/resources/captcha.ttf'
|
24
|
+
}
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + "/../spec_helper")
|
2
|
+
|
3
|
+
describe :captcha do
|
4
|
+
before(:each) do
|
5
|
+
@delay = 2 # 2 seconds
|
6
|
+
Captcha::Config.new(
|
7
|
+
:count => 10,
|
8
|
+
:destination => File.expand_path(File.dirname(__FILE__) + "/../tmp"),
|
9
|
+
:generate_every => @delay
|
10
|
+
)
|
11
|
+
FileUtils.rm_rf Captcha::Config.options[:destination]
|
12
|
+
@generator = Captcha::Generator.new
|
13
|
+
end
|
14
|
+
after(:all) do
|
15
|
+
FileUtils.rm_rf Captcha::Config.options[:destination]
|
16
|
+
end
|
17
|
+
it "should generate captchas" do
|
18
|
+
Captcha::Config.codes.length.should == 10
|
19
|
+
end
|
20
|
+
it "should only generate more captchas if the youngest file is older than the generate_every option" do
|
21
|
+
@generator.generate
|
22
|
+
Captcha::Config.codes.length.should == 10
|
23
|
+
sleep @delay
|
24
|
+
@generator.generate
|
25
|
+
Captcha::Config.codes.length.should == 20
|
26
|
+
end
|
27
|
+
it "should not allow more than twice the captcha limit to exist" do
|
28
|
+
sleep @delay
|
29
|
+
@generator.generate
|
30
|
+
Captcha::Config.codes.length.should == 20
|
31
|
+
sleep @delay
|
32
|
+
@generator.generate
|
33
|
+
Captcha::Config.codes.length.should == 20
|
34
|
+
end
|
35
|
+
it "should only destroy the oldest captchas" do
|
36
|
+
codes = Captcha::Config.codes
|
37
|
+
sleep @delay
|
38
|
+
@generator.generate
|
39
|
+
codes2 = Captcha::Config.codes
|
40
|
+
Captcha::Config.codes.length.should == 20
|
41
|
+
Captcha::Config.codes[9..-1].should_include_all_from(codes)
|
42
|
+
sleep @delay
|
43
|
+
@generator.generate
|
44
|
+
Captcha::Config.codes.length.should == 20
|
45
|
+
Captcha::Config.codes[9..-1].should_include_all_from(codes2)
|
46
|
+
Captcha::Config.codes.should_not_include_any_from(codes)
|
47
|
+
@generator.generate
|
48
|
+
Captcha::Config.codes.length.should == 20
|
49
|
+
Captcha::Config.codes.should_not_include_any_from(codes2)
|
50
|
+
end
|
51
|
+
class Array
|
52
|
+
def should_include_all_from(array)
|
53
|
+
included_all = true
|
54
|
+
array.each { |a| included_all = false unless self.include?(a) }
|
55
|
+
included_all
|
56
|
+
end
|
57
|
+
def should_not_include_any_from(array)
|
58
|
+
included_any = false
|
59
|
+
array.each { |a| included_any = true if self.include?(a) }
|
60
|
+
included_any
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
data/spec/spec.opts
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/spec/spec_helper.rb
ADDED
data/tasks/captcha.rake
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
require File.expand_path('../lib/captcha/captcha.rb', File.dirname(__FILE__))
|
2
|
+
|
3
|
+
desc 'Updates config/captcha.rb'
|
4
|
+
task :captcha => 'captcha:config'
|
5
|
+
|
6
|
+
namespace :captcha do
|
7
|
+
|
8
|
+
desc 'Updates config/captcha.rb'
|
9
|
+
task :config => 'captcha:config:to_app'
|
10
|
+
|
11
|
+
desc 'Generates captchas'
|
12
|
+
task :generate do
|
13
|
+
Captchas.new
|
14
|
+
end
|
15
|
+
|
16
|
+
namespace :config do
|
17
|
+
desc 'Copies plugin resources to app'
|
18
|
+
task :to_app do
|
19
|
+
captcha_resource 'captchas.rb', 'config/captchas.rb'
|
20
|
+
end
|
21
|
+
|
22
|
+
desc 'Copies app resources to plugin'
|
23
|
+
task :to_plugin do
|
24
|
+
captcha_resource 'captchas.rb', 'config/captchas.rb', true
|
25
|
+
end
|
26
|
+
|
27
|
+
desc 'Removes plugin resources from app'
|
28
|
+
task :remove do
|
29
|
+
rm_rf 'config/captchas.rb'
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def captcha_resource(type, to, reverse=false, overwrite=true)
|
34
|
+
from = "#{File.dirname(__FILE__)}/../resources/#{type}"
|
35
|
+
from, to = to, from if reverse
|
36
|
+
puts "=> Removing old #{type}..."
|
37
|
+
puts to
|
38
|
+
return if File.exists?(to) && !overwrite
|
39
|
+
if File.directory?(from)
|
40
|
+
FileUtils.remove_dir(to, true) if File.exists?(to)
|
41
|
+
FileUtils.mkdir_p to
|
42
|
+
else
|
43
|
+
File.unlink(to) if File.exists?(to)
|
44
|
+
end
|
45
|
+
puts "=> Copying #{type}..."
|
46
|
+
(File.directory?(from) ? Dir["#{from}/*"] : [from]).each do |f|
|
47
|
+
if File.directory? f
|
48
|
+
FileUtils.mkdir_p "#{to}/#{File.basename(f)}"
|
49
|
+
FileUtils.cp_r f, to
|
50
|
+
else
|
51
|
+
FileUtils.cp f, to
|
52
|
+
end
|
53
|
+
end if File.exists?(from)
|
54
|
+
end
|
55
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: winton-captcha
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Winton Welsh
|
@@ -9,11 +9,11 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date:
|
12
|
+
date: 2009-03-23 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|
16
|
-
description:
|
16
|
+
description: An Rmagick based, Google-style captcha generator
|
17
17
|
email: mail@wintoni.us
|
18
18
|
executables: []
|
19
19
|
|
@@ -22,12 +22,24 @@ extensions: []
|
|
22
22
|
extra_rdoc_files: []
|
23
23
|
|
24
24
|
files:
|
25
|
+
- README.markdown
|
26
|
+
- Rakefile
|
27
|
+
- captcha.gemspec
|
25
28
|
- init.rb
|
26
29
|
- lib/captcha.rb
|
27
|
-
- lib/captcha
|
30
|
+
- lib/captcha/action.rb
|
28
31
|
- lib/captcha/actions.rb
|
29
|
-
-
|
32
|
+
- lib/captcha/captcha.rb
|
33
|
+
- lib/captcha/config.rb
|
34
|
+
- lib/captcha/generator.rb
|
35
|
+
- lib/captcha/image.rb
|
36
|
+
- lib/captcha/routes.rb
|
30
37
|
- resources/captcha.ttf
|
38
|
+
- resources/captchas.rb
|
39
|
+
- spec/lib/captcha_spec.rb
|
40
|
+
- spec/spec.opts
|
41
|
+
- spec/spec_helper.rb
|
42
|
+
- tasks/captcha.rake
|
31
43
|
has_rdoc: false
|
32
44
|
homepage: http://github.com/winton/captcha
|
33
45
|
post_install_message:
|
@@ -53,6 +65,6 @@ rubyforge_project:
|
|
53
65
|
rubygems_version: 1.2.0
|
54
66
|
signing_key:
|
55
67
|
specification_version: 2
|
56
|
-
summary:
|
68
|
+
summary: An Rmagick based, Google-style captcha generator
|
57
69
|
test_files: []
|
58
70
|
|
data/lib/captcha/actions.rb
DELETED
@@ -1,26 +0,0 @@
|
|
1
|
-
module CaptchaActions
|
2
|
-
|
3
|
-
def self.included(base)
|
4
|
-
base.extend ClassMethods
|
5
|
-
end
|
6
|
-
|
7
|
-
module ClassMethods
|
8
|
-
def acts_as_captcha
|
9
|
-
include CaptchaActions::InstanceMethods
|
10
|
-
end
|
11
|
-
end
|
12
|
-
|
13
|
-
module InstanceMethods
|
14
|
-
def index
|
15
|
-
new unless session[:captcha]
|
16
|
-
send_file "#{RAILS_ROOT}/public/images/captchas/#{session[:captcha]}.jpg", :type => 'image/jpeg', :disposition => 'inline'
|
17
|
-
end
|
18
|
-
|
19
|
-
def new
|
20
|
-
files = Dir["#{RAILS_ROOT}/public/images/captchas/*.jpg"]
|
21
|
-
session[:captcha] = File.basename(files[rand(files.length)], '.jpg')
|
22
|
-
index
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
end
|