sequel_password 0.1 → 0.1.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c7be80a93422a9c18bd61e2d309b61481fb4c4d1
4
- data.tar.gz: b89e1934f8373ba7e341d50312b1620574f93f19
3
+ metadata.gz: 536c42e3a0e81d54a1ede80ebf0d02384efb8e9d
4
+ data.tar.gz: 85510cee1cc2c043139dee879e7b5eef2519436a
5
5
  SHA512:
6
- metadata.gz: a15ae5358ab1e5601c50dc6cc4c5b10bd4c223c3f3e5d2726e8a022b8dd28989a24e8b7b0e5321add1835549fcc5bbc1277e8df0ee12866db2748bb090e07863
7
- data.tar.gz: 1014dcda3e264885bb94301736b00bfce78f574444919b11d6f0c71c53079192fb81345403385cc838e552ddc79d021d65d2acc7a7ede82d426af3822ef7909a
6
+ metadata.gz: 4188cd381e1de2ed42f27881271bbdc385090cd4249c5b8ae7c67dc20f09fc7728285992e6fec3b5fc9b26cfce117a4db4446e0b6447dd9f19fa686ae8b524fb
7
+ data.tar.gz: 729291c54d8c8bdb03198ce58ddebc5909f9c16af68e5e0691c4dffee8063b1e5d856c5ba3a075c4e231f0ea3497a6af1da1d65d8100478ed0decdad11123ceb
data/.gitignore CHANGED
@@ -1 +1,2 @@
1
1
  coverage
2
+ *.gem
data/Gemfile.lock CHANGED
@@ -2,9 +2,9 @@ PATH
2
2
  remote: .
3
3
  specs:
4
4
  sequel_password (0.1)
5
- bcrypt (~> 3.1.10)
5
+ bcrypt (~> 3.1, >= 3.1.10)
6
6
  pbkdf2-ruby (~> 0.2.1)
7
- sequel (~> 4.21.0)
7
+ sequel (~> 4.21, >= 4.21.0)
8
8
 
9
9
  GEM
10
10
  remote: https://rubygems.org/
@@ -39,7 +39,7 @@ PLATFORMS
39
39
  ruby
40
40
 
41
41
  DEPENDENCIES
42
- rspec (~> 3.2.0)
42
+ rspec (~> 3.2, >= 3.2.0)
43
43
  sequel_password!
44
44
  simplecov (~> 0.9.2)
45
- sqlite3 (~> 1.3.10)
45
+ sqlite3 (~> 1.3, >= 1.3.10)
data/README.md CHANGED
@@ -2,3 +2,5 @@
2
2
 
3
3
  This sequel plugin adds authentication and password hashing to Sequel models.
4
4
  It supports pbkdf2 and bcrypt hashers.
5
+
6
+ # Usage
@@ -0,0 +1,118 @@
1
+ require "base64"
2
+ require "bcrypt"
3
+ require "openssl"
4
+ require "pbkdf2"
5
+ require "securerandom"
6
+
7
+ module Sequel
8
+ module Plugins
9
+ module Password
10
+ class Hasher
11
+ attr_reader :algorithm
12
+
13
+ def salt
14
+ # 72 bits
15
+ SecureRandom.hex(9)
16
+ end
17
+
18
+ def verify(password, encoded)
19
+ raise NotImplementedError
20
+ end
21
+
22
+ def encode(password, salt)
23
+ raise NotImplementedError
24
+ end
25
+
26
+ def must_update(encoded)
27
+ false
28
+ end
29
+
30
+ private
31
+
32
+ def constant_time_compare(a, b)
33
+ check = a.bytesize ^ b.bytesize
34
+ a.bytes.zip(b.bytes) { |x, y| check |= x ^ y }
35
+ check == 0
36
+ end
37
+ end
38
+
39
+ class PBKDF2Hasher < Hasher
40
+ def initialize
41
+ @algorithm = :pbkdf2_sha256
42
+ @iterations = 24000
43
+ @digest = OpenSSL::Digest::SHA256.new
44
+ end
45
+
46
+ def encode(password, salt, iterations = nil)
47
+ iterations = @iterations if iterations.nil?
48
+ hash = PBKDF2.new(password: password, salt: salt,
49
+ iterations: iterations, hash_function: @digest)
50
+ hash = Base64.strict_encode64(hash.value)
51
+ "#{@algorithm}$#{iterations}$#{salt}$#{hash}"
52
+ end
53
+
54
+ def verify(password, encoded)
55
+ algorithm, iterations, salt, hash = encoded.split('$', 4)
56
+ hash = encode(password, salt, iterations.to_i)
57
+ constant_time_compare(encoded, hash)
58
+ end
59
+
60
+ def must_update(encoded)
61
+ algorithm, iterations, salt, hash = encoded.split('$', 4)
62
+ iterations.to_i != @iterations
63
+ end
64
+ end
65
+
66
+ class BCryptSHA256Hasher < Hasher
67
+ def initialize
68
+ @algorithm = :bcrypt_sha256
69
+ @cost = 12
70
+ @digest = OpenSSL::Digest::SHA256.new
71
+ end
72
+
73
+ def salt
74
+ BCrypt::Engine.generate_salt(@cost)
75
+ end
76
+
77
+ def encode(password, salt)
78
+ password = @digest.digest(password) unless @digest.nil?
79
+ hash = BCrypt::Engine.hash_secret(password, salt)
80
+ "#{@algorithm}$#{hash}"
81
+ end
82
+
83
+ def verify(password, encoded)
84
+ algorithm, data = encoded.split('$', 2)
85
+ password = @digest.digest(password) unless @digest.nil?
86
+ hash = BCrypt::Engine.hash_secret(password, data)
87
+ constant_time_compare(data, hash)
88
+ end
89
+ end
90
+
91
+ class BCryptHasher < BCryptSHA256Hasher
92
+ def initialize
93
+ @algorithm = :bcrypt
94
+ @cost = 12
95
+ @digest = nil
96
+ end
97
+ end
98
+
99
+ class SHA1Hasher < Hasher
100
+ def initialize
101
+ @algorithm = :sha1
102
+ @digest = OpenSSL::Digest::SHA1.new
103
+ end
104
+
105
+ def encode(password, salt)
106
+ hash = @digest.digest(salt + password).unpack('H*').first
107
+ "#{@algorithm}$#{salt}$#{hash}"
108
+ end
109
+
110
+ def verify(password, encoded)
111
+ algorithm, salt, hash = encoded.split('$', 3)
112
+ hash = encode(password, salt)
113
+ constant_time_compare(encoded, hash)
114
+ end
115
+ end
116
+ end
117
+ end
118
+ end
@@ -1,8 +1,5 @@
1
- require "base64"
2
- require "bcrypt"
3
- require "openssl"
4
- require "pbkdf2"
5
1
  require "securerandom"
2
+ require "sequel_password/hashers"
6
3
 
7
4
  module Sequel
8
5
  module Plugins
@@ -33,10 +30,6 @@ module Sequel
33
30
  hasher(algorithm).encode(password, salt)
34
31
  end
35
32
 
36
- def hasher(algorithm = :default)
37
- @hashers.fetch(algorithm.to_sym, @hashers.values.first)
38
- end
39
-
40
33
  def usable_password?(encoded)
41
34
  return false if encoded.nil? || encoded.start_with?("!")
42
35
 
@@ -58,6 +51,12 @@ module Sequel
58
51
 
59
52
  correct
60
53
  end
54
+
55
+ private
56
+
57
+ def hasher(algorithm = :default)
58
+ @hashers.fetch(algorithm.to_sym, @hashers.values.first)
59
+ end
61
60
  end
62
61
 
63
62
  module InstanceMethods
@@ -74,113 +73,6 @@ module Sequel
74
73
  send("#{model.column}=", model.make_password(nil))
75
74
  end
76
75
  end
77
-
78
- class Hasher
79
- attr_reader :algorithm
80
-
81
- def salt
82
- # 72 bits
83
- SecureRandom.hex(9)
84
- end
85
-
86
- def verify(password, encoded)
87
- raise NotImplementedError
88
- end
89
-
90
- def encode(password, salt)
91
- raise NotImplementedError
92
- end
93
-
94
- def must_update(encoded)
95
- false
96
- end
97
-
98
- private
99
-
100
- def constant_time_compare(a, b)
101
- check = a.bytesize ^ b.bytesize
102
- a.bytes.zip(b.bytes) { |x, y| check |= x ^ y }
103
- check == 0
104
- end
105
- end
106
-
107
- class PBKDF2Hasher < Hasher
108
- def initialize
109
- @algorithm = :pbkdf2_sha256
110
- @iterations = 24000
111
- @digest = OpenSSL::Digest::SHA256.new
112
- end
113
-
114
- def encode(password, salt, iterations = nil)
115
- iterations = @iterations if iterations.nil?
116
- hash = PBKDF2.new(password: password, salt: salt,
117
- iterations: iterations, hash_function: @digest)
118
- hash = Base64.strict_encode64(hash.value)
119
- "#{@algorithm}$#{iterations}$#{salt}$#{hash}"
120
- end
121
-
122
- def verify(password, encoded)
123
- algorithm, iterations, salt, hash = encoded.split('$', 4)
124
- hash = encode(password, salt, iterations.to_i)
125
- constant_time_compare(encoded, hash)
126
- end
127
-
128
- def must_update(encoded)
129
- algorithm, iterations, salt, hash = encoded.split('$', 4)
130
- iterations.to_i != @iterations
131
- end
132
- end
133
-
134
- class BCryptSHA256Hasher < Hasher
135
- def initialize
136
- @algorithm = :bcrypt_sha256
137
- @cost = 12
138
- @digest = OpenSSL::Digest::SHA256.new
139
- end
140
-
141
- def salt
142
- BCrypt::Engine.generate_salt(@cost)
143
- end
144
-
145
- def encode(password, salt)
146
- password = @digest.digest(password) unless @digest.nil?
147
- hash = BCrypt::Engine.hash_secret(password, salt)
148
- "#{@algorithm}$#{hash}"
149
- end
150
-
151
- def verify(password, encoded)
152
- algorithm, data = encoded.split('$', 2)
153
- password = @digest.digest(password) unless @digest.nil?
154
- hash = BCrypt::Engine.hash_secret(password, data)
155
- constant_time_compare(data, hash)
156
- end
157
- end
158
-
159
- class BCryptHasher < BCryptSHA256Hasher
160
- def initialize
161
- @algorithm = :bcrypt
162
- @cost = 12
163
- @digest = nil
164
- end
165
- end
166
-
167
- class SHA1Hasher < Hasher
168
- def initialize
169
- @algorithm = :sha1
170
- @digest = OpenSSL::Digest::SHA1.new
171
- end
172
-
173
- def encode(password, salt)
174
- hash = @digest.digest(salt + password).unpack('H*').first
175
- "#{@algorithm}$#{salt}$#{hash}"
176
- end
177
-
178
- def verify(password, encoded)
179
- algorithm, salt, hash = encoded.split('$', 3)
180
- hash = encode(password, salt)
181
- constant_time_compare(encoded, hash)
182
- end
183
- end
184
76
  end
185
77
  end
186
78
  end
@@ -13,11 +13,11 @@ Gem::Specification.new do |gem|
13
13
  gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
14
14
  gem.name = "sequel_password"
15
15
  gem.require_paths = ["lib"]
16
- gem.version = '0.1'
16
+ gem.version = '0.1.1'
17
17
 
18
18
  gem.add_runtime_dependency 'sequel', '~> 4.21', '>= 4.21.0'
19
19
  gem.add_runtime_dependency 'bcrypt', '~> 3.1', '>= 3.1.10'
20
- gem.add_runtime_dependency 'pbkf2-ruby', '~> 0.2.1'
20
+ gem.add_runtime_dependency 'pbkdf2-ruby', '~> 0.2.1'
21
21
 
22
22
  gem.add_development_dependency 'rspec', '~> 3.2', '>= 3.2.0'
23
23
  gem.add_development_dependency 'simplecov', '~> 0.9.2'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sequel_password
3
3
  version: !ruby/object:Gem::Version
4
- version: '0.1'
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Timothée Peignier
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-04-04 00:00:00.000000000 Z
11
+ date: 2015-04-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: sequel
@@ -51,7 +51,7 @@ dependencies:
51
51
  - !ruby/object:Gem::Version
52
52
  version: 3.1.10
53
53
  - !ruby/object:Gem::Dependency
54
- name: pbkf2-ruby
54
+ name: pbkdf2-ruby
55
55
  requirement: !ruby/object:Gem::Requirement
56
56
  requirements:
57
57
  - - "~>"
@@ -132,6 +132,7 @@ files:
132
132
  - Gemfile.lock
133
133
  - README.md
134
134
  - lib/sequel_password.rb
135
+ - lib/sequel_password/hashers.rb
135
136
  - sequel_password.gemspec
136
137
  - spec/sequel_password_spec.rb
137
138
  - spec/spec_helper.rb