devise-security 0.11.1 → 0.12.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 (69) hide show
  1. checksums.yaml +5 -5
  2. data/.circleci/config.yml +41 -0
  3. data/.gitignore +1 -0
  4. data/.rubocop.yml +22 -2
  5. data/.ruby-version +1 -1
  6. data/.travis.yml +15 -3
  7. data/Appraisals +19 -0
  8. data/Gemfile +1 -0
  9. data/README.md +15 -10
  10. data/Rakefile +3 -1
  11. data/app/controllers/devise/paranoid_verification_code_controller.rb +1 -1
  12. data/app/controllers/devise/password_expired_controller.rb +1 -1
  13. data/app/views/devise/paranoid_verification_code/show.html.erb +2 -2
  14. data/app/views/devise/password_expired/show.html.erb +5 -5
  15. data/config/locales/de.yml +7 -7
  16. data/config/locales/en.yml +8 -8
  17. data/config/locales/es.yml +8 -8
  18. data/devise-security.gemspec +12 -6
  19. data/gemfiles/rails_4.1_stable.gemfile +8 -0
  20. data/gemfiles/rails_4.2_stable.gemfile +8 -0
  21. data/gemfiles/rails_5.0_stable.gemfile +8 -0
  22. data/gemfiles/rails_5.1_stable.gemfile +8 -0
  23. data/gemfiles/rails_5.2_rc1.gemfile +8 -0
  24. data/lib/devise-security/controllers/helpers.rb +2 -2
  25. data/lib/devise-security/hooks/session_limitable.rb +3 -3
  26. data/lib/devise-security/models/compatibility.rb +22 -0
  27. data/lib/devise-security/models/expirable.rb +13 -13
  28. data/lib/devise-security/models/old_password.rb +1 -1
  29. data/lib/devise-security/models/paranoid_verification.rb +5 -2
  30. data/lib/devise-security/models/password_archivable.rb +34 -38
  31. data/lib/devise-security/models/password_expirable.rb +1 -1
  32. data/lib/devise-security/models/secure_validatable.rb +16 -14
  33. data/lib/devise-security/models/security_questionable.rb +1 -2
  34. data/lib/devise-security/models/session_limitable.rb +3 -3
  35. data/lib/devise-security/orm/active_record.rb +1 -3
  36. data/lib/devise-security/patches/confirmations_controller_captcha.rb +2 -2
  37. data/lib/devise-security/patches/confirmations_controller_security_question.rb +2 -2
  38. data/lib/devise-security/patches/passwords_controller_captcha.rb +2 -2
  39. data/lib/devise-security/patches/passwords_controller_security_question.rb +2 -2
  40. data/lib/devise-security/patches/registrations_controller_captcha.rb +2 -2
  41. data/lib/devise-security/patches/sessions_controller_captcha.rb +3 -3
  42. data/lib/devise-security/patches/unlocks_controller_captcha.rb +2 -2
  43. data/lib/devise-security/patches/unlocks_controller_security_question.rb +2 -2
  44. data/lib/devise-security/rails.rb +2 -2
  45. data/lib/devise-security/routes.rb +2 -3
  46. data/lib/devise-security/schema.rb +11 -6
  47. data/lib/devise-security/version.rb +1 -1
  48. data/test/dummy/app/models/application_record.rb +3 -0
  49. data/test/dummy/app/models/captcha_user.rb +1 -1
  50. data/test/dummy/app/models/security_question_user.rb +2 -3
  51. data/test/dummy/app/models/user.rb +21 -4
  52. data/test/dummy/app/models/widget.rb +4 -0
  53. data/test/dummy/config/environments/test.rb +10 -2
  54. data/test/dummy/config/initializers/devise.rb +1 -0
  55. data/test/dummy/config/secrets.yml +1 -2
  56. data/test/dummy/db/migrate/20120508165529_create_tables.rb +9 -3
  57. data/test/dummy/db/migrate/20180318103603_add_expireable_columns.rb +6 -0
  58. data/test/dummy/db/migrate/20180318105329_add_confirmable_columns.rb +8 -0
  59. data/test/dummy/db/migrate/20180318105732_add_rememberable_columns.rb +5 -0
  60. data/test/dummy/db/migrate/20180318111336_add_recoverable_columns.rb +6 -0
  61. data/test/dummy/db/migrate/20180319114023_add_widget.rb +8 -0
  62. data/test/test_captcha_controller.rb +13 -13
  63. data/test/test_helper.rb +7 -0
  64. data/test/test_paranoid_verification.rb +2 -2
  65. data/test/test_password_archivable.rb +27 -13
  66. data/test/test_password_expirable.rb +2 -2
  67. data/test/test_password_expired_controller.rb +25 -10
  68. data/test/test_security_question_controller.rb +45 -21
  69. metadata +90 -13
@@ -10,13 +10,13 @@ module DeviseSecurity::Patches
10
10
  self.resource = resource_class.send_confirmation_instructions(params[resource_name])
11
11
 
12
12
  if successfully_sent?(resource)
13
- respond_with({}, :location => after_resending_confirmation_instructions_path_for(resource_name))
13
+ respond_with({}, location: after_resending_confirmation_instructions_path_for(resource_name))
14
14
  else
15
15
  respond_with(resource)
16
16
  end
17
17
  else
18
18
  flash[:alert] = t('devise.invalid_security_question') if is_navigational_format?
19
- respond_with({}, :location => new_confirmation_path(resource_name))
19
+ respond_with({}, location: new_confirmation_path(resource_name))
20
20
  end
21
21
  end
22
22
  end
@@ -6,13 +6,13 @@ module DeviseSecurity::Patches
6
6
  if valid_captcha_if_defined?(params[:captcha])
7
7
  self.resource = resource_class.send_reset_password_instructions(params[resource_name])
8
8
  if successfully_sent?(resource)
9
- respond_with({}, :location => new_session_path(resource_name))
9
+ respond_with({}, location: new_session_path(resource_name))
10
10
  else
11
11
  respond_with(resource)
12
12
  end
13
13
  else
14
14
  flash[:alert] = t('devise.invalid_captcha') if is_navigational_format?
15
- respond_with({}, :location => new_password_path(resource_name))
15
+ respond_with({}, location: new_password_path(resource_name))
16
16
  end
17
17
  end
18
18
  end
@@ -9,13 +9,13 @@ module DeviseSecurity::Patches
9
9
  if valid_captcha_or_security_question?(resource, params)
10
10
  self.resource = resource_class.send_reset_password_instructions(params[resource_name])
11
11
  if successfully_sent?(resource)
12
- respond_with({}, :location => new_session_path(resource_name))
12
+ respond_with({}, location: new_session_path(resource_name))
13
13
  else
14
14
  respond_with(resource)
15
15
  end
16
16
  else
17
17
  flash[:alert] = t('devise.invalid_security_question') if is_navigational_format?
18
- respond_with({}, :location => new_password_path(resource_name))
18
+ respond_with({}, location: new_password_path(resource_name))
19
19
  end
20
20
  end
21
21
  end
@@ -11,11 +11,11 @@ module DeviseSecurity::Patches
11
11
  if resource.active_for_authentication?
12
12
  set_flash_message :notice, :signed_up if is_flashing_format?
13
13
  sign_up(resource_name, resource)
14
- respond_with resource, :location => after_sign_up_path_for(resource)
14
+ respond_with resource, location: after_sign_up_path_for(resource)
15
15
  else
16
16
  set_flash_message :notice, :"signed_up_but_#{resource.inactive_message}" if is_flashing_format?
17
17
  expire_data_after_sign_in!
18
- respond_with resource, :location => after_inactive_sign_up_path_for(resource)
18
+ respond_with resource, location: after_inactive_sign_up_path_for(resource)
19
19
  end
20
20
  else
21
21
  clean_up_passwords resource
@@ -8,16 +8,16 @@ module DeviseSecurity::Patches
8
8
  set_flash_message(:notice, :signed_in) if is_flashing_format?
9
9
  sign_in(resource_name, resource)
10
10
  block.call(resource) if block
11
- respond_with resource, :location => after_sign_in_path_for(resource)
11
+ respond_with resource, location: after_sign_in_path_for(resource)
12
12
  else
13
13
  flash[:alert] = t('devise.invalid_captcha') if is_flashing_format?
14
- respond_with({}, :location => new_session_path(resource_name))
14
+ respond_with({}, location: new_session_path(resource_name))
15
15
  end
16
16
  end
17
17
 
18
18
  # for bad protected use in controller
19
19
  define_method :auth_options do
20
- { :scope => resource_name, :recall => "#{controller_path}#new" }
20
+ { scope: resource_name, recall: "#{controller_path}#new" }
21
21
  end
22
22
  end
23
23
  end
@@ -6,13 +6,13 @@ module DeviseSecurity::Patches
6
6
  if valid_captcha_if_defined?(params[:captcha])
7
7
  self.resource = resource_class.send_unlock_instructions(params[resource_name])
8
8
  if successfully_sent?(resource)
9
- respond_with({}, :location => new_session_path(resource_name))
9
+ respond_with({}, location: new_session_path(resource_name))
10
10
  else
11
11
  respond_with(resource)
12
12
  end
13
13
  else
14
14
  flash[:alert] = t('devise.invalid_captcha') if is_navigational_format?
15
- respond_with({}, :location => new_unlock_path(resource_name))
15
+ respond_with({}, location: new_unlock_path(resource_name))
16
16
  end
17
17
  end
18
18
  end
@@ -9,13 +9,13 @@ module DeviseSecurity::Patches
9
9
  if valid_captcha_or_security_question?(resource, params)
10
10
  self.resource = resource_class.send_unlock_instructions(params[resource_name])
11
11
  if successfully_sent?(resource)
12
- respond_with({}, :location => new_session_path(resource_name))
12
+ respond_with({}, location: new_session_path(resource_name))
13
13
  else
14
14
  respond_with(resource)
15
15
  end
16
16
  else
17
17
  flash[:alert] = t('devise.invalid_security_question') if is_navigational_format?
18
- respond_with({}, :location => new_unlock_path(resource_name))
18
+ respond_with({}, location: new_unlock_path(resource_name))
19
19
  end
20
20
  end
21
21
  end
@@ -3,8 +3,8 @@ module DeviseSecurity
3
3
  ActiveSupport.on_load(:action_controller) do
4
4
  include DeviseSecurity::Controllers::Helpers
5
5
  end
6
-
7
- if Rails.version > "5"
6
+
7
+ if Rails.version > '5'
8
8
  ActiveSupport::Reloader.to_prepare do
9
9
  DeviseSecurity::Patches.apply
10
10
  end
@@ -5,13 +5,12 @@ module ActionDispatch::Routing
5
5
 
6
6
  # route for handle expired passwords
7
7
  def devise_password_expired(mapping, controllers)
8
- resource :password_expired, :only => [:show, :update], :path => mapping.path_names[:password_expired], :controller => controllers[:password_expired]
8
+ resource :password_expired, only: [:show, :update], path: mapping.path_names[:password_expired], controller: controllers[:password_expired]
9
9
  end
10
10
 
11
11
  # route for handle paranoid verification
12
12
  def devise_verification_code(mapping, controllers)
13
- resource :paranoid_verification_code, :only => [:show, :update], :path => mapping.path_names[:verification_code], :controller => controllers[:paranoid_verification_code]
13
+ resource :paranoid_verification_code, only: [:show, :update], path: mapping.path_names[:verification_code], controller: controllers[:paranoid_verification_code]
14
14
  end
15
15
  end
16
16
  end
17
-
@@ -27,13 +27,13 @@ module DeviseSecurity
27
27
  # create_table :old_passwords do
28
28
  # t.password_archivable
29
29
  # end
30
- # add_index :old_passwords, [:password_archivable_type, :password_archivable_id], :name => :index_password_archivable
30
+ # add_index :old_passwords, [:password_archivable_type, :password_archivable_id], name: :index_password_archivable
31
31
  #
32
32
  def password_archivable
33
- apply_devise_schema :encrypted_password, String, :limit => 128, :null => false
33
+ apply_devise_schema :encrypted_password, String, limit: 128, null: false
34
34
  apply_devise_schema :password_salt, String
35
- apply_devise_schema :password_archivable_id, Integer, :null => false
36
- apply_devise_schema :password_archivable_type, String, :null => false
35
+ apply_devise_schema :password_archivable_id, Integer, null: false
36
+ apply_devise_schema :password_archivable_type, String, null: false
37
37
  apply_devise_schema :created_at, DateTime
38
38
  end
39
39
 
@@ -49,11 +49,16 @@ module DeviseSecurity
49
49
  #
50
50
  # # or if the resource's table already exists, define a migration and put this in:
51
51
  # change_table :the_resources do |t|
52
- # t.string :unique_session_id, :limit => 20
52
+ # t.string :unique_session_id, limit: 20
53
53
  # end
54
54
  #
55
55
  def session_limitable
56
- apply_devise_schema :unique_session_id, String, :limit => 20
56
+ apply_devise_schema :unique_session_id, String, limit: 20
57
+ end
58
+
59
+ def expirable
60
+ apply_devise_schema :expired_at, DateTime
61
+ apply_devise_schema :last_activity_at, DateTime
57
62
  end
58
63
  end
59
64
  end
@@ -1,3 +1,3 @@
1
1
  module DeviseSecurity
2
- VERSION = "0.11.1".freeze
2
+ VERSION = '0.12.0'.freeze
3
3
  end
@@ -0,0 +1,3 @@
1
+ class ApplicationRecord < ActiveRecord::Base
2
+ self.abstract_class = true
3
+ end
@@ -1,5 +1,5 @@
1
1
  class CaptchaUser < ActiveRecord::Base
2
- self.table_name = "users"
2
+ self.table_name = 'users'
3
3
  devise :database_authenticatable, :password_archivable,
4
4
  :paranoid_verification, :password_expirable
5
5
  end
@@ -1,6 +1,5 @@
1
1
  class SecurityQuestionUser < ActiveRecord::Base
2
- self.table_name = "users"
2
+ self.table_name = 'users'
3
3
  devise :database_authenticatable, :password_archivable, :lockable,
4
- :paranoid_verification, :password_expirable,
5
- :security_questionable
4
+ :paranoid_verification, :password_expirable, :security_questionable
6
5
  end
@@ -1,5 +1,22 @@
1
- class User < ActiveRecord::Base
2
- devise :database_authenticatable, :password_archivable, :lockable,
3
- :paranoid_verification, :password_expirable,
4
- :security_questionable
1
+ class User < ApplicationRecord
2
+
3
+ devise :database_authenticatable,
4
+ :confirmable,
5
+ :expirable,
6
+ :lockable,
7
+ :omniauthable,
8
+ :paranoid_verification,
9
+ :password_archivable,
10
+ :password_expirable,
11
+ :recoverable,
12
+ :registerable,
13
+ :rememberable,
14
+ :secure_validatable,
15
+ :security_questionable,
16
+ :session_limitable,
17
+ :timeoutable,
18
+ :trackable,
19
+ :validatable
20
+
21
+ has_many :widgets
5
22
  end
@@ -0,0 +1,4 @@
1
+ class Widget < ApplicationRecord
2
+ belongs_to :user
3
+ validates_associated :user
4
+ end
@@ -2,7 +2,7 @@ RailsApp::Application.configure do
2
2
  config.cache_classes = true
3
3
  config.eager_load = false
4
4
 
5
- if Rails.version > "5"
5
+ if Rails.version > '5'
6
6
  config.public_file_server.enabled = true
7
7
  config.public_file_server.headers = { 'Cache-Control' => 'public, max-age=3600' }
8
8
  else
@@ -15,7 +15,7 @@ RailsApp::Application.configure do
15
15
 
16
16
  config.action_dispatch.show_exceptions = false
17
17
 
18
- config.action_controller.allow_forgery_protection = false
18
+ config.action_controller.allow_forgery_protection = false
19
19
 
20
20
  config.action_mailer.delivery_method = :test
21
21
  config.action_mailer.default_url_options = { host: 'test.host' }
@@ -24,4 +24,12 @@ RailsApp::Application.configure do
24
24
  I18n.enforce_available_locales = false
25
25
 
26
26
  config.active_support.test_order = :sorted
27
+ config.log_level = :debug
28
+ if Rails.gem_version >= Gem::Version.new('4.2') && Rails.gem_version < Gem::Version.new('5.0')
29
+ config.active_record.raise_in_transactional_callbacks = true
30
+ end
31
+ if Rails.gem_version.release >= Gem::Version.new('5.2')
32
+ config.active_record.sqlite3.represent_boolean_as_integer = true
33
+ end
27
34
  end
35
+ ActiveSupport::Deprecation.debug = true
@@ -1,3 +1,4 @@
1
+ require 'rails_email_validator'
1
2
  Devise.setup do |config|
2
3
  config.mailer_sender = 'please-change-me-at-config-initializers-devise@example.com'
3
4
 
@@ -1,3 +1,2 @@
1
1
  test:
2
- secret_token: 'fooooooooooo'
3
- secret_key_base: 'fuuuuuuuuuuu'
2
+ secret_key_base: 'fuuuuuuuuuuu'
@@ -3,6 +3,7 @@ class CreateTables < MIGRATION_CLASS
3
3
  create_table :users do |t|
4
4
  t.string :username
5
5
  t.string :facebook_token
6
+ t.string :unique_session_id, :limit => 20
6
7
 
7
8
  ## Database authenticatable
8
9
  t.string :email, null: false, default: ''
@@ -11,6 +12,8 @@ class CreateTables < MIGRATION_CLASS
11
12
  t.datetime :password_changed_at
12
13
  t.timestamps null: false
13
14
  end
15
+ add_index :users, :password_changed_at
16
+ add_index :users, :email
14
17
 
15
18
  create_table :secure_users do |t|
16
19
  t.string :email
@@ -19,10 +22,13 @@ class CreateTables < MIGRATION_CLASS
19
22
  end
20
23
 
21
24
  create_table :old_passwords do |t|
22
- t.string :encrypted_password
23
-
24
- t.references :password_archivable, polymorphic: true
25
+ t.string :encrypted_password, :null => false
26
+ t.string :password_salt
27
+ t.string :password_archivable_type, :null => false
28
+ t.integer :password_archivable_id, :null => false
29
+ t.datetime :created_at
25
30
  end
31
+ add_index :old_passwords, [:password_archivable_type, :password_archivable_id], :name => :index_password_archivable
26
32
  end
27
33
 
28
34
  def self.down
@@ -0,0 +1,6 @@
1
+ class AddExpireableColumns < MIGRATION_CLASS
2
+ def change
3
+ add_column :users, :expired_at, :datetime
4
+ add_column :users, :last_activity_at, :datetime
5
+ end
6
+ end
@@ -0,0 +1,8 @@
1
+ class AddConfirmableColumns < MIGRATION_CLASS
2
+ def change
3
+ add_column :users, :confirmation_token, :string
4
+ add_column :users, :confirmed_at, :datetime
5
+ add_column :users, :confirmation_sent_at, :datetime
6
+ add_column :users, :unconfirmed_email, :string
7
+ end
8
+ end
@@ -0,0 +1,5 @@
1
+ class AddRememberableColumns < MIGRATION_CLASS
2
+ def change
3
+ add_column :users, :remember_created_at, :datetime
4
+ end
5
+ end
@@ -0,0 +1,6 @@
1
+ class AddRecoverableColumns < MIGRATION_CLASS
2
+ def change
3
+ add_column :users, :reset_password_token, :string
4
+ add_column :users, :reset_password_sent_at, :datetime
5
+ end
6
+ end
@@ -0,0 +1,8 @@
1
+ class AddWidget < MIGRATION_CLASS
2
+ def change
3
+ create_table :widgets do |t|
4
+ t.string :name
5
+ t.belongs_to :user
6
+ end
7
+ end
8
+ end
@@ -5,18 +5,18 @@ class TestWithCaptcha < ActionController::TestCase
5
5
  tests Captcha::SessionsController
6
6
 
7
7
  setup do
8
- @request.env["devise.mapping"] = Devise.mappings[:captcha_user]
8
+ @request.env['devise.mapping'] = Devise.mappings[:captcha_user]
9
9
  end
10
10
 
11
11
  test 'When captcha is enabled, it is inserted correctly' do
12
12
  post :create, params: {
13
13
  captcha_user: {
14
- email: "wrong@email.com",
15
- password: "wrongpassword"
14
+ email: 'wrong@email.com',
15
+ password: 'wrongpassword'
16
16
  }
17
17
  }
18
18
 
19
- assert_equal "The captcha input was invalid.", flash[:alert]
19
+ assert_equal 'The captcha input was invalid.', flash[:alert]
20
20
  assert_redirected_to new_captcha_user_session_path
21
21
  end
22
22
 
@@ -26,14 +26,14 @@ class TestWithCaptcha < ActionController::TestCase
26
26
  end
27
27
 
28
28
  post :create, params: {
29
- captcha: "ABCDE",
29
+ captcha: 'ABCDE',
30
30
  captcha_user: {
31
- email: "wrong@email.com",
32
- password: "wrongpassword"
31
+ email: 'wrong@email.com',
32
+ password: 'wrongpassword'
33
33
  }
34
34
  }
35
35
 
36
- assert_equal "Invalid Email or password.", flash[:alert]
36
+ assert_equal 'Invalid Email or password.', flash[:alert]
37
37
  end
38
38
  end
39
39
 
@@ -42,17 +42,17 @@ class TestWithoutCaptcha < ActionController::TestCase
42
42
  tests Devise::SessionsController
43
43
 
44
44
  setup do
45
- @request.env["devise.mapping"] = Devise.mappings[:user]
45
+ @request.env['devise.mapping'] = Devise.mappings[:user]
46
46
  end
47
47
 
48
48
  test 'When captcha is not enabled, it is not inserted' do
49
- post :create, params: {
49
+ post :create, params: {
50
50
  user: {
51
- email: "wrong@email.com",
52
- password: "wrongpassword"
51
+ email: 'wrong@email.com',
52
+ password: 'wrongpassword'
53
53
  }
54
54
  }
55
55
 
56
- assert_equal "Invalid Email or password.", flash[:alert]
56
+ assert_equal 'Invalid Email or password.', flash[:alert]
57
57
  end
58
58
  end
data/test/test_helper.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  ENV['RAILS_ENV'] ||= 'test'
2
2
 
3
+ require 'simplecov'
3
4
  require 'coveralls'
4
5
  Coveralls.wear!
5
6
 
@@ -11,3 +12,9 @@ require 'devise-security'
11
12
  ActiveRecord::Migration.verbose = false
12
13
  ActiveRecord::Base.logger = Logger.new(nil)
13
14
  ActiveRecord::Migrator.migrate(File.expand_path('../dummy/db/migrate', __FILE__))
15
+
16
+ SimpleCov.formatter = Coveralls::SimpleCov::Formatter
17
+ SimpleCov.start do
18
+ add_filter 'test/dummy'
19
+ add_filter 'gemfiles'
20
+ end