dionysus 0.3.0 → 0.3.1
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/Rakefile +2 -0
- data/VERSION +1 -1
- data/dionysus.gemspec +2 -2
- data/lib/dionysus/digest.rb +47 -17
- data/lib/dionysus/security/password_salt.rb +3 -11
- data/lib/dionysus/security/string.rb +22 -11
- data/lib/dionysus/string.rb +1 -0
- data/spec/digest_spec.rb +66 -8
- data/spec/password_salt_spec.rb +10 -0
- data/spec/string_security_spec.rb +22 -0
- metadata +3 -3
data/Rakefile
CHANGED
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.3.
|
1
|
+
0.3.1
|
data/dionysus.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{dionysus}
|
8
|
-
s.version = "0.3.
|
8
|
+
s.version = "0.3.1"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Travis D. Warlick, Jr."]
|
12
|
-
s.date = %q{2010-04-
|
12
|
+
s.date = %q{2010-04-04}
|
13
13
|
s.email = %q{warlickt@operissystems.com}
|
14
14
|
s.extra_rdoc_files = [
|
15
15
|
"LICENSE",
|
data/lib/dionysus/digest.rb
CHANGED
@@ -65,21 +65,15 @@ module Digest
|
|
65
65
|
##
|
66
66
|
# The lengths of the registered digests in the given encoding.
|
67
67
|
def self.digest_lengths( encoding = :binary )
|
68
|
-
if encoding
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
when :hex, :hexidecimal then 4
|
73
|
-
when :bit then 1
|
74
|
-
else raise ArgumentError, "Invalid encoding"
|
75
|
-
end
|
68
|
+
if encoding == :bit or encoding == 1
|
69
|
+
_digest_lengths(1)
|
70
|
+
elsif encoding.is_a?(Symbol) and String::ENCODING_BITS_PER_CHAR[encoding]
|
71
|
+
_digest_lengths(String::ENCODING_BITS_PER_CHAR[encoding])
|
76
72
|
elsif encoding.is_a?(Integer) and encoding > 0
|
77
|
-
|
73
|
+
_digest_lengths(encoding)
|
78
74
|
else
|
79
75
|
raise ArgumentError, "Invalid encoding"
|
80
76
|
end
|
81
|
-
|
82
|
-
Hash[ self.digests.collect { |dig, info| [dig, info[:bit_length] / bits_per_char] } ]
|
83
77
|
end
|
84
78
|
|
85
79
|
##
|
@@ -89,12 +83,48 @@ module Digest
|
|
89
83
|
#
|
90
84
|
# Digest.digest(:sha512, 'foobar') #=> binary digest
|
91
85
|
# Digest.digest(Digest::SHA512, 'foobar') #=> binary digest
|
92
|
-
def self.digest(
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
86
|
+
def self.digest( sym, str )
|
87
|
+
Digest.const_get(sym.to_s.upcase).digest(str)
|
88
|
+
end
|
89
|
+
|
90
|
+
##
|
91
|
+
# Detect the digest of the string. Returns nil if the digest cannot be
|
92
|
+
# determined.
|
93
|
+
#
|
94
|
+
# Example:
|
95
|
+
# Digest.detect_digest("wxeCFXPVXePFcpwuFDjonyn1G/w=", :base64) #=> :sha1
|
96
|
+
# Digest.detect_digest("foobar", :hex) #=> nil
|
97
|
+
def self.detect_digest( string, encoding = :binary )
|
98
|
+
string = string.strip unless encoding == :binary
|
99
|
+
dig = self.digest_lengths(encoding).invert[string.length]
|
100
|
+
dig = :sha256 if dig == :sha2
|
101
|
+
dig
|
102
|
+
end
|
103
|
+
|
104
|
+
##
|
105
|
+
# Detect the digest of the string. Returns nil if the digest cannot be
|
106
|
+
# determined.
|
107
|
+
#
|
108
|
+
# Example:
|
109
|
+
# Digest.detect_digest!("wxeCFXPVXePFcpwuFDjonyn1G/w=", :base64) #=> :sha1
|
110
|
+
# Digest.detect_digest!("foobar", :hex) #=> RuntimeError
|
111
|
+
def self.detect_digest!( string, encoding = :binary )
|
112
|
+
self.detect_digest(string, encoding) or raise("Unknown digest")
|
113
|
+
end
|
114
|
+
|
115
|
+
private
|
116
|
+
|
117
|
+
def self._digest_lengths( bits_per_char ) # :nodoc:
|
118
|
+
padding_factor = (bits_per_char.lcm(8) / bits_per_char)
|
119
|
+
|
120
|
+
returning result={} do
|
121
|
+
self.digests.each do |dig, info|
|
122
|
+
result[dig] = len = info[:bit_length] / bits_per_char
|
123
|
+
if (t_ = len % padding_factor) != 0
|
124
|
+
result[dig] = len + (padding_factor - t_)
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
98
128
|
end
|
99
129
|
end
|
100
130
|
|
@@ -77,19 +77,11 @@ class PasswordSalt
|
|
77
77
|
# Default: 8
|
78
78
|
def initialize( *args )
|
79
79
|
options = args.extract_options!
|
80
|
-
if args[0].nil? or args[0] == :new or args[0].is_a?(String)
|
81
|
-
self.string = args[0] || :new
|
82
|
-
end
|
83
80
|
|
84
|
-
|
85
|
-
|
86
|
-
elsif args[1].is_a?(Symbol)
|
87
|
-
self.placement = args[1]
|
88
|
-
else
|
89
|
-
self.placement = DEFAULT_PLACEMENT
|
90
|
-
end
|
81
|
+
self.string = args.detect { |val| val.is_a?(String) or val == :new }
|
82
|
+
self.placement = args.detect { |val| PLACEMENTS.include?(val) } || DEFAULT_PLACEMENT
|
91
83
|
|
92
|
-
if self.string == :new
|
84
|
+
if self.string == :new or self.string.nil?
|
93
85
|
self.string = self.class.generate(options[:length] || DEFAULT_LENGTH)
|
94
86
|
end
|
95
87
|
end
|
@@ -53,22 +53,33 @@ class String
|
|
53
53
|
def method_missing( method, *args )
|
54
54
|
super if block_given?
|
55
55
|
|
56
|
-
|
57
|
-
|
58
|
-
|
56
|
+
if Digest.available_digests.include?(method)
|
57
|
+
self.digest(method, *args)
|
58
|
+
else
|
59
|
+
super
|
59
60
|
end
|
60
|
-
super
|
61
61
|
end
|
62
62
|
|
63
63
|
##
|
64
|
-
# Detect the digest of the string
|
64
|
+
# Detect the digest of the string. Returns nil if the digest cannot be
|
65
|
+
# determined.
|
66
|
+
#
|
67
|
+
# Example:
|
68
|
+
# "wxeCFXPVXePFcpwuFDjonyn1G/w=".detect_digest(:base64) #=> :sha1
|
69
|
+
# "foobar".detect_digest(:hex) #=> nil
|
65
70
|
def detect_digest( encoding )
|
66
|
-
self
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
71
|
+
Digest.detect_digest(self, encoding)
|
72
|
+
end
|
73
|
+
|
74
|
+
##
|
75
|
+
# Detect the digest of the string. Raises "Unknown digest" if the digest
|
76
|
+
# cannot be determined.
|
77
|
+
#
|
78
|
+
# Example:
|
79
|
+
# "wxeCFXPVXePFcpwuFDjonyn1G/w=".detect_digest!(:base64) #=> :sha1
|
80
|
+
# "foobar".detect_digest!(:hex) #=> RuntimeError
|
81
|
+
def detect_digest!( encoding )
|
82
|
+
Digest.detect_digest!(self, encoding)
|
72
83
|
end
|
73
84
|
|
74
85
|
private
|
data/lib/dionysus/string.rb
CHANGED
data/spec/digest_spec.rb
CHANGED
@@ -3,6 +3,8 @@ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
|
3
3
|
require 'dionysus/digest'
|
4
4
|
|
5
5
|
describe Digest do
|
6
|
+
DIGESTS = { :md5 => 128, :sha1 => 160, :sha2 => 256,
|
7
|
+
:sha256 => 256, :sha384 => 384, :sha512 => 512 }
|
6
8
|
it 'should have the default available digests' do
|
7
9
|
Digest.available_digests.length.should == Digest::DEFAULT_DIGESTS.length
|
8
10
|
Digest::DEFAULT_DIGESTS.each do |dig|
|
@@ -87,8 +89,7 @@ describe Digest do
|
|
87
89
|
end
|
88
90
|
|
89
91
|
describe 'digest lengths' do
|
90
|
-
|
91
|
-
:sha256 => 256, :sha384 => 384, :sha512 => 512 }.each do |dig, bits|
|
92
|
+
DIGESTS.each do |dig, bits|
|
92
93
|
it "should have binary length for #{dig}" do
|
93
94
|
Digest.digest_lengths[dig].should == bits / 8
|
94
95
|
Digest.digest_lengths(:binary)[dig].should == bits / 8
|
@@ -102,8 +103,10 @@ describe Digest do
|
|
102
103
|
end
|
103
104
|
|
104
105
|
it "should have base64 length for #{dig}" do
|
105
|
-
|
106
|
-
|
106
|
+
len = bits / 6
|
107
|
+
expected = (len % 4 == 0 ? len : len + (4 - len % 4))
|
108
|
+
Digest.digest_lengths(:base64)[dig].should == expected
|
109
|
+
Digest.digest_lengths(6)[dig].should == expected
|
107
110
|
end
|
108
111
|
|
109
112
|
it "should have bit length for #{dig}" do
|
@@ -112,14 +115,69 @@ describe Digest do
|
|
112
115
|
end
|
113
116
|
|
114
117
|
it "should have arbitrary length for #{dig}" do
|
115
|
-
|
118
|
+
len = bits / 7
|
119
|
+
Digest.digest_lengths(7)[dig].should == len + (8 - len % 8)
|
116
120
|
end
|
117
121
|
end
|
118
122
|
|
119
123
|
it 'should reject bit length requests for < 0' do
|
120
|
-
lambda { Digest.digest_lengths(0).should raise_error(ArgumentError, 'Invalid encoding')
|
121
|
-
lambda { Digest.digest_lengths(-1).should raise_error(ArgumentError, 'Invalid encoding')
|
122
|
-
lambda { Digest.digest_lengths(-100).should raise_error(ArgumentError, 'Invalid encoding')
|
124
|
+
lambda { Digest.digest_lengths(0) }.should raise_error(ArgumentError, 'Invalid encoding')
|
125
|
+
lambda { Digest.digest_lengths(-1) }.should raise_error(ArgumentError, 'Invalid encoding')
|
126
|
+
lambda { Digest.digest_lengths(-100) }.should raise_error(ArgumentError, 'Invalid encoding')
|
127
|
+
end
|
128
|
+
|
129
|
+
it 'should reject bit length requests for unknown encodings' do
|
130
|
+
lambda { Digest.digest_lengths(:my_digest) }.should raise_error(ArgumentError, 'Invalid encoding')
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
describe "digest helper" do
|
135
|
+
DIGESTS.each do |dig, bits|
|
136
|
+
it "should run the digest for #{dig}" do
|
137
|
+
Digest.digest(dig, 'foobar').length.should == bits / 8
|
138
|
+
end
|
139
|
+
|
140
|
+
it "should still have working original digest methods" do
|
141
|
+
"Digest::#{dig.to_s.upcase}".constantize.digest('foobar').length.should == bits / 8
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
it "should fail invalid digest" do
|
146
|
+
lambda { Digest.digest(:my_digest, 'foobar') }.should raise_error(LoadError)
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
describe "detection" do
|
151
|
+
DIGESTS.each do |dig, bits|
|
152
|
+
it "should detect #{dig} in binary" do
|
153
|
+
str = Digest.digest(dig, 'foobar')
|
154
|
+
Digest.detect_digest(str).should == (dig == :sha2 ? :sha256 : dig)
|
155
|
+
Digest.detect_digest(str, :binary).should == (dig == :sha2 ? :sha256 : dig)
|
156
|
+
Digest.detect_digest!(str).should == (dig == :sha2 ? :sha256 : dig)
|
157
|
+
Digest.detect_digest!(str, :binary).should == (dig == :sha2 ? :sha256 : dig)
|
158
|
+
end
|
159
|
+
|
160
|
+
it "should detect #{dig} in base64" do
|
161
|
+
str = Digest.digest(dig, 'foobar').encode64s
|
162
|
+
Digest.detect_digest(str, :base64).should == (dig == :sha2 ? :sha256 : dig)
|
163
|
+
Digest.detect_digest!(str, :base64).should == (dig == :sha2 ? :sha256 : dig)
|
164
|
+
end
|
165
|
+
|
166
|
+
it "should detect #{dig} in hexidecimal" do
|
167
|
+
str = Digest.digest(dig, 'foobar').encode_hexidecimal
|
168
|
+
Digest.detect_digest(str, :hex).should == (dig == :sha2 ? :sha256 : dig)
|
169
|
+
Digest.detect_digest(str, :hexidecimal).should == (dig == :sha2 ? :sha256 : dig)
|
170
|
+
Digest.detect_digest!(str, :hex).should == (dig == :sha2 ? :sha256 : dig)
|
171
|
+
Digest.detect_digest!(str, :hexidecimal).should == (dig == :sha2 ? :sha256 : dig)
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
it "should return nil on unknown digest" do
|
176
|
+
Digest.detect_digest('blah').should be_nil
|
177
|
+
end
|
178
|
+
|
179
|
+
it "should fail on unknown digest with !" do
|
180
|
+
lambda { Digest.detect_digest!('blah') }.should raise_error(RuntimeError, "Unknown digest")
|
123
181
|
end
|
124
182
|
end
|
125
183
|
end
|
data/spec/password_salt_spec.rb
CHANGED
@@ -93,6 +93,10 @@ describe PasswordSalt do
|
|
93
93
|
salt.should_not match(/\A[A-Za-z0-9\+\/]{100}\Z/)
|
94
94
|
end
|
95
95
|
end
|
96
|
+
|
97
|
+
it "should raise an error with an invalid format" do
|
98
|
+
lambda { PasswordSalt.generate(10, :foobar) }.should raise_error(ArgumentError, "Invalid format: foobar")
|
99
|
+
end
|
96
100
|
end
|
97
101
|
|
98
102
|
describe "after placement" do
|
@@ -110,6 +114,12 @@ describe PasswordSalt do
|
|
110
114
|
salt = PasswordSalt.new(@salt, :after)
|
111
115
|
salt.salt_password(@password).should == @password+@salt
|
112
116
|
end
|
117
|
+
|
118
|
+
it "should raise an error with a bad placement" do
|
119
|
+
salt = PasswordSalt.new(@salt)
|
120
|
+
salt.instance_variable_set('@placement', :foobar)
|
121
|
+
lambda { salt.salt_password(@password) }.should raise_error(RuntimeError, "Invalid salt placement: foobar")
|
122
|
+
end
|
113
123
|
end
|
114
124
|
|
115
125
|
describe "before placement" do
|
@@ -179,4 +179,26 @@ describe String do
|
|
179
179
|
"abcde\240z405".digest(:md5, :encoding => :binary).should == digest
|
180
180
|
"abcde\240z405".md5(:encoding => :binary).should == digest
|
181
181
|
end
|
182
|
+
|
183
|
+
it "should fallback to super method missing with unavailable digest" do
|
184
|
+
lambda { "abcde\240z405".my_digest }.should raise_error(NoMethodError)
|
185
|
+
end
|
186
|
+
|
187
|
+
it "should raise an error with invalid encoding" do
|
188
|
+
lambda { "abcde\240z405".md5(:encoding => :foobar) }.should raise_error(ArgumentError, 'Invalid encoding: foobar')
|
189
|
+
end
|
190
|
+
|
191
|
+
describe "digest detection" do
|
192
|
+
it "should defer to Digest" do
|
193
|
+
str = "abcde\240z405"
|
194
|
+
Digest.should_receive(:detect_digest).with(str, :binary)
|
195
|
+
str.detect_digest(:binary)
|
196
|
+
end
|
197
|
+
|
198
|
+
it "should defer to Digest" do
|
199
|
+
str = "abcde\240z405"
|
200
|
+
Digest.should_receive(:detect_digest!).with(str, :binary)
|
201
|
+
str.detect_digest!(:binary)
|
202
|
+
end
|
203
|
+
end
|
182
204
|
end
|
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 0
|
7
7
|
- 3
|
8
|
-
-
|
9
|
-
version: 0.3.
|
8
|
+
- 1
|
9
|
+
version: 0.3.1
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Travis D. Warlick, Jr.
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2010-04-
|
17
|
+
date: 2010-04-04 00:00:00 -05:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|