devise-secure_password 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (35) hide show
  1. checksums.yaml +7 -0
  2. data/CODE_OF_CONDUCT.md +74 -0
  3. data/Dockerfile +44 -0
  4. data/Dockerfile.prev +44 -0
  5. data/Gemfile +13 -0
  6. data/Gemfile.lock +280 -0
  7. data/LICENSE.txt +21 -0
  8. data/README.md +326 -0
  9. data/Rakefile +11 -0
  10. data/app/controllers/devise/passwords_with_policy_controller.rb +52 -0
  11. data/app/views/devise/passwords_with_policy/edit.html.erb +16 -0
  12. data/bin/console +14 -0
  13. data/bin/setup +6 -0
  14. data/config/locales/en.yml +71 -0
  15. data/devise-secure_password.gemspec +57 -0
  16. data/docker-entrypoint.sh +6 -0
  17. data/gemfiles/rails-5_0_6.gemfile +17 -0
  18. data/gemfiles/rails-5_1_4.gemfile +16 -0
  19. data/lib/devise/secure_password.rb +70 -0
  20. data/lib/devise/secure_password/controllers/active_helpers.rb +40 -0
  21. data/lib/devise/secure_password/controllers/devise_helpers.rb +64 -0
  22. data/lib/devise/secure_password/hooks/password_requires_regular_updates.rb +5 -0
  23. data/lib/devise/secure_password/models/password_disallows_frequent_changes.rb +60 -0
  24. data/lib/devise/secure_password/models/password_disallows_frequent_reuse.rb +71 -0
  25. data/lib/devise/secure_password/models/password_has_required_content.rb +131 -0
  26. data/lib/devise/secure_password/models/password_requires_regular_updates.rb +56 -0
  27. data/lib/devise/secure_password/models/previous_password.rb +20 -0
  28. data/lib/devise/secure_password/routes.rb +11 -0
  29. data/lib/devise/secure_password/version.rb +5 -0
  30. data/lib/generators/devise/secure_password/install_generator.rb +30 -0
  31. data/lib/generators/devise/templates/README.txt +21 -0
  32. data/lib/generators/devise/templates/secure_password.rb +43 -0
  33. data/lib/support/string/character_counter.rb +53 -0
  34. data/pkg/devise-secure_password-1.0.0.gem +0 -0
  35. metadata +471 -0
@@ -0,0 +1,131 @@
1
+ module Devise
2
+ module Models
3
+ module PasswordHasRequiredContent
4
+ extend ActiveSupport::Concern
5
+
6
+ require 'support/string/character_counter'
7
+
8
+ LENGTH_MAX = 255
9
+
10
+ included do
11
+ validate :validate_password_content
12
+ validate :validate_password_confirmation_content
13
+ end
14
+
15
+ def validate_password_content
16
+ self.password ||= ''
17
+ validate_password_content_for(:password)
18
+ errors[:password].count.zero?
19
+ end
20
+
21
+ def validate_password_confirmation_content
22
+ self.password_confirmation ||= ''
23
+ validate_password_content_for(:password_confirmation)
24
+ errors[:password_confirmation].count.zero?
25
+ end
26
+
27
+ def validate_password_content_for(attr)
28
+ return unless respond_to?(attr) && !(password_obj = send(attr)).nil?
29
+ ::Support::String::CharacterCounter.new.count(password_obj).each do |type, dict|
30
+ error_string = case type
31
+ when :unknown then validate_unknown(dict)
32
+ else validate_type(type, dict)
33
+ end
34
+ errors.add(attr, error_string) if error_string.present?
35
+ end
36
+ end
37
+
38
+ protected
39
+
40
+ def validate_unknown(dict)
41
+ type_total = dict.values.reduce(0, :+)
42
+ return if type_total <= required_char_counts_for_type(:unknown)[:max]
43
+
44
+ error_string_for_unknown_chars(type_total, dict.keys)
45
+ end
46
+
47
+ def validate_type(type, dict)
48
+ type_total = dict.values.reduce(0, :+)
49
+ error_string = if type_total < required_char_counts_for_type(type)[:min]
50
+ error_string_for_length(type, :min)
51
+ elsif type_total > required_char_counts_for_type(type)[:max]
52
+ error_string_for_length(type, :max)
53
+ end
54
+ error_string
55
+ end
56
+
57
+ def error_string_for_length(type, threshold = :min)
58
+ lang_key = case threshold
59
+ when :min then 'secure_password.password_has_required_content.errors.messages.minimum_characters'
60
+ when :max then 'secure_password.password_has_required_content.errors.messages.maximum_characters'
61
+ else return ''
62
+ end
63
+
64
+ count = required_char_counts_for_type(type)[threshold]
65
+ error_string = I18n.t(lang_key, count: count, type: type.to_s, subject: 'character'.pluralize(count))
66
+ error_string + ' ' + dict_for_type(type)
67
+ end
68
+
69
+ def error_string_for_unknown_chars(total, chars = [])
70
+ I18n.t(
71
+ 'secure_password.password_has_required_content.errors.messages.unknown_characters',
72
+ count: total,
73
+ subject: 'character'.pluralize(total)
74
+ ) + " (#{chars.join('')})"
75
+ end
76
+
77
+ def dict_for_type(type)
78
+ character_counter = ::Support::String::CharacterCounter.new
79
+
80
+ case type
81
+ when :special, :unknown then "(#{character_counter.count_hash[type].keys.join('')})"
82
+ else
83
+ "(#{character_counter.count_hash[type].keys.first}..#{character_counter.count_hash[type].keys.last})"
84
+ end
85
+ end
86
+
87
+ def required_char_counts_for_type(type)
88
+ self.class.config[:REQUIRED_CHAR_COUNTS][type]
89
+ end
90
+
91
+ module ClassMethods
92
+ config_params = %i(
93
+ password_required_uppercase_count
94
+ password_required_lowercase_count
95
+ password_required_number_count
96
+ password_required_special_count
97
+ )
98
+ ::Devise::Models.config(self, *config_params)
99
+
100
+ # rubocop:disable Metrics/MethodLength
101
+ def config
102
+ {
103
+ REQUIRED_CHAR_COUNTS: {
104
+ uppercase: {
105
+ min: password_required_uppercase_count,
106
+ max: LENGTH_MAX
107
+ },
108
+ lowercase: {
109
+ min: password_required_lowercase_count,
110
+ max: LENGTH_MAX
111
+ },
112
+ number: {
113
+ min: password_required_number_count,
114
+ max: LENGTH_MAX
115
+ },
116
+ special: {
117
+ min: password_required_special_count,
118
+ max: LENGTH_MAX
119
+ },
120
+ unknown: {
121
+ min: 0,
122
+ max: 0
123
+ }
124
+ }
125
+ }
126
+ end
127
+ # rubocop:enable Metrics/MethodLength
128
+ end
129
+ end
130
+ end
131
+ end
@@ -0,0 +1,56 @@
1
+ module Devise
2
+ module Models
3
+ module PasswordRequiresRegularUpdates
4
+ extend ActiveSupport::Concern
5
+
6
+ require 'devise/secure_password/hooks/password_requires_regular_updates'
7
+
8
+ class ConfigurationError < RuntimeError; end
9
+
10
+ included do
11
+ set_callback(:initialize, :before, :before_regular_update_initialized)
12
+ set_callback(:initialize, :after, :after_regular_update_initialized)
13
+ end
14
+
15
+ def password_expired?
16
+ last_password = previous_passwords.unscoped.last
17
+ inconsistent_password?(last_password) || last_password.stale?(self.class.password_maximum_age)
18
+ end
19
+
20
+ protected
21
+
22
+ def before_regular_update_initialized
23
+ return if self.class.respond_to?(:password_previously_used_count)
24
+
25
+ raise ConfigurationError, <<-ERROR.strip_heredoc
26
+
27
+ The password_requires_regular_updates module depends on the
28
+ password_disallows_frequent_reuse module. Verify that you have
29
+ added both modules to your model, for example:
30
+
31
+ devise :database_authenticatable, :registerable,
32
+ :password_disallows_frequent_reuse,
33
+ :password_requires_regular_updates
34
+ ERROR
35
+ end
36
+
37
+ def after_regular_update_initialized
38
+ raise ConfigurationError, 'invalid type for password_maximum_age' \
39
+ unless self.class.password_maximum_age.is_a?(::ActiveSupport::Duration)
40
+ end
41
+
42
+ # Check if current password is out of sync with last_password
43
+ #
44
+ # @param last_password [PreviousPassword] Password to compare with current password
45
+ # @return [Boolean] True if password is nil or out of sync, otherwise false
46
+ #
47
+ def inconsistent_password?(last_password = nil)
48
+ last_password.nil? || (encrypted_password != last_password.encrypted_password)
49
+ end
50
+
51
+ module ClassMethods
52
+ ::Devise::Models.config(self, :password_maximum_age)
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,20 @@
1
+ module Devise
2
+ module Models
3
+ class PreviousPassword < ::ActiveRecord::Base
4
+ self.table_name = 'previous_passwords'
5
+ belongs_to :user
6
+ default_scope -> { order(created_at: :desc) }
7
+ validates :user_id, presence: true
8
+ validates :salt, presence: true
9
+ validates :encrypted_password, presence: true
10
+
11
+ def fresh?(minimum_age_duration, now = ::Time.zone.now)
12
+ now <= (created_at + minimum_age_duration)
13
+ end
14
+
15
+ def stale?(maximum_age_duration, now = ::Time.zone.now)
16
+ now > (created_at + maximum_age_duration)
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,11 @@
1
+ module ActionDispatch
2
+ module Routing
3
+ class Mapper
4
+ protected
5
+
6
+ def devise_passwords_with_policy(mapping, controllers)
7
+ resource :password_with_policy, only: %i(edit update), path: mapping.path_names[:change_password], controller: controllers[:passwords_with_policy]
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,5 @@
1
+ module Devise
2
+ module SecurePassword
3
+ VERSION = '1.0.0'.freeze
4
+ end
5
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Devise
4
+ module SecurePassword
5
+ module Generators
6
+ class InstallGenerator < Rails::Generators::Base
7
+ LOCALES = %w(en).freeze
8
+
9
+ source_root File.expand_path('../templates', __dir__)
10
+
11
+ desc 'Creates a Devise Secure Password extension initializer and copies locale files to your application.'
12
+
13
+ def copy_initializer
14
+ template 'secure_password.rb', 'config/initializers/secure_password.rb'
15
+ end
16
+
17
+ def copy_locale
18
+ LOCALES.each do |locale|
19
+ copy_file "../../../../config/locales/#{locale}.yml",
20
+ "config/locales/secure_password.#{locale}.yml"
21
+ end
22
+ end
23
+
24
+ def show_readme
25
+ readme 'README.txt' if behavior == :invoke
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,21 @@
1
+ ===============================================================================
2
+
3
+ Additional setup required:
4
+
5
+ 1. Verify that default settings in config/initializers/secure_password.rb
6
+ are suitable for your purposes.
7
+
8
+ 2. Enable secure_password modules by adding all of them or just the ones you
9
+ want to your User model. See the README for instructions.
10
+
11
+ 3. Perform a database migration to create the PreviousPasswords table. This
12
+ step is not necessary if you only intend to enable the password content
13
+ module (password_has_required_content). See the README for instructions.
14
+
15
+ 4. Add flash messages in app/views/layouts/application.html.erb.
16
+ For example:
17
+
18
+ <p class="notice"><%= notice %></p>
19
+ <p class="alert"><%= alert %></p>
20
+
21
+ ===============================================================================
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ Devise.setup do |config|
4
+ # ==> Configuration for the Devise Secure Password extension
5
+ # Module: password_has_required_content
6
+ #
7
+ # Configure password content requirements including the number of uppercase,
8
+ # lowercase, number, and special characters that are required. To configure the
9
+ # minimum and maximum length refer to the Devise config.password_length
10
+ # standard configuration parameter.
11
+
12
+ # Passwords consist of at least one uppercase letter (latin A-Z):
13
+ # config.password_required_uppercase_count = 1
14
+
15
+ # Passwords consist of at least one lowercase characters (latin a-z):
16
+ # config.password_required_lowercase_count = 1
17
+
18
+ # Passwords consist of at least one number (0-9):
19
+ # config.password_required_number_count = 1
20
+
21
+ # Passwords consist of at least one special character (!@#$%^&*()_+-=[]{}|'):
22
+ # config.password_required_special_character_count = 1
23
+
24
+ # ==> Configuration for the Devise Secure Password extension
25
+ # Module: password_disallows_frequent_reuse
26
+ #
27
+ # Passwords cannot be reused. A user's last 24 password hashes are saved:
28
+ # config.password_previously_used_count = 24
29
+
30
+ # ==> Configuration for the Devise Secure Password extension
31
+ # Module: password_disallows_frequent_changes
32
+ # *Requires* password_disallows_frequent_reuse
33
+ #
34
+ # Passwords cannot be changed more frequently than once per day:
35
+ # config.password_minimum_age = 1.day
36
+
37
+ # ==> Configuration for the Devise Secure Password extension
38
+ # Module: password_requires_regular_updates
39
+ # *Requires* password_disallows_frequent_reuse
40
+ #
41
+ # Passwords must be changed every 60 days:
42
+ # config.password_maximum_age = 60.days
43
+ end
@@ -0,0 +1,53 @@
1
+ # lib/support/character_counter.rb
2
+ #
3
+ module Support
4
+ module String
5
+ class CharacterCounter
6
+ attr_reader :count_hash
7
+
8
+ def initialize
9
+ @count_hash = {
10
+ uppercase: characters_to_dictionary(('A'..'Z').to_a),
11
+ lowercase: characters_to_dictionary(('a'..'z').to_a),
12
+ number: characters_to_dictionary(('0'..'9').to_a),
13
+ special: characters_to_dictionary(%w(! @ # $ % ^ & * ( ) _ + - = [ ] { } | ')),
14
+ unknown: {}
15
+ }
16
+ end
17
+
18
+ def count(string)
19
+ raise ArgumentError, "Invalid value for string: #{string}" if string.nil?
20
+
21
+ string.split('').each { |c| tally_character(c) }
22
+
23
+ @count_hash
24
+ end
25
+
26
+ private
27
+
28
+ def characters_to_dictionary(array)
29
+ dictionary = {}
30
+ array.each { |c| dictionary.store(c, 0) }
31
+
32
+ dictionary
33
+ end
34
+
35
+ def tally_character(character)
36
+ %i(uppercase lowercase number special unknown).each do |type|
37
+ if @count_hash[type].key?(character)
38
+ @count_hash[type][character] += 1
39
+ return @count_hash[type][character]
40
+ end
41
+ end
42
+
43
+ # must be new unknown char
44
+ @count_hash[:unknown][character] = 1
45
+ @count_hash[:unknown][character]
46
+ end
47
+
48
+ def character_in_dictionary?(character, dictionary)
49
+ dictionary.key?(character)
50
+ end
51
+ end
52
+ end
53
+ end
metadata ADDED
@@ -0,0 +1,471 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: devise-secure_password
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Mark Eissler
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2018-03-07 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: devise
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 4.0.0
20
+ - - "<"
21
+ - !ruby/object:Gem::Version
22
+ version: 5.0.0
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ version: 4.0.0
30
+ - - "<"
31
+ - !ruby/object:Gem::Version
32
+ version: 5.0.0
33
+ - !ruby/object:Gem::Dependency
34
+ name: railties
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: 5.0.0
40
+ - - "<"
41
+ - !ruby/object:Gem::Version
42
+ version: 6.0.0
43
+ type: :runtime
44
+ prerelease: false
45
+ version_requirements: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - ">="
48
+ - !ruby/object:Gem::Version
49
+ version: 5.0.0
50
+ - - "<"
51
+ - !ruby/object:Gem::Version
52
+ version: 6.0.0
53
+ - !ruby/object:Gem::Dependency
54
+ name: bundler
55
+ requirement: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - "~>"
58
+ - !ruby/object:Gem::Version
59
+ version: '1.16'
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: 1.16.1
63
+ type: :development
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - "~>"
68
+ - !ruby/object:Gem::Version
69
+ version: '1.16'
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ version: 1.16.1
73
+ - !ruby/object:Gem::Dependency
74
+ name: capybara
75
+ requirement: !ruby/object:Gem::Requirement
76
+ requirements:
77
+ - - "~>"
78
+ - !ruby/object:Gem::Version
79
+ version: '2.16'
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: 2.16.1
83
+ type: :development
84
+ prerelease: false
85
+ version_requirements: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '2.16'
90
+ - - ">="
91
+ - !ruby/object:Gem::Version
92
+ version: 2.16.1
93
+ - !ruby/object:Gem::Dependency
94
+ name: capybara-screenshot
95
+ requirement: !ruby/object:Gem::Requirement
96
+ requirements:
97
+ - - "~>"
98
+ - !ruby/object:Gem::Version
99
+ version: '1.0'
100
+ - - ">="
101
+ - !ruby/object:Gem::Version
102
+ version: 1.0.18
103
+ type: :development
104
+ prerelease: false
105
+ version_requirements: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - "~>"
108
+ - !ruby/object:Gem::Version
109
+ version: '1.0'
110
+ - - ">="
111
+ - !ruby/object:Gem::Version
112
+ version: 1.0.18
113
+ - !ruby/object:Gem::Dependency
114
+ name: coffee-rails
115
+ requirement: !ruby/object:Gem::Requirement
116
+ requirements:
117
+ - - "~>"
118
+ - !ruby/object:Gem::Version
119
+ version: '4.2'
120
+ type: :development
121
+ prerelease: false
122
+ version_requirements: !ruby/object:Gem::Requirement
123
+ requirements:
124
+ - - "~>"
125
+ - !ruby/object:Gem::Version
126
+ version: '4.2'
127
+ - !ruby/object:Gem::Dependency
128
+ name: database_cleaner
129
+ requirement: !ruby/object:Gem::Requirement
130
+ requirements:
131
+ - - "~>"
132
+ - !ruby/object:Gem::Version
133
+ version: '1.6'
134
+ - - ">="
135
+ - !ruby/object:Gem::Version
136
+ version: 1.6.2
137
+ type: :development
138
+ prerelease: false
139
+ version_requirements: !ruby/object:Gem::Requirement
140
+ requirements:
141
+ - - "~>"
142
+ - !ruby/object:Gem::Version
143
+ version: '1.6'
144
+ - - ">="
145
+ - !ruby/object:Gem::Version
146
+ version: 1.6.2
147
+ - !ruby/object:Gem::Dependency
148
+ name: devise
149
+ requirement: !ruby/object:Gem::Requirement
150
+ requirements:
151
+ - - "~>"
152
+ - !ruby/object:Gem::Version
153
+ version: '4.0'
154
+ type: :development
155
+ prerelease: false
156
+ version_requirements: !ruby/object:Gem::Requirement
157
+ requirements:
158
+ - - "~>"
159
+ - !ruby/object:Gem::Version
160
+ version: '4.0'
161
+ - !ruby/object:Gem::Dependency
162
+ name: flay
163
+ requirement: !ruby/object:Gem::Requirement
164
+ requirements:
165
+ - - "~>"
166
+ - !ruby/object:Gem::Version
167
+ version: '2.10'
168
+ - - ">="
169
+ - !ruby/object:Gem::Version
170
+ version: 2.10.0
171
+ type: :development
172
+ prerelease: false
173
+ version_requirements: !ruby/object:Gem::Requirement
174
+ requirements:
175
+ - - "~>"
176
+ - !ruby/object:Gem::Version
177
+ version: '2.10'
178
+ - - ">="
179
+ - !ruby/object:Gem::Version
180
+ version: 2.10.0
181
+ - !ruby/object:Gem::Dependency
182
+ name: launchy
183
+ requirement: !ruby/object:Gem::Requirement
184
+ requirements:
185
+ - - "~>"
186
+ - !ruby/object:Gem::Version
187
+ version: '2.4'
188
+ - - ">="
189
+ - !ruby/object:Gem::Version
190
+ version: 2.4.3
191
+ type: :development
192
+ prerelease: false
193
+ version_requirements: !ruby/object:Gem::Requirement
194
+ requirements:
195
+ - - "~>"
196
+ - !ruby/object:Gem::Version
197
+ version: '2.4'
198
+ - - ">="
199
+ - !ruby/object:Gem::Version
200
+ version: 2.4.3
201
+ - !ruby/object:Gem::Dependency
202
+ name: rails
203
+ requirement: !ruby/object:Gem::Requirement
204
+ requirements:
205
+ - - "~>"
206
+ - !ruby/object:Gem::Version
207
+ version: '5.1'
208
+ - - ">="
209
+ - !ruby/object:Gem::Version
210
+ version: 5.1.4
211
+ type: :development
212
+ prerelease: false
213
+ version_requirements: !ruby/object:Gem::Requirement
214
+ requirements:
215
+ - - "~>"
216
+ - !ruby/object:Gem::Version
217
+ version: '5.1'
218
+ - - ">="
219
+ - !ruby/object:Gem::Version
220
+ version: 5.1.4
221
+ - !ruby/object:Gem::Dependency
222
+ name: rake
223
+ requirement: !ruby/object:Gem::Requirement
224
+ requirements:
225
+ - - "~>"
226
+ - !ruby/object:Gem::Version
227
+ version: '12.3'
228
+ type: :development
229
+ prerelease: false
230
+ version_requirements: !ruby/object:Gem::Requirement
231
+ requirements:
232
+ - - "~>"
233
+ - !ruby/object:Gem::Version
234
+ version: '12.3'
235
+ - !ruby/object:Gem::Dependency
236
+ name: rspec
237
+ requirement: !ruby/object:Gem::Requirement
238
+ requirements:
239
+ - - "~>"
240
+ - !ruby/object:Gem::Version
241
+ version: '3.7'
242
+ type: :development
243
+ prerelease: false
244
+ version_requirements: !ruby/object:Gem::Requirement
245
+ requirements:
246
+ - - "~>"
247
+ - !ruby/object:Gem::Version
248
+ version: '3.7'
249
+ - !ruby/object:Gem::Dependency
250
+ name: rspec-rails
251
+ requirement: !ruby/object:Gem::Requirement
252
+ requirements:
253
+ - - "~>"
254
+ - !ruby/object:Gem::Version
255
+ version: '3.7'
256
+ type: :development
257
+ prerelease: false
258
+ version_requirements: !ruby/object:Gem::Requirement
259
+ requirements:
260
+ - - "~>"
261
+ - !ruby/object:Gem::Version
262
+ version: '3.7'
263
+ - !ruby/object:Gem::Dependency
264
+ name: rspec_junit_formatter
265
+ requirement: !ruby/object:Gem::Requirement
266
+ requirements:
267
+ - - "~>"
268
+ - !ruby/object:Gem::Version
269
+ version: '0.3'
270
+ type: :development
271
+ prerelease: false
272
+ version_requirements: !ruby/object:Gem::Requirement
273
+ requirements:
274
+ - - "~>"
275
+ - !ruby/object:Gem::Version
276
+ version: '0.3'
277
+ - !ruby/object:Gem::Dependency
278
+ name: rubocop
279
+ requirement: !ruby/object:Gem::Requirement
280
+ requirements:
281
+ - - "~>"
282
+ - !ruby/object:Gem::Version
283
+ version: '0'
284
+ type: :development
285
+ prerelease: false
286
+ version_requirements: !ruby/object:Gem::Requirement
287
+ requirements:
288
+ - - "~>"
289
+ - !ruby/object:Gem::Version
290
+ version: '0'
291
+ - !ruby/object:Gem::Dependency
292
+ name: ruby2ruby
293
+ requirement: !ruby/object:Gem::Requirement
294
+ requirements:
295
+ - - "~>"
296
+ - !ruby/object:Gem::Version
297
+ version: '2.4'
298
+ - - ">="
299
+ - !ruby/object:Gem::Version
300
+ version: 2.4.0
301
+ type: :development
302
+ prerelease: false
303
+ version_requirements: !ruby/object:Gem::Requirement
304
+ requirements:
305
+ - - "~>"
306
+ - !ruby/object:Gem::Version
307
+ version: '2.4'
308
+ - - ">="
309
+ - !ruby/object:Gem::Version
310
+ version: 2.4.0
311
+ - !ruby/object:Gem::Dependency
312
+ name: sass-rails
313
+ requirement: !ruby/object:Gem::Requirement
314
+ requirements:
315
+ - - "~>"
316
+ - !ruby/object:Gem::Version
317
+ version: '5.0'
318
+ type: :development
319
+ prerelease: false
320
+ version_requirements: !ruby/object:Gem::Requirement
321
+ requirements:
322
+ - - "~>"
323
+ - !ruby/object:Gem::Version
324
+ version: '5.0'
325
+ - !ruby/object:Gem::Dependency
326
+ name: selenium-webdriver
327
+ requirement: !ruby/object:Gem::Requirement
328
+ requirements:
329
+ - - "~>"
330
+ - !ruby/object:Gem::Version
331
+ version: '3.7'
332
+ - - ">="
333
+ - !ruby/object:Gem::Version
334
+ version: 3.7.0
335
+ type: :development
336
+ prerelease: false
337
+ version_requirements: !ruby/object:Gem::Requirement
338
+ requirements:
339
+ - - "~>"
340
+ - !ruby/object:Gem::Version
341
+ version: '3.7'
342
+ - - ">="
343
+ - !ruby/object:Gem::Version
344
+ version: 3.7.0
345
+ - !ruby/object:Gem::Dependency
346
+ name: simplecov
347
+ requirement: !ruby/object:Gem::Requirement
348
+ requirements:
349
+ - - "~>"
350
+ - !ruby/object:Gem::Version
351
+ version: 0.15.1
352
+ type: :development
353
+ prerelease: false
354
+ version_requirements: !ruby/object:Gem::Requirement
355
+ requirements:
356
+ - - "~>"
357
+ - !ruby/object:Gem::Version
358
+ version: 0.15.1
359
+ - !ruby/object:Gem::Dependency
360
+ name: simplecov-console
361
+ requirement: !ruby/object:Gem::Requirement
362
+ requirements:
363
+ - - "~>"
364
+ - !ruby/object:Gem::Version
365
+ version: 0.4.2
366
+ type: :development
367
+ prerelease: false
368
+ version_requirements: !ruby/object:Gem::Requirement
369
+ requirements:
370
+ - - "~>"
371
+ - !ruby/object:Gem::Version
372
+ version: 0.4.2
373
+ - !ruby/object:Gem::Dependency
374
+ name: sqlite3
375
+ requirement: !ruby/object:Gem::Requirement
376
+ requirements:
377
+ - - "~>"
378
+ - !ruby/object:Gem::Version
379
+ version: '1.3'
380
+ - - ">="
381
+ - !ruby/object:Gem::Version
382
+ version: 1.3.13
383
+ type: :development
384
+ prerelease: false
385
+ version_requirements: !ruby/object:Gem::Requirement
386
+ requirements:
387
+ - - "~>"
388
+ - !ruby/object:Gem::Version
389
+ version: '1.3'
390
+ - - ">="
391
+ - !ruby/object:Gem::Version
392
+ version: 1.3.13
393
+ - !ruby/object:Gem::Dependency
394
+ name: therubyracer
395
+ requirement: !ruby/object:Gem::Requirement
396
+ requirements:
397
+ - - "~>"
398
+ - !ruby/object:Gem::Version
399
+ version: 0.12.3
400
+ type: :development
401
+ prerelease: false
402
+ version_requirements: !ruby/object:Gem::Requirement
403
+ requirements:
404
+ - - "~>"
405
+ - !ruby/object:Gem::Version
406
+ version: 0.12.3
407
+ description: Adds configurable password policy enforcement to devise.
408
+ email:
409
+ - mark.eissler@valimail.com
410
+ executables: []
411
+ extensions: []
412
+ extra_rdoc_files: []
413
+ files:
414
+ - "./CODE_OF_CONDUCT.md"
415
+ - "./Dockerfile"
416
+ - "./Dockerfile.prev"
417
+ - "./Gemfile"
418
+ - "./Gemfile.lock"
419
+ - "./LICENSE.txt"
420
+ - "./README.md"
421
+ - "./Rakefile"
422
+ - "./app/controllers/devise/passwords_with_policy_controller.rb"
423
+ - "./app/views/devise/passwords_with_policy/edit.html.erb"
424
+ - "./bin/console"
425
+ - "./bin/setup"
426
+ - "./config/locales/en.yml"
427
+ - "./devise-secure_password.gemspec"
428
+ - "./docker-entrypoint.sh"
429
+ - "./gemfiles/rails-5_0_6.gemfile"
430
+ - "./gemfiles/rails-5_1_4.gemfile"
431
+ - "./lib/devise/secure_password.rb"
432
+ - "./lib/devise/secure_password/controllers/active_helpers.rb"
433
+ - "./lib/devise/secure_password/controllers/devise_helpers.rb"
434
+ - "./lib/devise/secure_password/hooks/password_requires_regular_updates.rb"
435
+ - "./lib/devise/secure_password/models/password_disallows_frequent_changes.rb"
436
+ - "./lib/devise/secure_password/models/password_disallows_frequent_reuse.rb"
437
+ - "./lib/devise/secure_password/models/password_has_required_content.rb"
438
+ - "./lib/devise/secure_password/models/password_requires_regular_updates.rb"
439
+ - "./lib/devise/secure_password/models/previous_password.rb"
440
+ - "./lib/devise/secure_password/routes.rb"
441
+ - "./lib/devise/secure_password/version.rb"
442
+ - "./lib/generators/devise/secure_password/install_generator.rb"
443
+ - "./lib/generators/devise/templates/README.txt"
444
+ - "./lib/generators/devise/templates/secure_password.rb"
445
+ - "./lib/support/string/character_counter.rb"
446
+ - "./pkg/devise-secure_password-1.0.0.gem"
447
+ homepage: https://github.com/valimail/devise-secure_password
448
+ licenses:
449
+ - MIT
450
+ metadata: {}
451
+ post_install_message:
452
+ rdoc_options: []
453
+ require_paths:
454
+ - lib
455
+ required_ruby_version: !ruby/object:Gem::Requirement
456
+ requirements:
457
+ - - ">="
458
+ - !ruby/object:Gem::Version
459
+ version: '2.4'
460
+ required_rubygems_version: !ruby/object:Gem::Requirement
461
+ requirements:
462
+ - - ">="
463
+ - !ruby/object:Gem::Version
464
+ version: '0'
465
+ requirements: []
466
+ rubyforge_project:
467
+ rubygems_version: 2.7.5
468
+ signing_key:
469
+ specification_version: 4
470
+ summary: A devise password policy enforcement extension.
471
+ test_files: []