devise-secure_password 1.0.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 (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: []