devise-security 0.14.1 → 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 (170) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +3 -1
  3. data/README.md +136 -61
  4. data/app/controllers/devise/paranoid_verification_code_controller.rb +26 -12
  5. data/app/controllers/devise/password_expired_controller.rb +32 -10
  6. data/app/views/devise/paranoid_verification_code/show.html.erb +3 -3
  7. data/app/views/devise/password_expired/show.html.erb +5 -5
  8. data/config/locales/bg.yml +42 -0
  9. data/config/locales/by.yml +50 -0
  10. data/config/locales/cs.yml +46 -0
  11. data/config/locales/de.yml +16 -2
  12. data/config/locales/en.yml +15 -2
  13. data/config/locales/es.yml +22 -9
  14. data/config/locales/fa.yml +42 -0
  15. data/config/locales/fr.yml +15 -2
  16. data/config/locales/hi.yml +43 -0
  17. data/config/locales/it.yml +36 -4
  18. data/config/locales/ja.yml +14 -1
  19. data/config/locales/nl.yml +42 -0
  20. data/config/locales/pt.yml +42 -0
  21. data/config/locales/ru.yml +50 -0
  22. data/config/locales/tr.yml +26 -1
  23. data/config/locales/uk.yml +50 -0
  24. data/config/locales/zh_CN.yml +42 -0
  25. data/config/locales/zh_TW.yml +42 -0
  26. data/lib/devise-security/controllers/helpers.rb +72 -51
  27. data/lib/devise-security/hooks/expirable.rb +3 -3
  28. data/lib/devise-security/hooks/paranoid_verification.rb +1 -3
  29. data/lib/devise-security/hooks/password_expirable.rb +3 -3
  30. data/lib/devise-security/hooks/session_limitable.rb +29 -14
  31. data/lib/devise-security/models/compatibility/{active_record.rb → active_record_patch.rb} +14 -2
  32. data/lib/devise-security/models/compatibility/{mongoid.rb → mongoid_patch.rb} +12 -1
  33. data/lib/devise-security/models/compatibility.rb +2 -2
  34. data/lib/devise-security/models/database_authenticatable_patch.rb +18 -10
  35. data/lib/devise-security/models/expirable.rb +6 -5
  36. data/lib/devise-security/models/paranoid_verification.rb +2 -2
  37. data/lib/devise-security/models/password_archivable.rb +3 -3
  38. data/lib/devise-security/models/password_expirable.rb +5 -1
  39. data/lib/devise-security/models/secure_validatable.rb +62 -11
  40. data/lib/devise-security/models/session_limitable.rb +17 -2
  41. data/lib/devise-security/orm/mongoid.rb +1 -1
  42. data/lib/devise-security/patches.rb +14 -8
  43. data/lib/devise-security/routes.rb +2 -3
  44. data/lib/devise-security/validators/password_complexity_validator.rb +53 -24
  45. data/lib/devise-security/version.rb +1 -1
  46. data/lib/devise-security.rb +15 -6
  47. data/lib/generators/devise_security/install_generator.rb +4 -6
  48. data/lib/generators/templates/{devise-security.rb → devise_security.rb} +9 -1
  49. data/test/controllers/test_paranoid_verification_code_controller.rb +133 -0
  50. data/test/controllers/test_password_expired_controller.rb +164 -0
  51. data/test/{test_security_question_controller.rb → controllers/test_security_question_controller.rb} +19 -37
  52. data/test/dummy/app/assets/config/manifest.js +3 -0
  53. data/test/dummy/app/controllers/overrides/paranoid_verification_code_controller.rb +7 -0
  54. data/test/dummy/app/controllers/overrides/password_expired_controller.rb +17 -0
  55. data/test/dummy/app/controllers/widgets_controller.rb +9 -0
  56. data/test/dummy/app/models/application_user_record.rb +2 -1
  57. data/test/dummy/app/models/mongoid/confirmable_fields.rb +2 -0
  58. data/test/dummy/app/models/mongoid/database_authenticable_fields.rb +4 -3
  59. data/test/dummy/app/models/mongoid/expirable_fields.rb +2 -0
  60. data/test/dummy/app/models/mongoid/lockable_fields.rb +2 -0
  61. data/test/dummy/app/models/mongoid/mappings.rb +4 -2
  62. data/test/dummy/app/models/mongoid/omniauthable_fields.rb +2 -0
  63. data/test/dummy/app/models/mongoid/paranoid_verification_fields.rb +2 -0
  64. data/test/dummy/app/models/mongoid/password_archivable_fields.rb +2 -0
  65. data/test/dummy/app/models/mongoid/password_expirable_fields.rb +2 -0
  66. data/test/dummy/app/models/mongoid/recoverable_fields.rb +2 -0
  67. data/test/dummy/app/models/mongoid/registerable_fields.rb +4 -2
  68. data/test/dummy/app/models/mongoid/rememberable_fields.rb +2 -0
  69. data/test/dummy/app/models/mongoid/secure_validatable_fields.rb +2 -0
  70. data/test/dummy/app/models/mongoid/security_questionable_fields.rb +2 -0
  71. data/test/dummy/app/models/mongoid/session_limitable_fields.rb +2 -0
  72. data/test/dummy/app/models/mongoid/timeoutable_fields.rb +2 -0
  73. data/test/dummy/app/models/mongoid/trackable_fields.rb +2 -0
  74. data/test/dummy/app/models/mongoid/validatable_fields.rb +2 -0
  75. data/test/dummy/app/models/paranoid_verification_user.rb +26 -0
  76. data/test/dummy/app/models/password_expired_user.rb +26 -0
  77. data/test/dummy/app/models/user.rb +10 -2
  78. data/test/dummy/app/models/widget.rb +1 -3
  79. data/test/dummy/app/mongoid/one_user.rb +5 -5
  80. data/test/dummy/app/mongoid/user_on_engine.rb +2 -2
  81. data/test/dummy/app/mongoid/user_on_main_app.rb +2 -2
  82. data/test/dummy/app/mongoid/user_with_validations.rb +3 -3
  83. data/test/dummy/app/mongoid/user_without_email.rb +7 -4
  84. data/test/dummy/config/application.rb +3 -7
  85. data/test/dummy/config/boot.rb +1 -1
  86. data/test/dummy/config/environment.rb +1 -1
  87. data/test/dummy/config/environments/test.rb +4 -13
  88. data/test/dummy/config/initializers/devise.rb +1 -5
  89. data/test/dummy/config/initializers/migration_class.rb +1 -8
  90. data/test/dummy/config/locales/en.yml +10 -0
  91. data/test/dummy/config/mongoid.yml +1 -1
  92. data/test/dummy/config/routes.rb +6 -3
  93. data/test/dummy/config.ru +1 -1
  94. data/test/dummy/db/migrate/20120508165529_create_tables.rb +15 -6
  95. data/test/dummy/lib/shared_expirable_columns.rb +1 -0
  96. data/test/dummy/lib/shared_security_questions_fields.rb +1 -0
  97. data/test/dummy/lib/shared_user.rb +17 -6
  98. data/test/dummy/lib/shared_user_without_omniauth.rb +12 -3
  99. data/test/dummy/lib/shared_verification_fields.rb +1 -0
  100. data/test/dummy/log/test.log +45240 -0
  101. data/test/i18n_test.rb +22 -0
  102. data/test/integration/test_paranoid_verification_code_workflow.rb +53 -0
  103. data/test/integration/test_password_expirable_workflow.rb +53 -0
  104. data/test/integration/test_session_limitable_workflow.rb +69 -0
  105. data/test/orm/active_record.rb +7 -4
  106. data/test/orm/mongoid.rb +2 -1
  107. data/test/support/integration_helpers.rb +35 -0
  108. data/test/support/mongoid.yml +1 -1
  109. data/test/test_compatibility.rb +15 -0
  110. data/test/test_complexity_validator.rb +251 -29
  111. data/test/test_database_authenticatable_patch.rb +146 -0
  112. data/test/test_helper.rb +23 -8
  113. data/test/test_install_generator.rb +12 -2
  114. data/test/test_paranoid_verification.rb +8 -9
  115. data/test/test_password_archivable.rb +34 -11
  116. data/test/test_password_expirable.rb +27 -27
  117. data/test/test_secure_validatable.rb +284 -50
  118. data/test/test_secure_validatable_overrides.rb +185 -0
  119. data/test/test_session_limitable.rb +57 -0
  120. data/test/tmp/config/initializers/devise_security.rb +52 -0
  121. data/test/tmp/config/locales/devise.security_extension.by.yml +50 -0
  122. data/test/tmp/config/locales/devise.security_extension.cs.yml +46 -0
  123. data/test/tmp/config/locales/devise.security_extension.de.yml +42 -0
  124. data/test/tmp/config/locales/devise.security_extension.en.yml +42 -0
  125. data/test/tmp/config/locales/devise.security_extension.es.yml +42 -0
  126. data/test/tmp/config/locales/devise.security_extension.fa.yml +42 -0
  127. data/test/tmp/config/locales/devise.security_extension.fr.yml +42 -0
  128. data/test/tmp/config/locales/devise.security_extension.hi.yml +43 -0
  129. data/test/tmp/config/locales/devise.security_extension.it.yml +42 -0
  130. data/test/tmp/config/locales/devise.security_extension.ja.yml +42 -0
  131. data/test/tmp/config/locales/devise.security_extension.nl.yml +42 -0
  132. data/test/tmp/config/locales/devise.security_extension.pt.yml +42 -0
  133. data/test/tmp/config/locales/devise.security_extension.ru.yml +50 -0
  134. data/test/tmp/config/locales/devise.security_extension.tr.yml +42 -0
  135. data/test/tmp/config/locales/devise.security_extension.uk.yml +50 -0
  136. data/test/tmp/config/locales/devise.security_extension.zh_CN.yml +42 -0
  137. data/test/tmp/config/locales/devise.security_extension.zh_TW.yml +42 -0
  138. metadata +202 -138
  139. data/.codeclimate.yml +0 -63
  140. data/.document +0 -5
  141. data/.gitignore +0 -43
  142. data/.mdlrc +0 -1
  143. data/.rubocop.yml +0 -64
  144. data/.ruby-version +0 -1
  145. data/.travis.yml +0 -39
  146. data/Appraisals +0 -35
  147. data/Gemfile +0 -10
  148. data/Rakefile +0 -27
  149. data/devise-security.gemspec +0 -50
  150. data/gemfiles/rails_4.2_stable.gemfile +0 -16
  151. data/gemfiles/rails_5.0_stable.gemfile +0 -15
  152. data/gemfiles/rails_5.1_stable.gemfile +0 -15
  153. data/gemfiles/rails_5.2_stable.gemfile +0 -15
  154. data/gemfiles/rails_6.0_beta.gemfile +0 -15
  155. data/lib/devise-security/orm/active_record.rb +0 -20
  156. data/lib/devise-security/patches/confirmations_controller_captcha.rb +0 -23
  157. data/lib/devise-security/patches/confirmations_controller_security_question.rb +0 -26
  158. data/lib/devise-security/patches/passwords_controller_captcha.rb +0 -22
  159. data/lib/devise-security/patches/passwords_controller_security_question.rb +0 -25
  160. data/lib/devise-security/patches/registrations_controller_captcha.rb +0 -35
  161. data/lib/devise-security/patches/sessions_controller_captcha.rb +0 -26
  162. data/lib/devise-security/patches/unlocks_controller_captcha.rb +0 -22
  163. data/lib/devise-security/patches/unlocks_controller_security_question.rb +0 -25
  164. data/lib/devise-security/schema.rb +0 -66
  165. data/test/dummy/app/controllers/foos_controller.rb +0 -0
  166. data/test/dummy/app/models/.gitkeep +0 -0
  167. data/test/dummy/app/models/secure_user.rb +0 -9
  168. data/test/dummy/lib/shared_user_without_email.rb +0 -28
  169. data/test/test_password_expired_controller.rb +0 -46
  170. /data/test/{test_captcha_controller.rb → controllers/test_captcha_controller.rb} +0 -0
@@ -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!
@@ -4,13 +4,8 @@ RailsApp::Application.configure do
4
4
  config.cache_classes = true
5
5
  config.eager_load = false
6
6
 
7
- if Rails.version > '5'
8
- config.public_file_server.enabled = true
9
- config.public_file_server.headers = { 'Cache-Control' => 'public, max-age=3600' }
10
- else
11
- config.serve_static_files = true
12
- config.static_cache_control = 'public, max-age=3600'
13
- end
7
+ config.public_file_server.enabled = true
8
+ config.public_file_server.headers = { 'Cache-Control' => 'public, max-age=3600' }
14
9
 
15
10
  config.consider_all_requests_local = true
16
11
  config.action_controller.perform_caching = false
@@ -27,11 +22,7 @@ RailsApp::Application.configure do
27
22
 
28
23
  config.active_support.test_order = :sorted
29
24
  config.log_level = :debug
30
- if Rails.gem_version >= Gem::Version.new('4.2') && Rails.gem_version.release < Gem::Version.new('5.0')
31
- config.active_record.raise_in_transactional_callbacks = true
32
- end
33
- if Rails.gem_version.release >= Gem::Version.new('5.2') && Rails.gem_version.release < Gem::Version.new('6.0')
34
- config.active_record.sqlite3.represent_boolean_as_integer = true
35
- end
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')
36
27
  end
37
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
@@ -1,10 +1,3 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- if DEVISE_ORM == :active_record
4
- MIGRATION_CLASS =
5
- if Rails.gem_version >= Gem::Version.new('5.0')
6
- ActiveRecord::Migration[Rails.version.to_f]
7
- else
8
- ActiveRecord::Migration
9
- end
10
- end
3
+ MIGRATION_CLASS = ActiveRecord::Migration[Rails.version.to_f] if DEVISE_ORM == :active_record
@@ -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
@@ -1,5 +1,5 @@
1
1
  test:
2
- <%= Mongoid::VERSION.to_i > 4 ? 'clients' : 'sessions' %>:
2
+ clients:
3
3
  default:
4
4
  database: devise_security_test
5
5
  hosts:
@@ -3,10 +3,13 @@
3
3
  RailsApp::Application.routes.draw do
4
4
  devise_for :users
5
5
 
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" }
6
+ devise_for :captcha_users, only: [:sessions], controllers: { sessions: 'captcha/sessions' }
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
12
+ resource :widgets
10
13
 
11
- root to: 'foos#index'
14
+ root to: 'widgets#show'
12
15
  end
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,17 +1,26 @@
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
8
- t.string :unique_session_id, :limit => 20
8
+
9
+ # session_limitable
10
+ t.string :unique_session_id
9
11
 
10
12
  ## Database authenticatable
11
13
  t.string :email, null: false, default: ''
12
14
  t.string :encrypted_password, null: false, default: ''
13
15
 
14
16
  t.datetime :password_changed_at
17
+
18
+ t.datetime :current_sign_in_at
19
+ t.datetime :last_sign_in_at
20
+ t.string :current_sign_in_ip
21
+ t.string :last_sign_in_ip
22
+ t.integer :sign_in_count, default: 0
23
+ t.integer :failed_attempts, default: 0
15
24
  t.timestamps null: false
16
25
  end
17
26
  add_index :users, :password_changed_at
@@ -24,13 +33,13 @@ class CreateTables < MIGRATION_CLASS
24
33
  end
25
34
 
26
35
  create_table :old_passwords do |t|
27
- t.string :encrypted_password, :null => false
36
+ t.string :encrypted_password, null: false
28
37
  t.string :password_salt
29
- t.string :password_archivable_type, :null => false
30
- t.integer :password_archivable_id, :null => false
38
+ t.string :password_archivable_type, null: false
39
+ t.integer :password_archivable_id, null: false
31
40
  t.datetime :created_at
32
41
  end
33
- 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'
34
43
  end
35
44
 
36
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