devise-security 0.11.1 → 0.12.0

Sign up to get free protection for your applications and to get access to all the features.
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