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
@@ -1,62 +0,0 @@
1
- # coding: utf-8
2
-
3
- module Passwd
4
- module ActiveRecord
5
- module ClassMethods
6
- def define_column(options={})
7
- id_name = options.fetch(:id, :email)
8
- salt_name = options.fetch(:salt, :salt)
9
- password_name = options.fetch(:password, :password)
10
-
11
- define_singleton_auth(id_name, salt_name, password_name)
12
- define_instance_auth(id_name, salt_name, password_name)
13
- define_set_password(id_name, salt_name, password_name)
14
- define_update_password(salt_name, password_name)
15
- end
16
-
17
- private
18
- def define_singleton_auth(id_name, salt_name, password_name)
19
- define_singleton_method :authenticate do |id, pass|
20
- user = self.where(id_name => id).first
21
- user if user && Passwd.auth(pass, user.send(salt_name), user.send(password_name))
22
- end
23
- end
24
-
25
- def define_instance_auth(id_name, salt_name, password_name)
26
- define_method :authenticate do |pass|
27
- Passwd.auth(pass, self.send(salt_name), self.send(password_name))
28
- end
29
- end
30
-
31
- def define_set_password(id_name, salt_name, password_name)
32
- define_method :set_password do |pass=nil|
33
- password = pass || Passwd.create
34
- salt = self.send(salt_name) || Passwd.hashing("#{self.send(id_name)}#{Time.now.to_s}")
35
- self.send("#{salt_name.to_s}=", salt)
36
- self.send("#{password_name.to_s}=", Passwd.hashing("#{salt}#{password}"))
37
- password
38
- end
39
- end
40
-
41
- def define_update_password(salt_name, password_name)
42
- define_method :update_password do |old_pass, new_pass, policy_check=false|
43
- if Passwd.auth(old_pass, self.send(salt_name), self.send(password_name))
44
- if policy_check
45
- raise Passwd::PolicyNotMatch, "Policy not match" unless Passwd.policy_check(new_pass)
46
- end
47
-
48
- set_password(new_pass)
49
- else
50
- raise Passwd::AuthError
51
- end
52
- end
53
- end
54
- end
55
-
56
- class << self
57
- def included(base)
58
- base.extend ClassMethods
59
- end
60
- end
61
- end
62
- end
@@ -1,37 +0,0 @@
1
- # coding: utf-8
2
-
3
- module Passwd
4
- class AbstractConfig
5
- VALID_OPTIONS_KEYS = [
6
- :algorithm,
7
- :length,
8
- :lower,
9
- :upper,
10
- :number,
11
- :letters_lower,
12
- :letters_upper,
13
- :letters_number
14
- ].freeze
15
-
16
- attr_accessor *VALID_OPTIONS_KEYS
17
-
18
- def configure
19
- yield self
20
- end
21
-
22
- def merge(configs)
23
- configs.keys.each do |k|
24
- send("#{k}=", configs[k])
25
- end
26
- end
27
-
28
- def letters
29
- chars = []
30
- chars.concat(self.letters_lower) if self.lower
31
- chars.concat(self.letters_upper) if self.upper
32
- chars.concat(self.letters_number) if self.number
33
- raise "letters is empty" if chars.empty?
34
- chars
35
- end
36
- end
37
- end
@@ -1,24 +0,0 @@
1
- # coding: utf-8
2
-
3
- require "passwd/configuration/abstract_config"
4
-
5
- module Passwd
6
- class Config < AbstractConfig
7
- include Singleton
8
-
9
- def initialize
10
- reset
11
- end
12
-
13
- def reset
14
- self.algorithm = :sha512
15
- self.length = 8
16
- self.lower = true
17
- self.upper = true
18
- self.number = true
19
- self.letters_lower = ("a".."z").to_a
20
- self.letters_upper = ("A".."Z").to_a
21
- self.letters_number = ("0".."9").to_a
22
- end
23
- end
24
- end
@@ -1,46 +0,0 @@
1
- # coding: utf-8
2
-
3
- module Passwd
4
- class Policy
5
- include Singleton
6
-
7
- VALID_OPTIONS_KEYS = [
8
- :min_length,
9
- :require_lower,
10
- :require_upper,
11
- :require_number
12
- ].freeze
13
-
14
- attr_accessor *VALID_OPTIONS_KEYS
15
-
16
- def initialize
17
- reset
18
- end
19
-
20
- def configure
21
- yield self
22
- end
23
-
24
- def valid?(password, config)
25
- return false if self.min_length > password.size
26
- return false if self.require_lower && !include_char?(config.letters_lower, password)
27
- return false if self.require_upper && !include_char?(config.letters_upper, password)
28
- return false if self.require_number && !include_char?(config.letters_number, password)
29
- true
30
- end
31
-
32
- def include_char?(letters, strings)
33
- strings.each_char do |c|
34
- return true if letters.include? c
35
- end
36
- false
37
- end
38
-
39
- def reset
40
- self.min_length = 8
41
- self.require_lower = true
42
- self.require_upper = false
43
- self.require_number = true
44
- end
45
- end
46
- end
@@ -1,18 +0,0 @@
1
- # coding: utf-8
2
-
3
- require "passwd/configuration/abstract_config"
4
-
5
- module Passwd
6
- class TmpConfig < AbstractConfig
7
- def initialize(config, options)
8
- config.instance_variables.each do |v|
9
- key = v.to_s.sub(/^@/, "").to_sym
10
- if options.has_key? key
11
- instance_variable_set v, options[key]
12
- else
13
- instance_variable_set v, config.instance_variable_get(v)
14
- end
15
- end
16
- end
17
- end
18
- end
@@ -1,163 +0,0 @@
1
- # coding: utf-8
2
-
3
- require "spec_helper"
4
-
5
- describe Passwd::ActiveRecord do
6
- class User
7
- include Passwd::ActiveRecord
8
- define_column
9
- end
10
-
11
- let(:salt) {Digest::SHA512.hexdigest("salt")}
12
- let(:password_text) {"secret"}
13
- let(:password_hash) {Digest::SHA512.hexdigest("#{salt}#{password_text}")}
14
-
15
- describe ".#included" do
16
- it "define singleton methods" do
17
- expect(User.respond_to? :define_column).to be_true
18
- end
19
- end
20
-
21
- describe "extend methods" do
22
- describe ".#define_column" do
23
- let(:user) {User.new}
24
-
25
- it "define singleton methods" do
26
- expect(User.respond_to? :authenticate).to be_true
27
- end
28
-
29
- it "define authenticate method" do
30
- expect(user.respond_to? :authenticate).to be_true
31
- end
32
-
33
- it "define set_password method" do
34
- expect(user.respond_to? :set_password).to be_true
35
- end
36
-
37
- it "define update_password" do
38
- expect(user.respond_to? :update_password).to be_true
39
- end
40
- end
41
- end
42
-
43
- describe "defined methods from define_column" do
44
- describe ".#authenticate" do
45
- let!(:record) {
46
- record = double("record mock")
47
- record.stub(:salt).and_return(salt)
48
- record.stub(:password).and_return(password_hash)
49
- response = [record]
50
- User.stub(:where).and_return(response)
51
- record
52
- }
53
-
54
- it "user should be returned if authentication is successful" do
55
- User.should_receive(:where)
56
- expect(User.authenticate("valid_id", password_text)).to eq(record)
57
- end
58
-
59
- it "should return nil if authentication failed" do
60
- User.should_receive(:where)
61
- expect(User.authenticate("valid_id", "invalid_secret")).to be_nil
62
- end
63
-
64
- it "should return nil if user not found" do
65
- User.should_receive(:where).with(:email => "invalid_id").and_return([])
66
- expect(User.authenticate("invalid_id", password_text)).to be_nil
67
- end
68
- end
69
-
70
- describe "#authenticate" do
71
- let!(:user) {
72
- user = User.new
73
- user.stub(:salt).and_return(salt)
74
- user.stub(:password).and_return(password_hash)
75
- user
76
- }
77
-
78
- it "should return true if authentication is successful" do
79
- expect(user.authenticate(password_text)).to be_true
80
- end
81
-
82
- it "should return false if authentication failed" do
83
- expect(user.authenticate("invalid_pass")).to be_false
84
- end
85
- end
86
-
87
- describe "#set_password" do
88
- let!(:user) {
89
- user = User.new
90
- user.stub(:salt).and_return(salt)
91
- user
92
- }
93
-
94
- it "should return set password" do
95
- user.should_receive(:salt=).with(salt)
96
- user.should_receive(:password=).with(Passwd.hashing("#{salt}#{password_text}"))
97
- expect(user.set_password(password_text)).to eq(password_text)
98
- end
99
-
100
- it "should set random password if not specified" do
101
- user.should_receive(:salt=).with(salt)
102
- random_password = Passwd.create
103
- Passwd.should_receive(:create).and_return(random_password)
104
- user.should_receive(:password=).with(Passwd.hashing("#{salt}#{random_password}"))
105
- user.set_password
106
- end
107
-
108
- it "should set salt if salt is nil" do
109
- mail_addr = "foo@example.com"
110
- time_now = Time.now
111
- salt2 = Passwd.hashing("#{mail_addr}#{time_now.to_s}")
112
- Time.stub(:now).and_return(time_now)
113
- user.stub(:email).and_return(mail_addr)
114
- user.should_receive(:salt).and_return(nil)
115
- user.should_receive(:salt=).with(salt2)
116
- user.should_receive(:password=).with(Passwd.hashing("#{salt2}#{password_text}"))
117
- user.set_password(password_text)
118
- end
119
- end
120
-
121
- describe "#update_password" do
122
- let!(:user) {
123
- user = User.new
124
- user.stub(:salt).and_return(salt)
125
- user.stub(:password).and_return(password_hash)
126
- user
127
- }
128
-
129
- context "without policy check" do
130
- it "should return update password" do
131
- pass = "new_password"
132
- user.should_receive(:set_password).with(pass).and_return(pass)
133
- expect(user.update_password(password_text, pass)).to eq(pass)
134
- end
135
-
136
- it "should generate exception if authentication failed" do
137
- Passwd.should_receive(:auth).and_return(false)
138
- user.should_not_receive(:set_password)
139
- expect {
140
- user.update_password("invalid_password", "new_password")
141
- }.to raise_error(Passwd::AuthError)
142
- end
143
- end
144
-
145
- context "with policy check" do
146
- it "should return update password" do
147
- pass = "new_password"
148
- Passwd.should_receive(:policy_check).and_return(true)
149
- user.should_receive(:set_password).with(pass).and_return(pass)
150
- expect(user.update_password(password_text, pass, true)).to eq(pass)
151
- end
152
-
153
- it "should generate exception if policy not match" do
154
- pass = "new_password"
155
- Passwd.should_receive(:policy_check).and_return(false)
156
- expect {
157
- user.update_password(password_text, pass, true)
158
- }.to raise_error(Passwd::PolicyNotMatch)
159
- end
160
- end
161
- end
162
- end
163
- end
@@ -1,250 +0,0 @@
1
- # coding: utf-8
2
-
3
- require "spec_helper"
4
-
5
- describe Passwd::Config do
6
- let(:config) {Passwd::Config.instance}
7
-
8
- describe "defined accessors" do
9
- it "defined algorithm" do
10
- expect(config.respond_to? :algorithm).to be_true
11
- end
12
-
13
- it "defined length" do
14
- expect(config.respond_to? :length).to be_true
15
- end
16
-
17
- it "defined lower" do
18
- expect(config.respond_to? :lower).to be_true
19
- end
20
-
21
- it "defined upper" do
22
- expect(config.respond_to? :upper).to be_true
23
- end
24
-
25
- it "defined number" do
26
- expect(config.respond_to? :number).to be_true
27
- end
28
-
29
- it "defined letters_lower" do
30
- expect(config.respond_to? :letters_lower).to be_true
31
- end
32
-
33
- it "defined letters_upper" do
34
- expect(config.respond_to? :letters_upper).to be_true
35
- end
36
-
37
- it "defined letters_number" do
38
- expect(config.respond_to? :letters_number).to be_true
39
- end
40
- end
41
-
42
- describe "#initialize" do
43
- it "algorithm should be a default" do
44
- expect(config.algorithm).to eq(:sha512)
45
- end
46
-
47
- it "length should be a default" do
48
- expect(config.length).to eq(8)
49
- end
50
-
51
- it "lower should be a default" do
52
- expect(config.lower).to be_true
53
- end
54
-
55
- it "upper should be a default" do
56
- expect(config.upper).to be_true
57
- end
58
-
59
- it "number should be a default" do
60
- expect(config.number).to be_true
61
- end
62
-
63
- it "letters_lower should be a default" do
64
- expect(config.letters_lower).to eq(("a".."z").to_a)
65
- end
66
-
67
- it "letters_upper should be a default" do
68
- expect(config.letters_upper).to eq(("A".."Z").to_a)
69
- end
70
-
71
- it "letters_number should be a default" do
72
- expect(config.letters_number).to eq(("0".."9").to_a)
73
- end
74
- end
75
-
76
- describe "#configure" do
77
- before {
78
- config.configure do |c|
79
- c.length = 20
80
- c.lower = false
81
- c.upper = false
82
- c.number = false
83
- c.letters_lower = ["a"]
84
- c.letters_upper = ["A"]
85
- c.letters_number = ["0"]
86
- end
87
- }
88
-
89
- it "set length from block" do
90
- expect(config.length).to eq(20)
91
- end
92
-
93
- it "set lower from block" do
94
- expect(config.lower).to be_false
95
- end
96
-
97
- it "set upper from block" do
98
- expect(config.upper).to be_false
99
- end
100
-
101
- it "set number from block" do
102
- expect(config.number).to be_false
103
- end
104
-
105
- it "set letters_lower from block" do
106
- expect(config.letters_lower).to eq(["a"])
107
- end
108
-
109
- it "set letters_upper from block" do
110
- expect(config.letters_upper).to eq(["A"])
111
- end
112
-
113
- it "set letters_number from block" do
114
- expect(config.letters_number).to eq(["0"])
115
- end
116
-
117
- it "raise error unknown setting" do
118
- expect {
119
- config.configure do |c|
120
- c.unknown = true
121
- end
122
- }.to raise_error
123
- end
124
- end
125
-
126
- describe "#merge" do
127
- it "set length from hash" do
128
- config.merge(length: 10)
129
- expect(config.length).to eq(10)
130
- end
131
-
132
- it "set lower from hash" do
133
- config.merge(lower: false)
134
- expect(config.lower).to be_false
135
- end
136
-
137
- it "set upper from hash" do
138
- config.merge(upper: false)
139
- expect(config.upper).to be_false
140
- end
141
-
142
- it "set number from hash" do
143
- config.merge(number: false)
144
- expect(config.number).to be_false
145
- end
146
-
147
- it "set letters_lower from hash" do
148
- config.merge(letters_lower: ["a"])
149
- expect(config.letters_lower).to eq(["a"])
150
- end
151
-
152
- it "set letters_upper from hash" do
153
- config.merge(letters_upper: ["A"])
154
- expect(config.letters_upper).to eq(["A"])
155
- end
156
-
157
- it "set letters_number from hash" do
158
- config.merge(letters_number: ["0"])
159
- expect(config.letters_number).to eq(["0"])
160
- end
161
-
162
- it "raise error unknown setting" do
163
- expect {
164
- config.merge(unknown: true)
165
- }.to raise_error
166
- end
167
- end
168
-
169
- describe "#letters" do
170
- it "return Array object" do
171
- expect(config.letters.is_a? Array).to be_true
172
- end
173
-
174
- it "all elements of the string" do
175
- config.letters.each do |l|
176
- expect(l.is_a? String).to be_true
177
- end
178
- end
179
-
180
- it "return all letters" do
181
- all_letters = ("a".."z").to_a.concat(("A".."Z").to_a).concat(("0".."9").to_a)
182
- expect(config.letters).to eq(all_letters)
183
- end
184
-
185
- it "return except for the lower case" do
186
- config.merge(lower: false)
187
- expect(config.letters.include? "a").to be_false
188
- end
189
-
190
- it "return except for the upper case" do
191
- config.merge(upper: false)
192
- expect(config.letters.include? "A").to be_false
193
- end
194
-
195
- it "return except for the number case" do
196
- config.merge(number: false)
197
- expect(config.letters.include? "0").to be_false
198
- end
199
-
200
- it "raise error if letters is empty" do
201
- config.merge(lower: false, upper: false, number: false)
202
- expect {
203
- config.letters
204
- }.to raise_error
205
- end
206
- end
207
-
208
- describe "#reset" do
209
- before {
210
- config.configure do |c|
211
- c.length = 20
212
- c.lower = false
213
- c.upper = false
214
- c.number = false
215
- c.letters_lower = ["a"]
216
- c.letters_upper = ["A"]
217
- c.letters_number = ["0"]
218
- end
219
- config.reset
220
- }
221
-
222
- it "length should be a default" do
223
- expect(config.length).to eq(8)
224
- end
225
-
226
- it "lower should be a default" do
227
- expect(config.lower).to be_true
228
- end
229
-
230
- it "upper should be a default" do
231
- expect(config.upper).to be_true
232
- end
233
-
234
- it "number should be a default" do
235
- expect(config.number).to be_true
236
- end
237
-
238
- it "letters_lower should be a default" do
239
- expect(config.letters_lower).to eq(("a".."z").to_a)
240
- end
241
-
242
- it "letters_upper should be a default" do
243
- expect(config.letters_upper).to eq(("A".."Z").to_a)
244
- end
245
-
246
- it "letters_number should be a default" do
247
- expect(config.letters_number).to eq(("0".."9").to_a)
248
- end
249
- end
250
- end