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.
- checksums.yaml +7 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Dockerfile +44 -0
- data/Dockerfile.prev +44 -0
- data/Gemfile +13 -0
- data/Gemfile.lock +280 -0
- data/LICENSE.txt +21 -0
- data/README.md +326 -0
- data/Rakefile +11 -0
- data/app/controllers/devise/passwords_with_policy_controller.rb +52 -0
- data/app/views/devise/passwords_with_policy/edit.html.erb +16 -0
- data/bin/console +14 -0
- data/bin/setup +6 -0
- data/config/locales/en.yml +71 -0
- data/devise-secure_password.gemspec +57 -0
- data/docker-entrypoint.sh +6 -0
- data/gemfiles/rails-5_0_6.gemfile +17 -0
- data/gemfiles/rails-5_1_4.gemfile +16 -0
- data/lib/devise/secure_password.rb +70 -0
- data/lib/devise/secure_password/controllers/active_helpers.rb +40 -0
- data/lib/devise/secure_password/controllers/devise_helpers.rb +64 -0
- data/lib/devise/secure_password/hooks/password_requires_regular_updates.rb +5 -0
- data/lib/devise/secure_password/models/password_disallows_frequent_changes.rb +60 -0
- data/lib/devise/secure_password/models/password_disallows_frequent_reuse.rb +71 -0
- data/lib/devise/secure_password/models/password_has_required_content.rb +131 -0
- data/lib/devise/secure_password/models/password_requires_regular_updates.rb +56 -0
- data/lib/devise/secure_password/models/previous_password.rb +20 -0
- data/lib/devise/secure_password/routes.rb +11 -0
- data/lib/devise/secure_password/version.rb +5 -0
- data/lib/generators/devise/secure_password/install_generator.rb +30 -0
- data/lib/generators/devise/templates/README.txt +21 -0
- data/lib/generators/devise/templates/secure_password.rb +43 -0
- data/lib/support/string/character_counter.rb +53 -0
- data/pkg/devise-secure_password-1.0.0.gem +0 -0
- 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,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
|
Binary file
|
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: []
|