winton-captcha 1.1.0 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/MIT-LICENSE +20 -0
- data/README.markdown +34 -31
- data/captcha.gemspec +7 -9
- data/lib/captcha/action.rb +15 -11
- data/lib/captcha/cipher.rb +40 -0
- data/lib/captcha/config.rb +31 -23
- data/lib/captcha/generator.rb +9 -12
- data/lib/captcha/image.rb +10 -9
- data/lib/captcha/model.rb +56 -0
- data/lib/captcha.rb +1 -0
- data/spec/lib/captcha_spec.rb +5 -37
- metadata +7 -9
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2008 Winton Welsh
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.markdown
CHANGED
@@ -1,8 +1,19 @@
|
|
1
1
|
captcha
|
2
2
|
=======
|
3
3
|
|
4
|
-
|
4
|
+
A Google-style captcha for enterprise Rails apps
|
5
5
|
|
6
|
+
Goals
|
7
|
+
-----
|
8
|
+
|
9
|
+
* Batch generate captchas
|
10
|
+
* Use ciphered filenames (no need to store filename/captcha code pairs)
|
11
|
+
* Captchas refresh automatically
|
12
|
+
* Easy configuration
|
13
|
+
** Number of captchas
|
14
|
+
** Period for captcha refresh
|
15
|
+
** Colors, wave, implode
|
16
|
+
* Handle lots of users
|
6
17
|
|
7
18
|
Install
|
8
19
|
-------
|
@@ -12,7 +23,9 @@ Install
|
|
12
23
|
### Create lib/captcha_config.rb (optional)
|
13
24
|
|
14
25
|
<pre>
|
15
|
-
|
26
|
+
Captcha::Config.new(
|
27
|
+
# Used for filename cipher
|
28
|
+
:password => 'something-unique',
|
16
29
|
# Captcha colors
|
17
30
|
:colors => {
|
18
31
|
:background => '#FFFFFF',
|
@@ -23,8 +36,8 @@ Install
|
|
23
36
|
# Where to write captchas
|
24
37
|
:destination => "#{RAILS_ROOT}/public/images/captchas",
|
25
38
|
# Generate new batch every day
|
26
|
-
:generate_every =>
|
27
|
-
|
39
|
+
:generate_every => 24 * 60 * 60
|
40
|
+
)
|
28
41
|
</pre>
|
29
42
|
|
30
43
|
See <code>lib/captcha/config.rb</code> for more options.
|
@@ -35,50 +48,40 @@ See <code>lib/captcha/config.rb</code> for more options.
|
|
35
48
|
public/images/captchas/*
|
36
49
|
</pre>
|
37
50
|
|
38
|
-
###
|
39
|
-
|
40
|
-
script/generate controller Captchas
|
41
|
-
|
42
|
-
### Add the resource to your routes.rb
|
43
|
-
|
44
|
-
map.resource :captcha
|
45
|
-
|
46
|
-
### Add acts\_as\_captcha to captchas_controller.rb
|
51
|
+
### Add acts\_as\_captcha to application_controller.rb
|
47
52
|
|
48
53
|
<pre>
|
49
|
-
class
|
54
|
+
class ApplicationController < ActionController::Base
|
50
55
|
acts_as_captcha
|
51
56
|
end
|
52
|
-
</pre>
|
57
|
+
</pre>
|
58
|
+
|
59
|
+
You may now use the <code>reset_captcha</code> method in any controller.
|
53
60
|
|
54
61
|
### Add acts\_as\_captcha to your model
|
55
62
|
|
56
63
|
<pre>
|
57
|
-
|
64
|
+
class User < ActiveRecord::Base
|
65
|
+
acts_as_captcha :base => "base error when captcha fails", :field => "field error when captcha fails"
|
66
|
+
end
|
58
67
|
</pre>
|
59
68
|
|
60
|
-
|
69
|
+
No parameters behaves like <code>:field => true</code>, a default error is added to the "captcha" field.
|
70
|
+
|
71
|
+
Use <code>:base => true</code> to activate a default error for base.
|
61
72
|
|
62
73
|
### In your view
|
63
74
|
|
64
75
|
<pre>
|
65
|
-
|
76
|
+
<img src="/images/captchas/<%= session[:captcha] %>.jpg" />
|
66
77
|
<%= text_field_tag(:captcha) %>
|
67
78
|
</pre>
|
68
79
|
|
69
80
|
### In your controller
|
70
81
|
|
71
82
|
<pre>
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
Captchas will generate and re-generate automatically when a Rails instance starts. Captcha keeps the old batch of captchas around until the next re-generate so users do not get 404s.
|
79
|
-
|
80
|
-
We used the following URLs in our view:
|
81
|
-
* <code>/captcha</code> to retrieve the image
|
82
|
-
* <code>/captcha/new</code> to grab a new image
|
83
|
-
|
84
|
-
Use <code>session[:captcha]</code> to store, retrieve, and reset the captcha code.
|
83
|
+
user = User.new
|
84
|
+
user.known_captcha = session[:captcha]
|
85
|
+
user.captcha = params[:captcha]
|
86
|
+
user.save
|
87
|
+
</pre>
|
data/captcha.gemspec
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = 'captcha'
|
3
|
-
s.version = '1.
|
4
|
-
s.date = '2009-03-
|
3
|
+
s.version = '1.2.0'
|
4
|
+
s.date = '2009-03-27'
|
5
5
|
|
6
|
-
s.summary = "
|
7
|
-
s.description = "
|
6
|
+
s.summary = "A Google-style captcha for enterprise Rails apps"
|
7
|
+
s.description = "A Google-style captcha for enterprise Rails apps"
|
8
8
|
|
9
9
|
s.author = 'Winton Welsh'
|
10
10
|
s.email = 'mail@wintoni.us'
|
@@ -14,24 +14,22 @@ Gem::Specification.new do |s|
|
|
14
14
|
|
15
15
|
# = MANIFEST =
|
16
16
|
s.files = %w[
|
17
|
+
MIT-LICENSE
|
17
18
|
README.markdown
|
18
19
|
Rakefile
|
19
20
|
captcha.gemspec
|
20
21
|
init.rb
|
21
22
|
lib/captcha.rb
|
22
23
|
lib/captcha/action.rb
|
23
|
-
lib/captcha/
|
24
|
-
lib/captcha/captcha.rb
|
24
|
+
lib/captcha/cipher.rb
|
25
25
|
lib/captcha/config.rb
|
26
26
|
lib/captcha/generator.rb
|
27
27
|
lib/captcha/image.rb
|
28
|
-
lib/captcha/
|
28
|
+
lib/captcha/model.rb
|
29
29
|
resources/captcha.ttf
|
30
|
-
resources/captchas.rb
|
31
30
|
spec/lib/captcha_spec.rb
|
32
31
|
spec/spec.opts
|
33
32
|
spec/spec_helper.rb
|
34
|
-
tasks/captcha.rake
|
35
33
|
]
|
36
34
|
# = MANIFEST =
|
37
35
|
end
|
data/lib/captcha/action.rb
CHANGED
@@ -7,22 +7,26 @@ module Captcha
|
|
7
7
|
|
8
8
|
module ClassMethods
|
9
9
|
def acts_as_captcha
|
10
|
-
include
|
10
|
+
unless included_modules.include? InstanceMethods
|
11
|
+
include InstanceMethods
|
12
|
+
end
|
13
|
+
before_filter :assign_captcha
|
11
14
|
end
|
12
15
|
end
|
13
16
|
|
14
17
|
module InstanceMethods
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
18
|
+
private
|
19
|
+
|
20
|
+
def assign_captcha
|
21
|
+
unless session[:captcha] && Captcha::Config.exists?(session[:captcha])
|
22
|
+
files = Captcha::Config.captchas
|
23
|
+
session[:captcha] = File.basename(files[rand(files.length)], '.jpg')
|
24
|
+
end
|
19
25
|
end
|
20
|
-
|
21
|
-
def
|
22
|
-
|
23
|
-
|
24
|
-
new and return unless File.exists?(file)
|
25
|
-
send_file(file, :disposition => 'inline', :type => 'image/jpeg')
|
26
|
+
|
27
|
+
def reset_captcha
|
28
|
+
session[:captcha] = nil
|
29
|
+
assign_captcha
|
26
30
|
end
|
27
31
|
end
|
28
32
|
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'openssl'
|
2
|
+
require 'digest/sha1'
|
3
|
+
|
4
|
+
module Captcha
|
5
|
+
class Cipher
|
6
|
+
@@key = Digest::SHA1.hexdigest(Config.options[:password])
|
7
|
+
@@iv = 'captchas'*2
|
8
|
+
|
9
|
+
def self.encrypt(text)
|
10
|
+
# Encrypt
|
11
|
+
cipher = OpenSSL::Cipher::Cipher.new("aes-256-cbc")
|
12
|
+
cipher.encrypt
|
13
|
+
cipher.key = @@key
|
14
|
+
cipher.iv = @@iv
|
15
|
+
encrypted = cipher.update(text)
|
16
|
+
encrypted << cipher.final
|
17
|
+
# Turn into chr codes separated by underscores
|
18
|
+
# 135_14_163_53_43_135_172_31_1_23_169_81_49_110_49_230
|
19
|
+
encrypted = (0..encrypted.length-1).collect do |x|
|
20
|
+
encrypted[x]
|
21
|
+
end
|
22
|
+
encrypted.join('_')
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.decrypt(text)
|
26
|
+
# Decode chr coded string
|
27
|
+
encrypted = text.split('_').collect do |x|
|
28
|
+
x.to_i.chr
|
29
|
+
end
|
30
|
+
encrypted = encrypted.join('')
|
31
|
+
# Decrypt
|
32
|
+
cipher = OpenSSL::Cipher::Cipher.new("aes-256-cbc")
|
33
|
+
cipher.decrypt
|
34
|
+
cipher.key = @@key
|
35
|
+
cipher.iv = @@iv
|
36
|
+
decrypted = cipher.update(encrypted)
|
37
|
+
decrypted << cipher.final
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
data/lib/captcha/config.rb
CHANGED
@@ -1,11 +1,19 @@
|
|
1
1
|
module Captcha
|
2
2
|
class Config
|
3
3
|
|
4
|
-
|
5
|
-
RAILS_ENV == 'production' || RAILS_ENV == 'staging'
|
6
|
-
|
4
|
+
if defined?(RAILS_ENV)
|
5
|
+
PRODUCTION = RAILS_ENV == 'production' || RAILS_ENV == 'staging'
|
6
|
+
ROOT = "#{RAILS_ROOT}/"
|
7
|
+
else
|
8
|
+
PRODUCTION = false
|
9
|
+
ROOT = ""
|
10
|
+
end
|
11
|
+
ONE_DAY = 24 * 60 * 60
|
7
12
|
|
13
|
+
@@exists = {}
|
14
|
+
@@exists_since = Time.now
|
8
15
|
@@options = {
|
16
|
+
:password => 'captcha',
|
9
17
|
:colors => {
|
10
18
|
:background => '#FFFFFF',
|
11
19
|
:font => '#080288'
|
@@ -19,7 +27,7 @@ module Captcha
|
|
19
27
|
# canvas width (px)
|
20
28
|
:width => 110
|
21
29
|
},
|
22
|
-
:generate_every => PRODUCTION ?
|
30
|
+
:generate_every => PRODUCTION ? ONE_DAY * 1 : ONE_DAY * 10000,
|
23
31
|
# http://www.imagemagick.org/RMagick/doc/image2.html#implode
|
24
32
|
:implode => 0.2,
|
25
33
|
:letters => {
|
@@ -27,7 +35,7 @@ module Captcha
|
|
27
35
|
:baseline => 25,
|
28
36
|
# number of letters in captcha
|
29
37
|
:count => 6,
|
30
|
-
:ignore => ['a','e','i','o','u','l','j','q'],
|
38
|
+
:ignore => ['a','e','i','o','u','l','j','q','v'],
|
31
39
|
# font size (pts)
|
32
40
|
:points => 38,
|
33
41
|
# width of a character (used to decrease or increase space between characters) (px)
|
@@ -47,29 +55,25 @@ module Captcha
|
|
47
55
|
@@options.merge!(options)
|
48
56
|
end
|
49
57
|
|
50
|
-
def self.
|
51
|
-
|
52
|
-
files_modified = Dir["#{@@options[:destination]}/*.jpg"].collect do |file|
|
53
|
-
[ file, File.mtime(file) ]
|
54
|
-
end
|
55
|
-
# Youngest to oldest
|
56
|
-
files_modified.sort! { |a, b| b[1] <=> a[1] }
|
57
|
-
files_modified.collect { |f| f[0] }
|
58
|
+
def self.captchas
|
59
|
+
Dir["#{@@options[:destination]}/*.jpg"]
|
58
60
|
end
|
59
|
-
|
61
|
+
|
60
62
|
def self.codes
|
61
|
-
self.
|
63
|
+
self.captchas.collect do |f|
|
62
64
|
File.basename f, '.jpg'
|
63
65
|
end
|
64
66
|
end
|
65
67
|
|
66
|
-
def self.
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
68
|
+
def self.exists?(code)
|
69
|
+
if Time.now - @@exists_since > 60 * 60
|
70
|
+
@@exists = {}
|
71
|
+
@@exists_since = Time.now
|
72
|
+
end
|
73
|
+
unless @@exists[code]
|
74
|
+
@@exists[code] = File.exists?("#{@@options[:destination]}/#{code}.jpg")
|
72
75
|
end
|
76
|
+
@@exists[code]
|
73
77
|
end
|
74
78
|
|
75
79
|
def self.options
|
@@ -77,8 +81,12 @@ module Captcha
|
|
77
81
|
end
|
78
82
|
|
79
83
|
def self.last_modified
|
80
|
-
|
81
|
-
|
84
|
+
file = self.captchas.first
|
85
|
+
if file
|
86
|
+
File.mtime(file)
|
87
|
+
else
|
88
|
+
nil
|
89
|
+
end
|
82
90
|
end
|
83
91
|
end
|
84
92
|
end
|
data/lib/captcha/generator.rb
CHANGED
@@ -7,23 +7,20 @@ module Captcha
|
|
7
7
|
def generate
|
8
8
|
return unless Config.options
|
9
9
|
return if Config.last_modified && Config.last_modified > Time.now - Config.options[:generate_every]
|
10
|
+
path = Config.options[:destination]
|
11
|
+
if File.exists?(path)
|
12
|
+
FileUtils.rm_rf Config.options[:destination]
|
13
|
+
end
|
10
14
|
FileUtils.mkdir_p Config.options[:destination]
|
11
15
|
(1..Config.options[:count]).each do |x|
|
12
|
-
|
13
|
-
|
14
|
-
|
16
|
+
image = Image.new Config.options
|
17
|
+
path = "#{Config.options[:destination]}/#{Cipher.encrypt(image.code)}.jpg"
|
18
|
+
next if File.exists?(path)
|
19
|
+
File.open(path, 'w') do |f|
|
20
|
+
f << image.data
|
15
21
|
end
|
16
22
|
end
|
17
|
-
destroy_if_over_limit
|
18
23
|
GC.start
|
19
24
|
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
25
|
end
|
29
26
|
end
|
data/lib/captcha/image.rb
CHANGED
@@ -4,13 +4,12 @@ module Captcha
|
|
4
4
|
class Image
|
5
5
|
|
6
6
|
include Magick
|
7
|
-
attr_reader :code, :
|
7
|
+
attr_reader :code, :data
|
8
8
|
|
9
9
|
def initialize(o)
|
10
|
-
|
10
|
+
generate_code o
|
11
11
|
|
12
|
-
canvas = Magick::
|
13
|
-
canvas.new_image(o[:dimensions][:width], o[:dimensions][:height]) {
|
12
|
+
canvas = Magick::Image.new(o[:dimensions][:width], o[:dimensions][:height]) {
|
14
13
|
self.background_color = o[:colors][:background]
|
15
14
|
}
|
16
15
|
|
@@ -30,17 +29,19 @@ module Captcha
|
|
30
29
|
canvas = canvas.wave(o[:wave][:amplitude], rand(w.last - w.first) + w.first)
|
31
30
|
canvas = canvas.implode(o[:implode])
|
32
31
|
|
33
|
-
@code
|
34
|
-
@
|
32
|
+
@code = @code.to_s
|
33
|
+
@data = canvas.to_blob { self.format = "JPG" }
|
34
|
+
canvas.destroy!
|
35
35
|
end
|
36
36
|
|
37
37
|
private
|
38
38
|
|
39
39
|
def generate_code(o)
|
40
40
|
chars = ('a'..'z').to_a - o[:letters][:ignore]
|
41
|
-
|
42
|
-
1.upto(o[:letters][:count])
|
43
|
-
|
41
|
+
@code = []
|
42
|
+
1.upto(o[:letters][:count]) do
|
43
|
+
@code << chars[rand(chars.length)]
|
44
|
+
end
|
44
45
|
end
|
45
46
|
end
|
46
47
|
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module Captcha
|
2
|
+
module Model
|
3
|
+
def self.included(base)
|
4
|
+
base.extend ActMethods
|
5
|
+
end
|
6
|
+
|
7
|
+
module ActMethods
|
8
|
+
def acts_as_captcha(options={})
|
9
|
+
extend ClassMethods
|
10
|
+
include InstanceMethods
|
11
|
+
attr_reader :captcha, :known_captcha
|
12
|
+
cattr_accessor :captcha_options
|
13
|
+
self.captcha_options = options
|
14
|
+
validate :captcha_must_match_known_captcha
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
module ClassMethods
|
19
|
+
end
|
20
|
+
|
21
|
+
module InstanceMethods
|
22
|
+
def captcha=(c)
|
23
|
+
@captcha = c || ''
|
24
|
+
end
|
25
|
+
|
26
|
+
def known_captcha=(c)
|
27
|
+
@known_captcha = c || ''
|
28
|
+
end
|
29
|
+
|
30
|
+
def captcha_must_match_known_captcha
|
31
|
+
return true if self.captcha.nil? || self.known_captcha.nil?
|
32
|
+
if self.captcha.strip.downcase != Captcha::Cipher.decrypt(self.known_captcha)
|
33
|
+
if self.captcha_options[:base]
|
34
|
+
self.errors.add_to_base(
|
35
|
+
case self.captcha_options[:base]
|
36
|
+
when true
|
37
|
+
"Enter the correct text in the image (6 characters)"
|
38
|
+
else
|
39
|
+
self.captcha_options[:base]
|
40
|
+
end
|
41
|
+
)
|
42
|
+
else
|
43
|
+
self.errors.add(:captcha,
|
44
|
+
case self.captcha_options[:field]
|
45
|
+
when true, nil
|
46
|
+
"text does not match the text in the image."
|
47
|
+
else
|
48
|
+
self.captcha_options[:field]
|
49
|
+
end
|
50
|
+
)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
data/lib/captcha.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require File.dirname(__FILE__) + "/captcha/action.rb"
|
2
2
|
require File.dirname(__FILE__) + "/captcha/image.rb"
|
3
3
|
require File.dirname(__FILE__) + "/captcha/config.rb"
|
4
|
+
require File.dirname(__FILE__) + "/captcha/cipher.rb"
|
4
5
|
require File.dirname(__FILE__) + "/captcha/generator.rb"
|
data/spec/lib/captcha_spec.rb
CHANGED
@@ -17,47 +17,15 @@ describe :captcha do
|
|
17
17
|
it "should generate captchas" do
|
18
18
|
Captcha::Config.codes.length.should == 10
|
19
19
|
end
|
20
|
-
it "should
|
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
|
20
|
+
it "should generate fresh captchas if the files are older than the generate_every option" do
|
36
21
|
codes = Captcha::Config.codes
|
37
22
|
sleep @delay
|
38
23
|
@generator.generate
|
39
|
-
|
40
|
-
|
41
|
-
|
24
|
+
codes.should_not == Captcha::Config.codes
|
25
|
+
end
|
26
|
+
it "should not allow more than the captcha limit to exist" do
|
42
27
|
sleep @delay
|
43
28
|
@generator.generate
|
44
|
-
Captcha::Config.codes.length.should ==
|
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
|
29
|
+
Captcha::Config.codes.length.should == 10
|
62
30
|
end
|
63
31
|
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.
|
4
|
+
version: 1.2.0
|
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: 2009-03-
|
12
|
+
date: 2009-03-27 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|
16
|
-
description:
|
16
|
+
description: A Google-style captcha for enterprise Rails apps
|
17
17
|
email: mail@wintoni.us
|
18
18
|
executables: []
|
19
19
|
|
@@ -22,24 +22,22 @@ extensions: []
|
|
22
22
|
extra_rdoc_files: []
|
23
23
|
|
24
24
|
files:
|
25
|
+
- MIT-LICENSE
|
25
26
|
- README.markdown
|
26
27
|
- Rakefile
|
27
28
|
- captcha.gemspec
|
28
29
|
- init.rb
|
29
30
|
- lib/captcha.rb
|
30
31
|
- lib/captcha/action.rb
|
31
|
-
- lib/captcha/
|
32
|
-
- lib/captcha/captcha.rb
|
32
|
+
- lib/captcha/cipher.rb
|
33
33
|
- lib/captcha/config.rb
|
34
34
|
- lib/captcha/generator.rb
|
35
35
|
- lib/captcha/image.rb
|
36
|
-
- lib/captcha/
|
36
|
+
- lib/captcha/model.rb
|
37
37
|
- resources/captcha.ttf
|
38
|
-
- resources/captchas.rb
|
39
38
|
- spec/lib/captcha_spec.rb
|
40
39
|
- spec/spec.opts
|
41
40
|
- spec/spec_helper.rb
|
42
|
-
- tasks/captcha.rake
|
43
41
|
has_rdoc: false
|
44
42
|
homepage: http://github.com/winton/captcha
|
45
43
|
post_install_message:
|
@@ -65,6 +63,6 @@ rubyforge_project:
|
|
65
63
|
rubygems_version: 1.2.0
|
66
64
|
signing_key:
|
67
65
|
specification_version: 2
|
68
|
-
summary:
|
66
|
+
summary: A Google-style captcha for enterprise Rails apps
|
69
67
|
test_files: []
|
70
68
|
|