passwd 0.1.5 → 0.2.0

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.
Files changed (98) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +4 -1
  3. data/CHANGELOG.md +30 -1
  4. data/Gemfile +0 -5
  5. data/LICENSE.txt +2 -1
  6. data/README.md +96 -156
  7. data/Rakefile +2 -1
  8. data/example/.gitignore +16 -0
  9. data/example/Gemfile +25 -0
  10. data/example/README.rdoc +28 -0
  11. data/example/Rakefile +6 -0
  12. data/example/app/assets/images/.keep +0 -0
  13. data/example/app/assets/javascripts/application.js +16 -0
  14. data/example/app/assets/stylesheets/application.css +16 -0
  15. data/example/app/controllers/application_controller.rb +10 -0
  16. data/example/app/controllers/concerns/.keep +0 -0
  17. data/example/app/controllers/profiles_controller.rb +28 -0
  18. data/example/app/controllers/root_controller.rb +5 -0
  19. data/example/app/controllers/sessions_controller.rb +29 -0
  20. data/example/app/helpers/application_helper.rb +2 -0
  21. data/example/app/mailers/.keep +0 -0
  22. data/example/app/models/.keep +0 -0
  23. data/example/app/models/concerns/.keep +0 -0
  24. data/example/app/models/user.rb +4 -0
  25. data/example/app/views/layouts/application.html.erb +15 -0
  26. data/example/app/views/profiles/edit.html.erb +14 -0
  27. data/example/app/views/profiles/show.html.erb +12 -0
  28. data/example/app/views/root/index.html.erb +5 -0
  29. data/example/app/views/sessions/new.html.erb +6 -0
  30. data/example/bin/bundle +3 -0
  31. data/example/bin/rails +4 -0
  32. data/example/bin/rake +4 -0
  33. data/example/config.ru +4 -0
  34. data/example/config/application.rb +40 -0
  35. data/example/config/boot.rb +4 -0
  36. data/example/config/database.yml +26 -0
  37. data/example/config/environment.rb +5 -0
  38. data/example/config/environments/development.rb +37 -0
  39. data/example/config/environments/production.rb +78 -0
  40. data/example/config/environments/test.rb +39 -0
  41. data/example/config/initializers/assets.rb +8 -0
  42. data/example/config/initializers/backtrace_silencers.rb +7 -0
  43. data/example/config/initializers/cookies_serializer.rb +3 -0
  44. data/example/config/initializers/filter_parameter_logging.rb +4 -0
  45. data/example/config/initializers/inflections.rb +16 -0
  46. data/example/config/initializers/mime_types.rb +4 -0
  47. data/example/config/initializers/passwd.rb +41 -0
  48. data/example/config/initializers/session_store.rb +3 -0
  49. data/example/config/initializers/wrap_parameters.rb +14 -0
  50. data/example/config/locales/en.yml +23 -0
  51. data/example/config/routes.rb +16 -0
  52. data/example/config/secrets.yml +22 -0
  53. data/example/db/migrate/20141122165914_create_users.rb +13 -0
  54. data/example/db/schema.rb +25 -0
  55. data/example/db/seeds.rb +7 -0
  56. data/example/lib/assets/.keep +0 -0
  57. data/example/lib/tasks/.keep +0 -0
  58. data/example/lib/tasks/user.rake +12 -0
  59. data/example/log/.keep +0 -0
  60. data/example/public/404.html +67 -0
  61. data/example/public/422.html +67 -0
  62. data/example/public/500.html +66 -0
  63. data/example/public/favicon.ico +0 -0
  64. data/example/public/robots.txt +5 -0
  65. data/example/vendor/assets/javascripts/.keep +0 -0
  66. data/example/vendor/assets/stylesheets/.keep +0 -0
  67. data/lib/generators/passwd/config_generator.rb +13 -0
  68. data/lib/generators/passwd/templates/passwd_config.rb +41 -0
  69. data/lib/passwd.rb +18 -3
  70. data/lib/passwd/action_controller_ext.rb +48 -0
  71. data/lib/passwd/active_record_ext.rb +65 -0
  72. data/lib/passwd/base.rb +17 -62
  73. data/lib/passwd/configuration.rb +82 -0
  74. data/lib/passwd/errors.rb +6 -13
  75. data/lib/passwd/password.rb +73 -25
  76. data/lib/passwd/policy.rb +28 -0
  77. data/lib/passwd/railtie.rb +19 -0
  78. data/lib/passwd/salt.rb +50 -0
  79. data/lib/passwd/version.rb +2 -1
  80. data/passwd.gemspec +8 -2
  81. data/spec/passwd/.keep +0 -0
  82. data/spec/passwd/active_record_ext_spec.rb +80 -0
  83. data/spec/passwd/base_spec.rb +55 -231
  84. data/spec/passwd/configuration_spec.rb +50 -0
  85. data/spec/passwd/password_spec.rb +129 -123
  86. data/spec/spec_helper.rb +14 -3
  87. data/spec/support/data_util.rb +11 -0
  88. data/spec/support/paths.rb +2 -0
  89. metadata +164 -30
  90. data/lib/passwd/active_record.rb +0 -62
  91. data/lib/passwd/configuration/abstract_config.rb +0 -37
  92. data/lib/passwd/configuration/config.rb +0 -24
  93. data/lib/passwd/configuration/policy.rb +0 -46
  94. data/lib/passwd/configuration/tmp_config.rb +0 -18
  95. data/spec/passwd/active_record_spec.rb +0 -163
  96. data/spec/passwd/configuration/config_spec.rb +0 -250
  97. data/spec/passwd/configuration/policy_spec.rb +0 -133
  98. data/spec/passwd/configuration/tmp_config_spec.rb +0 -265
@@ -0,0 +1,28 @@
1
+ module Passwd
2
+ class Policy
3
+ VALID_OPTIONS = [
4
+ :min_length,
5
+ :require_lower,
6
+ :require_upper,
7
+ :require_number
8
+ ].freeze
9
+
10
+ attr_accessor *VALID_OPTIONS
11
+
12
+ def initialize
13
+ reset
14
+ end
15
+
16
+ def configure
17
+ yield self
18
+ end
19
+
20
+ def reset
21
+ self.min_length = 8
22
+ self.require_lower = true
23
+ self.require_upper = false
24
+ self.require_number = true
25
+ end
26
+ end
27
+ end
28
+
@@ -0,0 +1,19 @@
1
+ module Passwd
2
+ class Railtie < ::Rails::Railtie
3
+ config.passwd = ActiveSupport::OrderedOptions.new
4
+
5
+ initializer "passwd" do
6
+ require "passwd/action_controller_ext"
7
+ require "passwd/active_record_ext"
8
+
9
+ ActiveSupport.on_load(:action_controller) do
10
+ ::ActionController::Base.send(:include, Passwd::ActionControllerExt)
11
+ end
12
+
13
+ ActiveSupport.on_load(:active_record) do
14
+ ::ActiveRecord::Base.send(:extend, Passwd::ActiveRecordExt)
15
+ end
16
+ end
17
+ end
18
+ end
19
+
@@ -0,0 +1,50 @@
1
+ module Passwd
2
+ class Salt
3
+ include Base
4
+
5
+ attr_reader :plain, :hash
6
+
7
+ def initialize(options = {})
8
+ options = default_options.merge(options)
9
+
10
+ @password = options[:password]
11
+ if options.has_key?(:hash)
12
+ @plain = nil
13
+ @hash = options[:hash]
14
+ else
15
+ @plain = options[:plain] || (raise ArgumentError)
16
+ @hash = digest_without_stretching(@plain)
17
+ end
18
+ end
19
+
20
+ def update_plain(value)
21
+ @plain = value
22
+ @hash = digest_without_stretching(@plain)
23
+ update_password!
24
+ end
25
+
26
+ def update_hash(value)
27
+ @plain = nil
28
+ @hash = value
29
+ update_password!
30
+ end
31
+
32
+ def self.from_plain(value, password = nil)
33
+ new(plain: value, password: password)
34
+ end
35
+
36
+ def self.from_hash(value, password = nil)
37
+ new(hash: value, password: password)
38
+ end
39
+
40
+ private
41
+ def default_options
42
+ {plain: Time.now.to_s}
43
+ end
44
+
45
+ def update_password!
46
+ @password.rehash if @password && @password.plain
47
+ end
48
+ end
49
+ end
50
+
@@ -1,3 +1,4 @@
1
1
  module Passwd
2
- VERSION = "0.1.5"
2
+ VERSION = "0.2.0"
3
3
  end
4
+
@@ -17,7 +17,13 @@ Gem::Specification.new do |spec|
17
17
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
18
18
  spec.require_paths = ["lib"]
19
19
 
20
- spec.add_development_dependency "bundler", "~> 1.3"
20
+ spec.add_development_dependency "bundler"
21
21
  spec.add_development_dependency "rake"
22
- spec.add_development_dependency "rspec"
22
+ spec.add_development_dependency "coveralls"
23
+ spec.add_development_dependency "simplecov"
24
+ spec.add_development_dependency "rails"
25
+ spec.add_development_dependency "rspec-rails"
26
+ spec.add_development_dependency "sqlite3"
27
+ spec.add_development_dependency "database_rewinder"
23
28
  end
29
+
File without changes
@@ -0,0 +1,80 @@
1
+ require "spec_helper"
2
+
3
+ describe Passwd::ActiveRecordExt do
4
+ describe ".with_authenticate" do
5
+ it { expect(ActiveRecord::Base).to respond_to(:with_authenticate) }
6
+
7
+ context User do
8
+ let(:new_pass) { "NewPassw0rd" }
9
+ let(:password) { Passwd::Password.new }
10
+ let(:user) {
11
+ User.create(
12
+ name: "i2bskn",
13
+ email: "i2bskn@example.com",
14
+ salt: password.salt.hash,
15
+ password: password.hash
16
+ )
17
+ }
18
+
19
+ it { is_expected.to respond_to(:passwd) }
20
+ it { is_expected.to respond_to(:authenticate) }
21
+ it { expect(User).to respond_to(:authenticate) }
22
+ it { is_expected.to respond_to(:set_password) }
23
+ it { is_expected.to respond_to(:update_password) }
24
+
25
+ context "#passwd" do
26
+ after { user.passwd }
27
+
28
+ it { expect(user.passwd.is_a?(Passwd::Password)).to be_truthy }
29
+ it { expect(user).to receive(:reload) }
30
+ it { expect(Passwd::Password).to receive(:from_hash) }
31
+
32
+ it {
33
+ user = User.new
34
+ expect(user).to receive(:set_password)
35
+ user.passwd
36
+ }
37
+ end
38
+
39
+ context ".authenticate" do
40
+ before { user }
41
+
42
+ it { expect(User.authenticate("i2bskn@example.com", password.plain)).not_to be_falsy }
43
+ it { expect(User.authenticate("i2bskn@example.com", "invalid")).to be_falsy }
44
+ end
45
+
46
+ context "#authenticate" do
47
+ it { expect(user.authenticate(password.plain)).not_to be_falsy }
48
+ it { expect(user.authenticate("invalid")).to be_falsy }
49
+ end
50
+
51
+ context "#set_password" do
52
+ it { expect { user.set_password }.to change { user.password } }
53
+ it { expect { user.set_password(new_pass) }.to change { user.password } }
54
+ end
55
+
56
+ context "#update_password" do
57
+ before { user }
58
+
59
+ it {
60
+ expect {
61
+ user.update_password(password.plain, new_pass)
62
+ }.to change { user.password }
63
+ }
64
+
65
+ it {
66
+ expect {
67
+ user.update_password(password.plain, "secret", true)
68
+ }.to raise_error(Passwd::PolicyNotMatch)
69
+ }
70
+
71
+ it {
72
+ expect {
73
+ user.update_password("invalid", new_pass)
74
+ }.to raise_error(Passwd::AuthenticationFails)
75
+ }
76
+ end
77
+ end
78
+ end
79
+ end
80
+
@@ -1,236 +1,60 @@
1
- # coding: utf-8
2
-
3
1
  require "spec_helper"
4
2
 
5
- describe Passwd do
6
- describe "extended Base" do
7
- describe "#create" do
8
- context "without arguments" do
9
- let(:password) {Passwd.create}
10
-
11
- it "TmpConfig should not be generated" do
12
- Passwd::TmpConfig.should_not_receive(:new)
13
- expect{password}.not_to raise_error
14
- end
15
-
16
- it "created password should be String object" do
17
- expect(password.is_a? String).to be_true
18
- end
19
-
20
- it "created password length should be default length" do
21
- expect(password.size).to eq(8)
22
- end
23
- end
24
-
25
- context "with arguments" do
26
- it "TmpConfig should be generated" do
27
- tmp_config = double("tmp_config mock", length: 8, letters: ["a", "b"])
28
- Passwd::TmpConfig.should_receive(:new).and_return(tmp_config)
29
- expect{Passwd.create(length: 10)}.not_to raise_error
30
- end
31
-
32
- it "password was created specified characters" do
33
- expect(Passwd.create(length: 10).size).to eq(10)
34
- end
35
-
36
- it "password create without lower case" do
37
- expect(("a".."z").to_a.include? Passwd.create(lower: false)).to be_false
38
- end
39
-
40
- it "password create without upper case" do
41
- expect(("A".."Z").to_a.include? Passwd.create(upper: false)).to be_false
42
- end
43
-
44
- it "password create without number" do
45
- expect(("0".."9").to_a.include? Passwd.create(number: false)).to be_false
46
- end
47
- end
48
- end
49
-
50
- describe "#auth" do
51
- let!(:password) do
52
- password = Passwd.create
53
- salt_hash = Passwd.hashing(Time.now.to_s)
54
- password_hash = Passwd.hashing("#{salt_hash}#{password}")
55
- {text: password, salt: salt_hash, hash: password_hash}
56
- end
57
-
58
- it "return true with valid password" do
59
- expect(Passwd.auth(password[:text], password[:salt], password[:hash])).to be_true
60
- end
61
-
62
- it "return false with invalid password" do
63
- expect(Passwd.auth("invalid", password[:salt], password[:hash])).to be_false
64
- end
65
-
66
- it "should create exception if not specified arguments" do
67
- expect(proc{Passwd.auth}).to raise_error
68
- end
69
- end
70
-
71
- describe "#hashing" do
72
- it "should call SHA512.#hexdigest" do
73
- Digest::SHA512.should_receive(:hexdigest)
74
- Passwd.hashing("secret")
75
- end
76
-
77
- it "return hashed password" do
78
- hashed = Digest::SHA512.hexdigest "secret"
79
- expect(Passwd.hashing("secret")).to eq(hashed)
80
- end
81
-
82
- it "return hashed password specified algorithm" do
83
- hashed = Digest::SHA256.hexdigest "secret"
84
- expect(Passwd.hashing("secret", :sha256)).to eq(hashed)
85
- end
86
-
87
- it "should create exception if not specified argument" do
88
- expect(proc{Passwd.hashing}).to raise_error
89
- end
90
- end
91
-
92
- describe "#confirm_check" do
93
- context "with out policy check" do
94
- it "should generate exception if password don't match" do
95
- expect{
96
- Passwd.confirm_check("secret", "invalid")
97
- }.to raise_error(Passwd::PasswordNotMatch)
98
- end
99
-
100
- it "return true if password matches" do
101
- expect(Passwd.confirm_check("secret", "secret")).to be_true
102
- end
103
- end
104
-
105
- context "with policy check" do
106
- it "return false if invalid password by policy" do
107
- expect(Passwd.confirm_check("secret", "secret", true)).to be_false
108
- end
109
-
110
- it "return true if valid password by policy" do
111
- expect(Passwd.confirm_check("secretpass", "secretpass", true)).to be_false
112
- end
113
- end
114
- end
115
-
116
- describe "#configure" do
117
- it "return configuration object" do
118
- expect(Passwd.configure.is_a? Passwd::Config).to be_true
119
- end
120
-
121
- it "set config value from block" do
122
- Passwd.configure do |c|
123
- c.length = 10
124
- end
125
- expect(Passwd.configure.length).not_to eq(8)
126
- expect(Passwd.configure.length).to eq(10)
127
- end
128
-
129
- it "set config value from hash" do
130
- Passwd.configure length: 20
131
- expect(Passwd.config.length).not_to eq(8)
132
- expect(Passwd.config.length).to eq(20)
133
- end
134
-
135
- it "alias of configure as config" do
136
- expect(Passwd.configure.object_id).to eq(Passwd.config.object_id)
137
- end
138
- end
139
-
140
- describe "#policy_configure" do
141
- it "return policy object" do
142
- expect(Passwd.policy_configure.is_a? Passwd::Policy).to be_true
143
- end
144
-
145
- it "set policy value from block" do
146
- Passwd.policy_configure do |c|
147
- c.min_length = 10
148
- end
149
- expect(Passwd.policy_configure.min_length).not_to eq(8)
150
- expect(Passwd.policy_configure.min_length).to eq(10)
151
- end
152
- end
153
-
154
- describe "#policy_check" do
155
- it "Policy#valid? should be called" do
156
- Passwd::Policy.instance.should_receive(:valid?).with("secret1234" ,Passwd::Config.instance)
157
- expect(Passwd.policy_check("secret1234")).not_to raise_error
158
- end
159
- end
160
-
161
- describe "#reset_policy" do
162
- let(:policy) {Passwd::Policy.instance}
163
-
164
- before {
165
- policy.configure do |c|
166
- c.min_length = 20
167
- c.require_lower = false
168
- c.require_upper = true
169
- c.require_number = false
170
- end
171
- Passwd.reset_policy
172
- }
173
-
174
- it "min_length should be a default" do
175
- expect(policy.min_length).to eq(8)
176
- end
177
-
178
- it "require_lower should be a default" do
179
- expect(policy.require_lower).to be_true
180
- end
181
-
182
- it "upper should be a default" do
183
- expect(policy.require_upper).to be_false
184
- end
185
-
186
- it "number should be a default" do
187
- expect(policy.require_number).to be_true
188
- end
189
- end
190
-
191
- describe "#reset_config" do
192
- let(:config) {Passwd::Config.instance}
193
-
194
- before {
195
- config.configure do |c|
196
- c.length = 20
197
- c.lower = false
198
- c.upper = false
199
- c.number = false
200
- c.letters_lower = ["a"]
201
- c.letters_upper = ["A"]
202
- c.letters_number = ["0"]
203
- end
204
- Passwd.reset_config
205
- }
206
-
207
- it "length should be a default" do
208
- expect(config.length).to eq(8)
209
- end
210
-
211
- it "lower should be a default" do
212
- expect(config.lower).to be_true
213
- end
214
-
215
- it "upper should be a default" do
216
- expect(config.upper).to be_true
217
- end
218
-
219
- it "number should be a default" do
220
- expect(config.number).to be_true
221
- end
222
-
223
- it "letters_lower should be a default" do
224
- expect(config.letters_lower).to eq(("a".."z").to_a)
225
- end
3
+ describe Passwd::Base do
4
+ let(:plain) { "secret" }
5
+
6
+ context "#random" do
7
+ it { expect(Passwd).to respond_to(:random) }
8
+ it { expect(Passwd.random.is_a?(String)).to be_truthy }
9
+ it { expect(Passwd.random.size).to eq(Passwd::PwConfig.length) }
10
+ it { expect(Passwd.random(lower: false)).not_to include(*"a".."z") }
11
+ it { expect(Passwd.random(upper: false)).not_to include(*"A".."Z") }
12
+ it { expect(Passwd.random(number: false)).not_to include(*"0".."9") }
13
+
14
+ it {
15
+ length = Passwd::PwConfig.length + 1
16
+ expect(Passwd.random(length: length).size).to eq(length)
17
+ }
18
+
19
+ it {
20
+ lower = ["a"]
21
+ expect(
22
+ Passwd.random(letters_lower: lower, upper: false, number: false)
23
+ .chars.uniq
24
+ ).to eq(lower)
25
+ }
26
+ end
226
27
 
227
- it "letters_upper should be a default" do
228
- expect(config.letters_upper).to eq(("A".."Z").to_a)
229
- end
28
+ context "#digest" do
29
+ it { expect(Passwd.respond_to?(:digest)).to be_truthy }
30
+ it { expect(Passwd.digest(plain).is_a?(String)).to be_truthy }
31
+ it { expect(Passwd.digest(plain)).not_to eq(plain) }
32
+
33
+ it {
34
+ hashed = Passwd.send(:algorithm, Passwd::PwConfig.algorithm).hexdigest plain
35
+ expect(Passwd.digest(plain)).to eq(hashed)
36
+ }
37
+
38
+ it {
39
+ not_default = :md5
40
+ hashed = Passwd.send(:algorithm, not_default).hexdigest plain
41
+ expect(Passwd.digest(plain, not_default)).to eq(hashed)
42
+ }
43
+ end
230
44
 
231
- it "letters_number should be a default" do
232
- expect(config.letters_number).to eq(("0".."9").to_a)
233
- end
234
- end
45
+ context "#algorithm" do
46
+ it { expect(Passwd.send(:algorithm, :sha1)).to eq(Digest::SHA1) }
47
+ it { expect(Passwd.send(:algorithm, :sha256)).to eq(Digest::SHA256) }
48
+ it { expect(Passwd.send(:algorithm, :sha384)).to eq(Digest::SHA384) }
49
+ it { expect(Passwd.send(:algorithm, :sha512)).to eq(Digest::SHA512) }
50
+ it { expect(Passwd.send(:algorithm, :md5)).to eq(Digest::MD5) }
51
+ it { expect(Passwd.send(:algorithm, :rmd160)).to eq(Digest::RMD160) }
52
+
53
+ it {
54
+ expect {
55
+ Passwd.send(:algorithm, :unknowAn)
56
+ }.to raise_error
57
+ }
235
58
  end
236
- end
59
+ end
60
+