validates_captcha 0.9.4 → 0.9.5
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.rdoc +9 -0
- data/README.rdoc +2 -2
- data/lib/validates_captcha.rb +3 -3
- data/lib/validates_captcha/image_generator/simple.rb +10 -4
- data/lib/validates_captcha/provider/{image.rb → dynamic_image.rb} +14 -14
- data/lib/validates_captcha/string_generator/simple.rb +6 -3
- data/lib/validates_captcha/symmetric_encryptor/simple.rb +52 -0
- data/lib/validates_captcha/version.rb +1 -1
- data/test/cases/controller_validation_test.rb +1 -1
- data/test/cases/model_validation_test.rb +1 -1
- data/test/cases/provider/{image_test.rb → dynamic_image_test.rb} +11 -11
- data/test/cases/{reversible_encrypter → symmetric_encryptor}/simple_test.rb +7 -7
- metadata +9 -9
- data/lib/validates_captcha/reversible_encrypter/simple.rb +0 -55
data/CHANGELOG.rdoc
CHANGED
@@ -1,3 +1,12 @@
|
|
1
|
+
== 0.9.5 (October 9, 2009)
|
2
|
+
|
3
|
+
* API change: renamed Provider::Image to Provider::DynamicImage in order to guard against confusion
|
4
|
+
|
5
|
+
* API change: renamed ReversibleEncrypter to SymmetricEncryptor
|
6
|
+
|
7
|
+
* ReversibleEncrypter::Simple class now uses ActiveSupport's MessageEncryptor instead of custom implementation
|
8
|
+
|
9
|
+
|
1
10
|
== 0.9.4 (October 7, 2009)
|
2
11
|
|
3
12
|
* Include new StaticImage provider
|
data/README.rdoc
CHANGED
@@ -178,7 +178,7 @@ You can set the captcha provider to use dynamically created image challenges
|
|
178
178
|
with the code below. Dynamic means that the captcha image is created on invocation.
|
179
179
|
If you want to utilize this provider, it is best to put this in a Rails initializer.
|
180
180
|
|
181
|
-
ValidatesCaptcha.provider = ValidatesCaptcha::Provider::
|
181
|
+
ValidatesCaptcha.provider = ValidatesCaptcha::Provider::DynamicImage.new
|
182
182
|
|
183
183
|
By default, image captchas have a length of 6 characters and the text displayed
|
184
184
|
on the captcha image is created by randomly selecting characters from a
|
@@ -233,7 +233,7 @@ that creates images that are harder to crack.
|
|
233
233
|
Please see the documentation of the following classes for further information.
|
234
234
|
|
235
235
|
* ValidatesCaptcha::StringGenerator::Simple
|
236
|
-
* ValidatesCaptcha::
|
236
|
+
* ValidatesCaptcha::SymmetricEncryptor::Simple
|
237
237
|
* ValidatesCaptcha::ImageGenerator::Simple
|
238
238
|
|
239
239
|
Or you can implement a custom captcha challenge provider and assign it to
|
data/lib/validates_captcha.rb
CHANGED
@@ -37,7 +37,7 @@ module ValidatesCaptcha
|
|
37
37
|
|
38
38
|
module Provider
|
39
39
|
autoload :Question, 'validates_captcha/provider/question'
|
40
|
-
autoload :
|
40
|
+
autoload :DynamicImage, 'validates_captcha/provider/dynamic_image'
|
41
41
|
autoload :StaticImage, 'validates_captcha/provider/static_image'
|
42
42
|
end
|
43
43
|
|
@@ -45,8 +45,8 @@ module ValidatesCaptcha
|
|
45
45
|
autoload :Simple, 'validates_captcha/string_generator/simple'
|
46
46
|
end
|
47
47
|
|
48
|
-
module
|
49
|
-
autoload :Simple, 'validates_captcha/
|
48
|
+
module SymmetricEncryptor
|
49
|
+
autoload :Simple, 'validates_captcha/symmetric_encryptor/simple'
|
50
50
|
end
|
51
51
|
|
52
52
|
module ImageGenerator
|
@@ -19,8 +19,7 @@ module ValidatesCaptcha
|
|
19
19
|
# for your own implementations.
|
20
20
|
#
|
21
21
|
# You can implement your own (better) image generator by creating a
|
22
|
-
# class that conforms to the method definitions of the example below
|
23
|
-
# assign an instance of it to ValidatesCaptcha::Provider::Image#image_generator=.
|
22
|
+
# class that conforms to the method definitions of the example below.
|
24
23
|
#
|
25
24
|
# Example for a custom image generator:
|
26
25
|
#
|
@@ -40,8 +39,15 @@ module ValidatesCaptcha
|
|
40
39
|
# end
|
41
40
|
# end
|
42
41
|
#
|
43
|
-
#
|
44
|
-
#
|
42
|
+
# Then assign an instance of it to ValidatesCaptcha::Provider::DynamicImage#image_generator=.
|
43
|
+
#
|
44
|
+
# ValidatesCaptcha::Provider::DynamicImage.image_generator = AdvancedImageGenerator.new
|
45
|
+
# ValidatesCaptcha.provider = ValidatesCaptcha::Provider::DynamicImage.new
|
46
|
+
#
|
47
|
+
# Or to ValidatesCaptcha::Provider::StaticImage#image_generator=.
|
48
|
+
#
|
49
|
+
# ValidatesCaptcha::Provider::StaticImage.image_generator = AdvancedImageGenerator.new
|
50
|
+
# ValidatesCaptcha.provider = ValidatesCaptcha::Provider::StaticImage.new
|
45
51
|
#
|
46
52
|
class Simple
|
47
53
|
MIME_TYPE = 'image/gif'.freeze
|
@@ -63,7 +63,7 @@ module ValidatesCaptcha
|
|
63
63
|
# An image captcha provider.
|
64
64
|
#
|
65
65
|
# This class contains the getters and setters for the backend classes:
|
66
|
-
# image generator, string generator, and
|
66
|
+
# image generator, string generator, and symmetric encryptor. This
|
67
67
|
# allows you to replace them with your custom implementations. For more
|
68
68
|
# information on how to bring the image provider to use your own
|
69
69
|
# implementation instead of the default one, consult the documentation
|
@@ -75,11 +75,11 @@ module ValidatesCaptcha
|
|
75
75
|
# But you are not bound to ImageMagick. If you want to provide a custom image
|
76
76
|
# generator, take a look at the documentation for
|
77
77
|
# ValidatesCaptcha::ImageGenerator::Simple on how to create your own.
|
78
|
-
class
|
78
|
+
class DynamicImage
|
79
79
|
include ActionView::Helpers
|
80
80
|
|
81
81
|
@@string_generator = nil
|
82
|
-
@@
|
82
|
+
@@symmetric_encryptor = nil
|
83
83
|
@@image_generator = nil
|
84
84
|
|
85
85
|
class << self
|
@@ -95,16 +95,16 @@ module ValidatesCaptcha
|
|
95
95
|
@@string_generator = generator
|
96
96
|
end
|
97
97
|
|
98
|
-
# Returns the current captcha
|
99
|
-
# instance of the ValidatesCaptcha::
|
100
|
-
def
|
101
|
-
@@
|
98
|
+
# Returns the current captcha symmetric encryptor. Defaults to an
|
99
|
+
# instance of the ValidatesCaptcha::SymmetricEncryptor::Simple class.
|
100
|
+
def symmetric_encryptor
|
101
|
+
@@symmetric_encryptor ||= ValidatesCaptcha::SymmetricEncryptor::Simple.new
|
102
102
|
end
|
103
103
|
|
104
|
-
# Sets the current captcha
|
105
|
-
# custom
|
106
|
-
def
|
107
|
-
@@
|
104
|
+
# Sets the current captcha symmetric encryptor. Used to set a
|
105
|
+
# custom symmetric encryptor.
|
106
|
+
def symmetric_encryptor=(encryptor)
|
107
|
+
@@symmetric_encryptor = encryptor
|
108
108
|
end
|
109
109
|
|
110
110
|
# Returns the current captcha image generator. Defaults to an
|
@@ -166,7 +166,7 @@ module ValidatesCaptcha
|
|
166
166
|
# Returns true if the captcha was solved using the given +challenge+ and +solution+,
|
167
167
|
# otherwise false.
|
168
168
|
def solved?(challenge, solution)
|
169
|
-
challenge ==
|
169
|
+
decrypt(challenge) == solution
|
170
170
|
end
|
171
171
|
|
172
172
|
# Returns an image tag with the source set to the url of the captcha image.
|
@@ -211,11 +211,11 @@ module ValidatesCaptcha
|
|
211
211
|
end
|
212
212
|
|
213
213
|
def encrypt(code) #:nodoc:
|
214
|
-
self.class.
|
214
|
+
self.class.symmetric_encryptor.encrypt code
|
215
215
|
end
|
216
216
|
|
217
217
|
def decrypt(encrypted_code) #:nodoc:
|
218
|
-
self.class.
|
218
|
+
self.class.symmetric_encryptor.decrypt encrypted_code
|
219
219
|
end
|
220
220
|
|
221
221
|
def generate_code #:nodoc:
|
@@ -10,7 +10,8 @@ module ValidatesCaptcha
|
|
10
10
|
#
|
11
11
|
# You can implement your own string generator by creating a
|
12
12
|
# class that conforms to the method definitions of the example below and
|
13
|
-
# assign an instance of it to
|
13
|
+
# assign an instance of it to
|
14
|
+
# ValidatesCaptcha::Provider::DynamicImage#string_generator=.
|
14
15
|
#
|
15
16
|
# Example for a custom string generator:
|
16
17
|
#
|
@@ -22,8 +23,10 @@ module ValidatesCaptcha
|
|
22
23
|
# end
|
23
24
|
# end
|
24
25
|
#
|
25
|
-
# ValidatesCaptcha::Provider::
|
26
|
-
# ValidatesCaptcha.provider = ValidatesCaptcha::Provider::
|
26
|
+
# ValidatesCaptcha::Provider::DynamicImage.string_generator = DictionaryGenerator.new
|
27
|
+
# ValidatesCaptcha.provider = ValidatesCaptcha::Provider::DynamicImage.new
|
28
|
+
#
|
29
|
+
# You can also assign it to ValidatesCaptcha::Provider::StaticImage#string_generator=.
|
27
30
|
#
|
28
31
|
class Simple
|
29
32
|
@@alphabet = 'abdefghjkmnqrtABDEFGHJKLMNQRT234678923467892346789'
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'active_support'
|
2
|
+
|
3
|
+
module ValidatesCaptcha
|
4
|
+
module SymmetricEncryptor
|
5
|
+
# This class is responsible for encrypting and decrypting captcha codes.
|
6
|
+
# It internally uses ActiveSupport's MessageEncryptor to do the string
|
7
|
+
# encryption/decryption.
|
8
|
+
#
|
9
|
+
# You can implement your own symmetric encryptor by creating a class
|
10
|
+
# that conforms to the method definitions of the example below and
|
11
|
+
# assign an instance of it to
|
12
|
+
# ValidatesCaptcha::Provider::DynamicImage#symmetric_encryptor=.
|
13
|
+
#
|
14
|
+
# Example for a custom symmetric encryptor:
|
15
|
+
#
|
16
|
+
# class ReverseString # very insecure and easily cracked
|
17
|
+
# def encrypt(code)
|
18
|
+
# code.reverse
|
19
|
+
# end
|
20
|
+
#
|
21
|
+
# def decrypt(encrypted_code)
|
22
|
+
# encrypted_code.reverse
|
23
|
+
# rescue SomeKindOfDecryptionError
|
24
|
+
# nil
|
25
|
+
# end
|
26
|
+
# end
|
27
|
+
#
|
28
|
+
# ValidatesCaptcha::Provider::DynamicImage.symmetric_encryptor = ReverseString.new
|
29
|
+
# ValidatesCaptcha.provider = ValidatesCaptcha::Provider::DynamicImage.new
|
30
|
+
#
|
31
|
+
# Please note: The #decrypt method should return +nil+ if decryption fails.
|
32
|
+
class Simple
|
33
|
+
KEY = ::ActiveSupport::SecureRandom.hex(64).freeze
|
34
|
+
|
35
|
+
def initialize #:nodoc:
|
36
|
+
@symmetric_encryptor = ::ActiveSupport::MessageEncryptor.new(KEY)
|
37
|
+
end
|
38
|
+
|
39
|
+
# Encrypts a cleartext string.
|
40
|
+
def encrypt(code)
|
41
|
+
@symmetric_encryptor.encrypt(code).gsub('+', '%2B').gsub('/', '%2F')
|
42
|
+
end
|
43
|
+
|
44
|
+
# Decrypts an encrypted string.
|
45
|
+
def decrypt(encrypted_code)
|
46
|
+
@symmetric_encryptor.decrypt encrypted_code.gsub('%2F', '/').gsub('%2B', '+')
|
47
|
+
rescue ::ActiveSupport::MessageEncryptor::InvalidMessage
|
48
|
+
nil
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -78,7 +78,7 @@ class ControllerValidationTest < ActionController::TestCase
|
|
78
78
|
|
79
79
|
def with_dynamic_image_provider(&block)
|
80
80
|
old_provider = ValidatesCaptcha.provider
|
81
|
-
provider = ValidatesCaptcha.provider = ValidatesCaptcha::Provider::
|
81
|
+
provider = ValidatesCaptcha.provider = ValidatesCaptcha::Provider::DynamicImage.new
|
82
82
|
yield provider
|
83
83
|
ValidatesCaptcha.provider = old_provider
|
84
84
|
end
|
@@ -3,7 +3,7 @@ require 'test_helper'
|
|
3
3
|
class ModelValidationTest < ValidatesCaptcha::TestCase
|
4
4
|
def with_dynamic_image_provider(&block)
|
5
5
|
old_provider = ValidatesCaptcha.provider
|
6
|
-
provider = ValidatesCaptcha.provider = ValidatesCaptcha::Provider::
|
6
|
+
provider = ValidatesCaptcha.provider = ValidatesCaptcha::Provider::DynamicImage.new
|
7
7
|
yield provider
|
8
8
|
ValidatesCaptcha.provider = old_provider
|
9
9
|
end
|
@@ -1,8 +1,8 @@
|
|
1
1
|
require 'test_helper'
|
2
2
|
|
3
|
-
IMAGE = ValidatesCaptcha::Provider::
|
3
|
+
IMAGE = ValidatesCaptcha::Provider::DynamicImage
|
4
4
|
|
5
|
-
class
|
5
|
+
class DynamicImageTest < ValidatesCaptcha::TestCase
|
6
6
|
test "defines a class level #string_generator method" do
|
7
7
|
assert_respond_to IMAGE, :string_generator
|
8
8
|
end
|
@@ -20,21 +20,21 @@ class ImageTest < ValidatesCaptcha::TestCase
|
|
20
20
|
IMAGE.string_generator = old_string_generator
|
21
21
|
end
|
22
22
|
|
23
|
-
test "defines a class level #
|
24
|
-
assert_respond_to IMAGE, :
|
23
|
+
test "defines a class level #symmetric_encryptor method" do
|
24
|
+
assert_respond_to IMAGE, :symmetric_encryptor
|
25
25
|
end
|
26
26
|
|
27
|
-
test "defines a class level #
|
28
|
-
assert_respond_to IMAGE, :
|
27
|
+
test "defines a class level #symmetric_encryptor= method" do
|
28
|
+
assert_respond_to IMAGE, :symmetric_encryptor=
|
29
29
|
end
|
30
30
|
|
31
|
-
test "#
|
32
|
-
|
31
|
+
test "#symmetric_encryptor method's return value should equal the value set using the #symmetric_encryptor= method" do
|
32
|
+
old_symmetric_encryptor = IMAGE.symmetric_encryptor
|
33
33
|
|
34
|
-
IMAGE.
|
35
|
-
assert_equal 'abc', IMAGE.
|
34
|
+
IMAGE.symmetric_encryptor = 'abc'
|
35
|
+
assert_equal 'abc', IMAGE.symmetric_encryptor
|
36
36
|
|
37
|
-
IMAGE.
|
37
|
+
IMAGE.symmetric_encryptor = old_symmetric_encryptor
|
38
38
|
end
|
39
39
|
|
40
40
|
test "defines a class level #image_generator method" do
|
@@ -1,27 +1,27 @@
|
|
1
1
|
require 'test_helper'
|
2
2
|
|
3
|
-
|
3
|
+
SE = ValidatesCaptcha::SymmetricEncryptor::Simple
|
4
4
|
|
5
|
-
class
|
5
|
+
class SymmetricEncryptorTest < ValidatesCaptcha::TestCase
|
6
6
|
test "defines an instance level #encrypt method" do
|
7
|
-
assert_respond_to
|
7
|
+
assert_respond_to SE.new, :encrypt
|
8
8
|
end
|
9
9
|
|
10
10
|
test "instance level #encrypt method returns a string" do
|
11
|
-
assert_kind_of String,
|
11
|
+
assert_kind_of String, SE.new.encrypt('abc')
|
12
12
|
end
|
13
13
|
|
14
14
|
test "defines an instance level #decrypt method" do
|
15
|
-
assert_respond_to
|
15
|
+
assert_respond_to SE.new, :decrypt
|
16
16
|
end
|
17
17
|
|
18
18
|
test "instance level #decrypt method returns nil if decryption failes" do
|
19
|
-
assert_nil
|
19
|
+
assert_nil SE.new.decrypt('invalid')
|
20
20
|
end
|
21
21
|
|
22
22
|
test "decryption of encryption of string should equal the string" do
|
23
23
|
%w(d3crypti0n 3ncrypt3d 5trin9 sh0u1d equ41 th3 c4ptch4).each do |captcha|
|
24
|
-
assert_equal captcha,
|
24
|
+
assert_equal captcha, SE.new.decrypt(SE.new.encrypt(captcha))
|
25
25
|
end
|
26
26
|
end
|
27
27
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: validates_captcha
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.9.
|
4
|
+
version: 0.9.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Martin Andert
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-10-
|
12
|
+
date: 2009-10-09 00:00:00 +02:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -53,11 +53,11 @@ files:
|
|
53
53
|
- lib/validates_captcha/form_helper.rb
|
54
54
|
- lib/validates_captcha/image_generator/simple.rb
|
55
55
|
- lib/validates_captcha/model_validation.rb
|
56
|
-
- lib/validates_captcha/provider/
|
56
|
+
- lib/validates_captcha/provider/dynamic_image.rb
|
57
57
|
- lib/validates_captcha/provider/question.rb
|
58
58
|
- lib/validates_captcha/provider/static_image.rb
|
59
|
-
- lib/validates_captcha/reversible_encrypter/simple.rb
|
60
59
|
- lib/validates_captcha/string_generator/simple.rb
|
60
|
+
- lib/validates_captcha/symmetric_encryptor/simple.rb
|
61
61
|
- lib/validates_captcha/test_case.rb
|
62
62
|
- lib/validates_captcha/version.rb
|
63
63
|
- rails/init.rb
|
@@ -65,11 +65,11 @@ files:
|
|
65
65
|
- test/cases/controller_validation_test.rb
|
66
66
|
- test/cases/image_generator/simple_test.rb
|
67
67
|
- test/cases/model_validation_test.rb
|
68
|
-
- test/cases/provider/
|
68
|
+
- test/cases/provider/dynamic_image_test.rb
|
69
69
|
- test/cases/provider/question_test.rb
|
70
70
|
- test/cases/provider/static_image_test.rb
|
71
|
-
- test/cases/reversible_encrypter/simple_test.rb
|
72
71
|
- test/cases/string_generator/simple_test.rb
|
72
|
+
- test/cases/symmetric_encryptor/simple_test.rb
|
73
73
|
- test/cases/validates_captcha_test.rb
|
74
74
|
- test/test_helper.rb
|
75
75
|
has_rdoc: true
|
@@ -79,7 +79,7 @@ licenses: []
|
|
79
79
|
post_install_message:
|
80
80
|
rdoc_options:
|
81
81
|
- --title
|
82
|
-
- Validates Captcha 0.9.
|
82
|
+
- Validates Captcha 0.9.5
|
83
83
|
- --main
|
84
84
|
- README.rdoc
|
85
85
|
- --line-numbers
|
@@ -111,10 +111,10 @@ test_files:
|
|
111
111
|
- test/cases/controller_validation_test.rb
|
112
112
|
- test/cases/image_generator/simple_test.rb
|
113
113
|
- test/cases/model_validation_test.rb
|
114
|
-
- test/cases/provider/
|
114
|
+
- test/cases/provider/dynamic_image_test.rb
|
115
115
|
- test/cases/provider/question_test.rb
|
116
116
|
- test/cases/provider/static_image_test.rb
|
117
|
-
- test/cases/reversible_encrypter/simple_test.rb
|
118
117
|
- test/cases/string_generator/simple_test.rb
|
118
|
+
- test/cases/symmetric_encryptor/simple_test.rb
|
119
119
|
- test/cases/validates_captcha_test.rb
|
120
120
|
- test/test_helper.rb
|
@@ -1,55 +0,0 @@
|
|
1
|
-
require 'openssl'
|
2
|
-
require 'active_support/secure_random'
|
3
|
-
|
4
|
-
module ValidatesCaptcha
|
5
|
-
module ReversibleEncrypter
|
6
|
-
# This class is responsible for encrypting and decrypting captcha codes.
|
7
|
-
# It internally uses AES256 to do the string encryption/decryption.
|
8
|
-
#
|
9
|
-
# You can implement your own reversible encrypter by creating a class
|
10
|
-
# that conforms to the method definitions of the example below and
|
11
|
-
# assign an instance of it to ValidatesCaptcha::Provider::Image#reversible_encrypter=.
|
12
|
-
#
|
13
|
-
# Example for a custom encrypter/decrypter:
|
14
|
-
#
|
15
|
-
# class ReverseString # very insecure and easily cracked
|
16
|
-
# def encrypt(code)
|
17
|
-
# code.reverse
|
18
|
-
# end
|
19
|
-
#
|
20
|
-
# def decrypt(encrypted_code)
|
21
|
-
# encrypted_code.reverse
|
22
|
-
# rescue SomeKindOfDecryptionError
|
23
|
-
# nil
|
24
|
-
# end
|
25
|
-
# end
|
26
|
-
#
|
27
|
-
# ValidatesCaptcha::Provider::Image.reversible_encrypter = ReverseString.new
|
28
|
-
# ValidatesCaptcha.provider = ValidatesCaptcha::Provider::Image.new
|
29
|
-
#
|
30
|
-
# Please note: The #decrypt method should return +nil+ if decryption fails.
|
31
|
-
class Simple
|
32
|
-
KEY = ::ActiveSupport::SecureRandom.hex(32).freeze
|
33
|
-
|
34
|
-
def initialize #:nodoc:
|
35
|
-
@aes = OpenSSL::Cipher::Cipher.new('AES-256-ECB')
|
36
|
-
end
|
37
|
-
|
38
|
-
# Encrypts a cleartext string using #key as encryption key.
|
39
|
-
def encrypt(code)
|
40
|
-
@aes.encrypt
|
41
|
-
@aes.key = KEY
|
42
|
-
[@aes.update(code) + @aes.final].pack("m").tr('+/=', '-_ ').strip.gsub("\n", '')
|
43
|
-
end
|
44
|
-
|
45
|
-
# Decrypts an encrypted string using using #key as decryption key.
|
46
|
-
def decrypt(encrypted_code)
|
47
|
-
@aes.decrypt
|
48
|
-
@aes.key = KEY
|
49
|
-
@aes.update((encrypted_code + '=' * (4 - encrypted_code.size % 4)).tr('-_', '+/').unpack("m").first) + @aes.final
|
50
|
-
rescue # OpenSSL::CipherError, OpenSSL::Cipher::CipherError
|
51
|
-
nil
|
52
|
-
end
|
53
|
-
end
|
54
|
-
end
|
55
|
-
end
|