dionysus 0.3.0 → 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
data/Rakefile CHANGED
@@ -44,3 +44,5 @@ Rake::RDocTask.new do |rdoc|
44
44
  rdoc.rdoc_files.include('README*', 'LICENSE', 'VERSION')
45
45
  rdoc.rdoc_files.include('lib/**/*.rb')
46
46
  end
47
+
48
+ task :clobber => [:clobber_rcov, :clobber_rdoc]
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.3.0
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.0"
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-02}
12
+ s.date = %q{2010-04-04}
13
13
  s.email = %q{warlickt@operissystems.com}
14
14
  s.extra_rdoc_files = [
15
15
  "LICENSE",
@@ -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.is_a?(Symbol)
69
- bits_per_char = case encoding
70
- when :binary then 8
71
- when :base64 then 6
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
- bits_per_char = encoding
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( sym_or_klass, str )
93
- if sym_or_klass.is_a?(Class)
94
- sym_or_klass
95
- else
96
- Digest.const_get(sym_or_klass.to_s.upcase)
97
- end.digest(str)
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
- if args[0].is_a?(Symbol) and args[0] != :new
85
- self.placement = args[0]
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
- begin
57
- return self.digest(method, *args)
58
- rescue NameError
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.class.available_digests.each do |dig|
67
- if ''.digest(dig, :encoding => encoding).length == self.length
68
- return dig
69
- end
70
- end
71
- raise "Unknown digest."
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
@@ -8,6 +8,7 @@ require 'active_support/base64'
8
8
  class String
9
9
  HEX_REGEXP = /^[a-f0-9]+$/
10
10
  BASE64_REGEXP = /^[A-Za-z0-9\+\/\=]+$/
11
+ ENCODING_BITS_PER_CHAR = {:binary => 8, :base64 => 6, :hex => 4, :hexidecimal => 4}
11
12
 
12
13
  ##
13
14
  # Encode the Base64 (without newlines)
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
- { :md5 => 128, :sha1 => 160, :sha2 => 256,
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
- Digest.digest_lengths(:base64)[dig].should == bits / 6
106
- Digest.digest_lengths(6)[dig].should == bits / 6
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
- Digest.digest_lengths(7)[dig].should == bits / 7
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
@@ -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
- - 0
9
- version: 0.3.0
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-02 00:00:00 -05:00
17
+ date: 2010-04-04 00:00:00 -05:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency