winton-captcha 1.0.3 → 1.0.4
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/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
|