devise 4.7.3 → 4.9.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +62 -0
  3. data/MIT-LICENSE +1 -1
  4. data/README.md +51 -24
  5. data/app/controllers/devise/confirmations_controller.rb +1 -0
  6. data/app/controllers/devise/passwords_controller.rb +2 -2
  7. data/app/controllers/devise/registrations_controller.rb +1 -1
  8. data/app/controllers/devise/sessions_controller.rb +1 -1
  9. data/app/controllers/devise/unlocks_controller.rb +1 -0
  10. data/app/controllers/devise_controller.rb +1 -0
  11. data/app/views/devise/registrations/edit.html.erb +1 -1
  12. data/app/views/devise/shared/_error_messages.html.erb +1 -1
  13. data/app/views/devise/shared/_links.html.erb +1 -1
  14. data/config/locales/en.yml +1 -1
  15. data/lib/devise/controllers/responder.rb +35 -0
  16. data/lib/devise/controllers/sign_in_out.rb +3 -1
  17. data/lib/devise/failure_app.rb +6 -2
  18. data/lib/devise/hooks/csrf_cleaner.rb +6 -1
  19. data/lib/devise/hooks/lockable.rb +2 -5
  20. data/lib/devise/models/authenticatable.rb +7 -3
  21. data/lib/devise/models/confirmable.rb +16 -37
  22. data/lib/devise/models/database_authenticatable.rb +9 -28
  23. data/lib/devise/models/lockable.rb +10 -2
  24. data/lib/devise/models/omniauthable.rb +2 -2
  25. data/lib/devise/models/recoverable.rb +6 -17
  26. data/lib/devise/models/rememberable.rb +1 -1
  27. data/lib/devise/models/timeoutable.rb +1 -1
  28. data/lib/devise/models/validatable.rb +4 -9
  29. data/lib/devise/models.rb +1 -0
  30. data/lib/devise/omniauth.rb +2 -5
  31. data/lib/devise/orm.rb +71 -0
  32. data/lib/devise/rails/deprecated_constant_accessor.rb +39 -0
  33. data/lib/devise/version.rb +1 -1
  34. data/lib/devise.rb +30 -7
  35. data/lib/generators/active_record/devise_generator.rb +17 -2
  36. data/lib/generators/templates/devise.rb +10 -8
  37. data/lib/generators/templates/simple_form_for/registrations/edit.html.erb +1 -1
  38. metadata +19 -7
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: '056338b76007de25ec62deff781ba493d0d063184f70373d31406faf1fc8a219'
4
- data.tar.gz: 43919f99b2b775b213bf40d5849138339b99462700e58ce5e4a843ab5a63c22f
3
+ metadata.gz: 7640b97ddd188a63e29076d8d94b0a4ebaecc23aad53b8e608b4b1d029818570
4
+ data.tar.gz: 7e8b512895f0fd73e307bebe494ea3d7d0bd9ecd562b917016b1f7f56d483d2c
5
5
  SHA512:
6
- metadata.gz: b21e1c4b5658dc2077d4eeb4fa70fa25c108bcdbe03b1b1f587d1a8f5c49a2c3b0fa299dc5a45af8b743ba8d8dc968bab768587df12350d41beeb163f6d80af3
7
- data.tar.gz: c12702819c331ce7739ee30a34cdf550d85db4edbe90ad1c3adffe51c910a27f969938dc098940637c49acc31da0195cc351b56558bf4c2be69961f3071a23c6
6
+ metadata.gz: b7cd4534d2abb7ba16353d4f41ea63ed0334eccf68c1357dc37c68b51ad90f1a9cb8544e8f90c2249b2067bdfd0b6c19d245562a1eecef2291ea8705143878ec
7
+ data.tar.gz: f9bc9ea3a1dfdf86ab79dc47839c79b07fd5613dddfb40022fa508729dded4971dd30055f6f8b901c6a9182513414750825064db278d7865ae7a4576513c08f7
data/CHANGELOG.md CHANGED
@@ -1,3 +1,65 @@
1
+ ### Unreleased
2
+
3
+ * deprecations
4
+ * Bring back `Devise.activerecord51?` and deprecate it, in order to avoid breakage with some libraries that apparently relied on it.
5
+
6
+ ### 4.9.1 - 2023-03-31
7
+
8
+ * enhancements
9
+ * Allow resource class scopes to override the global configuration for `sign_in_after_reset_password` behaviour. [#5429](https://github.com/heartcombo/devise/pull/5429) [@mattr](https://github.com/mattr)
10
+ * Refactor conditional dirty tracking logic to a centralized module to simplify usage throughout the codebase. [#5575](https://github.com/heartcombo/devise/pull/5575)
11
+ * Improve support for Devise in apps with Active Record and Mongoid ORMs loaded, so it does not incorrectly uses new Active Record dirty tracking APIs with a Mongoid Devise model. [#5576](https://github.com/heartcombo/devise/pull/5576)
12
+
13
+ * bug fixes
14
+ * Failure app will respond with configured `redirect_status` instead of `error_status` if the recall app returns a redirect status (300..399) [#5573](https://github.com/heartcombo/devise/pull/5573)
15
+ * Fix frozen string exception in validatable. [#5563](https://github.com/heartcombo/devise/pull/5563) [#5465](https://github.com/heartcombo/devise/pull/5465) [@mameier](https://github.com/mameier)
16
+
17
+ ### 4.9.0 - 2023-02-17
18
+
19
+ * enhancements
20
+ * Add support for Ruby 3.1/3.2.
21
+ * Add support for Hotwire + Turbo, default in Rails 7+.
22
+ * Devise uses the latest `responders` version (v3.1.0 or higher), which allows configuring the status used for validation error responses (`error_status`) and for redirects after POST/PUT/PATCH/DELETE requests (`redirect_status`). For backwards compatibility, Devise keeps `error_status` as `:ok` which returns a `200 OK` response, and `redirect_status` to `:found` which returns a `302 Found` response, but you can configure it to return `422 Unprocessable Entity` and `303 See Other` respectively, to match the behavior expected by Hotwire/Turbo:
23
+
24
+ ```ruby
25
+ # config/initializers/devise.rb
26
+ Devise.setup do |config|
27
+ # ...
28
+ config.responder.error_status = :unprocessable_entity
29
+ config.responder.redirect_status = :see_other
30
+ # ...
31
+ end
32
+ ```
33
+
34
+ These configs are already generated by default with new apps, and existing apps may opt-in as described above. Trying to set these with an older version of `responders` will issue a warning and have no effect, so please upgrade the `responders` version if you're upgrading Devise for this integration. Note that these defaults may change in future versions of Devise, to better match the Rails + Hotwire/Turbo defaults across the board.
35
+ * If you have a custom responder set on your application and expect it to affect Devise as well, you may need to override the Devise responder entirely with `config.responder = MyApplicationResponder`, so that it uses your custom one. The main reason Devise uses a custom responder is to be able to configure the statuses as described above, but you can also change that config on your own responder if you want. Check the `responders` readme for more info on that.
36
+ * If you have created a custom responder and/or failure app just to customize responses for better Hotwire/Turbo integration, they should no longer be necessary.
37
+ * `:turbo_stream` is now treated as a navigational format, so it works like HTML navigation when using Turbo. Note: if you relied on `:turbo_stream` to be treated as a non-navigational format before, you can reconfigure your `navigational_formats` in the Devise initializer file to exclude it.
38
+ * OmniAuth "Sign in with" links were changed to buttons that generate HTML forms with method=POST, instead of using link + method=POST that required rails-ujs to work. Since rails-ujs is no longer the default for new Rails apps, this allows the OmniAuth buttons to work in any scenario, with or without rails-ujs and/or Turbo. This only affects apps that are using the default `devise/shared/_links.html.erb` partial from Devise with OmniAuth enabled.
39
+ * The "Cancel my account" button was changed to include the `data-turbo-confirm` option, so that it works with both rails-ujs and Turbo by default.
40
+ * Devise does not provide "sign out" links/buttons in its shared views, but if you're using `sign_out_via` with `:delete` (the default), and are using links with `method: :delete`, those need to be updated with `data: { turbo_method: :delete }` instead for Turbo.
41
+ * Check [this upgrade guide](https://github.com/heartcombo/devise/wiki/How-To:-Upgrade-to-Devise-4.9.0-[Hotwire-Turbo-integration]) for more detailed information.
42
+
43
+ ### 4.8.1 - 2021-12-16
44
+
45
+ * enhancements
46
+ * Add support for Rails 7.0. Please note that Turbo integration is not fully supported by Devise yet.
47
+
48
+ ### 4.8.0 - 2021-04-29
49
+
50
+ * enhancements
51
+ * Devise now enables the upgrade of OmniAuth 2+. Previously Devise would raise an error if you'd try to upgrade. Please note that OmniAuth 2 is considered a security upgrade and recommended to everyone. You can read more about the details (and possible necessary changes to your app as part of the upgrade) in [their release notes](https://github.com/omniauth/omniauth/releases/tag/v2.0.0). [Devise's OmniAuth Overview wiki](https://github.com/heartcombo/devise/wiki/OmniAuth:-Overview) was also updated to cover OmniAuth 2.0 requirements.
52
+ - Note that the upgrade required Devise shared links that initiate the OmniAuth flow to be changed to `method: :post`, which is now a requirement for OmniAuth, part of the security improvement. If you have copied and customized the Devise shared links partial to your app, or if you have other links in your app that initiate the OmniAuth flow, they will have to be updated to use `method: :post`, or changed to use buttons (e.g. `button_to`) to work with OmniAuth 2. (if you're using links with `method: :post`, make sure your app has `rails-ujs` or `jquery-ujs` included in order for these links to work properly.)
53
+ - As part of the OmniAuth 2.0 upgrade you might also need to add the [`omniauth-rails_csrf_protection`](https://github.com/cookpad/omniauth-rails_csrf_protection) gem to your app if you don't have it already. (and you don't want to roll your own code to verify requests.) Check the OmniAuth v2 release notes for more info.
54
+ * Introduce `Lockable#reset_failed_attempts!` model method to reset failed attempts counter to 0 after the user signs in.
55
+ - This logic existed inside the lockable warden hook and is triggered automatically after the user signs in. The new model method is an extraction to allow you to override it in the application to implement things like switching to a write database if you're using the new multi-DB infrastructure from Rails for example, similar to how it's already possible with `Trackable#update_tracked_fields!`.
56
+ * Add support for Ruby 3.
57
+ * Add support for Rails 6.1.
58
+ * Move CI to GitHub Actions.
59
+
60
+ * deprecations
61
+ * `Devise::Models::Authenticatable::BLACKLIST_FOR_SERIALIZATION` is deprecated in favor of `Devise::Models::Authenticatable::UNSAFE_ATTRIBUTES_FOR_SERIALIZATION` (@hanachin)
62
+
1
63
  ### 4.7.3 - 2020-09-20
2
64
 
3
65
  * bug fixes
data/MIT-LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright 2020 Rafael França, Leonardo Tegon, Carlos Antônio da Silva.
1
+ Copyright 2020-2023 Rafael França, Leonardo Tegon, Carlos Antônio da Silva.
2
2
  Copyright 2009-2019 Plataformatec.
3
3
 
4
4
  Permission is hereby granted, free of charge, to any person obtaining
data/README.md CHANGED
@@ -1,7 +1,4 @@
1
- ![Devise Logo](https://raw.github.com/heartcombo/devise/master/devise.png)
2
-
3
- [![Build Status](https://api.travis-ci.org/heartcombo/devise.svg?branch=master)](http://travis-ci.org/heartcombo/devise)
4
- [![Code Climate](https://codeclimate.com/github/heartcombo/devise.svg)](https://codeclimate.com/github/heartcombo/devise)
1
+ ![Devise Logo](https://raw.github.com/heartcombo/devise/main/devise.png)
5
2
 
6
3
  Devise is a flexible authentication solution for Rails based on Warden. It:
7
4
 
@@ -12,16 +9,16 @@ Devise is a flexible authentication solution for Rails based on Warden. It:
12
9
 
13
10
  It's composed of 10 modules:
14
11
 
15
- * [Database Authenticatable](http://www.rubydoc.info/github/heartcombo/devise/master/Devise/Models/DatabaseAuthenticatable): hashes and stores a password in the database to validate the authenticity of a user while signing in. The authentication can be done both through POST requests or HTTP Basic Authentication.
16
- * [Omniauthable](http://www.rubydoc.info/github/heartcombo/devise/master/Devise/Models/Omniauthable): adds OmniAuth (https://github.com/omniauth/omniauth) support.
17
- * [Confirmable](http://www.rubydoc.info/github/heartcombo/devise/master/Devise/Models/Confirmable): sends emails with confirmation instructions and verifies whether an account is already confirmed during sign in.
18
- * [Recoverable](http://www.rubydoc.info/github/heartcombo/devise/master/Devise/Models/Recoverable): resets the user password and sends reset instructions.
19
- * [Registerable](http://www.rubydoc.info/github/heartcombo/devise/master/Devise/Models/Registerable): handles signing up users through a registration process, also allowing them to edit and destroy their account.
20
- * [Rememberable](http://www.rubydoc.info/github/heartcombo/devise/master/Devise/Models/Rememberable): manages generating and clearing a token for remembering the user from a saved cookie.
21
- * [Trackable](http://www.rubydoc.info/github/heartcombo/devise/master/Devise/Models/Trackable): tracks sign in count, timestamps and IP address.
22
- * [Timeoutable](http://www.rubydoc.info/github/heartcombo/devise/master/Devise/Models/Timeoutable): expires sessions that have not been active in a specified period of time.
23
- * [Validatable](http://www.rubydoc.info/github/heartcombo/devise/master/Devise/Models/Validatable): provides validations of email and password. It's optional and can be customized, so you're able to define your own validations.
24
- * [Lockable](http://www.rubydoc.info/github/heartcombo/devise/master/Devise/Models/Lockable): locks an account after a specified number of failed sign-in attempts. Can unlock via email or after a specified time period.
12
+ * [Database Authenticatable](http://www.rubydoc.info/github/heartcombo/devise/main/Devise/Models/DatabaseAuthenticatable): hashes and stores a password in the database to validate the authenticity of a user while signing in. The authentication can be done both through POST requests or HTTP Basic Authentication.
13
+ * [Omniauthable](http://www.rubydoc.info/github/heartcombo/devise/main/Devise/Models/Omniauthable): adds OmniAuth (https://github.com/omniauth/omniauth) support.
14
+ * [Confirmable](http://www.rubydoc.info/github/heartcombo/devise/main/Devise/Models/Confirmable): sends emails with confirmation instructions and verifies whether an account is already confirmed during sign in.
15
+ * [Recoverable](http://www.rubydoc.info/github/heartcombo/devise/main/Devise/Models/Recoverable): resets the user password and sends reset instructions.
16
+ * [Registerable](http://www.rubydoc.info/github/heartcombo/devise/main/Devise/Models/Registerable): handles signing up users through a registration process, also allowing them to edit and destroy their account.
17
+ * [Rememberable](http://www.rubydoc.info/github/heartcombo/devise/main/Devise/Models/Rememberable): manages generating and clearing a token for remembering the user from a saved cookie.
18
+ * [Trackable](http://www.rubydoc.info/github/heartcombo/devise/main/Devise/Models/Trackable): tracks sign in count, timestamps and IP address.
19
+ * [Timeoutable](http://www.rubydoc.info/github/heartcombo/devise/main/Devise/Models/Timeoutable): expires sessions that have not been active in a specified period of time.
20
+ * [Validatable](http://www.rubydoc.info/github/heartcombo/devise/main/Devise/Models/Validatable): provides validations of email and password. It's optional and can be customized, so you're able to define your own validations.
21
+ * [Lockable](http://www.rubydoc.info/github/heartcombo/devise/main/Devise/Models/Lockable): locks an account after a specified number of failed sign-in attempts. Can unlock via email or after a specified time period.
25
22
 
26
23
  ## Table of Contents
27
24
 
@@ -92,7 +89,7 @@ https://groups.google.com/group/plataformatec-devise
92
89
 
93
90
  You can view the Devise documentation in RDoc format here:
94
91
 
95
- http://rubydoc.info/github/heartcombo/devise/master/frames
92
+ http://rubydoc.info/github/heartcombo/devise/main/frames
96
93
 
97
94
  If you need to use Devise with previous versions of Rails, you can always run "gem server" from the command line after you install the gem to access the old documentation.
98
95
 
@@ -118,7 +115,7 @@ You will usually want to write tests for your changes. To run the test suite, g
118
115
  Devise works with multiple Ruby and Rails versions, and ActiveRecord and Mongoid ORMs, which means you can run the test suite with some modifiers: `DEVISE_ORM` and `BUNDLE_GEMFILE`.
119
116
 
120
117
  ### DEVISE_ORM
121
- Since Devise support both Mongoid and ActiveRecord, we rely on this variable to run specific code for each ORM.
118
+ Since Devise supports both Mongoid and ActiveRecord, we rely on this variable to run specific code for each ORM.
122
119
  The default value of `DEVISE_ORM` is `active_record`. To run the tests for Mongoid, you can pass `mongoid`:
123
120
  ```
124
121
  DEVISE_ORM=mongoid bin/test
@@ -131,7 +128,7 @@ Please note that the command output will show the variable value being used.
131
128
 
132
129
  ### BUNDLE_GEMFILE
133
130
  We can use this variable to tell bundler what Gemfile it should use (instead of the one in the current directory).
134
- Inside the [gemfiles](https://github.com/heartcombo/devise/tree/master/gemfiles) directory, we have one for each version of Rails we support. When you send us a pull request, it may happen that the test suite breaks on Travis using some of them. If that's the case, you can simulate the same environment using the `BUNDLE_GEMFILE` variable.
131
+ Inside the [gemfiles](https://github.com/heartcombo/devise/tree/main/gemfiles) directory, we have one for each version of Rails we support. When you send us a pull request, it may happen that the test suite breaks using some of them. If that's the case, you can simulate the same environment using the `BUNDLE_GEMFILE` variable.
135
132
  For example, if the tests broke using Ruby 2.4.2 and Rails 4.1, you can do the following:
136
133
  ```bash
137
134
  rbenv shell 2.4.2 # or rvm use 2.4.2
@@ -385,7 +382,7 @@ $ rails generate devise:views users
385
382
  ```
386
383
 
387
384
  If you would like to generate only a few sets of views, like the ones for the `registerable` and `confirmable` module,
388
- you can pass a list of modules to the generator with the `-v` flag.
385
+ you can pass a list of views to the generator with the `-v` flag.
389
386
 
390
387
  ```console
391
388
  $ rails generate devise:views -v registrations confirmations
@@ -413,7 +410,7 @@ If the customization at the views level is not enough, you can customize each co
413
410
  ...
414
411
  end
415
412
  ```
416
- (Use the -c flag to specify a controller, for example: `rails generate devise:controllers users -c=sessions`)
413
+ Use the `-c` flag to specify one or more controllers, for example: `rails generate devise:controllers users -c sessions`)
417
414
 
418
415
  2. Tell the router to use this controller:
419
416
 
@@ -421,7 +418,7 @@ If the customization at the views level is not enough, you can customize each co
421
418
  devise_for :users, controllers: { sessions: 'users/sessions' }
422
419
  ```
423
420
 
424
- 3. Copy the views from `devise/sessions` to `users/sessions`. Since the controller was changed, it won't use the default views located in `devise/sessions`.
421
+ 3. Recommended but not required: copy (or move) the views from `devise/sessions` to `users/sessions`. Rails will continue using the views from `devise/sessions` due to inheritance if you skip this step, but having the views matching the controller(s) keeps things consistent.
425
422
 
426
423
  4. Finally, change or extend the desired controller actions.
427
424
 
@@ -459,7 +456,7 @@ Devise also ships with default routes. If you need to customize them, you should
459
456
  devise_for :users, path: 'auth', path_names: { sign_in: 'login', sign_out: 'logout', password: 'secret', confirmation: 'verification', unlock: 'unblock', registration: 'register', sign_up: 'cmon_let_me_in' }
460
457
  ```
461
458
 
462
- Be sure to check `devise_for` [documentation](http://www.rubydoc.info/github/heartcombo/devise/master/ActionDispatch/Routing/Mapper%3Adevise_for) for details.
459
+ Be sure to check `devise_for` [documentation](http://www.rubydoc.info/github/heartcombo/devise/main/ActionDispatch/Routing/Mapper%3Adevise_for) for details.
463
460
 
464
461
  If you have the need for more deep customization, for instance to also allow "/sign_in" besides "/users/sign_in", all you need to do is create your routes normally and wrap them in a `devise_scope` block in the router:
465
462
 
@@ -477,6 +474,36 @@ Please note: You will still need to add `devise_for` in your routes in order to
477
474
  devise_for :users, skip: :all
478
475
  ```
479
476
 
477
+ ### Hotwire/Turbo
478
+
479
+ Devise integrates with Hotwire/Turbo by treating such requests as navigational, and configuring certain responses for errors and redirects to match the expected behavior. New apps are generated with the following response configuration by default, and existing apps may opt-in by adding the config to their Devise initializers:
480
+
481
+ ```ruby
482
+ Devise.setup do |config|
483
+ # ...
484
+ # When using Devise with Hotwire/Turbo, the http status for error responses
485
+ # and some redirects must match the following. The default in Devise for existing
486
+ # apps is `200 OK` and `302 Found respectively`, but new apps are generated with
487
+ # these new defaults that match Hotwire/Turbo behavior.
488
+ # Note: These might become the new default in future versions of Devise.
489
+ config.responder.error_status = :unprocessable_entity
490
+ config.responder.redirect_status = :see_other
491
+ end
492
+ ```
493
+
494
+ **Important**: these custom responses require the `responders` gem version to be `3.1.0` or higher, please make sure you update it if you're going to use this configuration. Check [this upgrade guide](https://github.com/heartcombo/devise/wiki/How-To:-Upgrade-to-Devise-4.9.0-[Hotwire-Turbo-integration]) for more info.
495
+
496
+ _Note_: the above statuses configuration may become the default for Devise in a future release.
497
+
498
+ There are a couple other changes you might need to make in your app to work with Hotwire/Turbo, if you're migrating from rails-ujs:
499
+
500
+ * The `data-confirm` option that adds a confirmation modal to buttons/forms before submission needs to change to `data-turbo-confirm`, so that Turbo handles those appropriately.
501
+ * The `data-method` option that sets the request method for link submissions needs to change to `data-turbo-method`. This is not necessary for `button_to` or `form`s since Turbo can handle those.
502
+
503
+ If you're setting up Devise to sign out via `:delete`, and you're using links (instead of buttons wrapped in a form) to sign out with the `method: :delete` option, they will need to be updated as described above. (Devise does not provide sign out links/buttons in its shared views.)
504
+
505
+ Make sure to inspect your views looking for those, and change appropriately.
506
+
480
507
  ### I18n
481
508
 
482
509
  Devise uses flash messages with I18n, in conjunction with the flash keys :notice and :alert. To customize your app, you can set up your locale file:
@@ -680,12 +707,12 @@ end
680
707
 
681
708
  ### Password reset tokens and Rails logs
682
709
 
683
- If you enable the [Recoverable](http://rubydoc.info/github/heartcombo/devise/master/Devise/Models/Recoverable) module, note that a stolen password reset token could give an attacker access to your application. Devise takes effort to generate random, secure tokens, and stores only token digests in the database, never plaintext. However the default logging behavior in Rails can cause plaintext tokens to leak into log files:
710
+ If you enable the [Recoverable](http://rubydoc.info/github/heartcombo/devise/main/Devise/Models/Recoverable) module, note that a stolen password reset token could give an attacker access to your application. Devise takes effort to generate random, secure tokens, and stores only token digests in the database, never plaintext. However the default logging behavior in Rails can cause plaintext tokens to leak into log files:
684
711
 
685
712
  1. Action Mailer logs the entire contents of all outgoing emails to the DEBUG level. Password reset tokens delivered to users in email will be leaked.
686
713
  2. Active Job logs all arguments to every enqueued job at the INFO level. If you configure Devise to use `deliver_later` to send password reset emails, password reset tokens will be leaked.
687
714
 
688
- Rails sets the production logger level to DEBUG by default. Consider changing your production logger level to WARN if you wish to prevent tokens from being leaked into your logs. In `config/environments/production.rb`:
715
+ Rails sets the production logger level to INFO by default. Consider changing your production logger level to WARN if you wish to prevent tokens from being leaked into your logs. In `config/environments/production.rb`:
689
716
 
690
717
  ```ruby
691
718
  config.log_level = :warn
@@ -740,6 +767,6 @@ https://github.com/heartcombo/devise/graphs/contributors
740
767
 
741
768
  ## License
742
769
 
743
- MIT License. Copyright 2020 Rafael França, Leonardo Tegon, Carlos Antônio da Silva. Copyright 2009-2019 Plataformatec.
770
+ MIT License. Copyright 2020-2023 Rafael França, Leonardo Tegon, Carlos Antônio da Silva. Copyright 2009-2019 Plataformatec.
744
771
 
745
772
  The Devise logo is licensed under [Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License](https://creativecommons.org/licenses/by-nc-nd/4.0/).
@@ -27,6 +27,7 @@ class Devise::ConfirmationsController < DeviseController
27
27
  set_flash_message!(:notice, :confirmed)
28
28
  respond_with_navigational(resource){ redirect_to after_confirmation_path_for(resource_name, resource) }
29
29
  else
30
+ # TODO: use `error_status` when the default changes to `:unprocessable_entity`.
30
31
  respond_with_navigational(resource.errors, status: :unprocessable_entity){ render :new }
31
32
  end
32
33
  end
@@ -36,7 +36,7 @@ class Devise::PasswordsController < DeviseController
36
36
 
37
37
  if resource.errors.empty?
38
38
  resource.unlock_access! if unlockable?(resource)
39
- if Devise.sign_in_after_reset_password
39
+ if resource_class.sign_in_after_reset_password
40
40
  flash_message = resource.active_for_authentication? ? :updated : :updated_not_active
41
41
  set_flash_message!(:notice, flash_message)
42
42
  resource.after_database_authentication
@@ -53,7 +53,7 @@ class Devise::PasswordsController < DeviseController
53
53
 
54
54
  protected
55
55
  def after_resetting_password_path_for(resource)
56
- Devise.sign_in_after_reset_password ? after_sign_in_path_for(resource) : new_session_path(resource_name)
56
+ resource_class.sign_in_after_reset_password ? after_sign_in_path_for(resource) : new_session_path(resource_name)
57
57
  end
58
58
 
59
59
  # The path used after sending reset password instructions
@@ -67,7 +67,7 @@ class Devise::RegistrationsController < DeviseController
67
67
  Devise.sign_out_all_scopes ? sign_out : sign_out(resource_name)
68
68
  set_flash_message! :notice, :destroyed
69
69
  yield resource if block_given?
70
- respond_with_navigational(resource){ redirect_to after_sign_out_path_for(resource_name) }
70
+ respond_with_navigational(resource){ redirect_to after_sign_out_path_for(resource_name), status: Devise.responder.redirect_status }
71
71
  end
72
72
 
73
73
  # GET /resource/cancel
@@ -77,7 +77,7 @@ class Devise::SessionsController < DeviseController
77
77
  # support returning empty response on GET request
78
78
  respond_to do |format|
79
79
  format.all { head :no_content }
80
- format.any(*navigational_formats) { redirect_to after_sign_out_path_for(resource_name) }
80
+ format.any(*navigational_formats) { redirect_to after_sign_out_path_for(resource_name), status: Devise.responder.redirect_status }
81
81
  end
82
82
  end
83
83
  end
@@ -29,6 +29,7 @@ class Devise::UnlocksController < DeviseController
29
29
  set_flash_message! :notice, :unlocked
30
30
  respond_with_navigational(resource){ redirect_to after_unlock_path_for(resource) }
31
31
  else
32
+ # TODO: use `error_status` when the default changes to `:unprocessable_entity`.
32
33
  respond_with_navigational(resource.errors, status: :unprocessable_entity){ render :new }
33
34
  end
34
35
  end
@@ -15,6 +15,7 @@ class DeviseController < Devise.parent_controller.constantize
15
15
  end
16
16
 
17
17
  prepend_before_action :assert_is_devise_resource!
18
+ self.responder = Devise.responder
18
19
  respond_to :html if mimes_for_respond_to.empty?
19
20
 
20
21
  # Override prefixes to consider the scoped view.
@@ -38,6 +38,6 @@
38
38
 
39
39
  <h3>Cancel my account</h3>
40
40
 
41
- <p>Unhappy? <%= button_to "Cancel my account", registration_path(resource_name), data: { confirm: "Are you sure?" }, method: :delete %></p>
41
+ <div>Unhappy? <%= button_to "Cancel my account", registration_path(resource_name), data: { confirm: "Are you sure?", turbo_confirm: "Are you sure?" }, method: :delete %></div>
42
42
 
43
43
  <%= link_to "Back", :back %>
@@ -1,5 +1,5 @@
1
1
  <% if resource.errors.any? %>
2
- <div id="error_explanation">
2
+ <div id="error_explanation" data-turbo-cache="false">
3
3
  <h2>
4
4
  <%= I18n.t("errors.messages.not_saved",
5
5
  count: resource.errors.count,
@@ -20,6 +20,6 @@
20
20
 
21
21
  <%- if devise_mapping.omniauthable? %>
22
22
  <%- resource_class.omniauth_providers.each do |provider| %>
23
- <%= link_to "Sign in with #{OmniAuth::Utils.camelize(provider)}", omniauth_authorize_path(resource_name, provider) %><br />
23
+ <%= button_to "Sign in with #{OmniAuth::Utils.camelize(provider)}", omniauth_authorize_path(resource_name, provider), data: { turbo: false } %><br />
24
24
  <% end %>
25
25
  <% end %>
@@ -44,7 +44,7 @@ en:
44
44
  signed_up_but_unconfirmed: "A message with a confirmation link has been sent to your email address. Please follow the link to activate your account."
45
45
  update_needs_confirmation: "You updated your account successfully, but we need to verify your new email address. Please check your email and follow the confirmation link to confirm your new email address."
46
46
  updated: "Your account has been updated successfully."
47
- updated_but_not_signed_in: "Your account has been updated successfully, but since your password was changed, you need to sign in again"
47
+ updated_but_not_signed_in: "Your account has been updated successfully, but since your password was changed, you need to sign in again."
48
48
  sessions:
49
49
  signed_in: "Signed in successfully."
50
50
  signed_out: "Signed out successfully."
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Devise
4
+ module Controllers
5
+ # Custom Responder to configure default statuses that only apply to Devise,
6
+ # and allow to integrate more easily with Hotwire/Turbo.
7
+ class Responder < ActionController::Responder
8
+ if respond_to?(:error_status=) && respond_to?(:redirect_status=)
9
+ self.error_status = :ok
10
+ self.redirect_status = :found
11
+ else
12
+ # TODO: remove this support for older Rails versions, which aren't supported by Turbo
13
+ # and/or responders. It won't allow configuring a custom response, but it allows Devise
14
+ # to use these methods and defaults across the implementation more easily.
15
+ def self.error_status
16
+ :ok
17
+ end
18
+
19
+ def self.redirect_status
20
+ :found
21
+ end
22
+
23
+ def self.error_status=(*)
24
+ warn "[DEVISE] Setting the error status on the Devise responder has no effect with this " \
25
+ "version of `responders`, please make sure you're using a newer version. Check the changelog for more info."
26
+ end
27
+
28
+ def self.redirect_status=(*)
29
+ warn "[DEVISE] Setting the redirect status on the Devise responder has no effect with this " \
30
+ "version of `responders`, please make sure you're using a newer version. Check the changelog for more info."
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -21,7 +21,7 @@ module Devise
21
21
  # to the set_user method in warden.
22
22
  # If you are using a custom warden strategy and the timeoutable module, you have to
23
23
  # set `env["devise.skip_timeout"] = true` in the request to use this method, like we do
24
- # in the sessions controller: https://github.com/heartcombo/devise/blob/master/app/controllers/devise/sessions_controller.rb#L7
24
+ # in the sessions controller: https://github.com/heartcombo/devise/blob/main/app/controllers/devise/sessions_controller.rb#L7
25
25
  #
26
26
  # Examples:
27
27
  #
@@ -106,10 +106,12 @@ module Devise
106
106
  private
107
107
 
108
108
  def expire_data_after_sign_in!
109
+ # TODO: remove once Rails 5.2+ and forward are only supported.
109
110
  # session.keys will return an empty array if the session is not yet loaded.
110
111
  # This is a bug in both Rack and Rails.
111
112
  # A call to #empty? forces the session to be loaded.
112
113
  session.empty?
114
+
113
115
  session.keys.grep(/^devise\./).each { |k| session.delete(k) }
114
116
  end
115
117
 
@@ -71,7 +71,11 @@ module Devise
71
71
  end
72
72
 
73
73
  flash.now[:alert] = i18n_message(:invalid) if is_flashing_format?
74
- self.response = recall_app(warden_options[:recall]).call(request.env)
74
+ self.response = recall_app(warden_options[:recall]).call(request.env).tap { |response|
75
+ response[0] = Rack::Utils.status_code(
76
+ response[0].in?(300..399) ? Devise.responder.redirect_status : Devise.responder.error_status
77
+ )
78
+ }
75
79
  end
76
80
 
77
81
  def redirect
@@ -167,7 +171,7 @@ module Devise
167
171
  end
168
172
 
169
173
  def skip_format?
170
- %w(html */*).include? request_format.to_s
174
+ %w(html */* turbo_stream).include? request_format.to_s
171
175
  end
172
176
 
173
177
  # Choose whether we should respond in an HTTP authentication fashion,
@@ -4,6 +4,11 @@ Warden::Manager.after_authentication do |record, warden, options|
4
4
  clean_up_for_winning_strategy = !warden.winning_strategy.respond_to?(:clean_up_csrf?) ||
5
5
  warden.winning_strategy.clean_up_csrf?
6
6
  if Devise.clean_up_csrf_token_on_authentication && clean_up_for_winning_strategy
7
- warden.request.session.try(:delete, :_csrf_token)
7
+ if warden.request.respond_to?(:reset_csrf_token)
8
+ # Rails 7.1+
9
+ warden.request.reset_csrf_token
10
+ else
11
+ warden.request.session.try(:delete, :_csrf_token)
12
+ end
8
13
  end
9
14
  end
@@ -3,10 +3,7 @@
3
3
  # After each sign in, if resource responds to failed_attempts, sets it to 0
4
4
  # This is only triggered when the user is explicitly set (with set_user)
5
5
  Warden::Manager.after_set_user except: :fetch do |record, warden, options|
6
- if record.respond_to?(:failed_attempts) && warden.authenticated?(options[:scope])
7
- unless record.failed_attempts.to_i.zero?
8
- record.failed_attempts = 0
9
- record.save(validate: false)
10
- end
6
+ if record.respond_to?(:reset_failed_attempts!) && warden.authenticated?(options[:scope])
7
+ record.reset_failed_attempts!
11
8
  end
12
9
  end
@@ -2,6 +2,7 @@
2
2
 
3
3
  require 'devise/hooks/activatable'
4
4
  require 'devise/hooks/csrf_cleaner'
5
+ require 'devise/rails/deprecated_constant_accessor'
5
6
 
6
7
  module Devise
7
8
  module Models
@@ -9,7 +10,7 @@ module Devise
9
10
  #
10
11
  # == Options
11
12
  #
12
- # Authenticatable adds the following options to devise_for:
13
+ # Authenticatable adds the following options to +devise+:
13
14
  #
14
15
  # * +authentication_keys+: parameters used for authentication. By default [:email].
15
16
  #
@@ -55,11 +56,14 @@ module Devise
55
56
  module Authenticatable
56
57
  extend ActiveSupport::Concern
57
58
 
58
- BLACKLIST_FOR_SERIALIZATION = [:encrypted_password, :reset_password_token, :reset_password_sent_at,
59
+ UNSAFE_ATTRIBUTES_FOR_SERIALIZATION = [:encrypted_password, :reset_password_token, :reset_password_sent_at,
59
60
  :remember_created_at, :sign_in_count, :current_sign_in_at, :last_sign_in_at, :current_sign_in_ip,
60
61
  :last_sign_in_ip, :password_salt, :confirmation_token, :confirmed_at, :confirmation_sent_at,
61
62
  :remember_token, :unconfirmed_email, :failed_attempts, :unlock_token, :locked_at]
62
63
 
64
+ include Devise::DeprecatedConstantAccessor
65
+ deprecate_constant "BLACKLIST_FOR_SERIALIZATION", "Devise::Models::Authenticatable::UNSAFE_ATTRIBUTES_FOR_SERIALIZATION"
66
+
63
67
  included do
64
68
  class_attribute :devise_modules, instance_writer: false
65
69
  self.devise_modules ||= []
@@ -109,7 +113,7 @@ module Devise
109
113
  if options[:force_except]
110
114
  options[:except].concat Array(options[:force_except])
111
115
  else
112
- options[:except].concat BLACKLIST_FOR_SERIALIZATION
116
+ options[:except].concat UNSAFE_ATTRIBUTES_FOR_SERIALIZATION
113
117
  end
114
118
 
115
119
  super(options)
@@ -48,7 +48,7 @@ module Devise
48
48
  included do
49
49
  before_create :generate_confirmation_token, if: :confirmation_required?
50
50
  after_create :skip_reconfirmation_in_callback!, if: :send_confirmation_notification?
51
- if defined?(ActiveRecord) && self < ActiveRecord::Base # ActiveRecord
51
+ if Devise::Orm.active_record?(self) # ActiveRecord
52
52
  after_commit :send_on_create_confirmation_instructions, on: :create, if: :send_confirmation_notification?
53
53
  after_commit :send_reconfirmation_instructions, on: :update, if: :reconfirmation_required?
54
54
  else # Mongoid
@@ -258,44 +258,23 @@ module Devise
258
258
  generate_confirmation_token && save(validate: false)
259
259
  end
260
260
 
261
- if Devise.activerecord51?
262
- def postpone_email_change_until_confirmation_and_regenerate_confirmation_token
263
- @reconfirmation_required = true
264
- self.unconfirmed_email = self.email
265
- self.email = self.email_in_database
266
- self.confirmation_token = nil
267
- generate_confirmation_token
268
- end
269
- else
270
- def postpone_email_change_until_confirmation_and_regenerate_confirmation_token
271
- @reconfirmation_required = true
272
- self.unconfirmed_email = self.email
273
- self.email = self.email_was
274
- self.confirmation_token = nil
275
- generate_confirmation_token
276
- end
261
+
262
+ def postpone_email_change_until_confirmation_and_regenerate_confirmation_token
263
+ @reconfirmation_required = true
264
+ self.unconfirmed_email = self.email
265
+ self.email = self.devise_email_in_database
266
+ self.confirmation_token = nil
267
+ generate_confirmation_token
277
268
  end
278
269
 
279
- if Devise.activerecord51?
280
- def postpone_email_change?
281
- postpone = self.class.reconfirmable &&
282
- will_save_change_to_email? &&
283
- !@bypass_confirmation_postpone &&
284
- self.email.present? &&
285
- (!@skip_reconfirmation_in_callback || !self.email_in_database.nil?)
286
- @bypass_confirmation_postpone = false
287
- postpone
288
- end
289
- else
290
- def postpone_email_change?
291
- postpone = self.class.reconfirmable &&
292
- email_changed? &&
293
- !@bypass_confirmation_postpone &&
294
- self.email.present? &&
295
- (!@skip_reconfirmation_in_callback || !self.email_was.nil?)
296
- @bypass_confirmation_postpone = false
297
- postpone
298
- end
270
+ def postpone_email_change?
271
+ postpone = self.class.reconfirmable &&
272
+ devise_will_save_change_to_email? &&
273
+ !@bypass_confirmation_postpone &&
274
+ self.email.present? &&
275
+ (!@skip_reconfirmation_in_callback || !self.devise_email_in_database.nil?)
276
+ @bypass_confirmation_postpone = false
277
+ postpone
299
278
  end
300
279
 
301
280
  def reconfirmation_required?
@@ -13,7 +13,7 @@ module Devise
13
13
  #
14
14
  # == Options
15
15
  #
16
- # DatabaseAuthenticatable adds the following options to devise_for:
16
+ # DatabaseAuthenticatable adds the following options to +devise+:
17
17
  #
18
18
  # * +pepper+: a random string used to provide a more secure hash. Use
19
19
  # `rails secret` to generate new keys.
@@ -42,7 +42,7 @@ module Devise
42
42
  def initialize(*args, &block)
43
43
  @skip_email_changed_notification = false
44
44
  @skip_password_change_notification = false
45
- super
45
+ super
46
46
  end
47
47
 
48
48
  # Skips sending the email changed notification after_update
@@ -177,16 +177,9 @@ module Devise
177
177
  encrypted_password[0,29] if encrypted_password
178
178
  end
179
179
 
180
- if Devise.activerecord51?
181
- # Send notification to user when email changes.
182
- def send_email_changed_notification
183
- send_devise_notification(:email_changed, to: email_before_last_save)
184
- end
185
- else
186
- # Send notification to user when email changes.
187
- def send_email_changed_notification
188
- send_devise_notification(:email_changed, to: email_was)
189
- end
180
+ # Send notification to user when email changes.
181
+ def send_email_changed_notification
182
+ send_devise_notification(:email_changed, to: devise_email_before_last_save)
190
183
  end
191
184
 
192
185
  # Send notification to user when password changes.
@@ -205,24 +198,12 @@ module Devise
205
198
  Devise::Encryptor.digest(self.class, password)
206
199
  end
207
200
 
208
- if Devise.activerecord51?
209
- def send_email_changed_notification?
210
- self.class.send_email_changed_notification && saved_change_to_email? && !@skip_email_changed_notification
211
- end
212
- else
213
- def send_email_changed_notification?
214
- self.class.send_email_changed_notification && email_changed? && !@skip_email_changed_notification
215
- end
201
+ def send_email_changed_notification?
202
+ self.class.send_email_changed_notification && devise_saved_change_to_email? && !@skip_email_changed_notification
216
203
  end
217
204
 
218
- if Devise.activerecord51?
219
- def send_password_change_notification?
220
- self.class.send_password_change_notification && saved_change_to_encrypted_password? && !@skip_password_change_notification
221
- end
222
- else
223
- def send_password_change_notification?
224
- self.class.send_password_change_notification && encrypted_password_changed? && !@skip_password_change_notification
225
- end
205
+ def send_password_change_notification?
206
+ self.class.send_password_change_notification && devise_saved_change_to_encrypted_password? && !@skip_password_change_notification
226
207
  end
227
208
 
228
209
  module ClassMethods
@@ -18,7 +18,7 @@ module Devise
18
18
  # * +maximum_attempts+: how many attempts should be accepted before blocking the user.
19
19
  # * +lock_strategy+: lock the user account by :failed_attempts or :none.
20
20
  # * +unlock_strategy+: unlock the user account by :time, :email, :both or :none.
21
- # * +unlock_in+: the time you want to lock the user after to lock happens. Only available when unlock_strategy is :time or :both.
21
+ # * +unlock_in+: the time you want to unlock the user after lock happens. Only available when unlock_strategy is :time or :both.
22
22
  # * +unlock_keys+: the keys you want to use when locking and unlocking an account
23
23
  #
24
24
  module Lockable
@@ -57,6 +57,14 @@ module Devise
57
57
  save(validate: false)
58
58
  end
59
59
 
60
+ # Resets failed attempts counter to 0.
61
+ def reset_failed_attempts!
62
+ if respond_to?(:failed_attempts) && !failed_attempts.to_i.zero?
63
+ self.failed_attempts = 0
64
+ save(validate: false)
65
+ end
66
+ end
67
+
60
68
  # Verifies whether a user is locked or not.
61
69
  def access_locked?
62
70
  !!locked_at && !lock_expired?
@@ -110,7 +118,7 @@ module Devise
110
118
  false
111
119
  end
112
120
  end
113
-
121
+
114
122
  def increment_failed_attempts
115
123
  self.class.increment_counter(:failed_attempts, id)
116
124
  reload
@@ -8,11 +8,11 @@ module Devise
8
8
  #
9
9
  # == Options
10
10
  #
11
- # Oauthable adds the following options to devise_for:
11
+ # Oauthable adds the following options to +devise+:
12
12
  #
13
13
  # * +omniauth_providers+: Which providers are available to this model. It expects an array:
14
14
  #
15
- # devise_for :database_authenticatable, :omniauthable, omniauth_providers: [:twitter]
15
+ # devise :database_authenticatable, :omniauthable, omniauth_providers: [:twitter]
16
16
  #
17
17
  module Omniauthable
18
18
  extend ActiveSupport::Concern
@@ -7,7 +7,7 @@ module Devise
7
7
  #
8
8
  # ==Options
9
9
  #
10
- # Recoverable adds the following options to devise_for:
10
+ # Recoverable adds the following options to +devise+:
11
11
  #
12
12
  # * +reset_password_keys+: the keys you want to use when recovering the password for an account
13
13
  # * +reset_password_within+: the time period within which the password must be reset or the token expires.
@@ -99,24 +99,13 @@ module Devise
99
99
  send_devise_notification(:reset_password_instructions, token, {})
100
100
  end
101
101
 
102
- if Devise.activerecord51?
103
- def clear_reset_password_token?
104
- encrypted_password_changed = respond_to?(:will_save_change_to_encrypted_password?) && will_save_change_to_encrypted_password?
105
- authentication_keys_changed = self.class.authentication_keys.any? do |attribute|
106
- respond_to?("will_save_change_to_#{attribute}?") && send("will_save_change_to_#{attribute}?")
107
- end
108
-
109
- authentication_keys_changed || encrypted_password_changed
102
+ def clear_reset_password_token?
103
+ encrypted_password_changed = devise_respond_to_and_will_save_change_to_attribute?(:encrypted_password)
104
+ authentication_keys_changed = self.class.authentication_keys.any? do |attribute|
105
+ devise_respond_to_and_will_save_change_to_attribute?(attribute)
110
106
  end
111
- else
112
- def clear_reset_password_token?
113
- encrypted_password_changed = respond_to?(:encrypted_password_changed?) && encrypted_password_changed?
114
- authentication_keys_changed = self.class.authentication_keys.any? do |attribute|
115
- respond_to?("#{attribute}_changed?") && send("#{attribute}_changed?")
116
- end
117
107
 
118
- authentication_keys_changed || encrypted_password_changed
119
- end
108
+ authentication_keys_changed || encrypted_password_changed
120
109
  end
121
110
 
122
111
  module ClassMethods
@@ -15,7 +15,7 @@ module Devise
15
15
  #
16
16
  # == Options
17
17
  #
18
- # Rememberable adds the following options in devise_for:
18
+ # Rememberable adds the following options to +devise+:
19
19
  #
20
20
  # * +remember_for+: the time you want the user will be remembered without
21
21
  # asking for credentials. After this time the user will be blocked and
@@ -11,7 +11,7 @@ module Devise
11
11
  #
12
12
  # == Options
13
13
  #
14
- # Timeoutable adds the following options to devise_for:
14
+ # Timeoutable adds the following options to +devise+:
15
15
  #
16
16
  # * +timeout_in+: the interval to timeout the user session without activity.
17
17
  #
@@ -9,7 +9,7 @@ module Devise
9
9
  #
10
10
  # == Options
11
11
  #
12
- # Validatable adds the following options to devise_for:
12
+ # Validatable adds the following options to +devise+:
13
13
  #
14
14
  # * +email_regexp+: the regular expression used to validate e-mails;
15
15
  # * +password_length+: a range expressing password length. Defaults to 6..128.
@@ -29,13 +29,8 @@ module Devise
29
29
 
30
30
  base.class_eval do
31
31
  validates_presence_of :email, if: :email_required?
32
- if Devise.activerecord51?
33
- validates_uniqueness_of :email, allow_blank: true, case_sensitive: true, if: :will_save_change_to_email?
34
- validates_format_of :email, with: email_regexp, allow_blank: true, if: :will_save_change_to_email?
35
- else
36
- validates_uniqueness_of :email, allow_blank: true, if: :email_changed?
37
- validates_format_of :email, with: email_regexp, allow_blank: true, if: :email_changed?
38
- end
32
+ validates_uniqueness_of :email, allow_blank: true, case_sensitive: true, if: :devise_will_save_change_to_email?
33
+ validates_format_of :email, with: email_regexp, allow_blank: true, if: :devise_will_save_change_to_email?
39
34
 
40
35
  validates_presence_of :password, if: :password_required?
41
36
  validates_confirmation_of :password, if: :password_required?
@@ -47,7 +42,7 @@ module Devise
47
42
  unavailable_validations = VALIDATIONS.select { |v| !base.respond_to?(v) }
48
43
 
49
44
  unless unavailable_validations.empty?
50
- raise "Could not use :validatable module since #{base} does not respond " <<
45
+ raise "Could not use :validatable module since #{base} does not respond " \
51
46
  "to the following methods: #{unavailable_validations.to_sentence}."
52
47
  end
53
48
  end
data/lib/devise/models.rb CHANGED
@@ -84,6 +84,7 @@ module Devise
84
84
  end
85
85
 
86
86
  devise_modules_hook! do
87
+ include Devise::Orm
87
88
  include Devise::Models::Authenticatable
88
89
 
89
90
  selected_modules.each do |m|
@@ -1,17 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  begin
4
+ gem "omniauth", ">= 1.0.0"
5
+
4
6
  require "omniauth"
5
- require "omniauth/version"
6
7
  rescue LoadError
7
8
  warn "Could not load 'omniauth'. Please ensure you have the omniauth gem >= 1.0.0 installed and listed in your Gemfile."
8
9
  raise
9
10
  end
10
11
 
11
- unless OmniAuth::VERSION =~ /^1\./
12
- raise "You are using an old OmniAuth version, please ensure you have 1.0.0.pr2 version or later installed."
13
- end
14
-
15
12
  # Clean up the default path_prefix. It will be automatically set by Devise.
16
13
  OmniAuth.config.path_prefix = nil
17
14
 
data/lib/devise/orm.rb ADDED
@@ -0,0 +1,71 @@
1
+ module Devise
2
+ module Orm # :nodoc:
3
+ def self.active_record?(model)
4
+ defined?(ActiveRecord) && model < ActiveRecord::Base
5
+ end
6
+
7
+ def self.active_record_51?(model)
8
+ active_record?(model) && ActiveRecord.gem_version >= Gem::Version.new("5.1.x")
9
+ end
10
+
11
+ def self.included(model)
12
+ if Devise::Orm.active_record_51?(model)
13
+ model.include DirtyTrackingNewMethods
14
+ else
15
+ model.include DirtyTrackingOldMethods
16
+ end
17
+ end
18
+
19
+ module DirtyTrackingNewMethods
20
+ def devise_email_before_last_save
21
+ email_before_last_save
22
+ end
23
+
24
+ def devise_email_in_database
25
+ email_in_database
26
+ end
27
+
28
+ def devise_saved_change_to_email?
29
+ saved_change_to_email?
30
+ end
31
+
32
+ def devise_saved_change_to_encrypted_password?
33
+ saved_change_to_encrypted_password?
34
+ end
35
+
36
+ def devise_will_save_change_to_email?
37
+ will_save_change_to_email?
38
+ end
39
+
40
+ def devise_respond_to_and_will_save_change_to_attribute?(attribute)
41
+ respond_to?("will_save_change_to_#{attribute}?") && send("will_save_change_to_#{attribute}?")
42
+ end
43
+ end
44
+
45
+ module DirtyTrackingOldMethods
46
+ def devise_email_before_last_save
47
+ email_was
48
+ end
49
+
50
+ def devise_email_in_database
51
+ email_was
52
+ end
53
+
54
+ def devise_saved_change_to_email?
55
+ email_changed?
56
+ end
57
+
58
+ def devise_saved_change_to_encrypted_password?
59
+ encrypted_password_changed?
60
+ end
61
+
62
+ def devise_will_save_change_to_email?
63
+ email_changed?
64
+ end
65
+
66
+ def devise_respond_to_and_will_save_change_to_attribute?(attribute)
67
+ respond_to?("#{attribute}_changed?") && send("#{attribute}_changed?")
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ begin
4
+ require 'active_support/deprecation/constant_accessor'
5
+
6
+ module Devise
7
+ DeprecatedConstantAccessor = ActiveSupport::Deprecation::DeprecatedConstantAccessor #:nodoc:
8
+ end
9
+ rescue LoadError
10
+
11
+ # Copy of constant deprecation module from Rails / Active Support version 6, so we can use it
12
+ # with Rails <= 5.0 versions. This can be removed once we support only Rails 5.1 or greater.
13
+ module Devise
14
+ module DeprecatedConstantAccessor #:nodoc:
15
+ def self.included(base)
16
+ require "active_support/inflector/methods"
17
+
18
+ extension = Module.new do
19
+ def const_missing(missing_const_name)
20
+ if class_variable_defined?(:@@_deprecated_constants)
21
+ if (replacement = class_variable_get(:@@_deprecated_constants)[missing_const_name.to_s])
22
+ replacement[:deprecator].warn(replacement[:message] || "#{name}::#{missing_const_name} is deprecated! Use #{replacement[:new]} instead.", Rails::VERSION::MAJOR == 4 ? caller : caller_locations)
23
+ return ActiveSupport::Inflector.constantize(replacement[:new].to_s)
24
+ end
25
+ end
26
+ super
27
+ end
28
+
29
+ def deprecate_constant(const_name, new_constant, message: nil, deprecator: ActiveSupport::Deprecation.instance)
30
+ class_variable_set(:@@_deprecated_constants, {}) unless class_variable_defined?(:@@_deprecated_constants)
31
+ class_variable_get(:@@_deprecated_constants)[const_name.to_s] = { new: new_constant, message: message, deprecator: deprecator }
32
+ end
33
+ end
34
+ base.singleton_class.prepend extension
35
+ end
36
+ end
37
+ end
38
+
39
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Devise
4
- VERSION = "4.7.3".freeze
4
+ VERSION = "4.9.2".freeze
5
5
  end
data/lib/devise.rb CHANGED
@@ -13,6 +13,7 @@ module Devise
13
13
  autoload :Encryptor, 'devise/encryptor'
14
14
  autoload :FailureApp, 'devise/failure_app'
15
15
  autoload :OmniAuth, 'devise/omniauth'
16
+ autoload :Orm, 'devise/orm'
16
17
  autoload :ParameterFilter, 'devise/parameter_filter'
17
18
  autoload :ParameterSanitizer, 'devise/parameter_sanitizer'
18
19
  autoload :TestHelpers, 'devise/test_helpers'
@@ -23,6 +24,7 @@ module Devise
23
24
  module Controllers
24
25
  autoload :Helpers, 'devise/controllers/helpers'
25
26
  autoload :Rememberable, 'devise/controllers/rememberable'
27
+ autoload :Responder, 'devise/controllers/responder'
26
28
  autoload :ScopedViews, 'devise/controllers/scoped_views'
27
29
  autoload :SignInOut, 'devise/controllers/sign_in_out'
28
30
  autoload :StoreLocation, 'devise/controllers/store_location'
@@ -217,7 +219,16 @@ module Devise
217
219
 
218
220
  # Which formats should be treated as navigational.
219
221
  mattr_accessor :navigational_formats
220
- @@navigational_formats = ["*/*", :html]
222
+ @@navigational_formats = ["*/*", :html, :turbo_stream]
223
+
224
+ # The default responder used by Devise, used to customize status codes with:
225
+ #
226
+ # `config.responder.error_status`
227
+ # `config.responder.redirect_status`
228
+ #
229
+ # Can be replaced by a custom application responder.
230
+ mattr_accessor :responder
231
+ @@responder = Devise::Controllers::Responder
221
232
 
222
233
  # When set to true, signing out a user signs out all other scopes.
223
234
  mattr_accessor :sign_out_all_scopes
@@ -297,10 +308,6 @@ module Devise
297
308
  mattr_accessor :sign_in_after_change_password
298
309
  @@sign_in_after_change_password = true
299
310
 
300
- def self.activerecord51? # :nodoc:
301
- defined?(ActiveRecord) && ActiveRecord.gem_version >= Gem::Version.new("5.1.x")
302
- end
303
-
304
311
  # Default way to set up Devise. Run rails generate devise_install to create
305
312
  # a fresh initializer with all configuration values.
306
313
  def self.setup
@@ -313,12 +320,20 @@ module Devise
313
320
  end
314
321
 
315
322
  def get
316
- ActiveSupport::Dependencies.constantize(@name)
323
+ # TODO: Remove AS::Dependencies usage when dropping support to Rails < 7.
324
+ if ActiveSupport::Dependencies.respond_to?(:constantize)
325
+ ActiveSupport::Dependencies.constantize(@name)
326
+ else
327
+ @name.constantize
328
+ end
317
329
  end
318
330
  end
319
331
 
320
332
  def self.ref(arg)
321
- ActiveSupport::Dependencies.reference(arg)
333
+ # TODO: Remove AS::Dependencies usage when dropping support to Rails < 7.
334
+ if ActiveSupport::Dependencies.respond_to?(:reference)
335
+ ActiveSupport::Dependencies.reference(arg)
336
+ end
322
337
  Getter.new(arg)
323
338
  end
324
339
 
@@ -505,6 +520,14 @@ module Devise
505
520
  b.each_byte { |byte| res |= byte ^ l.shift }
506
521
  res == 0
507
522
  end
523
+
524
+ def self.activerecord51? # :nodoc:
525
+ ActiveSupport::Deprecation.warn <<-DEPRECATION.strip_heredoc
526
+ [Devise] `Devise.activerecord51?` is deprecated and will be removed in the next major version.
527
+ It is a non-public method that's no longer used internally, but that other libraries have been relying on.
528
+ DEPRECATION
529
+ defined?(ActiveRecord) && ActiveRecord.gem_version >= Gem::Version.new("5.1.x")
530
+ end
508
531
  end
509
532
 
510
533
  require 'warden'
@@ -86,9 +86,24 @@ RUBY
86
86
  Rails::VERSION::MAJOR >= 5
87
87
  end
88
88
 
89
+ def rails61_and_up?
90
+ Rails::VERSION::MAJOR > 6 || (Rails::VERSION::MAJOR == 6 && Rails::VERSION::MINOR >= 1)
91
+ end
92
+
89
93
  def postgresql?
90
- config = ActiveRecord::Base.configurations[Rails.env]
91
- config && config['adapter'] == 'postgresql'
94
+ ar_config && ar_config['adapter'] == 'postgresql'
95
+ end
96
+
97
+ def ar_config
98
+ if ActiveRecord::Base.configurations.respond_to?(:configs_for)
99
+ if rails61_and_up?
100
+ ActiveRecord::Base.configurations.configs_for(env_name: Rails.env, name: "primary").configuration_hash
101
+ else
102
+ ActiveRecord::Base.configurations.configs_for(env_name: Rails.env, spec_name: "primary").config
103
+ end
104
+ else
105
+ ActiveRecord::Base.configurations[Rails.env]
106
+ end
92
107
  end
93
108
 
94
109
  def migration_version
@@ -256,14 +256,14 @@ Devise.setup do |config|
256
256
 
257
257
  # ==> Navigation configuration
258
258
  # Lists the formats that should be treated as navigational. Formats like
259
- # :html, should redirect to the sign in page when the user does not have
259
+ # :html should redirect to the sign in page when the user does not have
260
260
  # access, but formats like :xml or :json, should return 401.
261
261
  #
262
262
  # If you have any extra navigational formats, like :iphone or :mobile, you
263
263
  # should add them to the navigational formats lists.
264
264
  #
265
265
  # The "*/*" below is required to match Internet Explorer requests.
266
- # config.navigational_formats = ['*/*', :html]
266
+ # config.navigational_formats = ['*/*', :html, :turbo_stream]
267
267
 
268
268
  # The default HTTP method used to sign out a resource. Default is :delete.
269
269
  config.sign_out_via = :delete
@@ -296,12 +296,14 @@ Devise.setup do |config|
296
296
  # so you need to do it manually. For the users scope, it would be:
297
297
  # config.omniauth_path_prefix = '/my_engine/users/auth'
298
298
 
299
- # ==> Turbolinks configuration
300
- # If your app is using Turbolinks, Turbolinks::Controller needs to be included to make redirection work correctly:
301
- #
302
- # ActiveSupport.on_load(:devise_failure_app) do
303
- # include Turbolinks::Controller
304
- # end
299
+ # ==> Hotwire/Turbo configuration
300
+ # When using Devise with Hotwire/Turbo, the http status for error responses
301
+ # and some redirects must match the following. The default in Devise for existing
302
+ # apps is `200 OK` and `302 Found respectively`, but new apps are generated with
303
+ # these new defaults that match Hotwire/Turbo behavior.
304
+ # Note: These might become the new default in future versions of Devise.
305
+ config.responder.error_status = :unprocessable_entity
306
+ config.responder.redirect_status = :see_other
305
307
 
306
308
  # ==> Configuration for :registerable
307
309
 
@@ -30,6 +30,6 @@
30
30
 
31
31
  <h3>Cancel my account</h3>
32
32
 
33
- <p>Unhappy? <%= link_to "Cancel my account", registration_path(resource_name), data: { confirm: "Are you sure?" }, method: :delete %></p>
33
+ <div>Unhappy? <%= button_to "Cancel my account", registration_path(resource_name), data: { confirm: "Are you sure?", turbo_confirm: "Are you sure?" }, method: :delete %></div>
34
34
 
35
35
  <%= link_to "Back", :back %>
metadata CHANGED
@@ -1,15 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: devise
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.7.3
4
+ version: 4.9.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - José Valim
8
8
  - Carlos Antônio
9
- autorequire:
9
+ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2020-09-21 00:00:00.000000000 Z
12
+ date: 2023-04-03 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: warden
@@ -117,6 +117,7 @@ files:
117
117
  - lib/devise.rb
118
118
  - lib/devise/controllers/helpers.rb
119
119
  - lib/devise/controllers/rememberable.rb
120
+ - lib/devise/controllers/responder.rb
120
121
  - lib/devise/controllers/scoped_views.rb
121
122
  - lib/devise/controllers/sign_in_out.rb
122
123
  - lib/devise/controllers/store_location.rb
@@ -150,11 +151,13 @@ files:
150
151
  - lib/devise/omniauth.rb
151
152
  - lib/devise/omniauth/config.rb
152
153
  - lib/devise/omniauth/url_helpers.rb
154
+ - lib/devise/orm.rb
153
155
  - lib/devise/orm/active_record.rb
154
156
  - lib/devise/orm/mongoid.rb
155
157
  - lib/devise/parameter_filter.rb
156
158
  - lib/devise/parameter_sanitizer.rb
157
159
  - lib/devise/rails.rb
160
+ - lib/devise/rails/deprecated_constant_accessor.rb
158
161
  - lib/devise/rails/routes.rb
159
162
  - lib/devise/rails/warden_compat.rb
160
163
  - lib/devise/secret_key_finder.rb
@@ -201,8 +204,17 @@ files:
201
204
  homepage: https://github.com/heartcombo/devise
202
205
  licenses:
203
206
  - MIT
204
- metadata: {}
205
- post_install_message:
207
+ metadata:
208
+ homepage_uri: https://github.com/heartcombo/devise
209
+ documentation_uri: https://rubydoc.info/github/heartcombo/devise
210
+ changelog_uri: https://github.com/heartcombo/devise/blob/main/CHANGELOG.md
211
+ source_code_uri: https://github.com/heartcombo/devise
212
+ bug_tracker_uri: https://github.com/heartcombo/devise/issues
213
+ wiki_uri: https://github.com/heartcombo/devise/wiki
214
+ post_install_message: "\n[DEVISE] Please review the [changelog] and [upgrade guide]
215
+ for more info on Hotwire / Turbo integration.\n\n [changelog] https://github.com/heartcombo/devise/blob/main/CHANGELOG.md\n
216
+ \ [upgrade guide] https://github.com/heartcombo/devise/wiki/How-To:-Upgrade-to-Devise-4.9.0-%5BHotwire-Turbo-integration%5D\n
217
+ \ "
206
218
  rdoc_options: []
207
219
  require_paths:
208
220
  - lib
@@ -217,8 +229,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
217
229
  - !ruby/object:Gem::Version
218
230
  version: '0'
219
231
  requirements: []
220
- rubygems_version: 3.0.3
221
- signing_key:
232
+ rubygems_version: 3.0.3.1
233
+ signing_key:
222
234
  specification_version: 4
223
235
  summary: Flexible authentication solution for Rails with Warden
224
236
  test_files: []