devise-security 0.16.0 → 0.18.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 (140) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +3 -1
  3. data/README.md +18 -7
  4. data/app/controllers/devise/paranoid_verification_code_controller.rb +26 -12
  5. data/app/controllers/devise/password_expired_controller.rb +22 -5
  6. data/config/locales/bg.yml +42 -0
  7. data/config/locales/by.yml +1 -0
  8. data/config/locales/cs.yml +5 -0
  9. data/config/locales/de.yml +3 -0
  10. data/config/locales/en.yml +2 -1
  11. data/config/locales/es.yml +12 -0
  12. data/config/locales/fa.yml +1 -0
  13. data/config/locales/fr.yml +14 -2
  14. data/config/locales/hi.yml +1 -0
  15. data/config/locales/it.yml +1 -0
  16. data/config/locales/ja.yml +12 -0
  17. data/config/locales/nl.yml +1 -0
  18. data/config/locales/pt.yml +1 -0
  19. data/config/locales/ru.yml +1 -0
  20. data/config/locales/tr.yml +25 -1
  21. data/config/locales/uk.yml +1 -0
  22. data/config/locales/zh_CN.yml +1 -0
  23. data/config/locales/zh_TW.yml +1 -0
  24. data/lib/devise-security/controllers/helpers.rb +23 -11
  25. data/lib/devise-security/hooks/expirable.rb +3 -3
  26. data/lib/devise-security/hooks/paranoid_verification.rb +1 -3
  27. data/lib/devise-security/hooks/password_expirable.rb +1 -3
  28. data/lib/devise-security/hooks/session_limitable.rb +4 -4
  29. data/lib/devise-security/models/compatibility/active_record_patch.rb +4 -3
  30. data/lib/devise-security/models/compatibility/mongoid_patch.rb +3 -2
  31. data/lib/devise-security/models/database_authenticatable_patch.rb +18 -10
  32. data/lib/devise-security/models/expirable.rb +6 -5
  33. data/lib/devise-security/models/paranoid_verification.rb +2 -2
  34. data/lib/devise-security/models/password_archivable.rb +3 -3
  35. data/lib/devise-security/models/secure_validatable.rb +57 -20
  36. data/lib/devise-security/orm/mongoid.rb +1 -1
  37. data/lib/devise-security/patches.rb +14 -8
  38. data/lib/devise-security/routes.rb +2 -3
  39. data/lib/devise-security/validators/password_complexity_validator.rb +53 -26
  40. data/lib/devise-security/version.rb +1 -1
  41. data/lib/devise-security.rb +9 -3
  42. data/lib/generators/devise_security/install_generator.rb +3 -5
  43. data/lib/generators/templates/devise_security.rb +6 -1
  44. data/test/controllers/test_paranoid_verification_code_controller.rb +133 -0
  45. data/test/controllers/test_password_expired_controller.rb +87 -33
  46. data/test/controllers/test_security_question_controller.rb +25 -19
  47. data/test/dummy/app/controllers/overrides/paranoid_verification_code_controller.rb +7 -0
  48. data/test/dummy/app/controllers/overrides/password_expired_controller.rb +17 -0
  49. data/test/dummy/app/controllers/widgets_controller.rb +3 -0
  50. data/test/dummy/app/models/application_user_record.rb +2 -1
  51. data/test/dummy/app/models/mongoid/confirmable_fields.rb +2 -0
  52. data/test/dummy/app/models/mongoid/database_authenticable_fields.rb +4 -3
  53. data/test/dummy/app/models/mongoid/expirable_fields.rb +2 -0
  54. data/test/dummy/app/models/mongoid/lockable_fields.rb +2 -0
  55. data/test/dummy/app/models/mongoid/mappings.rb +4 -2
  56. data/test/dummy/app/models/mongoid/omniauthable_fields.rb +2 -0
  57. data/test/dummy/app/models/mongoid/paranoid_verification_fields.rb +2 -0
  58. data/test/dummy/app/models/mongoid/password_archivable_fields.rb +2 -0
  59. data/test/dummy/app/models/mongoid/password_expirable_fields.rb +2 -0
  60. data/test/dummy/app/models/mongoid/recoverable_fields.rb +2 -0
  61. data/test/dummy/app/models/mongoid/registerable_fields.rb +4 -2
  62. data/test/dummy/app/models/mongoid/rememberable_fields.rb +2 -0
  63. data/test/dummy/app/models/mongoid/secure_validatable_fields.rb +2 -0
  64. data/test/dummy/app/models/mongoid/security_questionable_fields.rb +2 -0
  65. data/test/dummy/app/models/mongoid/session_limitable_fields.rb +2 -0
  66. data/test/dummy/app/models/mongoid/timeoutable_fields.rb +2 -0
  67. data/test/dummy/app/models/mongoid/trackable_fields.rb +2 -0
  68. data/test/dummy/app/models/mongoid/validatable_fields.rb +2 -0
  69. data/test/dummy/app/models/paranoid_verification_user.rb +26 -0
  70. data/test/dummy/app/models/password_expired_user.rb +26 -0
  71. data/test/dummy/app/models/user.rb +5 -5
  72. data/test/dummy/app/models/widget.rb +1 -3
  73. data/test/dummy/app/mongoid/one_user.rb +5 -5
  74. data/test/dummy/app/mongoid/user_on_engine.rb +2 -2
  75. data/test/dummy/app/mongoid/user_on_main_app.rb +2 -2
  76. data/test/dummy/app/mongoid/user_with_validations.rb +3 -3
  77. data/test/dummy/app/mongoid/user_without_email.rb +7 -4
  78. data/test/dummy/config/application.rb +3 -7
  79. data/test/dummy/config/boot.rb +1 -1
  80. data/test/dummy/config/environment.rb +1 -1
  81. data/test/dummy/config/environments/test.rb +1 -0
  82. data/test/dummy/config/initializers/devise.rb +1 -5
  83. data/test/dummy/config/locales/en.yml +10 -0
  84. data/test/dummy/config/routes.rb +3 -1
  85. data/test/dummy/config.ru +1 -1
  86. data/test/dummy/db/migrate/20120508165529_create_tables.rb +5 -5
  87. data/test/dummy/lib/shared_expirable_columns.rb +1 -0
  88. data/test/dummy/lib/shared_security_questions_fields.rb +1 -0
  89. data/test/dummy/lib/shared_user.rb +17 -6
  90. data/test/dummy/lib/shared_user_without_omniauth.rb +12 -3
  91. data/test/dummy/lib/shared_verification_fields.rb +1 -0
  92. data/test/dummy/log/test.log +39637 -16086
  93. data/test/i18n_test.rb +22 -0
  94. data/test/integration/test_paranoid_verification_code_workflow.rb +53 -0
  95. data/test/integration/test_password_expirable_workflow.rb +2 -2
  96. data/test/integration/test_session_limitable_workflow.rb +5 -3
  97. data/test/orm/active_record.rb +7 -7
  98. data/test/support/integration_helpers.rb +18 -12
  99. data/test/test_compatibility.rb +2 -0
  100. data/test/test_complexity_validator.rb +247 -37
  101. data/test/test_database_authenticatable_patch.rb +146 -0
  102. data/test/test_helper.rb +7 -8
  103. data/test/test_install_generator.rb +1 -1
  104. data/test/test_paranoid_verification.rb +8 -9
  105. data/test/test_password_archivable.rb +34 -11
  106. data/test/test_password_expirable.rb +27 -27
  107. data/test/test_secure_validatable.rb +265 -107
  108. data/test/test_secure_validatable_overrides.rb +185 -0
  109. data/test/test_session_limitable.rb +9 -9
  110. data/test/tmp/config/initializers/{devise-security.rb → devise_security.rb} +6 -1
  111. data/test/tmp/config/locales/devise.security_extension.by.yml +1 -0
  112. data/test/tmp/config/locales/devise.security_extension.cs.yml +5 -0
  113. data/test/tmp/config/locales/devise.security_extension.de.yml +3 -0
  114. data/test/tmp/config/locales/devise.security_extension.en.yml +2 -1
  115. data/test/tmp/config/locales/devise.security_extension.es.yml +12 -0
  116. data/test/tmp/config/locales/devise.security_extension.fa.yml +1 -0
  117. data/test/tmp/config/locales/devise.security_extension.fr.yml +14 -2
  118. data/test/tmp/config/locales/devise.security_extension.hi.yml +21 -20
  119. data/test/tmp/config/locales/devise.security_extension.it.yml +1 -0
  120. data/test/tmp/config/locales/devise.security_extension.ja.yml +12 -0
  121. data/test/tmp/config/locales/devise.security_extension.nl.yml +1 -0
  122. data/test/tmp/config/locales/devise.security_extension.pt.yml +1 -0
  123. data/test/tmp/config/locales/devise.security_extension.ru.yml +1 -0
  124. data/test/tmp/config/locales/devise.security_extension.tr.yml +25 -1
  125. data/test/tmp/config/locales/devise.security_extension.uk.yml +1 -0
  126. data/test/tmp/config/locales/devise.security_extension.zh_CN.yml +1 -0
  127. data/test/tmp/config/locales/devise.security_extension.zh_TW.yml +1 -0
  128. metadata +82 -41
  129. data/lib/devise-security/patches/confirmations_controller_captcha.rb +0 -23
  130. data/lib/devise-security/patches/confirmations_controller_security_question.rb +0 -26
  131. data/lib/devise-security/patches/passwords_controller_captcha.rb +0 -22
  132. data/lib/devise-security/patches/passwords_controller_security_question.rb +0 -25
  133. data/lib/devise-security/patches/registrations_controller_captcha.rb +0 -35
  134. data/lib/devise-security/patches/sessions_controller_captcha.rb +0 -26
  135. data/lib/devise-security/patches/unlocks_controller_captcha.rb +0 -22
  136. data/lib/devise-security/patches/unlocks_controller_security_question.rb +0 -25
  137. data/test/dummy/app/controllers/foos_controller.rb +0 -0
  138. data/test/dummy/app/models/secure_user.rb +0 -9
  139. data/test/dummy/lib/shared_user_without_email.rb +0 -28
  140. data/test/dummy/log/development.log +0 -883
@@ -11,16 +11,16 @@ class OneUser
11
11
  field :password_changed_at, type: Time
12
12
  index({ password_changed_at: 1 }, {})
13
13
 
14
- #field :paranoid_verification_code, type: String
15
- #field :paranoid_verified_at, type: Time
16
- #field :paranoid_verification_attempt, type: Integer, default: 0
14
+ field :paranoid_verification_code, type: String
15
+ field :paranoid_verified_at, type: Time
16
+ field :paranoid_verification_attempt, type: Integer, default: 0
17
17
 
18
18
  field :username, type: String
19
19
  field :facebook_token, type: String
20
20
 
21
21
  ## Database authenticatable
22
- field :email, type: String, default: ""
23
- field :encrypted_password, type: String, default: ""
22
+ field :email, type: String, default: ''
23
+ field :encrypted_password, type: String, default: ''
24
24
 
25
25
  ## Recoverable
26
26
  field :reset_password_token, type: String
@@ -11,8 +11,8 @@ class UserOnEngine
11
11
  field :facebook_token, type: String
12
12
 
13
13
  ## Database authenticatable
14
- field :email, type: String, default: ""
15
- field :encrypted_password, type: String, default: ""
14
+ field :email, type: String, default: ''
15
+ field :encrypted_password, type: String, default: ''
16
16
 
17
17
  ## Recoverable
18
18
  field :reset_password_token, type: String
@@ -11,8 +11,8 @@ class UserOnMainApp
11
11
  field :facebook_token, type: String
12
12
 
13
13
  ## Database authenticatable
14
- field :email, type: String, default: ""
15
- field :encrypted_password, type: String, default: ""
14
+ field :email, type: String, default: ''
15
+ field :encrypted_password, type: String, default: ''
16
16
 
17
17
  ## Recoverable
18
18
  field :reset_password_token, type: String
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "shared_user"
3
+ require 'shared_user'
4
4
 
5
5
  class UserWithValidations
6
6
  include Mongoid::Document
@@ -11,8 +11,8 @@ class UserWithValidations
11
11
  field :facebook_token, type: String
12
12
 
13
13
  ## Database authenticatable
14
- field :email, type: String, default: ""
15
- field :encrypted_password, type: String, default: ""
14
+ field :email, type: String, default: ''
15
+ field :encrypted_password, type: String, default: ''
16
16
 
17
17
  ## Recoverable
18
18
  field :reset_password_token, type: String
@@ -1,18 +1,21 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "shared_user_without_email"
3
+ require 'shared_user_without_email'
4
4
 
5
5
  class UserWithoutEmail
6
6
  include Mongoid::Document
7
7
  include Shim
8
- include SharedUserWithoutEmail
8
+
9
+ devise :database_authenticatable, :lockable, :recoverable,
10
+ :registerable, :rememberable, :timeoutable,
11
+ :trackable
9
12
 
10
13
  field :username, type: String
11
14
  field :facebook_token, type: String
12
15
 
13
16
  ## Database authenticatable
14
- field :email, type: String, default: ""
15
- field :encrypted_password, type: String, default: ""
17
+ field :email, type: String, default: ''
18
+ field :encrypted_password, type: String, default: ''
16
19
 
17
20
  ## Recoverable
18
21
  field :reset_password_token, type: String
@@ -1,10 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require File.expand_path('../boot', __FILE__)
3
+ require File.expand_path('boot', __dir__)
4
4
 
5
5
  require 'action_mailer/railtie'
6
- require "action_mailer/railtie"
7
- require "rails/test_unit/railtie"
6
+ require 'rails/test_unit/railtie'
8
7
  DEVISE_ORM = ENV.fetch('DEVISE_ORM', 'active_record').to_sym
9
8
 
10
9
  Bundler.require :default, DEVISE_ORM
@@ -22,9 +21,6 @@ module RailsApp
22
21
  config.autoload_paths += ["#{config.root}/app/#{DEVISE_ORM}"]
23
22
  config.autoload_paths += ["#{config.root}/lib"]
24
23
 
25
- config.assets.enabled = true
26
-
27
- config.assets.version = '1.0'
28
- config.secret_key_base = 'fuuuuuuuuuuu'
24
+ config.secret_key_base = 'foobar'
29
25
  end
30
26
  end
@@ -3,6 +3,6 @@
3
3
  require 'rubygems'
4
4
 
5
5
  # Set up gems listed in the Gemfile.
6
- ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
6
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__)
7
7
 
8
8
  require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE'])
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Load the rails application
4
- require File.expand_path('../application', __FILE__)
4
+ require File.expand_path('application', __dir__)
5
5
 
6
6
  # Initialize the rails application
7
7
  RailsApp::Application.initialize!
@@ -23,5 +23,6 @@ RailsApp::Application.configure do
23
23
  config.active_support.test_order = :sorted
24
24
  config.log_level = :debug
25
25
  config.active_record.sqlite3.represent_boolean_as_integer = true if Rails.gem_version.release >= Gem::Version.new('5.2') && Rails.gem_version.release < Gem::Version.new('6.0')
26
+ config.active_record.legacy_connection_handling = false if Rails.gem_version.release >= Gem::Version.new('6.1')
26
27
  end
27
28
  ActiveSupport::Deprecation.debug = true
@@ -8,10 +8,6 @@ Devise.setup do |config|
8
8
  config.secret_key = 'f08cf11a38906f531d2dfc9a2c2d671aa0021be806c21255d4'
9
9
  config.case_insensitive_keys = [:email]
10
10
  config.strip_whitespace_keys = [:email]
11
- config.password_complexity = {
12
- digit: 1,
13
- lower: 1,
14
- upper: 1,
15
- }
11
+ config.password_complexity = { digit: 1, lower: 1, upper: 1 }
16
12
  config.password_length = 7..128
17
13
  end
@@ -0,0 +1,10 @@
1
+ en:
2
+ errors:
3
+ messages:
4
+ password_complexity:
5
+ letter:
6
+ one: must contain at least one letter
7
+ other: must contain at least %{count} letters
8
+ alnum:
9
+ one: must contain at least one letter or number
10
+ other: must contain at least %{count} letters or numbers
@@ -4,7 +4,9 @@ RailsApp::Application.routes.draw do
4
4
  devise_for :users
5
5
 
6
6
  devise_for :captcha_users, only: [:sessions], controllers: { sessions: 'captcha/sessions' }
7
- devise_for :security_question_users, only: [:sessions, :unlocks], controllers: { unlocks: 'security_question/unlocks' }
7
+ devise_for :password_expired_users, only: [:password_expired], controllers: { password_expired: 'overrides/password_expired' }
8
+ devise_for :paranoid_verification_users, only: [:verification_code], controllers: { paranoid_verification_code: 'overrides/paranoid_verification_code' }
9
+ devise_for :security_question_users, only: %i[sessions unlocks], controllers: { unlocks: 'security_question/unlocks' }
8
10
 
9
11
  resources :foos
10
12
  resource :widgets
data/test/dummy/config.ru CHANGED
@@ -2,5 +2,5 @@
2
2
 
3
3
  # This file is used by Rack-based servers to start the application.
4
4
 
5
- require ::File.expand_path('../config/environment', __FILE__)
5
+ require ::File.expand_path('config/environment', __dir__)
6
6
  run RailsApp::Application
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class CreateTables < MIGRATION_CLASS
4
- def self.up
4
+ def self.up # rubocop:disable Metrics/AbcSize
5
5
  create_table :users do |t|
6
6
  t.string :username
7
7
  t.string :facebook_token
@@ -33,13 +33,13 @@ class CreateTables < MIGRATION_CLASS
33
33
  end
34
34
 
35
35
  create_table :old_passwords do |t|
36
- t.string :encrypted_password, :null => false
36
+ t.string :encrypted_password, null: false
37
37
  t.string :password_salt
38
- t.string :password_archivable_type, :null => false
39
- t.integer :password_archivable_id, :null => false
38
+ t.string :password_archivable_type, null: false
39
+ t.integer :password_archivable_id, null: false
40
40
  t.datetime :created_at
41
41
  end
42
- add_index :old_passwords, [:password_archivable_type, :password_archivable_id], name: 'index_password_archivable'
42
+ add_index :old_passwords, %i[password_archivable_type password_archivable_id], name: 'index_password_archivable'
43
43
  end
44
44
 
45
45
  def self.down
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require 'shared_user'
3
4
 
4
5
  module SharedVerificationColumns
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require 'shared_user'
3
4
 
4
5
  module SharedSecurityQuestionsFields
@@ -4,10 +4,21 @@ module SharedUser
4
4
  extend ActiveSupport::Concern
5
5
 
6
6
  included do
7
- devise :database_authenticatable, :confirmable, :lockable, :recoverable,
8
- :registerable, :rememberable, :timeoutable,
9
- :trackable, :secure_validatable, :omniauthable, :validatable, password_length: 7..72,
10
- reconfirmable: false
7
+ devise(
8
+ :database_authenticatable,
9
+ :confirmable,
10
+ :lockable,
11
+ :recoverable,
12
+ :registerable,
13
+ :rememberable,
14
+ :timeoutable,
15
+ :trackable,
16
+ :secure_validatable,
17
+ :omniauthable,
18
+ :validatable,
19
+ password_length: 7..72,
20
+ reconfirmable: false
21
+ )
11
22
 
12
23
  attr_accessor :other_key
13
24
 
@@ -22,8 +33,8 @@ module SharedUser
22
33
  module ExtendMethods
23
34
  def new_with_session(params, session)
24
35
  super.tap do |user|
25
- if data = session["devise.facebook_data"]
26
- user.email = data["email"]
36
+ if (data = session['devise.facebook_data'])
37
+ user.email = data['email']
27
38
  user.confirmed_at = Time.zone.now
28
39
  end
29
40
  end
@@ -4,9 +4,18 @@ module SharedUserWithoutOmniauth
4
4
  extend ActiveSupport::Concern
5
5
 
6
6
  included do
7
- devise :database_authenticatable, :confirmable, :lockable, :recoverable,
8
- :registerable, :rememberable, :timeoutable,
9
- :trackable, :validatable, reconfirmable: false
7
+ devise(
8
+ :database_authenticatable,
9
+ :confirmable,
10
+ :lockable,
11
+ :recoverable,
12
+ :registerable,
13
+ :rememberable,
14
+ :timeoutable,
15
+ :trackable,
16
+ :validatable,
17
+ reconfirmable: false
18
+ )
10
19
  end
11
20
 
12
21
  def raw_confirmation_token
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require 'shared_user'
3
4
 
4
5
  module SharedVerificationFields