Compare commits

...

121 Commits

Author SHA1 Message Date
José Valim
1516a0ae6d Release v3.5.4 2016-01-18 15:12:07 +01:00
José Valim
c92996646a Store creation timestamp on remember cookies
Signed-off-by: José Valim <jose.valim@plataformatec.com.br>
2016-01-18 14:47:31 +01:00
Kacper Walanus
ba5dd0a41a test for save in after_create hook breaks devise confirmation [3787] 2015-12-15 11:41:48 -02:00
Christian Macias
f63be5039a changed email_was !='' to email_was.present? 2015-12-15 11:41:33 -02:00
Christian Macias
f25562fd4b fix for #3787, save in after_create hook breaks devise confirmation 2015-12-15 11:41:33 -02:00
Siva Gollapalli
2a2fd806a8 FIX# Comparing times in UTC 2015-12-15 11:40:59 -02:00
Lucas Mazza
032eb145df Release 3.5.3. 2015-12-10 14:36:34 -02:00
José Valim
0d941b7ba5 Merge pull request #3847 from stanhu/reset-token-only-on-update
Only clear the reset token on an update
2015-12-09 20:28:06 +01:00
Stan Hu
f71d843f93 Only clear the reset token on an update
This solves the issue where a package might do:

```
user = User.new
user.email = 'test@test.com'
token = user.generate_reset_token
user.save

send_reset_email(token)
```

Since the save clears the reset token, the user will receive a stale token that no longer works.

Closes #3774
2015-12-09 11:14:50 -08:00
Lucas Mazza
7d825c93b6 Update CHANGELOG [ci skip]. 2015-12-09 13:53:29 -02:00
José Valim
19b1e2a6bc Merge pull request #3846 from seddy/make_email_optional_on_recoverable
Allow resources with no email field to be recoverable
2015-12-09 14:39:32 +01:00
José Valim
901919f25f Revert "Merge pull request #3774 from stanhu/reset-token-only-if-not-persisted"
This reverts commit 15c38d918f, reversing
changes made to 508c3418f9.
2015-12-09 14:21:09 +01:00
Lucas Mazza
15c38d918f Merge pull request #3774 from stanhu/reset-token-only-if-not-persisted
Only clear the reset password token if the model has already been persisted
2015-12-09 10:54:36 -02:00
Lucas Mazza
508c3418f9 Merge pull request #3826 from andygeers/master
Don't error if resource doesn't need confirming
2015-12-09 10:52:35 -02:00
Ed Saunders
d98e98fe77 Add a test for when a recoverable resource has a non-AR email field 2015-12-08 16:01:39 +00:00
Ed Saunders
4a45eb9899 Allow resources with no email field to be recoverable
The current implementation is opinionated about the resource should have
an "email" column on it if it is to be recoverable, which isn't
necessarily the case.  For example, developers may decide to pull emails
out into their own model or have some other way of communicating
password resets to their users (e.g. text message)

I'm not sure there's an easy test to put together for this case, as
minitest doesn't make it very easy to stub the "email_changed?" to raise
an error. Happy to look into building another model in the
"test/rails_app" if you want to have this properly tested though? Or for
a nice way to get calls to "email_changed?" to raise; minitest isn't
a test framework I'm overly familiar with :).

As a side note, it would be nice if the Validatable module also took
this into account, I may raise another PR for that.

This comes off the back of comments on this commit:
e641b4b7b9
2015-12-07 17:01:31 +00:00
José Valim
45fc964470 Merge pull request #3739 from stanhu/support-relative-urls-in-failure-app
Account for relative_url_root in FailureApp's recall method
2015-11-25 20:03:28 +01:00
Stan Hu
56fed052f8 Wrap logic for resetting token into instance method and add comments 2015-11-24 23:23:34 -08:00
Andy Geers
d3f521925e Write unit test for bug fix 2015-11-18 22:21:03 +00:00
Andy Geers
8a8887ea82 Don't error if resource doesn't need confirming 2015-11-18 22:21:03 +00:00
José Valim
d22ac4a4fb Merge pull request #3813 from jlerpscher/set-minimum-password-length-on-failure
set minimum password length on reset failure
2015-11-10 09:37:59 -02:00
Julien Lerpscher
8426b12550 set minimum password length on reset failure 2015-11-10 12:17:29 +01:00
José Valim
57bf362b55 Merge pull request #3808 from blase/skip-timeoutable
Allow skipping the timeoutable hook
2015-11-04 18:15:03 -02:00
José Valim
18a8260535 Merge pull request #3805 from robuye/master
Remove outdated example from documentation
2015-11-04 00:48:35 -02:00
Błażej Pankowiak
9f32f421a5 Allow skipping the timeoutable hook 2015-11-02 23:53:09 +01:00
robuye
df6a83b27b Remove outdated example from documentation
`#reset_password` always saves the record if validation passes.
2015-11-02 23:06:38 +01:00
Lucas Mazza
4477bab1aa Update Travis CI notification settings. 2015-11-01 19:54:58 -02:00
José Valim
d6dc93ca3d Merge pull request #3792 from excid3/master
Automatically underscore and pluralize scoped views generator
2015-10-22 00:42:40 +02:00
Chris Oliver
005d514adf Automatically underscore and pluralize scoped views generator. Fixes #3790 2015-10-21 14:53:03 -04:00
Lucas Mazza
9568e28d66 Merge pull request #3783 from yui-knk/doc_singular_option
[ci skip] Write how to use `singular` option of `ActionDispatch::Rout…
2015-10-19 09:15:34 -04:00
yui-knk
4f2571a408 [ci skip] Write how to use singular option of ActionDispatch::Routing::Mapper#devise_for
* Replace "the instance variable name in controller" with "the helper methods
  names in controller".
  Devise dose not define instance variable for controllers but define helper
  methods for controllers.
* Replace "the name in routes" with "the scope name in routes".
  `singular` is used as an argument of `devise_scope`.
* Add sample codes of routing and controller.
2015-10-16 11:57:42 +09:00
Rafael Mendonça França
e33d285e4a Update the documentation to use current Rails code [ci skip] 2015-10-15 16:13:06 -03:00
Stan Hu
619128cb9b Only clear the reset password token if the model has already been persisted
If a new user is created with a reset password token, the previous behavior
would automatically clear the token even when it was desired for setting
the password for the first time.
2015-10-02 12:30:57 -07:00
George Guimarães
9f37b6eff7 Merge pull request #3769 from xymbol/fix_typos
Fix typos
2015-09-30 19:39:49 -03:00
Adrian Mugnolo
2380612b6e Fix typo: authenticatable 2015-09-30 19:32:44 -03:00
Adrian Mugnolo
c334179c95 Fix typo: successful 2015-09-30 19:31:49 -03:00
José Valim
827d009b3c Merge pull request #3766 from nambrot/patch-1
Add missing comma
2015-09-28 17:28:41 +02:00
Nam Chu Hoai
56edeec958 Add missing comma 2015-09-28 11:25:03 -04:00
Lucas Mazza
7df57d5081 Merge pull request #3732 from posgarou/refactor/respond_to_helper_method
Wrap helper_method calls in respond_to?(:helper_method)
2015-09-26 11:05:30 -03:00
George Guimarães
2ccffc80b0 Merge pull request #3743 from plataformatec/fdf-add-code-of-conduct
Add a Code of Conduct
2015-09-08 00:02:47 -03:00
Flavia Fortes
797a19352c Add a Code of Conduct 2015-09-07 23:59:51 -03:00
Stan Hu
7025f968c6 Account for relative_url_root in FailureApp's recall method
Closes #3738
2015-09-06 00:05:19 -07:00
Ryan Mitchell
04e01f49a9 Use builtin matchers in helper tests 2015-08-31 09:58:25 -04:00
Ryan Mitchell
a3da40a701 Wrap helper_method calls in respond_to?(:helper_method) 2015-08-29 05:29:05 -04:00
Lucas Mazza
40258bf100 Remove the custom OmniAuth camelization on teardown. 2015-08-28 11:26:41 -03:00
Lucas Mazza
d3baff221d Merge pull request #3730 from timoschilling/omin-auth-camelization
use OmniAuth::Utils.camelize
2015-08-28 10:57:20 -03:00
Timo Schilling
f5e984c151 use OmniAuth::Utils.camelize
This will display the provider name with the original camelization:
facebook => Facebook
github => GitHub
linkedin => LinkedIn
2015-08-28 07:51:37 +02:00
Lucas Mazza
6ed6e09bf3 Merge pull request #3642 from jphenow/add-password-change-notification
Add password change notification
2015-08-27 12:48:14 -03:00
Jon Phenow
05ccdfbacd Merge branch 'add-password-change-notification' of github.com:jphenow/devise into add-password-change-notification 2015-08-27 10:43:51 -05:00
Jon Phenow
9bcc2d1c5f CHANGELOG 2015-08-27 10:26:42 -05:00
Jon Phenow
211159f2eb translation for mailer subject 2015-08-27 10:26:12 -05:00
Jon Phenow
ab141a8779 move model stubs 2015-08-27 10:26:12 -05:00
Jon Phenow
e9c82472ff quick comment touch-ups 2015-08-27 10:26:12 -05:00
Jon Phenow
48ed2fd1aa templates, config documentation 2015-08-27 10:26:12 -05:00
Jon Phenow
0fa74d863d functionality 2015-08-27 10:26:12 -05:00
Jon Phenow
c744dcf07a tests 2015-08-27 10:26:12 -05:00
Lucas Mazza
eb091b867f Fix rails g devise:views -v mailer with the Simple Form generator.
Our Simple Form generator shouldn't be responsible for generating the `mailer`
view directory, so we should skip it and let the Erb generator do the job.

Closes #3254.
2015-08-27 12:12:13 -03:00
Lucas Mazza
fb3568308e Merge pull request #3707 from LimeBlast/master
modifys markerb templates to use markdown links, not html ones.
2015-08-27 10:28:02 -03:00
Lucas Mazza
93b8f01583 Merge pull request #3719 from dgynn/doc_api_change
Update docs for Devise::Models.config
2015-08-26 14:56:22 -03:00
Dave Gynn
068da8045b update api docs for Models.config
config no longer takes a default value since 80699c58b4.
also, :streches was moved to DatabaseAuthenticatable.
2015-08-21 00:50:31 -07:00
José Valim
b12658782f Merge pull request #3717 from MarkMT/patch-2
Update comment on Devise.add_module
2015-08-21 09:18:19 +02:00
José Valim
3e87489c5b Merge pull request #3715 from evopark/feature/enhance_failure_app_url_options
Use default_url_options from parent_controller
2015-08-21 09:15:56 +02:00
Marcus Ilgner
8aa0e2655e Use default_url_options from parent_controller
Use a configured Devise.parent_controller, not ApplicationController
Also remove passing `*args` since it's a class-level attribute, not
a method.
2015-08-21 08:32:43 +02:00
MarkMT
155e23a73e Update comment on Devise.add_module
The existing comment suggests that add_module is used only for modules that are not provided by Devise itself.
2015-08-20 19:17:52 -05:00
José Valim
359fba970e Merge pull request #3713 from MarkMT/patch-1
Update comment on Devise.configure_warden
2015-08-19 10:04:31 +02:00
MarkMT
3a056f6d10 Update comment on Devise.configure_warden
The existing comment seems to be either outdated or obscure. I interpret it as meaning that configure_warden! is invoked by an 'initializer' block in class Devise::Engine, i.e. in lib/devise/rails.rb. However, as far as I can tell the only time the method is invoked is when ActionDispatch::Routing::RouteSet#finalize! is called, and this is aliased by devise to finalize_with_devise!.
2015-08-18 22:41:58 -05:00
José Valim
213aa51126 Merge pull request #3708 from dayweek/patch-1
Add removed method to CHANGELOG
2015-08-14 14:12:01 +02:00
David Hrachovy
8588387fad Add removed method to CHANGELOG
my app failed to start because the method was removed. I think it makes sense to mention it here.
2015-08-14 14:02:57 +02:00
Daniel Hollands
8c6de852c6 modifys markerb templates to use markdown links, not html ones. 2015-08-13 13:57:01 +01:00
Carlos Antonio da Silva
52e35f69c5 Fix typo in changelo [ci skip]
Thanks @reedloden.
2015-08-10 20:39:22 -03:00
José Valim
d9939d1ea0 Release v3.5.2 2015-08-10 14:46:36 +02:00
José Valim
703a0e0240 Merge pull request #3678 from OliveTreeBible/dctrotz-basic-auth-patch
Basic auth case insensitive pattern match
2015-08-10 14:14:06 +02:00
José Valim
48d8285344 Merge pull request #3699 from NeilvB/fix-line-break-edit-password
Remove unnecessary line break on edit password page.
2015-08-06 19:53:52 +02:00
Neil van Beinum
710496b6a8 Remove unnecessary line break on edit password page. 2015-08-06 18:21:34 +01:00
José Valim
2f45755e6c Merge pull request #3695 from yakovenkodenis/minor_grammar_improvements_at_readme
Improve grammar on lines 189 and 352 in readme
2015-08-02 13:53:24 +02:00
Denis Yakovenko
021f2da1e4 Improve grammar on lines 189 and 352 in readme 2015-08-02 13:48:31 +03:00
José Valim
bc6361ab9b Merge pull request #3661 from vincentwoo/plain_confirmation
Do not use digests for confirmation tokens
2015-07-30 11:43:10 +02:00
Vincent Woo
eb640ed344 Do not use digests for confirmation tokens 2015-07-30 01:55:50 -07:00
David Trotz
5c244d9e2b Basic auth case insensitive pattern match
Allow basic authentication to be case insensitive as per the HTTP 1.1 spec RFC 2068 Section 11
> It uses an extensible, case-insensitive token to identify the authentication scheme, followed by a comma-separated list of attribute-value pairs which carry the parameters necessary for achieving authentication via that scheme.

We have a particular client in production that has basic auth hard-coded as `basic` rather than `Basic` and devise is rejecting perfectly fine credentials. Making this small change has allowed us to authenticate this client with no issues.
2015-07-16 10:58:59 -07:00
José Valim
e538f02f30 Merge pull request #3672 from deivid-rodriguez/remove_obsolete_unused_config
Remove obsolete unused `expire_auth_token_on_timeout` config
2015-07-11 19:35:29 +02:00
David Rodríguez
4064641967 Remove obsolete expire_auth_token_on_timeout
This should have been removed in dff7891b97
when token authentication (and the reset_authentication_token! method)
were removed.
2015-07-11 09:01:22 -03:00
David Rodríguez
c72be1531c Keep Gemfile.lock in sync
Forgotten in b23f5223dd
2015-07-11 08:57:40 -03:00
José Valim
f0a168da5a Merge pull request #3670 from fengye87/master
redirect to after_resetting_password_path always
2015-07-10 17:32:37 +02:00
Feng Ye
4d89c709a5 redirect to after_resetting_password_path always 2015-07-10 20:01:42 +08:00
José Valim
737a55f9e1 Merge pull request #3659 from abevoelker/fix-auth-route-redirect
Fix infinite redirect in Rails 4.2 authenticated routes. Closes #3643
2015-07-04 11:38:21 +02:00
Carlos Antonio da Silva
fe5b7db6ab Merge pull request #3662 from vincentwoo/fix_mongo_dep
Just use regular 4.x mongoid gem
2015-06-30 22:33:45 -03:00
Vincent Woo
b23f5223dd just use regular 4.x mongoid gem 2015-06-30 16:02:06 -07:00
Abe Voelker
aa675f7f66 Fix infinite redirect in Rails 4.2 authenticated routes. Closes #3643 2015-06-27 14:25:09 -05:00
José Valim
181920886e Merge pull request #3653 from Envek/fix_routes_dynamic_segment_message
Provided another solution in error message when using omniauth callbacks under a dynamic segment
2015-06-24 19:41:28 +02:00
Andrey Novikov
4d8bec435d Provided another solution in error message when using omniauth callbacks under a dynamic segment
Previous solution was too complex and wasn't worked for everyone. See discussion at https://github.com/plataformatec/devise/pull/2227

Fixes #3651 [ci skip]
2015-06-24 20:39:25 +03:00
Jon Phenow
89dbbfd0fd CHANGELOG 2015-06-24 11:13:06 -05:00
Jon Phenow
0164f5862c translation for mailer subject 2015-06-24 11:01:46 -05:00
Jon Phenow
e966ba72b1 move model stubs 2015-06-24 10:50:54 -05:00
Jon Phenow
464edd5e5f quick comment touch-ups 2015-06-24 10:50:43 -05:00
Lucas Mazza
5ba8f36958 Merge pull request #3641 from camelmasa/fix-cve
Update rails gem for security
2015-06-23 11:21:48 -03:00
José Valim
e2041d02e8 Merge pull request #3648 from samdec11/master
Fix default email_regexp config to disallow trailing non-word characters
2015-06-22 16:05:34 +02:00
Sean Marzug-McCarthy
d49533bedc Fix default email_regexp config to disallow trailing non-word characters 2015-06-22 15:41:49 +02:00
José Valim
3dc15c03a7 Merge pull request #3644 from takiy33/patch-1
Remove rubyforge_project option
2015-06-21 11:19:59 +02:00
takiy33
954767d456 Remove rubyforge_project option
rubyforge_project option is deprecated.
2015-06-21 18:12:28 +09:00
Jon Phenow
6c993beb22 templates, config documentation 2015-06-19 14:22:54 -05:00
Jon Phenow
cc9a4e3edc functionality 2015-06-19 14:22:37 -05:00
Jon Phenow
0d59781ea8 tests 2015-06-19 14:21:10 -05:00
camelmasa
1aaf6345a4 Update rails gem for security
See. http://weblog.rubyonrails.org/2015/6/16/Rails-3-2-22-4-1-11-and-4-2-2-have-been-released-and-more/
2015-06-17 15:42:42 +09:00
Carlos Antonio da Silva
15b99977a2 Fix count of starting with rails resources
After 055f67e414. [ci skip]
2015-06-16 07:22:55 -03:00
José Valim
055f67e414 Update README.md
See discussion in #3607
2015-06-15 22:58:25 +02:00
Carlos Antonio da Silva
099aee5c5b Merge pull request #3630 from NAndreasson/fix/autoload-encryptor
Autoload Encryptor
2015-06-12 08:38:24 -03:00
Niklas Andréasson
65dc208ad7 Rm require 'devise/encryptor' in database_authenticable.rb 2015-06-12 13:18:34 +02:00
Niklas Andréasson
e3244b2c31 Autoload Encryptor 2015-06-12 10:36:45 +02:00
Carlos Antonio da Silva
aa49dd53b5 Merge pull request #3627 from vishaldeepak/master
Add codecademy authorization tutorial
2015-06-09 07:32:02 -03:00
VISHAL DEEPAK
916c0fc60b Add codecademy authorization tutorial
A really good , learn by doing, tutorial at codecademy
2015-06-09 15:51:45 +05:30
José Valim
4acb504324 Merge pull request #3616 from yui-knk/refactor/alias
Refactoring `expire_data_after_sign_out!`
2015-06-03 09:01:43 +02:00
yui-knk
3207c73d4b Refactoring expire_data_after_sign_out!
This method is same to `expire_data_after_sign_in!`,
so alias it
2015-06-03 13:14:18 +09:00
Carlos Antonio da Silva
2510c949e5 Merge pull request #3615 from Dbz/fixed_typo
fixed typo referring to routes.rb file
2015-06-02 23:03:51 -03:00
Danny Burt
29e257e8ba fixed typo referring to routes.rb file 2015-06-02 18:10:22 -07:00
José Valim
1a0192201b Merge pull request #3607 from rodrigoargumedo/patch-1
Add GoRails resource into README.md
2015-05-27 09:43:57 +02:00
Rodrigo Argumedo
8db50f4377 Add GoRails resource into README.md 2015-05-26 17:53:10 -06:00
José Valim
42c1ad3c78 Release v3.5.1 2015-05-26 15:10:29 +02:00
José Valim
e641b4b7b9 Also reset password token on email change 2015-05-26 15:09:07 +02:00
José Valim
fe49e625e8 Do not accept empty authentication_salt too 2015-05-26 15:04:27 +02:00
José Valim
31901bc862 Clear up reset password token whenever encrypted password changes 2015-05-26 15:00:12 +02:00
José Valim
b14995167b Do not mark _prefixes as protected 2015-05-26 09:53:38 +02:00
61 changed files with 665 additions and 387 deletions

View File

@@ -38,8 +38,7 @@ script: "bundle exec rake test"
notifications:
email: false
campfire:
slack:
on_success: change
on_failure: always
rooms:
- secure: "TRiqvuM4i/QmRDWjUSNitE5/P91BOzDkNl53+bZjjtxcISCswZtmECWBR7n9\n3xwqCOU1o2lfohxZ32OHOj/Nj7o+90zWJfWxcv+if0hIXRiil62M5pg0lZUd\nyJ4M5VQ0lSWo5he1OUrXhSabPJeaK3B8yT/tdh+qO5yzR+vb/jc="
secure: Q3M+kmude3FjisibEeeGe0wSMXgvwLH+vL7Zrx9//q4QtkfnrQ/BBMvY9KXxPEsNF+eys4YopYjTkJ8uRmeboUATW/oQ4Jrv3+u3zkIHK2sFn/Q2cQWpK5w+CbgEnHPjKYnUu34b09njXTgDlr/mqtbPqrKeZ1dLlpKXCB/q4GY=

View File

@@ -1,4 +1,39 @@
### 3.5.0 - 2015-05-23
### 3.5.4 - 2016-18-01
* bug fixes
* Store creation timestamps on remember cookies
### 3.5.3 - 2015-12-10
* bug fixes
* Fix password reset for records where `confirmation_required?` is disabled and
`confirmation_sent_at` is nil. (by @andygeers)
* Allow resources with no `email` field to be recoverable (and do not clear the
reset password token if the model was already persisted). (by @seddy, @stanhu)
* enhancements
* Upon setting `Devise.send_password_change_notification = true` a user will receive notification when their password has been changed.
### 3.5.2 - 2015-08-10
* enhancements
* Perform case insensitive basic authorization matching
* bug fixes
* Do not use digests for password confirmation token
* Fix infinite redirect in Rails 4.2 authenticated routes
* Autoload Devise::Encryptor to avoid errors on thread-safe mode
* deprecations
* `config.expire_auth_token_on_timeout` was removed
### 3.5.1 - 2015-05-24
Note: 3.5.0 has been yanked due to a regression
* security improvements
* Clean up reset password token whenever e-mail or password changes. thanks to George Deglin & Dennis Charles Hackethal for reporting this bug
* Ensure empty `authenticable_salt` cannot be used as remember token. This bug can only affect users who manually implement their own `authenticable_salt` and allow empty values as salt
* enhancements
* The hint about minimum password length required both `@validatable` and `@minimum_password_length` variables on the views, it now uses only the latter. If you have generated the views relying on the `@validatable` variable, replace it with `@minimum_password_length`.

22
CODE_OF_CONDUCT.md Normal file
View File

@@ -0,0 +1,22 @@
# Contributor Code of Conduct
As contributors and maintainers of this project, and in the interest of fostering an open and welcoming community, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities.
We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, religion, or nationality.
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery
* Personal attacks
* Trolling or insulting/derogatory comments
* Public or private harassment
* Publishing other's private information, such as physical or electronic addresses, without explicit permission
* Other unethical or unprofessional conduct.
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. By adopting this Code of Conduct, project maintainers commit themselves to fairly and consistently applying these principles to every aspect of managing this project. Project maintainers who do not follow or enforce the Code of Conduct may be permanently removed from the project team.
This code of conduct applies both within project spaces and in public spaces when an individual is representing the project or its community.
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by sending an email to [conduct@plataformatec.com.br](conduct@plataformatec.com.br) or contacting one or more of the project maintainers.
This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.2.0, available at [http://contributor-covenant.org/version/1/2/0/](http://contributor-covenant.org/version/1/2/0/)

View File

@@ -8,6 +8,8 @@
4) When reporting an issue, include Rails, Devise and Warden versions. If you are getting exceptions, please include the full backtrace.
5) Notice that all of your interactions in the project are expected to follow our [Code of Conduct](CODE_OF_CONDUCT.md)
That's it! The more information you give, the easier it becomes for us to track it down and fix it.
Ideally, you should provide an application that reproduces the error or a test case to Devise's suite.

View File

@@ -2,7 +2,7 @@ source "https://rubygems.org"
gemspec
gem "rails", "4.2.1"
gem "rails", "4.2.2"
gem "omniauth", "~> 1.2.0"
gem "omniauth-oauth2", "~> 1.1.0"
gem "rdoc"
@@ -25,5 +25,5 @@ platforms :ruby do
end
group :mongoid do
gem "mongoid", github: "mongoid/mongoid", branch: "master"
gem "mongoid", "~> 4.0"
end

View File

@@ -1,7 +1,7 @@
PATH
remote: .
specs:
devise (3.5.0)
devise (3.5.4)
bcrypt (~> 3.0)
orm_adapter (~> 0.1)
railties (>= 3.2.6, < 5)
@@ -9,50 +9,39 @@ PATH
thread_safe (~> 0.1)
warden (~> 1.2.3)
GIT
remote: git://github.com/mongoid/mongoid.git
revision: a4365d7ecfa8221bfcf36a4e7ce7993142fc5940
branch: master
specs:
mongoid (4.0.0)
activemodel (~> 4.0)
moped (~> 2.0.0)
origin (~> 2.1)
tzinfo (>= 0.3.37)
GEM
remote: https://rubygems.org/
specs:
actionmailer (4.2.1)
actionpack (= 4.2.1)
actionview (= 4.2.1)
activejob (= 4.2.1)
actionmailer (4.2.2)
actionpack (= 4.2.2)
actionview (= 4.2.2)
activejob (= 4.2.2)
mail (~> 2.5, >= 2.5.4)
rails-dom-testing (~> 1.0, >= 1.0.5)
actionpack (4.2.1)
actionview (= 4.2.1)
activesupport (= 4.2.1)
actionpack (4.2.2)
actionview (= 4.2.2)
activesupport (= 4.2.2)
rack (~> 1.6)
rack-test (~> 0.6.2)
rails-dom-testing (~> 1.0, >= 1.0.5)
rails-html-sanitizer (~> 1.0, >= 1.0.1)
actionview (4.2.1)
activesupport (= 4.2.1)
actionview (4.2.2)
activesupport (= 4.2.2)
builder (~> 3.1)
erubis (~> 2.7.0)
rails-dom-testing (~> 1.0, >= 1.0.5)
rails-html-sanitizer (~> 1.0, >= 1.0.1)
activejob (4.2.1)
activesupport (= 4.2.1)
activejob (4.2.2)
activesupport (= 4.2.2)
globalid (>= 0.3.0)
activemodel (4.2.1)
activesupport (= 4.2.1)
activemodel (4.2.2)
activesupport (= 4.2.2)
builder (~> 3.1)
activerecord (4.2.1)
activemodel (= 4.2.1)
activesupport (= 4.2.1)
activerecord (4.2.2)
activemodel (= 4.2.2)
activesupport (= 4.2.2)
arel (~> 6.0)
activesupport (4.2.1)
activesupport (4.2.2)
i18n (~> 0.7)
json (~> 1.7, >= 1.7.7)
minitest (~> 5.1)
@@ -60,34 +49,38 @@ GEM
tzinfo (~> 1.1)
arel (6.0.0)
bcrypt (3.1.10)
bson (2.3.0)
bson (3.1.2)
builder (3.2.2)
connection_pool (2.1.3)
connection_pool (2.2.0)
erubis (2.7.0)
faraday (0.9.1)
multipart-post (>= 1.2, < 3)
globalid (0.3.3)
globalid (0.3.5)
activesupport (>= 4.1.0)
hashie (3.4.0)
hike (1.2.3)
i18n (0.7.0)
json (1.8.2)
json (1.8.3)
jwt (1.4.1)
loofah (2.0.1)
loofah (2.0.2)
nokogiri (>= 1.5.9)
mail (2.6.3)
mime-types (>= 1.16, < 3)
metaclass (0.0.4)
mime-types (2.4.3)
mime-types (2.6.1)
mini_portile (0.6.2)
minitest (5.5.1)
minitest (5.7.0)
mocha (1.1.0)
metaclass (~> 0.0.1)
moped (2.0.4)
bson (~> 2.2)
mongoid (4.0.2)
activemodel (~> 4.0)
moped (~> 2.0.0)
origin (~> 2.1)
tzinfo (>= 0.3.37)
moped (2.0.6)
bson (~> 3.0)
connection_pool (~> 2.0)
optionable (~> 0.2.0)
multi_json (1.11.0)
multi_json (1.11.1)
multi_xml (0.5.5)
multipart-post (2.0.0)
nokogiri (1.6.6.2)
@@ -114,22 +107,22 @@ GEM
optionable (0.2.0)
origin (2.1.1)
orm_adapter (0.5.0)
rack (1.6.0)
rack (1.6.2)
rack-openid (1.3.1)
rack (>= 1.1.0)
ruby-openid (>= 2.1.8)
rack-test (0.6.3)
rack (>= 1.0)
rails (4.2.1)
actionmailer (= 4.2.1)
actionpack (= 4.2.1)
actionview (= 4.2.1)
activejob (= 4.2.1)
activemodel (= 4.2.1)
activerecord (= 4.2.1)
activesupport (= 4.2.1)
rails (4.2.2)
actionmailer (= 4.2.2)
actionpack (= 4.2.2)
actionview (= 4.2.2)
activejob (= 4.2.2)
activemodel (= 4.2.2)
activerecord (= 4.2.2)
activesupport (= 4.2.2)
bundler (>= 1.3.0, < 2.0)
railties (= 4.2.1)
railties (= 4.2.2)
sprockets-rails
rails-deprecated_sanitizer (1.0.3)
activesupport (>= 4.2.0.alpha)
@@ -139,32 +132,28 @@ GEM
rails-deprecated_sanitizer (>= 1.0.1)
rails-html-sanitizer (1.0.2)
loofah (~> 2.0)
railties (4.2.1)
actionpack (= 4.2.1)
activesupport (= 4.2.1)
railties (4.2.2)
actionpack (= 4.2.2)
activesupport (= 4.2.2)
rake (>= 0.8.7)
thor (>= 0.18.1, < 2.0)
rake (10.4.2)
rdoc (4.2.0)
responders (2.1.0)
railties (>= 4.2.0, < 5)
responders (2.1.1)
railties (>= 4.2.0, < 5.1)
ruby-openid (2.7.0)
sprockets (2.12.3)
hike (~> 1.2)
multi_json (~> 1.0)
sprockets (3.2.0)
rack (~> 1.0)
tilt (~> 1.1, != 1.3.0)
sprockets-rails (2.2.4)
sprockets-rails (2.3.1)
actionpack (>= 3.0)
activesupport (>= 3.0)
sprockets (>= 2.8, < 4.0)
sqlite3 (1.3.10)
thor (0.19.1)
thread_safe (0.3.5)
tilt (1.4.1)
tzinfo (1.2.2)
thread_safe (~> 0.1)
warden (1.2.3)
warden (1.2.4)
rack (>= 1.0)
webrat (0.7.3)
nokogiri (>= 1.2.0)
@@ -180,12 +169,15 @@ DEPENDENCIES
devise!
jruby-openssl
mocha (~> 1.1)
mongoid!
mongoid (~> 4.0)
omniauth (~> 1.2.0)
omniauth-facebook
omniauth-oauth2 (~> 1.1.0)
omniauth-openid (~> 1.0.1)
rails (= 4.2.1)
rails (= 4.2.2)
rdoc
sqlite3
webrat (= 0.7.3)
BUNDLED WITH
1.11.2

View File

@@ -82,10 +82,11 @@ You will usually want to write tests for your changes. To run the test suite, g
## Starting with Rails?
If you are building your first Rails application, we recommend you *do not* use Devise. Devise requires a good understanding of the Rails Framework. In such cases, we advise you to start a simple authentication system from scratch. Today we have two resources that should help you get started:
If you are building your first Rails application, we recommend you *do not* use Devise. Devise requires a good understanding of the Rails Framework. In such cases, we advise you to start a simple authentication system from scratch. Today, we have three resources that should help you get started:
* Michael Hartl's online book: https://www.railstutorial.org/book/modeling_users
* Ryan Bates' Railscast: http://railscasts.com/episodes/250-authentication-from-scratch
* Codecademy's Ruby on Rails: Authentication and Authorization: http://www.codecademy.com/en/learn/rails-auth
Once you have solidified your understanding of Rails and authentication mechanisms, we assure you Devise will be very pleasant to work with. :smiley:
@@ -185,7 +186,7 @@ Besides `:stretches`, you can define `:pepper`, `:encryptor`, `:confirm_within`,
When you customize your own views, you may end up adding new attributes to forms. Rails 4 moved the parameter sanitization from the model to the controller, causing Devise to handle this concern at the controller as well.
There are just three actions in Devise that allows any set of parameters to be passed down to the model, therefore requiring sanitization. Their names and the permitted parameters by default are:
There are just three actions in Devise that allow any set of parameters to be passed down to the model, therefore requiring sanitization. Their names and the permitted parameters by default are:
* `sign_in` (`Devise::SessionsController#create`) - Permits only the authentication keys (like `email`)
* `sign_up` (`Devise::RegistrationsController#create`) - Permits authentication keys plus `password` and `password_confirmation`
@@ -348,7 +349,7 @@ devise_for :users, path: "auth", path_names: { sign_in: 'login', sign_out: 'logo
Be sure to check `devise_for` documentation for details.
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 to create your routes normally and wrap them in a `devise_scope` block in the router:
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:
```ruby
devise_scope :user do

View File

@@ -38,19 +38,19 @@ class Devise::PasswordsController < DeviseController
flash_message = resource.active_for_authentication? ? :updated : :updated_not_active
set_flash_message(:notice, flash_message) if is_flashing_format?
sign_in(resource_name, resource)
respond_with resource, location: after_resetting_password_path_for(resource)
else
set_flash_message(:notice, :updated_not_active) if is_flashing_format?
respond_with resource, location: new_session_path(resource_name)
end
respond_with resource, location: after_resetting_password_path_for(resource)
else
set_minimum_password_length
respond_with resource
end
end
protected
def after_resetting_password_path_for(resource)
after_sign_in_path_for(resource)
Devise.sign_in_after_reset_password ? after_sign_in_path_for(resource) : new_session_path(resource_name)
end
# The path used after sending reset password instructions

View File

@@ -11,6 +11,21 @@ class DeviseController < Devise.parent_controller.constantize
prepend_before_filter :assert_is_devise_resource!
respond_to :html if mimes_for_respond_to.empty?
# Override prefixes to consider the scoped view.
# Notice we need to check for the request due to a bug in
# Action Controller tests that forces _prefixes to be
# loaded before even having a request object.
#
# This method should be public as it is is in ActionPack
# itself. Changing its visibility may break other gems.
def _prefixes #:nodoc:
@_prefixes ||= if self.class.scoped_views? && request && devise_mapping
["#{devise_mapping.scoped_path}/#{controller_name}"] + super
else
super
end
end
protected
# Gets the actual resource stored in the instance variable
@@ -39,20 +54,6 @@ class DeviseController < Devise.parent_controller.constantize
@devise_mapping ||= request.env["devise.mapping"]
end
# Override prefixes to consider the scoped view.
# Notice we need to check for the request due to a bug in
# Action Controller tests that forces _prefixes to be
# loaded before even having a request object.
def _prefixes #:nodoc:
@_prefixes ||= if self.class.scoped_views? && request && devise_mapping
["#{devise_mapping.scoped_path}/#{controller_name}"] + super
else
super
end
end
# Checks whether it's a devise mapped resource or not.
def assert_is_devise_resource! #:nodoc:
unknown_action! <<-MESSAGE unless devise_mapping

View File

@@ -16,5 +16,9 @@ if defined?(ActionMailer)
@token = token
devise_mail(record, :unlock_instructions, opts)
end
def password_change(record, opts={})
devise_mail(record, :password_change, opts)
end
end
end

View File

@@ -0,0 +1,3 @@
<p>Hello <%= @resource.email %>!</p>
<p>We're contacting you to notify you that your password has been changed.</p>

View File

@@ -7,8 +7,8 @@
<div class="field">
<%= f.label :password, "New password" %><br />
<% if @minimum_password_length %>
<em>(<%= @minimum_password_length %> characters minimum)</em>
<% end %><br />
<em>(<%= @minimum_password_length %> characters minimum)</em><br />
<% end %>
<%= f.password_field :password, autofocus: true, autocomplete: "off" %>
</div>

View File

@@ -20,6 +20,6 @@
<%- if devise_mapping.omniauthable? %>
<%- resource_class.omniauth_providers.each do |provider| %>
<%= link_to "Sign in with #{provider.to_s.titleize}", omniauth_authorize_path(resource_name, provider) %><br />
<%= link_to "Sign in with #{OmniAuth::Utils.camelize(provider)}", omniauth_authorize_path(resource_name, provider) %><br />
<% end -%>
<% end -%>

View File

@@ -23,6 +23,8 @@ en:
subject: "Reset password instructions"
unlock_instructions:
subject: "Unlock instructions"
password_change:
subject: "Password Changed"
omniauth_callbacks:
failure: "Could not authenticate you from %{kind} because \"%{reason}\"."
success: "Successfully authenticated from %{kind} account."

View File

@@ -13,8 +13,6 @@ Gem::Specification.new do |s|
s.description = "Flexible authentication solution for Rails with Warden"
s.authors = ['José Valim', 'Carlos Antônio']
s.rubyforge_project = "devise"
s.files = `git ls-files`.split("\n")
s.test_files = `git ls-files -- test/*`.split("\n")
s.require_paths = ["lib"]

View File

@@ -49,7 +49,7 @@ GIT
PATH
remote: ..
specs:
devise (3.4.1)
devise (3.5.3)
bcrypt (~> 3.0)
orm_adapter (~> 0.1)
railties (>= 3.2.6, < 5)
@@ -142,7 +142,7 @@ GEM
polyglot
polyglot (>= 0.3.1)
tzinfo (0.3.43)
warden (1.2.3)
warden (1.2.4)
rack (>= 1.0)
webrat (0.7.3)
nokogiri (>= 1.2.0)
@@ -167,3 +167,6 @@ DEPENDENCIES
rdoc
sqlite3
webrat (= 0.7.3)
BUNDLED WITH
1.10.6

View File

@@ -43,7 +43,7 @@ GIT
PATH
remote: ..
specs:
devise (3.4.1)
devise (3.5.3)
bcrypt (~> 3.0)
orm_adapter (~> 0.1)
railties (>= 3.2.6, < 5)
@@ -136,7 +136,7 @@ GEM
thread_safe (0.3.5)
tilt (1.4.1)
tzinfo (0.3.43)
warden (1.2.3)
warden (1.2.4)
rack (>= 1.0)
webrat (0.7.3)
nokogiri (>= 1.2.0)
@@ -161,3 +161,6 @@ DEPENDENCIES
rdoc
sqlite3
webrat (= 0.7.3)
BUNDLED WITH
1.10.6

View File

@@ -48,7 +48,7 @@ GIT
PATH
remote: ..
specs:
devise (3.4.1)
devise (3.5.3)
bcrypt (~> 3.0)
orm_adapter (~> 0.1)
railties (>= 3.2.6, < 5)
@@ -142,7 +142,7 @@ GEM
tilt (1.4.1)
tzinfo (1.2.2)
thread_safe (~> 0.1)
warden (1.2.3)
warden (1.2.4)
rack (>= 1.0)
webrat (0.7.3)
nokogiri (>= 1.2.0)
@@ -167,3 +167,6 @@ DEPENDENCIES
rdoc
sqlite3
webrat (= 0.7.3)
BUNDLED WITH
1.10.6

View File

@@ -58,7 +58,7 @@ GIT
PATH
remote: ..
specs:
devise (3.4.1)
devise (3.5.3)
bcrypt (~> 3.0)
orm_adapter (~> 0.1)
railties (>= 3.2.6, < 5)
@@ -164,7 +164,7 @@ GEM
tilt (1.4.1)
tzinfo (1.2.2)
thread_safe (~> 0.1)
warden (1.2.3)
warden (1.2.4)
rack (>= 1.0)
webrat (0.7.3)
nokogiri (>= 1.2.0)
@@ -189,3 +189,6 @@ DEPENDENCIES
rdoc
sqlite3
webrat (= 0.7.3)
BUNDLED WITH
1.10.6

View File

@@ -8,6 +8,7 @@ require 'responders'
module Devise
autoload :Delegator, 'devise/delegator'
autoload :Encryptor, 'devise/encryptor'
autoload :FailureApp, 'devise/failure_app'
autoload :OmniAuth, 'devise/omniauth'
autoload :ParameterFilter, 'devise/parameter_filter'
@@ -105,7 +106,7 @@ module Devise
# an one (and only one) @ exists in the given string. This is mainly
# to give user feedback and not to assert the e-mail validity.
mattr_accessor :email_regexp
@@email_regexp = /\A[^@\s]+@([^@\s]+\.)+[^@\s]+\z/
@@email_regexp = /\A[^@\s]+@([^@\s]+\.)+[^@\W]+\z/
# Range validation for password length
mattr_accessor :password_length
@@ -115,6 +116,7 @@ module Devise
mattr_accessor :remember_for
@@remember_for = 2.weeks
# TODO: extend_remember_period is no longer used
# If true, extends the user's remember period when remembered via cookie.
mattr_accessor :extend_remember_period
@@extend_remember_period = false
@@ -145,14 +147,14 @@ module Devise
mattr_accessor :timeout_in
@@timeout_in = 30.minutes
# Authentication token expiration on timeout
mattr_accessor :expire_auth_token_on_timeout
@@expire_auth_token_on_timeout = false
# Used to encrypt password. Please generate one with rake secret.
mattr_accessor :pepper
@@pepper = nil
# Used to enable sending notification to user when their password is changed
mattr_accessor :send_password_change_notification
@@send_password_change_notification = false
# Scoped views. Since it relies on fallbacks to render default views, it's
# turned off by default.
mattr_accessor :scoped_views
@@ -328,7 +330,12 @@ module Devise
mapping
end
# Make Devise aware of an 3rd party Devise-module (like invitable). For convenience.
# Register available devise modules. For the standard modules that Devise provides, this method is
# called from lib/devise/modules.rb. Third-party modules need to be added explicitly using this method.
#
# Note that adding a module using this method does not cause it to be used in the authentication
# process. That requires that the module be listed in the arguments passed to the 'devise' method
# in the model class definition.
#
# == Options:
#
@@ -436,8 +443,8 @@ module Devise
Devise::Controllers::UrlHelpers.generate_helpers!
end
# A method used internally to setup warden manager from the Rails initialize
# block.
# A method used internally to complete the setup of warden manager after routes are loaded.
# See lib/devise/rails/routes.rb - ActionDispatch::Routing::RouteSet#finalize_with_devise!
def self.configure_warden! #:nodoc:
@@warden_configured ||= begin
warden_config.failure_app = Devise::Delegator.new

View File

@@ -7,7 +7,9 @@ module Devise
include Devise::Controllers::StoreLocation
included do
helper_method :warden, :signed_in?, :devise_controller?
if respond_to?(:helper_method)
helper_method :warden, :signed_in?, :devise_controller?
end
end
module ClassMethods
@@ -69,7 +71,9 @@ module Devise
end.compact
end
helper_method "current_#{group_name}", "current_#{group_name.to_s.pluralize}", "#{group_name}_signed_in?"
if respond_to?(:helper_method)
helper_method "current_#{group_name}", "current_#{group_name.to_s.pluralize}", "#{group_name}_signed_in?"
end
METHODS
end
@@ -126,7 +130,9 @@ module Devise
METHODS
ActiveSupport.on_load(:action_controller) do
helper_method "current_#{mapping}", "#{mapping}_signed_in?", "#{mapping}_session"
if respond_to?(:helper_method)
helper_method "current_#{mapping}", "#{mapping}_signed_in?", "#{mapping}_session"
end
end
end
@@ -190,10 +196,10 @@ module Devise
# root path. For a user scope, you can define the default url in
# the following way:
#
# map.user_root '/users', controller: 'users' # creates user_root_path
# get '/users' => 'users#index', as: :user_root # creates user_root_path
#
# map.namespace :user do |user|
# user.root controller: 'users' # creates user_root_path
# namespace :user do
# root 'users#index' # creates user_root_path
# end
#
# If the resource root path is not defined, root_path is used. However,

View File

@@ -13,7 +13,7 @@ module Devise
def remember_me(resource)
return if env["devise.skip_storage"]
scope = Devise::Mapping.find_scope!(resource)
resource.remember_me!(resource.extend_remember_period)
resource.remember_me!
cookies.signed[remember_key(resource, scope)] = remember_cookie_values(resource)
end

View File

@@ -90,13 +90,7 @@ module Devise
session.keys.grep(/^devise\./).each { |k| session.delete(k) }
end
def expire_data_after_sign_out!
# session.keys will return an empty array if the session is not yet loaded.
# This is a bug in both Rack and Rails.
# A call to #empty? forces the session to be loaded.
session.empty?
session.keys.grep(/^devise\./).each { |k| session.delete(k) }
end
alias :expire_data_after_sign_out! :expire_data_after_sign_in!
end
end
end

View File

@@ -22,9 +22,12 @@ module Devise
@respond.call(env)
end
# Try retrieving the URL options from the parent controller (usually
# ApplicationController). Instance methods are not supported at the moment,
# so only the class-level attribute is used.
def self.default_url_options(*args)
if defined?(ApplicationController)
ApplicationController.default_url_options(*args)
if defined?(Devise.parent_controller.constantize)
Devise.parent_controller.constantize.try(:default_url_options) || {}
else
{}
end
@@ -48,7 +51,18 @@ module Devise
end
def recall
env["PATH_INFO"] = attempted_path
config = Rails.application.config
if config.try(:relative_url_root)
base_path = Pathname.new(config.relative_url_root)
full_path = Pathname.new(attempted_path)
env["SCRIPT_NAME"] = config.relative_url_root
env["PATH_INFO"] = '/' + full_path.relative_path_from(base_path).to_s
else
env["PATH_INFO"] = attempted_path
end
flash.now[:alert] = i18n_message(:invalid) if is_flashing_format?
self.response = recall_app(warden_options[:recall]).call(env)
end
@@ -118,8 +132,13 @@ module Devise
config = Rails.application.config
if config.respond_to?(:relative_url_root) && config.relative_url_root.present?
opts[:script_name] = config.relative_url_root
# Rails 4.2 goes into an infinite loop if opts[:script_name] is unset
if (Rails::VERSION::MAJOR >= 4) && (Rails::VERSION::MINOR >= 2)
opts[:script_name] = (config.relative_url_root if config.respond_to?(:relative_url_root))
else
if config.respond_to?(:relative_url_root) && config.relative_url_root.present?
opts[:script_name] = config.relative_url_root
end
end
router_name = Devise.mappings[scope].router_name || Devise.available_router_name

View File

@@ -7,7 +7,8 @@ Warden::Manager.after_set_user do |record, warden, options|
scope = options[:scope]
env = warden.request.env
if record && record.respond_to?(:timedout?) && warden.authenticated?(scope) && options[:store] != false
if record && record.respond_to?(:timedout?) && warden.authenticated?(scope) &&
options[:store] != false && !env['devise.skip_timeoutable']
last_request_at = warden.session(scope)['last_request_at']
if last_request_at.is_a? Integer
@@ -21,10 +22,6 @@ Warden::Manager.after_set_user do |record, warden, options|
if record.timedout?(last_request_at) && !env['devise.skip_timeout']
Devise.sign_out_all_scopes ? proxy.sign_out : proxy.sign_out(scope)
if record.respond_to?(:expire_auth_token_on_timeout) && record.expire_auth_token_on_timeout
record.reset_authentication_token!
end
throw :warden, scope: scope, message: :timeout
end

View File

@@ -12,7 +12,7 @@ module Devise
# Creates configuration values for Devise and for the given module.
#
# Devise::Models.config(Devise::Authenticatable, :stretches, 10)
# Devise::Models.config(Devise::DatabaseAuthenticatable, :stretches)
#
# The line above creates:
#

View File

@@ -7,7 +7,7 @@ module Devise
#
# Confirmable tracks the following columns:
#
# * confirmation_token - An OpenSSL::HMAC.hexdigest of @raw_confirmation_token
# * confirmation_token - A unique random token
# * confirmed_at - A timestamp when the user clicked the confirmation link
# * confirmation_sent_at - A timestamp when the confirmation_token was generated (not sent)
# * unconfirmed_email - An email address copied from the email attr. After confirmation
@@ -24,11 +24,13 @@ module Devise
# By default allow_unconfirmed_access_for is zero, it means users always have to confirm to sign in.
# * +reconfirmable+: requires any email changes to be confirmed (exactly the same way as
# initial account confirmation) to be applied. Requires additional unconfirmed_email
# db field to be setup (t.reconfirmable in migrations). Until confirmed new email is
# db field to be setup (t.reconfirmable in migrations). Until confirmed, new email is
# stored in unconfirmed email column, and copied to email column on successful
# confirmation.
# * +confirm_within+: the time before a sent confirmation token becomes invalid.
# You can use this to force the user to confirm within a set period of time.
# Confirmable will not generate a new token if a repeat confirmation is requested
# during this time frame, unless the user's email changed too.
#
# == Examples
#
@@ -214,7 +216,7 @@ module Devise
# confirmation_period_expired? # will always return false
#
def confirmation_period_expired?
self.class.confirm_within && (Time.now > self.confirmation_sent_at + self.class.confirm_within)
self.class.confirm_within && self.confirmation_sent_at && (Time.now > self.confirmation_sent_at + self.class.confirm_within)
end
# Checks whether the record requires any confirmation.
@@ -230,10 +232,13 @@ module Devise
# Generates a new random token for confirmation, and stores
# the time this token is being generated in confirmation_sent_at
def generate_confirmation_token
raw, enc = Devise.token_generator.generate(self.class, :confirmation_token)
@raw_confirmation_token = raw
self.confirmation_token = enc
self.confirmation_sent_at = Time.now.utc
if self.confirmation_token && !confirmation_period_expired?
@raw_confirmation_token = self.confirmation_token
else
raw, _ = Devise.token_generator.generate(self.class, :confirmation_token)
self.confirmation_token = @raw_confirmation_token = raw
self.confirmation_sent_at = Time.now.utc
end
end
def generate_confirmation_token!
@@ -244,11 +249,12 @@ module Devise
@reconfirmation_required = true
self.unconfirmed_email = self.email
self.email = self.email_was
self.confirmation_token = nil
generate_confirmation_token
end
def postpone_email_change?
postpone = self.class.reconfirmable && email_changed? && !@bypass_confirmation_postpone && self.email.present?
postpone = self.class.reconfirmable && email_changed? && email_was.present? && !@bypass_confirmation_postpone && self.email.present?
@bypass_confirmation_postpone = false
postpone
end
@@ -293,12 +299,17 @@ module Devise
# If the user is already confirmed, create an error for the user
# Options must have the confirmation_token
def confirm_by_token(confirmation_token)
original_token = confirmation_token
confirmation_token = Devise.token_generator.digest(self, :confirmation_token, confirmation_token)
confirmable = find_first_by_auth_conditions(confirmation_token: confirmation_token)
unless confirmable
confirmation_digest = Devise.token_generator.digest(self, :confirmation_token, confirmation_token)
confirmable = find_or_initialize_with_error_by(:confirmation_token, confirmation_digest)
end
# TODO: replace above lines with
# confirmable = find_or_initialize_with_error_by(:confirmation_token, confirmation_token)
# after enough time has passed that Devise clients do not use digested tokens
confirmable = find_or_initialize_with_error_by(:confirmation_token, confirmation_token)
confirmable.confirm if confirmable.persisted?
confirmable.confirmation_token = original_token
confirmable
end

View File

@@ -1,5 +1,4 @@
require 'devise/strategies/database_authenticatable'
require 'devise/encryptor'
module Devise
def self.bcrypt(klass, password)
@@ -13,7 +12,7 @@ module Devise
#
# == Options
#
# DatabaseAuthenticable adds the following options to devise_for:
# DatabaseAuthenticatable adds the following options to devise_for:
#
# * +pepper+: a random string used to provide a more secure hash. Use
# `rake secret` to generate new keys.
@@ -28,6 +27,8 @@ module Devise
extend ActiveSupport::Concern
included do
after_update :send_password_change_notification, if: :send_password_change_notification?
attr_reader :password, :current_password
attr_accessor :password_confirmation
end
@@ -134,6 +135,10 @@ module Devise
encrypted_password[0,29] if encrypted_password
end
def send_password_change_notification
send_devise_notification(:password_change)
end
protected
# Digests the password using bcrypt. Custom encryption should override
@@ -145,8 +150,12 @@ module Devise
Devise::Encryptor.digest(self.class, password)
end
def send_password_change_notification?
self.class.send_password_change_notification && encrypted_password_changed?
end
module ClassMethods
Devise::Models.config(self, :pepper, :stretches)
Devise::Models.config(self, :pepper, :stretches, :send_password_change_notification)
# We assume this method already gets the sanitized values from the
# DatabaseAuthenticatable strategy. If you are using this method on

View File

@@ -16,10 +16,6 @@ module Devise
# # resets the user password and save the record, true if valid passwords are given, otherwise false
# User.find(1).reset_password('password123', 'password123')
#
# # only resets the user password, without saving the record
# user = User.find(1)
# user.reset_password('password123', 'password123')
#
# # creates a new token and send it with instructions about how to reset the password
# User.find(1).send_reset_password_instructions
#
@@ -30,14 +26,22 @@ module Devise
[:reset_password_sent_at, :reset_password_token]
end
included do
before_update do
if (respond_to?(:email_changed?) && email_changed?) || encrypted_password_changed?
clear_reset_password_token
end
end
end
# Update password saving the record and clearing token. Returns true if
# the passwords are valid and the record was saved, false otherwise.
def reset_password(new_password, new_password_confirmation)
self.password = new_password
self.password_confirmation = new_password_confirmation
if valid?
clear_reset_password_token
if respond_to?(:after_password_reset) && valid?
ActiveSupport::Deprecation.warn "after_password_reset is deprecated"
after_password_reset
end
@@ -79,7 +83,7 @@ module Devise
# reset_password_period_valid? # will always return false
#
def reset_password_period_valid?
reset_password_sent_at && reset_password_sent_at.utc >= self.class.reset_password_within.ago
reset_password_sent_at && reset_password_sent_at.utc >= self.class.reset_password_within.ago.utc
end
protected
@@ -90,19 +94,6 @@ module Devise
self.reset_password_sent_at = nil
end
# A callback initiated after password is successfully reset. This can
# be used to insert your own logic that is only run after the user
# successfully resets their password.
#
# Example:
#
# def after_password_reset
# self.update_attribute(:invite_code, nil)
# end
#
def after_password_reset
end
def set_reset_password_token
raw, enc = Devise.token_generator.generate(self.class, :reset_password_token)

View File

@@ -45,11 +45,11 @@ module Devise
[:remember_created_at]
end
# Generate a new remember token and save the record without validations
# if remember expired (token is no longer valid) or extend_remember_period is true
def remember_me!(extend_period=false)
self.remember_token = self.class.remember_token if generate_remember_token?
self.remember_created_at = Time.now.utc if generate_remember_timestamp?(extend_period)
# TODO: We were used to receive a extend period argument but we no longer do.
# Remove this for Devise 4.0.
def remember_me!(*)
self.remember_token = self.class.remember_token if respond_to?(:remember_token)
self.remember_created_at ||= Time.now.utc
save(validate: false) if self.changed?
end
@@ -57,25 +57,19 @@ module Devise
# it exists), and save the record without validations.
def forget_me!
return unless persisted?
self.remember_token = nil if respond_to?(:remember_token=)
self.remember_token = nil if respond_to?(:remember_token)
self.remember_created_at = nil if self.class.expire_all_remember_me_on_sign_out
save(validate: false)
end
# Remember token should be expired if expiration time not overpass now.
def remember_expired?
remember_created_at.nil? || (remember_expires_at <= Time.now.utc)
end
# Remember token expires at created time + remember_for configuration
def remember_expires_at
remember_created_at + self.class.remember_for
self.class.remember_for.from_now
end
def rememberable_value
if respond_to?(:remember_token)
remember_token
elsif respond_to?(:authenticatable_salt) && (salt = authenticatable_salt)
elsif respond_to?(:authenticatable_salt) && (salt = authenticatable_salt.presence)
salt
else
raise "authenticable_salt returned nil for the #{self.class.name} model. " \
@@ -104,27 +98,30 @@ module Devise
protected
def generate_remember_token? #:nodoc:
respond_to?(:remember_token) && remember_expired?
end
# Generate a timestamp if extend_remember_period is true, if no remember_token
# exists, or if an existing remember token has expired.
def generate_remember_timestamp?(extend_period) #:nodoc:
extend_period || remember_expired?
end
module ClassMethods
# Create the cookie key using the record id and remember_token
def serialize_into_cookie(record)
[record.to_key, record.rememberable_value]
[record.to_key, record.rememberable_value, Time.now.utc]
end
# Recreate the user based on the stored cookie
def serialize_from_cookie(id, remember_token)
record = to_adapter.get(id)
record if record && !record.remember_expired? &&
Devise.secure_compare(record.rememberable_value, remember_token)
def serialize_from_cookie(*args)
id, token, generated_at = args
# The token is only valid if:
# 1. we have a date
# 2. the current time does not pass the expiry period
# 3. there is a record with the given id
# 4. the record has a remember_created_at date
# 5. the token date is bigger than the remember_created_at
# 6. the token matches
if generated_at &&
(self.remember_for.ago < generated_at) &&
(record = to_adapter.get(id)) &&
(generated_at > (record.remember_created_at || Time.now).utc) &&
Devise.secure_compare(record.rememberable_value, token)
record
end
end
# Generate a token checking if one does not already exist in the database.
@@ -135,6 +132,7 @@ module Devise
end
end
# TODO: extend_remember_period is no longer used
Devise::Models.config(self, :remember_for, :extend_remember_period, :rememberable_options, :expire_all_remember_me_on_sign_out)
end
end

View File

@@ -26,7 +26,6 @@ module Devise
# Checks whether the user session has expired based on configured time.
def timedout?(last_access)
return false if remember_exists_and_not_expired?
!timeout_in.nil? && last_access && last_access <= timeout_in.ago
end
@@ -36,11 +35,6 @@ module Devise
private
def remember_exists_and_not_expired?
return false unless respond_to?(:remember_created_at) && respond_to?(:remember_expired?)
remember_created_at && !remember_expired?
end
module ClassMethods
Devise::Models.config(self, :timeout_in)
end

View File

@@ -94,10 +94,24 @@ module ActionDispatch::Routing
#
# devise_for :users, path: 'accounts'
#
# * singular: setup the singular name for the given resource. This is used as the instance variable
# name in controller, as the name in routes and the scope given to warden.
# * singular: setup the singular name for the given resource. This is used as the helper methods
# names in controller ("authenticate_#{singular}!", "#{singular}_signed_in?", "current_#{singular}"
# and "#{singular}_session"), as the scope name in routes and as the scope given to warden.
#
# devise_for :users, singular: :user
# devise_for :admins, singular: :manager
#
# devise_scope :manager do
# ...
# end
#
# class ManagerController < ApplicationController
# before_filter authenticate_manager!
#
# def show
# @manager = current_manager
# ...
# end
# end
#
# * path_names: configure different path names to overwrite defaults :sign_in, :sign_out, :sign_up,
# :password, :confirmation, :unlock.
@@ -404,19 +418,14 @@ module ActionDispatch::Routing
raise <<-ERROR
Devise does not support scoping OmniAuth callbacks under a dynamic segment
and you have set #{mapping.fullpath.inspect}. You can work around by passing
`skip: :omniauth_callbacks` and manually defining the routes. Here is an example:
`skip: :omniauth_callbacks` to the `devise_for` call and extract omniauth
options to another `devise_for` call outside the scope. Here is an example:
match "/users/auth/:provider",
constraints: { provider: /google|facebook/ },
to: "devise/omniauth_callbacks#passthru",
as: :omniauth_authorize,
via: [:get, :post]
devise_for :users, only: :omniauth_callbacks, controllers: {omniauth_callbacks: 'users/omniauth_callbacks'}
match "/users/auth/:action/callback",
constraints: { action: /google|facebook/ },
to: "devise/omniauth_callbacks#:action",
as: :omniauth_callback,
via: [:get, :post]
scope '/(:locale)', locale: /ru|en/ do
devise_for :users, skip: :omniauth_callbacks
end
ERROR
end

View File

@@ -27,7 +27,7 @@ module Devise
# Receives a resource and check if it is valid by calling valid_for_authentication?
# An optional block that will be triggered while validating can be optionally
# given as parameter. Check Devise::Models::Authenticable.valid_for_authentication?
# given as parameter. Check Devise::Models::Authenticatable.valid_for_authentication?
# for more information.
#
# In case the resource can't be validated, it will fail with the given
@@ -118,7 +118,7 @@ module Devise
# Helper to decode credentials from HTTP.
def decode_credentials
return [] unless request.authorization && request.authorization =~ /^Basic (.*)/m
return [] unless request.authorization && request.authorization =~ /^Basic (.*)/mi
Base64.decode64($1).split(/:/, 2)
end

View File

@@ -1,3 +1,3 @@
module Devise
VERSION = "3.5.0".freeze
VERSION = "3.5.4".freeze
end

View File

@@ -47,7 +47,7 @@ module Devise
def view_directory(name, _target_path = nil)
directory name.to_s, _target_path || "#{target_path}/#{name}" do |content|
if scope
content.gsub "devise/shared/links", "#{scope}/shared/links"
content.gsub "devise/shared/links", "#{plural_scope}/shared/links"
else
content
end
@@ -55,7 +55,11 @@ module Devise
end
def target_path
@target_path ||= "app/views/#{scope || :devise}"
@target_path ||= "app/views/#{plural_scope || :devise}"
end
def plural_scope
@plural_scope ||= scope.presence && scope.underscore.pluralize
end
end
@@ -83,6 +87,13 @@ module Devise
source_root File.expand_path("../../templates/simple_form_for", __FILE__)
desc "Copies simple form enabled views to your application."
hide!
def copy_views
if options[:views]
options[:views].delete('mailer')
end
super
end
end
class ErbGenerator < Rails::Generators::Base #:nodoc:
@@ -111,7 +122,7 @@ module Devise
end
def target_path
"app/views/#{scope || :devise}/mailer"
"app/views/#{plural_scope || :devise}/mailer"
end
end

View File

@@ -2,7 +2,7 @@
Some setup you must do manually if you haven't yet:
Ensure you have overridden routes for generated controllers in your route.rb.
Ensure you have overridden routes for generated controllers in your routes.rb.
For example:
Rails.application.routes.draw do

View File

@@ -105,6 +105,9 @@ Devise.setup do |config|
# Setup a pepper to generate the encrypted password.
# config.pepper = '<%= SecureRandom.hex(64) %>'
# Send a notification email when the user's password is changed
# config.send_password_change_notification = false
# ==> Configuration for :confirmable
# A period that the user is allowed to access the website even without
# confirming their account. For instance, if set to 2.days, the user will be
@@ -158,9 +161,6 @@ Devise.setup do |config|
# time the user will be asked for credentials again. Default is 30 minutes.
# config.timeout_in = 30.minutes
# If true, expires auth token on session timeout.
# config.expire_auth_token_on_timeout = false
# ==> Configuration for :lockable
# Defines which strategy will be used to lock an account.
# :failed_attempts = Locks an account after a number of failed attempts to sign in.

View File

@@ -2,4 +2,4 @@ Welcome <%= @email %>!
You can confirm your account through the link below:
<%= link_to 'Confirm my account', confirmation_url(@resource, confirmation_token: @token) %>
[Confirm my account](<%= confirmation_url(@resource, confirmation_token: @token) %>)

View File

@@ -0,0 +1,3 @@
<p>Hello <%= @resource.email %>!</p>
<p>We're contacting you to notify you that your password has been changed.</p>

View File

@@ -2,7 +2,7 @@ Hello <%= @resource.email %>!
Someone has requested a link to change your password, and you can do this through the link below.
<%= link_to 'Change my password', edit_password_url(@resource, reset_password_token: @token) %>
[Change my password](<%= edit_password_url(@resource, reset_password_token: @token) %>)
If you didn't request this, please ignore this email.
Your password won't change until you access the link above and create a new one.

View File

@@ -4,4 +4,4 @@ Your account has been locked due to an excessive number of unsuccessful sign in
Click the link below to unlock your account:
<%= link_to 'Unlock my account', unlock_url(@resource, unlock_token: @token) %>
[Unlock my account](<%= unlock_url(@resource, unlock_token: @token) %>)

View File

@@ -0,0 +1,21 @@
require 'test_helper'
class ApiController < ActionController::Metal
include Devise::Controllers::Helpers
end
class HelperMethodsTest < ActionController::TestCase
tests ApiController
test 'includes Devise::Controllers::Helpers' do
assert_includes @controller.class.ancestors, Devise::Controllers::Helpers
end
test 'does not respond_to helper_method' do
refute_respond_to @controller.class, :helper_method
end
test 'defines methods like current_user' do
assert_respond_to @controller, :current_user
end
end

View File

@@ -95,7 +95,7 @@ class DeviseTest < ActiveSupport::TestCase
test 'Devise.email_regexp should match valid email addresses' do
valid_emails = ["test@example.com", "jo@jo.co", "f4$_m@you.com", "testing.example@example.com.ua"]
non_valid_emails = ["rex", "test@go,com", "test user@example.com", "test_user@example server.com"]
non_valid_emails = ["rex", "test@go,com", "test user@example.com", "test_user@example server.com", "test_user@example.com."]
valid_emails.each do |email|
assert_match Devise.email_regexp, email

View File

@@ -294,5 +294,22 @@ class FailureTest < ActiveSupport::TestCase
assert @response.third.body.include?('<h2>Log in</h2>')
assert @response.third.body.include?('Your account is not activated yet.')
end
if Rails.application.config.respond_to?(:relative_url_root)
test 'calls the original controller with the proper environment considering the relative url root' do
swap Rails.application.config, relative_url_root: "/sample" do
env = {
"warden.options" => { recall: "devise/sessions#new", attempted_path: "/sample/users/sign_in"},
"devise.mapping" => Devise.mappings[:user],
"warden" => stub_everything
}
call_failure(env)
assert @response.third.body.include?('<h2>Log in</h2>')
assert @response.third.body.include?('Invalid email or password.')
assert_equal @request.env["SCRIPT_NAME"], '/sample'
assert_equal @request.env["PATH_INFO"], '/users/sign_in'
end
end
end
end
end

View File

@@ -46,6 +46,13 @@ class ViewsGeneratorTest < Rails::Generators::TestCase
assert_no_file "app/views/devise/mailer/confirmation_instructions.html.erb"
end
test "Assert mailer specific directory with simple form" do
run_generator %w(-v mailer -b simple_form_for)
assert_file "app/views/devise/mailer/confirmation_instructions.html.erb"
assert_file "app/views/devise/mailer/reset_password_instructions.html.erb"
assert_file "app/views/devise/mailer/unlock_instructions.html.erb"
end
test "Assert specified directories with scope" do
run_generator %w(users -v sessions)
assert_file "app/views/users/sessions/new.html.erb"

View File

@@ -20,9 +20,11 @@ class OmniauthableIntegrationTest < ActionDispatch::IntegrationTest
"credentials" => {"token" => 'plataformatec'},
"extra" => {"user_hash" => FACEBOOK_INFO}
}
OmniAuth.config.add_camelization 'facebook', 'FaceBook'
end
teardown do
OmniAuth.config.camelizations.delete('facebook')
OmniAuth.config.test_mode = false
end
@@ -40,7 +42,7 @@ class OmniauthableIntegrationTest < ActionDispatch::IntegrationTest
test "can access omniauth.auth in the env hash" do
visit "/users/sign_in"
click_link "Sign in with Facebook"
click_link "Sign in with FaceBook"
json = ActiveSupport::JSON.decode(response.body)
@@ -54,7 +56,7 @@ class OmniauthableIntegrationTest < ActionDispatch::IntegrationTest
test "cleans up session on sign up" do
assert_no_difference "User.count" do
visit "/users/sign_in"
click_link "Sign in with Facebook"
click_link "Sign in with FaceBook"
end
assert session["devise.facebook_data"]
@@ -75,7 +77,7 @@ class OmniauthableIntegrationTest < ActionDispatch::IntegrationTest
test "cleans up session on cancel" do
assert_no_difference "User.count" do
visit "/users/sign_in"
click_link "Sign in with Facebook"
click_link "Sign in with FaceBook"
end
assert session["devise.facebook_data"]
@@ -86,7 +88,7 @@ class OmniauthableIntegrationTest < ActionDispatch::IntegrationTest
test "cleans up session on sign in" do
assert_no_difference "User.count" do
visit "/users/sign_in"
click_link "Sign in with Facebook"
click_link "Sign in with FaceBook"
end
assert session["devise.facebook_data"]
@@ -96,13 +98,13 @@ class OmniauthableIntegrationTest < ActionDispatch::IntegrationTest
test "sign in and send remember token if configured" do
visit "/users/sign_in"
click_link "Sign in with Facebook"
click_link "Sign in with FaceBook"
assert_nil warden.cookies["remember_user_token"]
stub_action!(:sign_in_facebook) do
create_user
visit "/users/sign_in"
click_link "Sign in with Facebook"
click_link "Sign in with FaceBook"
assert warden.authenticated?(:user)
assert warden.cookies["remember_user_token"]
end
@@ -118,16 +120,16 @@ class OmniauthableIntegrationTest < ActionDispatch::IntegrationTest
OmniAuth.config.mock_auth[:facebook] = :access_denied
visit "/users/auth/facebook/callback?error=access_denied"
assert_current_url "/users/sign_in"
assert_contain 'Could not authenticate you from Facebook because "Access denied".'
assert_contain 'Could not authenticate you from FaceBook because "Access denied".'
end
test "handles other exceptions from OmniAuth" do
OmniAuth.config.mock_auth[:facebook] = :invalid_credentials
visit "/users/sign_in"
click_link "Sign in with Facebook"
click_link "Sign in with FaceBook"
assert_current_url "/users/sign_in"
assert_contain 'Could not authenticate you from Facebook because "Invalid credentials".'
assert_contain 'Could not authenticate you from FaceBook because "Invalid credentials".'
end
end

View File

@@ -4,7 +4,7 @@ class RememberMeTest < ActionDispatch::IntegrationTest
def create_user_and_remember(add_to_token='')
user = create_user
user.remember_me!
raw_cookie = User.serialize_into_cookie(user).tap { |a| a.last << add_to_token }
raw_cookie = User.serialize_into_cookie(user).tap { |a| a[1] << add_to_token }
cookies['remember_user_token'] = generate_signed_cookie(raw_cookie)
user
end
@@ -135,7 +135,7 @@ class RememberMeTest < ActionDispatch::IntegrationTest
test 'do not remember with expired token' do
create_user_and_remember
swap Devise, remember_for: 0 do
swap Devise, remember_for: 0.days do
get users_path
assert_not warden.authenticated?(:user)
assert_redirected_to new_user_session_path

View File

@@ -24,6 +24,18 @@ class SessionTimeoutTest < ActionDispatch::IntegrationTest
assert_equal old_last_request, last_request_at
end
test 'does not set last request at in user session after each request if timeoutable is disabled' do
sign_in_as_user
old_last_request = last_request_at
assert_not_nil last_request_at
new_time = 2.seconds.from_now
Time.stubs(:now).returns(new_time)
get users_path, {}, 'devise.skip_timeoutable' => true
assert_equal old_last_request, last_request_at
end
test 'does not time out user session before default limit time' do
sign_in_as_user
assert_response :success
@@ -110,23 +122,6 @@ class SessionTimeoutTest < ActionDispatch::IntegrationTest
assert_contain 'You are signed in'
end
test 'admin does not explode on time out' do
admin = sign_in_as_admin
get expire_admin_path(admin)
Admin.send :define_method, :reset_authentication_token! do
nil
end
begin
get admins_path
assert_redirected_to admins_path
assert_not warden.authenticated?(:admin)
ensure
Admin.send(:remove_method, :reset_authentication_token!)
end
end
test 'user configured timeout limit' do
swap Devise, timeout_in: 8.minutes do
user = sign_in_as_user
@@ -170,16 +165,6 @@ class SessionTimeoutTest < ActionDispatch::IntegrationTest
end
end
test 'time out not triggered if remembered' do
user = sign_in_as_user remember_me: true
get expire_user_path(user)
assert_not_nil last_request_at
get users_path
assert_response :success
assert warden.authenticated?(:user)
end
test 'does not crashes when the last_request_at is a String' do
user = sign_in_as_user

View File

@@ -86,7 +86,7 @@ class ConfirmationInstructionsTest < ActionMailer::TestCase
host, port = ActionMailer::Base.default_url_options.values_at :host, :port
if mail.body.encoded =~ %r{<a href=\"http://#{host}:#{port}/users/confirmation\?confirmation_token=([^"]+)">}
assert_equal Devise.token_generator.digest(user.class, :confirmation_token, $1), user.confirmation_token
assert_equal $1, user.confirmation_token
else
flunk "expected confirmation url regex to match"
end

View File

@@ -250,6 +250,16 @@ class ConfirmableTest < ActiveSupport::TestCase
assert user.reload.active_for_authentication?
end
test 'should not break when a user tries to reset their password in the case where confirmation is not required and confirm_within is set' do
swap Devise, confirm_within: 3.days do
user = create_user
user.instance_eval { def confirmation_required?; false end }
user.confirmation_sent_at = nil
user.save
assert user.reload.confirm!
end
end
test 'should find a user to send email instructions for the user confirm its email by authentication_keys' do
swap Devise, authentication_keys: [:username, :email] do
user = create_user
@@ -291,12 +301,23 @@ class ConfirmableTest < ActiveSupport::TestCase
end
end
test 'always generate a new token on resend' do
test 'do not generate a new token on resend' do
user = create_user
old = user.confirmation_token
user = User.find(user.id)
user.resend_confirmation_instructions
assert_not_equal user.confirmation_token, old
assert_equal user.confirmation_token, old
end
test 'generate a new token after first has expired' do
swap Devise, confirm_within: 3.days do
user = create_user
old = user.confirmation_token
user.update_attribute(:confirmation_sent_at, 4.days.ago)
user = User.find(user.id)
user.resend_confirmation_instructions
assert_not_equal user.confirmation_token, old
end
end
test 'should call after_confirmation if confirmed' do
@@ -465,4 +486,18 @@ class ReconfirmableTest < ActiveSupport::TestCase
:unconfirmed_email
]
end
test 'should not require reconfirmation after creating a record' do
user = create_admin
assert !user.pending_reconfirmation?
end
test 'should not require reconfirmation after creating a record with #save called in callback' do
class Admin::WithSaveInCallback < Admin
after_create :save
end
user = Admin::WithSaveInCallback.create(valid_attributes.except(:username))
assert !user.pending_reconfirmation?
end
end

View File

@@ -3,6 +3,10 @@ require 'test_models'
require 'digest/sha1'
class DatabaseAuthenticatableTest < ActiveSupport::TestCase
def setup
setup_mailer
end
test 'should downcase case insensitive keys when saving' do
# case_insensitive_keys is set to :email by default.
email = 'Foo@Bar.com'
@@ -225,6 +229,22 @@ class DatabaseAuthenticatableTest < ActiveSupport::TestCase
assert_match "can't be blank", user.errors[:current_password].join
end
test 'should not email on password change' do
user = create_user
assert_email_not_sent do
assert user.update_attributes(password: 'newpass', password_confirmation: 'newpass')
end
end
test 'should email on password change when configured' do
swap Devise, send_password_change_notification: true do
user = create_user
assert_email_sent user.email do
assert user.update_attributes(password: 'newpass', password_confirmation: 'newpass')
end
end
end
test 'downcase_keys with validation' do
User.create(email: "HEllO@example.com", password: "123456")
user = User.create(email: "HEllO@example.com", password: "123456")

View File

@@ -14,7 +14,7 @@ class LockableTest < ActiveSupport::TestCase
end
end
test "should increment failed_attempts on successfull validation if the user is already locked" do
test "should increment failed_attempts on successful validation if the user is already locked" do
user = create_user
user.confirm

View File

@@ -42,6 +42,52 @@ class RecoverableTest < ActiveSupport::TestCase
assert_nil user.reset_password_token
end
test 'should not clear reset password token for new user' do
user = new_user
assert_nil user.reset_password_token
user.send_reset_password_instructions
assert_present user.reset_password_token
user.save
assert_present user.reset_password_token
end
test 'should clear reset password token if changing password' do
user = create_user
assert_nil user.reset_password_token
user.send_reset_password_instructions
assert_present user.reset_password_token
user.password = "123456678"
user.password_confirmation = "123456678"
user.save!
assert_nil user.reset_password_token
end
test 'should clear reset password token if changing email' do
user = create_user
assert_nil user.reset_password_token
user.send_reset_password_instructions
assert_present user.reset_password_token
user.email = "another@example.com"
user.save!
assert_nil user.reset_password_token
end
test 'should clear reset password successfully even if there is no email' do
user = create_user_without_email
assert_nil user.reset_password_token
user.send_reset_password_instructions
assert_present user.reset_password_token
user.password = "123456678"
user.password_confirmation = "123456678"
user.save!
assert_nil user.reset_password_token
end
test 'should not clear reset password token if record is invalid' do
user = create_user
user.send_reset_password_instructions

View File

@@ -13,6 +13,7 @@ class RememberableTest < ActiveSupport::TestCase
user = create_user
user.expects(:valid?).never
user.remember_me!
assert user.remember_created_at
end
test 'forget_me should not clear remember token if using salt' do
@@ -33,18 +34,56 @@ class RememberableTest < ActiveSupport::TestCase
test 'serialize into cookie' do
user = create_user
user.remember_me!
assert_equal [user.to_key, user.authenticatable_salt], User.serialize_into_cookie(user)
id, token, date = User.serialize_into_cookie(user)
assert_equal id, user.to_key
assert_equal token, user.authenticatable_salt
assert date.is_a?(Time)
end
test 'serialize from cookie' do
user = create_user
user.remember_me!
assert_equal user, User.serialize_from_cookie(user.to_key, user.authenticatable_salt)
assert_equal user, User.serialize_from_cookie(user.to_key, user.authenticatable_salt, Time.now.utc)
end
test 'raises a RuntimeError if authenticatable_salt is nil' do
test 'serialize from cookie should return nil if no resource is found' do
assert_nil resource_class.serialize_from_cookie([0], "123", Time.now.utc)
end
test 'serialize from cookie should return nil if no timestamp' do
user = create_user
user.remember_me!
assert_nil User.serialize_from_cookie(user.to_key, user.authenticatable_salt)
end
test 'serialize from cookie should return nil if timestamp is earlier than token creation' do
user = create_user
user.remember_me!
assert_nil User.serialize_from_cookie(user.to_key, user.authenticatable_salt, 1.day.ago)
end
test 'serialize from cookie should return nil if timestamp is older than remember_for' do
user = create_user
user.remember_created_at = 1.month.ago
user.remember_me!
assert_nil User.serialize_from_cookie(user.to_key, user.authenticatable_salt, 3.weeks.ago)
end
test 'serialize from cookie me return nil if is a valid resource with invalid token' do
user = create_user
user.remember_me!
assert_nil User.serialize_from_cookie(user.to_key, "123", Time.now.utc)
end
test 'raises a RuntimeError if authenticatable_salt is nil or empty' do
user = User.new
user.encrypted_password = nil
def user.authenticable_salt; nil; end
assert_raise RuntimeError do
user.rememberable_value
end
user = User.new
def user.authenticable_salt; ""; end
assert_raise RuntimeError do
user.rememberable_value
end
@@ -87,28 +126,7 @@ class RememberableTest < ActiveSupport::TestCase
resource.forget_me!
end
test 'remember is expired if not created at timestamp is set' do
assert create_resource.remember_expired?
end
test 'serialize should return nil if no resource is found' do
assert_nil resource_class.serialize_from_cookie([0], "123")
end
test 'remember me return nil if is a valid resource with invalid token' do
resource = create_resource
assert_nil resource_class.serialize_from_cookie([resource.id], "123")
end
test 'remember for should fallback to devise remember for default configuration' do
swap Devise, remember_for: 1.day do
resource = create_resource
resource.remember_me!
assert_not resource.remember_expired?
end
end
test 'remember expires at should sum date of creation with remember for configuration' do
test 'remember expires at uses remember for configuration' do
swap Devise, remember_for: 3.days do
resource = create_resource
resource.remember_me!
@@ -119,77 +137,6 @@ class RememberableTest < ActiveSupport::TestCase
end
end
test 'remember should be expired if remember_for is zero' do
swap Devise, remember_for: 0.days do
Devise.remember_for = 0.days
resource = create_resource
resource.remember_me!
assert resource.remember_expired?
end
end
test 'remember should be expired if it was created before limit time' do
swap Devise, remember_for: 1.day do
resource = create_resource
resource.remember_me!
resource.remember_created_at = 2.days.ago
resource.save
assert resource.remember_expired?
end
end
test 'remember should not be expired if it was created within the limit time' do
swap Devise, remember_for: 30.days do
resource = create_resource
resource.remember_me!
resource.remember_created_at = (30.days.ago + 2.minutes)
resource.save
assert_not resource.remember_expired?
end
end
test 'if extend_remember_period is false, remember_me! should generate a new timestamp if expired' do
swap Devise, remember_for: 5.minutes do
resource = create_resource
resource.remember_me!(false)
assert resource.remember_created_at
resource.remember_created_at = old = 10.minutes.ago
resource.save
resource.remember_me!(false)
assert_not_equal old.to_i, resource.remember_created_at.to_i
end
end
test 'if extend_remember_period is false, remember_me! should not generate a new timestamp' do
swap Devise, remember_for: 1.year do
resource = create_resource
resource.remember_me!(false)
assert resource.remember_created_at
resource.remember_created_at = old = 10.minutes.ago.utc
resource.save
resource.remember_me!(false)
assert_equal old.to_i, resource.remember_created_at.to_i
end
end
test 'if extend_remember_period is true, remember_me! should always generate a new timestamp' do
swap Devise, remember_for: 1.year do
resource = create_resource
resource.remember_me!(true)
assert resource.remember_created_at
resource.remember_created_at = old = 10.minutes.ago
resource.save
resource.remember_me!(true)
assert_not_equal old, resource.remember_created_at
end
end
test 'should have the required_fields array' do
assert_same_content Devise::Models::Rememberable.required_fields(User), [
:remember_created_at

View File

@@ -92,13 +92,20 @@ class ActiveRecordTest < ActiveSupport::TestCase
end
end
module StubModelFilters
def stub_filter(name)
define_singleton_method(name) { |*| nil }
end
end
class CheckFieldsTest < ActiveSupport::TestCase
test 'checks if the class respond_to the required fields' do
Player = Class.new do
extend Devise::Models
extend StubModelFilters
def self.before_validation(instance)
end
stub_filter :before_validation
stub_filter :after_update
devise :database_authenticatable
@@ -113,9 +120,10 @@ class CheckFieldsTest < ActiveSupport::TestCase
test 'raises Devise::Models::MissingAtrribute and shows the missing attribute if the class doesn\'t respond_to one of the attributes' do
Clown = Class.new do
extend Devise::Models
extend StubModelFilters
def self.before_validation(instance)
end
stub_filter :before_validation
stub_filter :after_update
devise :database_authenticatable
@@ -130,9 +138,10 @@ class CheckFieldsTest < ActiveSupport::TestCase
test 'raises Devise::Models::MissingAtrribute with all the missing attributes if there is more than one' do
Magician = Class.new do
extend Devise::Models
extend StubModelFilters
def self.before_validation(instance)
end
stub_filter :before_validation
stub_filter :after_update
devise :database_authenticatable
end

View File

@@ -0,0 +1,8 @@
require "shared_user_without_email"
class UserWithoutEmail < ActiveRecord::Base
self.table_name = 'users'
include Shim
include SharedUserWithoutEmail
end

View File

@@ -3,9 +3,4 @@ class AdminsController < ApplicationController
def index
end
def expire
admin_session['last_request_at'] = 31.minutes.ago.utc
render text: 'Admin will be expired on next request'
end
end

View File

@@ -0,0 +1,33 @@
require "shared_user_without_email"
class UserWithoutEmail
include Mongoid::Document
include Shim
include SharedUserWithoutEmail
field :username, type: String
field :facebook_token, type: String
## Database authenticatable
field :email, type: String, default: ""
field :encrypted_password, type: String, default: ""
## Recoverable
field :reset_password_token, type: String
field :reset_password_sent_at, type: Time
## Rememberable
field :remember_created_at, type: Time
## Trackable
field :sign_in_count, type: Integer, default: 0
field :current_sign_in_at, type: Time
field :last_sign_in_at, type: Time
field :current_sign_in_ip, type: String
field :last_sign_in_ip, type: String
## Lockable
field :failed_attempts, type: Integer, default: 0 # Only if lock strategy is :failed_attempts
field :unlock_token, type: String # Only if unlock strategy is :email or :both
field :locked_at, type: Time
end

View File

@@ -13,9 +13,7 @@ Rails.application.routes.draw do
end
end
resources :admins, only: [:index] do
get :expire, on: :member
end
resources :admins, only: [:index]
# Users scope
devise_for :users, controllers: { omniauth_callbacks: "users/omniauth_callbacks" }
@@ -30,6 +28,11 @@ Rails.application.routes.draw do
router_name: :fake_engine,
module: :devise
devise_for :user_without_email,
class_name: 'UserWithoutEmail',
router_name: :main_app,
module: :devise
as :user do
get "/as/sign_in", to: "devise/sessions#new"
end

View File

@@ -0,0 +1,26 @@
module SharedUserWithoutEmail
extend ActiveSupport::Concern
included do
# NOTE: This is missing :validatable and :confirmable, as they both require
# an email field at the moment. It is also missing :omniauthable because that
# adds unnecessary complexity to the setup
devise :database_authenticatable, :lockable, :recoverable,
:registerable, :rememberable, :timeoutable,
:trackable
end
# This test stub is a bit rubbish because it's tied very closely to the
# implementation where we care about this one case. However, completely
# removing the email field breaks "recoverable" tests completely, so we are
# just taking the approach here that "email" is something that is a not an
# ActiveRecord field.
def email_changed?
raise NoMethodError
end
def respond_to?(method_name, include_all=false)
return false if method_name.to_sym == :email_changed?
super(method_name, include_all)
end
end

View File

@@ -46,6 +46,10 @@ class ActiveSupport::TestCase
Admin.create!(valid_attributes)
end
def create_user_without_email(attributes={})
UserWithoutEmail.create!(valid_attributes(attributes))
end
# Execute the block setting the given values and restoring old values after
# the block is executed.
def swap(object, new_values)