Compare commits

..

29 Commits
v4.7.0 ... 5-rc

Author SHA1 Message Date
Marcos Ferreira
4be9389dcb Merge pull request #5032 from JanBussieck/pure-signed_in-method
Use warden’s `authenticated?` for query methods to avoid side effects
2019-09-19 14:32:41 -03:00
Jan Bussieck
2fde07b9be Fix test case descriptions, since we are testing proxying to 'authenticated?' 2019-09-19 17:18:02 +02:00
Jan Bussieck
70c5f4bfaf Use warden’s authenticated? for query methods to avoid side effects
Previously checks whether a certain scope is signed in were performed using warden’s
`authenticate?` or `authenticate` methods which would run the strategies and sign in the
scope if valid params were given. We want to remove this side effect from query methods.
2019-09-19 17:18:02 +02:00
Jeremy Wadsack
0a2e67878a When password reset token expires, redirect to new password path (#4837) 2019-09-19 10:22:30 -03:00
Leonardo Tegon
c381c916f3 Remove circular argument reference
/Users/tegon/src/public/plataformatec/devise/app/controllers/devise/sessions_controller.rb:75: warning: circular argument reference - status
2019-09-19 10:22:30 -03:00
Felipe Renan
9999072620 Update CHANGELOG.md [ci skip] 2019-09-19 10:22:30 -03:00
Marc Busqué
34238e9f18 Update trackable fields only in a database sign in
References #4584 and waiting-for-dev/devise-jwt#23

* Bug
Users that use devise-jwt, will not have the correct behavior of trackable
feature. As a request for APIs always requires authentication since there
is no session in APIs world, Devise counts +1 on every request since it
contains authentication info.

It happens because Devise has a trackable hook that updates the trackable
info everytime that the user is signed in by Warden.

* Fix
We are moving update_trackable_fields! from trackable hook (which was removed)
to sign_in_out and database_authenticatable. This way, update_trackable_fields!
is going to run only when the user signed in by Devise (only one time).
2019-09-19 10:22:29 -03:00
Felipe Renan
a1c493b009 Remove unnecessary checks for Rails 4 2019-09-19 10:22:29 -03:00
Felipe Renan
e7f9805fd4 Update CHANGELOG.md 2019-09-19 10:22:29 -03:00
Felipe Renan
8956d4caa1 Remove Ruby 2.2 and Ruby 2.1 support 2019-09-19 10:22:29 -03:00
Julius Graakjær Grantzau
b85911dee3 Downcase authentication keys and humanize error message (#4834) 2019-09-19 10:21:02 -03:00
Felipe Renan
2d1a961c1b Remove Rails 4 support 2019-09-19 10:20:59 -03:00
Adan Amarillas
195cbfb9e5 Modified sessions controller to return 401 for destroy action with no user signed in (#4878) 2019-09-19 10:06:14 -03:00
Leonardo Tegon
96a3153c23 Update CHANGELOG.md 2019-09-19 10:06:14 -03:00
Shriram
64238fc80e Make secure_compare handle empty strings comparison correctly
Used Rails' secure_compare method inside the definition of secure_compare. This will handle the empty strings comparison and return true when both the parameters are blank strings.

Fixes #4441
2019-09-19 10:06:14 -03:00
Siva Gollapalli
afaad713ff Added translations according to unlock strategy 2019-09-19 10:06:13 -03:00
Marcos Ferreira
f48b6f1651 Merge pull request #5067 from shobhitic/master
Using scoped errors for scoped views. Fixes #5066
2019-09-17 14:49:57 -03:00
Marcos Ferreira
34ed989725 Move PR #5074 to unreleased in changelog [skip ci] 2019-09-17 13:38:00 -03:00
Marcos Ferreira
b52e642c01 Merge pull request #5074 from sergey-alekseev/increase-default-stretches-to-12
Increase default stretches to 12
2019-09-17 13:30:55 -03:00
Leonardo Tegon
098345aace Prepare for version 4.7.1 2019-09-06 10:20:20 -03:00
Leonardo Tegon
caa1a55d17 Update CHANGELOG.md [ci skip] 2019-09-05 09:55:12 -03:00
Leonardo Tegon
fee43f3c11 Always return an error when confirmation_token is blank (#5132)
As reported in https://github.com/plataformatec/devise/issues/5071, if
for some reason, a user in the database had the `confirmation_token`
column as a blank string, Devise would confirm that user after receiving
a request with a blank `confirmation_token` parameter.
After this commit, a request sending a blank `confirmation_token`
parameter will receive a validation error.
For applications that have users with a blank `confirmation_token` in
the database, it's recommended to manually regenerate or to nullify
them.
2019-09-04 15:42:48 -03:00
Leonardo Tegon
fad60747d5 Merge pull request #5125 from olleolleolle/patch-1
CI: Drop unused Travis sudo: false directive
2019-08-30 19:30:03 -03:00
Leonardo Tegon
5ceef2d4de Merge pull request #5131 from lslm/ls-fix-typo
Fix typo in email update message
2019-08-30 17:26:22 -03:00
Lucas Santos
6635caf12e Fix typo 2019-08-30 14:35:19 -03:00
Olle Jonsson
e051360ea2 CI: Drop unused Travis sudo: false directive 2019-08-26 13:36:34 +02:00
Sergey Alekseev
45245df16a update changelog
[skip ci]
2019-05-13 14:15:14 +03:00
Sergey Alekseev
63ea6533de increase default stretches to 12
Test script
---

```ruby
require 'bcrypt'
require 'benchmark'
Benchmark.measure { BCrypt::Password.create('password', cost: 12) }
```

Test results
---

- [Intel(R) Core(TM) i5-7360U CPU @ 2.30GHz](https://ark.intel.com/content/www/us/en/ark/products/97535/intel-core-i5-7360u-processor-4m-cache-up-to-3-60-ghz.html): `#<Benchmark::Tms:0x00007fdd00a4eb30 @label="", @real=0.21730700000080105, @cstime=0.0, @cutime=0.0, @stime=0.00020399999999999585, @utime=0.21685199999999996, @total=0.21705599999999997>`
- [Intel(R) Core(TM) i7-8559U CPU @ 2.70GHz](https://ark.intel.com/content/www/us/en/ark/products/137979/intel-core-i7-8559u-processor-8m-cache-up-to-4-50-ghz.html): `#<Benchmark::Tms:0x00007fe91094fd30 @label="", @real=0.17964200000278652, @cstime=0.0, @cutime=0.0, @stime=7.399999999996298e-05, @utime=0.17950799999999845, @total=0.1795819999999984>`

Other gems
---

- bcrypt-ruby which is used by devise [updated](https://github.com/codahale/bcrypt-ruby/pull/181) their default cost to 12 (not released a gem version yet).
- rails has [a PR](https://github.com/rails/rails/pull/35321) from the Rails core team member to update their `ActiveModel::SecurePassword` which powers `has_secure_password` default cost to 13 (not merged yet).

Previous changes
---

[Previous PR](https://github.com/plataformatec/devise/pull/3549) to increase the default stretches to 12 was created more than 4 years ago. That time the default stretches value [was increased](9efc601c73) from 10 to 11.
2019-05-11 19:35:13 +03:00
Shobhit Bakliwal
a823e510f3 Using scoped errors for scoped views. Fixes #5066 2019-05-02 13:24:01 +05:30
65 changed files with 339 additions and 336 deletions

View File

@@ -1,8 +1,6 @@
language: ruby
rvm:
- 2.1.10
- 2.2.10
- 2.3.8
- 2.4.5
- 2.5.3
@@ -14,41 +12,14 @@ gemfile:
- gemfiles/Gemfile.rails-6.0-stable
- gemfiles/Gemfile.rails-5.2-stable
- gemfiles/Gemfile.rails-5.0-stable
- gemfiles/Gemfile.rails-4.2-stable
- gemfiles/Gemfile.rails-4.1-stable
matrix:
exclude:
- rvm: 2.1.10
gemfile: Gemfile
- rvm: 2.1.10
gemfile: gemfiles/Gemfile.rails-6.0-stable
- rvm: 2.1.10
gemfile: gemfiles/Gemfile.rails-5.2-stable
- rvm: 2.1.10
gemfile: gemfiles/Gemfile.rails-5.0-stable
- rvm: 2.2.10
gemfile: Gemfile
- rvm: 2.2.10
gemfile: gemfiles/Gemfile.rails-6.0-stable
- rvm: 2.2.10
gemfile: gemfiles/Gemfile.rails-5.2-stable
- rvm: 2.3.8
gemfile: gemfiles/Gemfile.rails-6.0-stable
- rvm: 2.4.5
gemfile: gemfiles/Gemfile.rails-4.1-stable
- rvm: 2.4.5
gemfile: gemfiles/Gemfile.rails-6.0-stable
- rvm: 2.5.3
gemfile: gemfiles/Gemfile.rails-4.1-stable
- rvm: 2.6.0
gemfile: gemfiles/Gemfile.rails-4.1-stable
- rvm: 2.6.0
gemfile: gemfiles/Gemfile.rails-4.2-stable
- rvm: ruby-head
gemfile: gemfiles/Gemfile.rails-4.1-stable
- rvm: ruby-head
gemfile: gemfiles/Gemfile.rails-4.2-stable
- env: DEVISE_ORM=mongoid
gemfile: Gemfile
- env: DEVISE_ORM=mongoid
@@ -64,8 +35,6 @@ matrix:
services:
- mongodb
sudo: false
cache: bundler
env:
@@ -73,10 +42,7 @@ env:
- DEVISE_ORM=active_record
- DEVISE_ORM=mongoid
before_install:
- gem uninstall -v '>= 2' -i $(rvm gemdir)@global -ax bundler || true
- gem install bundler -v '< 2'
- "rm ${BUNDLE_GEMFILE}.lock"
before_install: "rm ${BUNDLE_GEMFILE}.lock"
before_script: "bundle update"

View File

@@ -1,4 +1,22 @@
### 5.0.0-rc
* enhancements
* Suport multiple translations according to unlock strategy (by @sivagollapalli)
* Use `ActiveSupport::SecurityUtils.secure_compare` inside `Devise.secure_compare` (by @shrirambalakrishnan)
* Update trackable fields only in a database sign in (by @waiting-for-dev)
* deprecations
* Remove Rails 4, Ruby 2.1 and Ruby 2.2 support (by @feliperenan)
### Unreleased
* enhancements
* Increase default stretches to 12 (by @sergey-alekseev)
### 4.7.1 - 2019-09-06
* bug fixes
* Fix an edge case where records with a blank `confirmation_token` could be confirmed (by @tegon)
* Fix typo inside `update_needs_confirmation` i18n key (by @lslm)
### 4.7.0 - 2019-08-19

View File

@@ -10,10 +10,10 @@ GIT
PATH
remote: .
specs:
devise (4.7.0)
devise (4.7.1)
bcrypt (~> 3.0)
orm_adapter (~> 0.1)
railties (>= 4.1.0)
railties (>= 5.0)
responders
warden (~> 1.2.3)

View File

@@ -137,17 +137,17 @@ Please note that the command output will show the variable value being used.
### BUNDLE_GEMFILE
We can use this variable to tell bundler what Gemfile it should use (instead of the one in the current directory).
Inside the [gemfiles](https://github.com/plataformatec/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.
For example, if the tests broke using Ruby 2.4.2 and Rails 4.1, you can do the following:
For example, if the tests broke using Ruby 2.5.0 and Rails 5.0, you can do the following:
```bash
rbenv shell 2.4.2 # or rvm use 2.4.2
BUNDLE_GEMFILE=gemfiles/Gemfile.rails-4.1-stable bundle install
BUNDLE_GEMFILE=gemfiles/Gemfile.rails-4.1-stable bin/test
rbenv shell 2.5.0 # or rvm use 2.5.0
BUNDLE_GEMFILE=gemfiles/Gemfile.rails-5.0-stable bundle install
BUNDLE_GEMFILE=gemfiles/Gemfile.rails-5.0-stable bin/test
```
You can also combine both of them if the tests broke for Mongoid:
```bash
BUNDLE_GEMFILE=gemfiles/Gemfile.rails-4.1-stable bundle install
BUNDLE_GEMFILE=gemfiles/Gemfile.rails-4.1-stable DEVISE_ORM=mongoid bin/test
BUNDLE_GEMFILE=gemfiles/Gemfile.rails-5.0-stable bundle install
BUNDLE_GEMFILE=gemfiles/Gemfile.rails-5.0-stable DEVISE_ORM=mongoid bin/test
```
### Running tests
@@ -180,7 +180,7 @@ Once you have solidified your understanding of Rails and authentication mechanis
## Getting started
Devise 4.0 works with Rails 4.1 onwards. Add the following line to your Gemfile:
Devise 5.0 works with Rails 5.0 onwards. Add the following line to your Gemfile:
```ruby
gem 'devise'
@@ -270,7 +270,7 @@ member_session
The Devise method in your models also accepts some options to configure its modules. For example, you can choose the cost of the hashing algorithm with:
```ruby
devise :database_authenticatable, :registerable, :confirmable, :recoverable, stretches: 12
devise :database_authenticatable, :registerable, :confirmable, :recoverable, stretches: 13
```
Besides `:stretches`, you can define `:pepper`, `:encryptor`, `:confirm_within`, `:remember_for`, `:timeout_in`, `:unlock_in` among other options. For more details, see the initializer file that was created when you invoked the "devise:install" generator described above. This file is usually located at `/config/initializers/devise.rb`.

View File

@@ -47,7 +47,12 @@ class Devise::PasswordsController < DeviseController
respond_with resource, location: after_resetting_password_path_for(resource)
else
set_minimum_password_length
respond_with resource
if expired_token_error?(resource)
redirect_to new_password_path(resource_name), alert: t('devise.passwords.expired_token')
else
respond_with resource
end
end
end
@@ -80,4 +85,9 @@ class Devise::PasswordsController < DeviseController
def translation_scope
'devise.passwords'
end
private
def expired_token_error?(resource)
resource.errors.details[:reset_password_token].any? { |error| error[:error] == :expired }
end
end

View File

@@ -28,7 +28,7 @@ class Devise::SessionsController < DeviseController
signed_out = (Devise.sign_out_all_scopes ? sign_out : sign_out(resource_name))
set_flash_message! :notice, :signed_out if signed_out
yield if block_given?
respond_to_on_destroy
respond_to_on_destroy(status: :no_content)
end
protected
@@ -62,7 +62,7 @@ class Devise::SessionsController < DeviseController
if all_signed_out?
set_flash_message! :notice, :already_signed_out
respond_to_on_destroy
respond_to_on_destroy(status: :unauthorized)
end
end
@@ -72,11 +72,11 @@ class Devise::SessionsController < DeviseController
users.all?(&:blank?)
end
def respond_to_on_destroy
def respond_to_on_destroy(status:)
# We actually need to hardcode this as Rails default responder doesn't
# support returning empty response on GET request
respond_to do |format|
format.all { head :no_content }
format.all { head status }
format.any(*navigational_formats) { redirect_to after_sign_out_path_for(resource_name) }
end
end

View File

@@ -10,7 +10,11 @@ en:
already_authenticated: "You are already signed in."
inactive: "Your account is not activated yet."
invalid: "Invalid %{authentication_keys} or password."
locked: "Your account is locked."
locked:
none: "Your account is locked."
email: "Your account is locked. An email has been sent with instructions on how to unlock your account."
time: "Your account is locked. Your account will become available after a certain amount of time."
both: "Your account is locked. An email has been sent with instructions on how to unlock your account, or wait a certain amount of time and try again."
last_attempt: "You have one more attempt before your account is locked."
not_found_in_database: "Invalid %{authentication_keys} or password."
timeout: "Your session expired. Please sign in again to continue."
@@ -36,13 +40,14 @@ en:
send_paranoid_instructions: "If your email address exists in our database, you will receive a password recovery link at your email address in a few minutes."
updated: "Your password has been changed successfully. You are now signed in."
updated_not_active: "Your password has been changed successfully."
expired_token: "The password recovery link expired. Please request a new one."
registrations:
destroyed: "Bye! Your account has been successfully cancelled. We hope to see you again soon."
signed_up: "Welcome! You have signed up successfully."
signed_up_but_inactive: "You have signed up successfully. However, we could not sign you in because your account is not yet activated."
signed_up_but_locked: "You have signed up successfully. However, we could not sign you in because your account is locked."
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."
update_needs_confirmation: "You updated your account successfully, but we need to verify your new email address. Please check your email and follow the confirm link to confirm your new email address."
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."
updated: "Your account has been updated successfully."
updated_but_not_signed_in: "Your account has been updated successfully, but since your password was changed, you need to sign in again"
sessions:

View File

@@ -17,11 +17,11 @@ Gem::Specification.new do |s|
s.files = Dir["{app,config,lib}/**/*", "CHANGELOG.md", "MIT-LICENSE", "README.md"]
s.require_paths = ["lib"]
s.required_ruby_version = '>= 2.1.0'
s.required_ruby_version = '>= 2.3.0'
s.add_dependency("warden", "~> 1.2.3")
s.add_dependency("orm_adapter", "~> 0.1")
s.add_dependency("bcrypt", "~> 3.0")
s.add_dependency("railties", ">= 4.1.0")
s.add_dependency("railties", ">= 5.0")
s.add_dependency("responders")
end

View File

@@ -21,10 +21,10 @@ GIT
PATH
remote: ..
specs:
devise (4.6.2)
devise (4.7.1)
bcrypt (~> 3.0)
orm_adapter (~> 0.1)
railties (>= 4.1.0, < 6.0)
railties (>= 4.1.0)
responders
warden (~> 1.2.3)
@@ -54,7 +54,7 @@ GEM
thread_safe (~> 0.1)
tzinfo (~> 1.1)
arel (5.0.1.20140414130214)
bcrypt (3.1.12)
bcrypt (3.1.13)
bson (3.2.6)
builder (3.2.3)
concurrent-ruby (1.0.5)

View File

@@ -57,10 +57,10 @@ GIT
PATH
remote: ..
specs:
devise (4.6.2)
devise (4.7.1)
bcrypt (~> 3.0)
orm_adapter (~> 0.1)
railties (>= 4.1.0, < 6.0)
railties (>= 4.1.0)
responders
warden (~> 1.2.3)
@@ -68,7 +68,7 @@ GEM
remote: https://rubygems.org/
specs:
arel (6.0.4)
bcrypt (3.1.12)
bcrypt (3.1.13)
bson (3.2.6)
builder (3.2.3)
concurrent-ruby (1.0.5)

View File

@@ -21,7 +21,6 @@ group :test do
gem "timecop"
gem "webrat", "0.7.3", require: false
gem "mocha", "~> 1.1", require: false
gem 'test_after_commit', require: false
end
platforms :ruby do

View File

@@ -10,10 +10,10 @@ GIT
PATH
remote: ..
specs:
devise (4.7.0)
devise (4.7.1)
bcrypt (~> 3.0)
orm_adapter (~> 0.1)
railties (>= 4.1.0)
railties (>= 5.0)
responders
warden (~> 1.2.3)
@@ -153,8 +153,6 @@ GEM
activesupport (>= 4.0)
sprockets (>= 3.0.0)
sqlite3 (1.3.13)
test_after_commit (1.1.0)
activerecord (>= 3.2)
thor (0.19.4)
thread_safe (0.3.6)
timecop (0.8.1)
@@ -191,4 +189,4 @@ DEPENDENCIES
webrat (= 0.7.3)
BUNDLED WITH
1.17.1
1.17.3

View File

@@ -19,7 +19,6 @@ group :test do
gem "timecop"
gem "webrat", "0.7.3", require: false
gem "mocha", "~> 1.1", require: false
gem 'test_after_commit', require: false
end
platforms :ruby do

View File

@@ -10,10 +10,10 @@ GIT
PATH
remote: ..
specs:
devise (4.7.0)
devise (4.7.1)
bcrypt (~> 3.0)
orm_adapter (~> 0.1)
railties (>= 4.1.0)
railties (>= 5.0)
responders
warden (~> 1.2.3)
@@ -162,8 +162,6 @@ GEM
activesupport (>= 4.0)
sprockets (>= 3.0.0)
sqlite3 (1.3.13)
test_after_commit (1.1.0)
activerecord (>= 3.2)
thor (0.20.0)
thread_safe (0.3.6)
timecop (0.9.1)
@@ -200,4 +198,4 @@ DEPENDENCIES
webrat (= 0.7.3)
BUNDLED WITH
1.17.1
1.17.3

View File

@@ -10,10 +10,10 @@ GIT
PATH
remote: ..
specs:
devise (4.7.0)
devise (4.7.1)
bcrypt (~> 3.0)
orm_adapter (~> 0.1)
railties (>= 4.1.0)
railties (>= 5.0)
responders
warden (~> 1.2.3)
@@ -216,4 +216,4 @@ DEPENDENCIES
webrat (= 0.7.3)
BUNDLED WITH
1.17.2
1.17.3

View File

@@ -71,7 +71,7 @@ module Devise
# The number of times to hash the password.
mattr_accessor :stretches
@@stretches = 11
@@stretches = 12
# The default key used when authenticating over http auth.
mattr_accessor :http_authentication_key
@@ -502,12 +502,8 @@ module Devise
# constant-time comparison algorithm to prevent timing attacks
def self.secure_compare(a, b)
return false if a.blank? || b.blank? || a.bytesize != b.bytesize
l = a.unpack "C#{a.bytesize}"
res = 0
b.each_byte { |byte| res |= byte ^ l.shift }
res == 0
return false if a.nil? || b.nil?
ActiveSupport::SecurityUtils.secure_compare(a, b)
end
end

View File

@@ -53,7 +53,7 @@ module Devise
def #{group_name}_signed_in?
#{mappings}.any? do |mapping|
warden.authenticate?(scope: mapping)
warden.authenticated?(scope: mapping)
end
end
@@ -119,7 +119,7 @@ module Devise
end
def #{mapping}_signed_in?
!!current_#{mapping}
!!(@current_#{mapping} || warden.authenticated?(scope: :#{mapping}))
end
def current_#{mapping}

View File

@@ -12,7 +12,7 @@ module Devise
# authentication hooks, you can directly call `warden.authenticated?(scope: scope)`
def signed_in?(scope=nil)
[scope || Devise.mappings.keys].flatten.any? do |_scope|
warden.authenticate?(scope: _scope)
warden.authenticated?(scope: _scope)
end
end
@@ -51,6 +51,7 @@ module Devise
true
else
warden.set_user(resource, options.merge!(scope: scope))
resource.update_tracked_fields!(warden.request) if resource.respond_to?(:update_tracked_fields!)
end
end

View File

@@ -103,11 +103,14 @@ module Devise
options[:scope] = "devise.failure"
options[:default] = [message]
auth_keys = scope_class.authentication_keys
keys = (auth_keys.respond_to?(:keys) ? auth_keys.keys : auth_keys).map { |key| scope_class.human_attribute_name(key) }
keys = (auth_keys.respond_to?(:keys) ? auth_keys.keys : auth_keys).map { |key| scope_class.human_attribute_name(key).downcase }
options[:authentication_keys] = keys.join(I18n.translate(:"support.array.words_connector"))
options = i18n_options(options)
translated_message = I18n.t(:"#{scope}.#{message}", options)
I18n.t(:"#{scope}.#{message}", options)
# only call `#humanize` when the message is `:invalid` to ensure the original format
# of other messages - like `:does_not_exist` - is kept.
message == :invalid ? translated_message.humanize : translated_message
else
message.to_s
end

View File

@@ -1,11 +0,0 @@
# frozen_string_literal: true
# After each sign in, update sign in time, sign in count and sign in IP.
# This is only triggered when the user is explicitly set (with set_user)
# and on authentication. Retrieving the user from session (:fetch) does
# not trigger it.
Warden::Manager.after_set_user except: :fetch do |record, warden, options|
if record.respond_to?(:update_tracked_fields!) && warden.authenticated?(options[:scope]) && !warden.request.env['devise.skip_trackable']
record.update_tracked_fields!(warden.request)
end
end

View File

@@ -182,11 +182,8 @@ module Devise
# # Deliver later with Active Job's `deliver_later`
# if message.respond_to?(:deliver_later)
# message.deliver_later
# # Remove once we move to Rails 4.2+ only, as `deliver` is deprecated.
# elsif message.respond_to?(:deliver_now)
# message.deliver_now
# else
# message.deliver
# message.deliver_now
# end
# end
#
@@ -194,12 +191,7 @@ module Devise
#
def send_devise_notification(notification, *args)
message = devise_mailer.send(notification, self, *args)
# Remove once we move to Rails 4.2+ only.
if message.respond_to?(:deliver_now)
message.deliver_now
else
message.deliver
end
message.deliver_now
end
def downcase_keys

View File

@@ -348,7 +348,19 @@ 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)
# When the `confirmation_token` parameter is blank, if there are any users with a blank
# `confirmation_token` in the database, the first one would be confirmed here.
# The error is being manually added here to ensure no users are confirmed by mistake.
# This was done in the model for convenience, since validation errors are automatically
# displayed in the view.
if confirmation_token.blank?
confirmable = new
confirmable.errors.add(:confirmation_token, :blank)
return confirmable
end
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)

View File

@@ -80,16 +80,7 @@ module Devise
# users to change relevant information like the e-mail without changing
# their password). In case the password field is rejected, the confirmation
# is also rejected as long as it is also blank.
def update_with_password(params, *options)
if options.present?
ActiveSupport::Deprecation.warn <<-DEPRECATION.strip_heredoc
[Devise] The second argument of `DatabaseAuthenticatable#update_with_password`
(`options`) is deprecated and it will be removed in the next major version.
It was added to support a feature deprecated in Rails 4, so you can safely remove it
from your code.
DEPRECATION
end
def update_with_password(params)
current_password = params.delete(:current_password)
if params[:password].blank?
@@ -98,9 +89,9 @@ module Devise
end
result = if valid_password?(current_password)
update(params, *options)
update(params)
else
assign_attributes(params, *options)
assign_attributes(params)
valid?
errors.add(:current_password, current_password.blank? ? :blank : :invalid)
false
@@ -122,20 +113,11 @@ module Devise
# super(params)
# end
#
def update_without_password(params, *options)
if options.present?
ActiveSupport::Deprecation.warn <<-DEPRECATION.strip_heredoc
[Devise] The second argument of `DatabaseAuthenticatable#update_without_password`
(`options`) is deprecated and it will be removed in the next major version.
It was added to support a feature deprecated in Rails 4, so you can safely remove it
from your code.
DEPRECATION
end
def update_without_password(params)
params.delete(:password)
params.delete(:password_confirmation)
result = update(params, *options)
result = update(params)
clean_up_passwords
result
end

View File

@@ -122,7 +122,15 @@ module Devise
if Devise.paranoid
super
elsif access_locked? || (lock_strategy_enabled?(:failed_attempts) && attempts_exceeded?)
:locked
if unlock_strategy_enabled?(:both)
'locked.both'.to_sym
elsif unlock_strategy_enabled?(:email)
'locked.email'.to_sym
elsif unlock_strategy_enabled?(:time)
'locked.time'.to_sym
else
'locked.none'.to_sym
end
elsif lock_strategy_enabled?(:failed_attempts) && last_attempt? && self.class.last_attempt_warning
:last_attempt
else

View File

@@ -1,7 +1,5 @@
# frozen_string_literal: true
require 'devise/hooks/trackable'
module Devise
module Models
# Track information about your user sign in. It tracks the following columns:
@@ -36,6 +34,8 @@ module Devise
# See https://github.com/plataformatec/devise/issues/4673 for more details.
return if new_record?
return if skip_trackable_and_not_active_for_authentication?(request)
update_tracked_fields(request)
save(validate: false)
end
@@ -46,6 +46,11 @@ module Devise
request.remote_ip
end
private
def skip_trackable_and_not_active_for_authentication?(request)
request.env['devise.skip_trackable'] || !active_for_authentication?
end
end
end
end

View File

@@ -130,8 +130,7 @@ module Devise
#
# Returns an +ActiveSupport::HashWithIndifferentAccess+.
def cast_to_hash(params)
# TODO: Remove the `with_indifferent_access` method call when we only support Rails 5+.
params && params.to_h.with_indifferent_access
params && params.to_h
end
def default_params

View File

@@ -12,6 +12,7 @@ module Devise
if validate(resource){ hashed = true; resource.valid_password?(password) }
remember_me(resource)
resource.update_tracked_fields!(request) if resource.respond_to?(:update_tracked_fields!)
resource.after_database_authentication
success!(resource)
end

View File

@@ -139,7 +139,6 @@ module Devise
status, headers, response = Devise.warden_config[:failure_app].call(env).to_a
@controller.response.headers.merge!(headers)
@controller.response.content_type = headers["Content-Type"] unless Rails::VERSION::MAJOR >= 5
@controller.status = status
@controller.response.body = response.body
nil # causes process return @response

View File

@@ -1,5 +1,5 @@
# frozen_string_literal: true
module Devise
VERSION = "4.7.0".freeze
VERSION = "4.7.1".freeze
end

View File

@@ -82,23 +82,17 @@ RUBY
postgresql?
end
def rails5_and_up?
Rails::VERSION::MAJOR >= 5
end
def postgresql?
config = ActiveRecord::Base.configurations[Rails.env]
config && config['adapter'] == 'postgresql'
end
def migration_version
if rails5_and_up?
"[#{Rails::VERSION::MAJOR}.#{Rails::VERSION::MINOR}]"
end
"[#{Rails::VERSION::MAJOR}.#{Rails::VERSION::MINOR}]"
end
def primary_key_type
primary_key_string if rails5_and_up?
primary_key_string
end
def primary_key_string

View File

@@ -37,10 +37,6 @@ module Devise
def show_readme
readme "README" if behavior == :invoke
end
def rails_4?
Rails::VERSION::MAJOR == 4
end
end
end
end

View File

@@ -42,7 +42,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", "#{plural_scope}/shared/links"
content.gsub("devise/shared/links", "#{plural_scope}/shared/links").gsub("devise/shared/error_messages", "#{plural_scope}/shared/error_messages")
else
content
end

View File

@@ -103,7 +103,7 @@ Devise.setup do |config|
# config.reload_routes = true
# ==> Configuration for :database_authenticatable
# For bcrypt, this is the cost for hashing the password and defaults to 11. If
# For bcrypt, this is the cost for hashing the password and defaults to 12. If
# using other algorithms, it sets how many times you want the password to be hashed.
#
# Limiting the stretches to just one in testing will increase the performance of
@@ -111,7 +111,7 @@ Devise.setup do |config|
# a value less than 10 in other environments. Note that, for bcrypt (the default
# algorithm), the cost increases exponentially with the number of stretches (e.g.
# a value of 20 is already extremely slow: approx. 60 seconds for 1 calculation).
config.stretches = Rails.env.test? ? 1 : 11
config.stretches = Rails.env.test? ? 1 : 12
# Set up a pepper to generate the hashed password.
# config.pepper = '<%= SecureRandom.hex(64) %>'

View File

@@ -15,21 +15,21 @@ class ControllerAuthenticatableTest < Devise::ControllerTestCase
assert_equal @mock_warden, @controller.warden
end
test 'proxy signed_in?(scope) to authenticate?' do
@mock_warden.expects(:authenticate?).with(scope: :my_scope)
test 'proxy signed_in?(scope) to authenticated?' do
@mock_warden.expects(:authenticated?).with(scope: :my_scope)
@controller.signed_in?(:my_scope)
end
test 'proxy signed_in?(nil) to authenticate?' do
test 'proxy signed_in?(nil) to authenticated?' do
Devise.mappings.keys.each do |scope| # :user, :admin, :manager
@mock_warden.expects(:authenticate?).with(scope: scope)
@mock_warden.expects(:authenticated?).with(scope: scope)
end
@controller.signed_in?
end
test 'proxy [group]_signed_in? to authenticate? with each scope' do
test 'proxy [group]_signed_in? to authenticated? with each scope' do
[:user, :admin].each do |scope|
@mock_warden.expects(:authenticate?).with(scope: scope).returns(false)
@mock_warden.expects(:authenticated?).with(scope: scope).returns(false)
end
@controller.commenter_signed_in?
end
@@ -81,7 +81,7 @@ class ControllerAuthenticatableTest < Devise::ControllerTestCase
test 'proxy authenticate_[group]! to authenticate!? with each scope' do
[:user, :admin].each do |scope|
@mock_warden.expects(:authenticate!).with(scope: scope)
@mock_warden.expects(:authenticate?).with(scope: scope).returns(false)
@mock_warden.expects(:authenticated?).with(scope: scope).returns(false)
end
@controller.authenticate_commenter!
end
@@ -91,18 +91,18 @@ class ControllerAuthenticatableTest < Devise::ControllerTestCase
@controller.authenticate_publisher_account!
end
test 'proxy user_signed_in? to authenticate with user scope' do
@mock_warden.expects(:authenticate).with(scope: :user).returns("user")
test 'proxy user_signed_in? to authenticated? with user scope' do
@mock_warden.expects(:authenticated?).with(scope: :user).returns("user")
assert @controller.user_signed_in?
end
test 'proxy admin_signed_in? to authenticatewith admin scope' do
@mock_warden.expects(:authenticate).with(scope: :admin)
test 'proxy admin_signed_in? to authenticated? with admin scope' do
@mock_warden.expects(:authenticated?).with(scope: :admin)
refute @controller.admin_signed_in?
end
test 'proxy publisher_account_signed_in? to authenticate with namespaced publisher account scope' do
@mock_warden.expects(:authenticate).with(scope: :publisher_account)
test 'proxy publisher_account_signed_in? to authenticated? with namespaced publisher account scope' do
@mock_warden.expects(:authenticated?).with(scope: :publisher_account)
@controller.publisher_account_signed_in?
end

View File

@@ -36,4 +36,10 @@ class PasswordsControllerTest < Devise::ControllerTestCase
User.any_instance.expects :after_database_authentication
put_update_with_params
end
test 'redirects to new_password_path when token has expired' do
@user.update(reset_password_sent_at: Time.now - 1.year)
put_update_with_params
assert_redirected_to new_user_password_path
end
end

View File

@@ -74,7 +74,7 @@ class SessionsControllerTest < Devise::ControllerTestCase
assert_template "devise/sessions/new"
end
test "#destroy doesn't set the flash if the requested format is not navigational" do
test "#destroy doesn't set the flash and returns 204 status if the requested format is not navigational" do
request.env["devise.mapping"] = Devise.mappings[:user]
user = create_user
user.confirm
@@ -88,6 +88,17 @@ class SessionsControllerTest < Devise::ControllerTestCase
assert_equal 204, @response.status
end
test "#destroy returns 401 status if user is not signed in and the requested format is not navigational" do
delete :destroy, format: 'json'
assert_equal 401, @response.status
end
test "#destroy returns 302 status if user is not signed in and the requested format is navigational" do
request.env["devise.mapping"] = Devise.mappings[:user]
delete :destroy
assert_equal 302, @response.status
end
if defined?(ActiveRecord) && ActiveRecord::Base.respond_to?(:mass_assignment_sanitizer)
test "#new doesn't raise mass-assignment exception even if sign-in key is attr_protected" do
request.env["devise.mapping"] = Devise.mappings[:user]

View File

@@ -90,11 +90,14 @@ class DeviseTest < ActiveSupport::TestCase
[nil, ""].each do |empty|
refute Devise.secure_compare(empty, "something")
refute Devise.secure_compare("something", empty)
refute Devise.secure_compare(empty, empty)
end
refute Devise.secure_compare("size_1", "size_four")
end
test 'Devise.secure_compare should return true if strings are same' do
assert Devise.secure_compare('', '')
end
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", "test@tt", "test@valid---domain.com"]
non_valid_emails = ["rex", "test user@example.com", "test_user@example server.com"]

View File

@@ -185,17 +185,27 @@ class FailureTest < ActiveSupport::TestCase
test 'uses the proxy failure message as symbol' do
call_failure('warden' => OpenStruct.new(message: :invalid))
assert_equal 'Invalid Email or password.', @request.flash[:alert]
assert_equal 'Invalid email or password.', @request.flash[:alert]
assert_equal 'http://test.host/users/sign_in', @response.second["Location"]
end
test 'supports authentication_keys as a Hash for the flash message' do
swap Devise, authentication_keys: { email: true, login: true } do
call_failure('warden' => OpenStruct.new(message: :invalid))
assert_equal 'Invalid Email, Login or password.', @request.flash[:alert]
assert_equal 'Invalid email, login or password.', @request.flash[:alert]
end
end
test 'downcases authentication_keys for the flash message' do
call_failure('warden' => OpenStruct.new(message: :invalid))
assert_equal 'Invalid email or password.', @request.flash[:alert]
end
test 'humanizes the flash message' do
call_failure('warden' => OpenStruct.new(message: :invalid))
assert_equal @request.flash[:alert], @request.flash[:alert].humanize
end
test 'uses custom i18n options' do
call_failure('warden' => OpenStruct.new(message: :does_not_exist), app: FailureWithI18nOptions)
assert_equal 'User Steve does not exist', @request.flash[:alert]
@@ -278,7 +288,7 @@ class FailureTest < ActiveSupport::TestCase
test 'uses the failure message as response body' do
call_failure('formats' => Mime[:xml], 'warden' => OpenStruct.new(message: :invalid))
assert_match '<error>Invalid Email or password.</error>', @response.third.body
assert_match '<error>Invalid email or password.</error>', @response.third.body
end
context 'on ajax call' do
@@ -327,7 +337,7 @@ class FailureTest < ActiveSupport::TestCase
}
call_failure(env)
assert @response.third.body.include?('<h2>Log in</h2>')
assert @response.third.body.include?('Invalid Email or password.')
assert @response.third.body.include?('Invalid email or password.')
end
test 'calls the original controller if not confirmed email' do
@@ -362,7 +372,7 @@ class FailureTest < ActiveSupport::TestCase
}
call_failure(env)
assert @response.third.body.include?('<h2>Log in</h2>')
assert @response.third.body.include?('Invalid Email or password.')
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

View File

@@ -48,7 +48,6 @@ if DEVISE_ORM == :active_record
run_generator %w(monster)
assert_file "app/models/monster.rb"
run_generator %w(monster)
if Rails.version >= '5.0.3'
assert_migration "db2/migrate/add_devise_to_monsters.rb"
else
@@ -84,11 +83,7 @@ if DEVISE_ORM == :active_record
test "add primary key type with rails 5 when specified in rails generator" do
run_generator ["monster", "--primary_key_type=uuid"]
if Devise::Test.rails5_and_up?
assert_migration "db/migrate/devise_create_monsters.rb", /create_table :monsters, id: :uuid do/
else
assert_migration "db/migrate/devise_create_monsters.rb", /create_table :monsters do/
end
assert_migration "db/migrate/devise_create_monsters.rb", /create_table :monsters, id: :uuid do/
end
end

View File

@@ -11,16 +11,19 @@ class ViewsGeneratorTest < Rails::Generators::TestCase
run_generator
assert_files
assert_shared_links
assert_error_messages
end
test "Assert all views are properly created with scope param" do
run_generator %w(users)
assert_files "users"
assert_shared_links "users"
assert_error_messages "users"
run_generator %w(admins)
assert_files "admins"
assert_shared_links "admins"
assert_error_messages "admins"
end
test "Assert views with simple form" do
@@ -88,6 +91,7 @@ class ViewsGeneratorTest < Rails::Generators::TestCase
assert_file "app/views/#{scope}/registrations/edit.html.erb"
assert_file "app/views/#{scope}/sessions/new.html.erb"
assert_file "app/views/#{scope}/shared/_links.html.erb"
assert_file "app/views/#{scope}/shared/_error_messages.html.erb"
assert_file "app/views/#{scope}/unlocks/new.html.erb"
end
@@ -102,4 +106,16 @@ class ViewsGeneratorTest < Rails::Generators::TestCase
assert_file "app/views/#{scope}/sessions/new.html.erb", link
assert_file "app/views/#{scope}/unlocks/new.html.erb", link
end
def assert_error_messages(scope = nil)
scope = "devise" if scope.nil?
link = /<%= render \"#{scope}\/shared\/error_messages\", resource: resource %>/
assert_file "app/views/#{scope}/passwords/edit.html.erb", link
assert_file "app/views/#{scope}/passwords/new.html.erb", link
assert_file "app/views/#{scope}/confirmations/new.html.erb", link
assert_file "app/views/#{scope}/registrations/new.html.erb", link
assert_file "app/views/#{scope}/registrations/edit.html.erb", link
assert_file "app/views/#{scope}/unlocks/new.html.erb", link
end
end

View File

@@ -557,7 +557,7 @@ class AuthenticationKeysTest < Devise::IntegrationTest
test 'missing authentication keys cause authentication to abort' do
swap Devise, authentication_keys: [:subdomain] do
sign_in_as_user
assert_contain "Invalid Subdomain or password."
assert_contain "Invalid subdomain or password."
refute warden.authenticated?(:user)
end
end
@@ -596,7 +596,7 @@ class AuthenticationRequestKeysTest < Devise::IntegrationTest
swap Devise, request_keys: [:subdomain] do
sign_in_as_user
assert_contain "Invalid Email or password."
assert_contain "Invalid email or password."
refute warden.authenticated?(:user)
end
end

View File

@@ -142,7 +142,7 @@ class ConfirmationTest < Devise::IntegrationTest
fill_in 'password', with: 'invalid'
end
assert_contain 'Invalid Email or password'
assert_contain 'Invalid email or password'
refute warden.authenticated?(:user)
end
end
@@ -175,6 +175,36 @@ class ConfirmationTest < Devise::IntegrationTest
assert_current_url '/users/sign_in'
end
test "should not be able to confirm an email with a blank confirmation token" do
visit_user_confirmation_with_token("")
assert_contain "Confirmation token can't be blank"
end
test "should not be able to confirm an email with a nil confirmation token" do
visit_user_confirmation_with_token(nil)
assert_contain "Confirmation token can't be blank"
end
test "should not be able to confirm user with blank confirmation token" do
user = create_user(confirm: false)
user.update_attribute(:confirmation_token, "")
visit_user_confirmation_with_token("")
assert_contain "Confirmation token can't be blank"
end
test "should not be able to confirm user with nil confirmation token" do
user = create_user(confirm: false)
user.update_attribute(:confirmation_token, nil)
visit_user_confirmation_with_token(nil)
assert_contain "Confirmation token can't be blank"
end
test 'error message is configurable by resource name' do
store_translations :en, devise: {
failure: { user: { unconfirmed: "Not confirmed user" } }

View File

@@ -70,7 +70,7 @@ class DatabaseAuthenticationTest < Devise::IntegrationTest
fill_in 'password', with: 'abcdef'
end
assert_contain 'Invalid Email or password'
assert_contain 'Invalid email or password'
refute warden.authenticated?(:admin)
end
@@ -82,7 +82,7 @@ class DatabaseAuthenticationTest < Devise::IntegrationTest
end
assert_not_contain 'Not found in database'
assert_contain 'Invalid Email or password.'
assert_contain 'Invalid email or password.'
end
end
end

View File

@@ -52,7 +52,7 @@ class HttpAuthenticationTest < Devise::IntegrationTest
sign_in_as_new_user_with_http("unknown")
assert_equal 401, status
assert_equal "application/xml; charset=utf-8", headers["Content-Type"]
assert_match "<error>Invalid Email or password.</error>", response.body
assert_match "<error>Invalid email or password.</error>", response.body
end
test 'returns a custom response with www-authenticate and chosen realm' do

View File

@@ -104,7 +104,7 @@ class LockTest < Devise::IntegrationTest
test 'error message is configurable by resource name' do
store_translations :en, devise: {
failure: {user: {locked: "You are locked!"}}
failure: {user: {locked: { both: "You are locked!" }}}
} do
user = create_user(locked: true)
@@ -118,7 +118,7 @@ class LockTest < Devise::IntegrationTest
test "user should not be able to sign in when locked" do
store_translations :en, devise: {
failure: {user: {locked: "You are locked!"}}
failure: {user: {locked: {both: "You are locked!"}}}
} do
user = create_user(locked: true)

View File

@@ -152,6 +152,19 @@ class PasswordTest < Devise::IntegrationTest
refute user.reload.valid_password?('987654321')
end
test 'not authenticated user with expired reset password token should be redirected to new password path' do
user = create_user
request_forgot_password
user.update(reset_password_sent_at: Time.now - 1.year)
visit edit_user_password_path(reset_password_token: 'abcdef')
fill_in 'New password', with: '987654321'
fill_in 'Confirm new password', with: '987654321'
click_button 'Change my password'
assert_contain 'The password recovery link expired. Please request a new one.'
end
test 'not authenticated user with valid reset password token but invalid password should not be able to change their password' do
user = create_user
request_forgot_password

View File

@@ -14,10 +14,8 @@ class RememberMeTest < Devise::IntegrationTest
def generate_signed_cookie(raw_cookie)
request = if Devise::Test.rails51? || Devise::Test.rails52_and_up?
ActionController::TestRequest.create(Class.new) # needs a "controller class"
elsif Devise::Test.rails5?
ActionController::TestRequest.create
else
ActionController::TestRequest.new
ActionController::TestRequest.create
end
request.cookie_jar.signed['raw_cookie'] = raw_cookie
request.cookie_jar['raw_cookie']

View File

@@ -95,5 +95,4 @@ class TrackableHooksTest < Devise::IntegrationTest
user.reload
assert_equal 1, user.sign_in_count
end
end

View File

@@ -77,6 +77,24 @@ class ConfirmableTest < ActiveSupport::TestCase
assert_equal "can't be blank", confirmed_user.errors[:confirmation_token].join
end
test 'should return a new record with errors when a blank token is given and a record exists on the database' do
user = create_user(confirmation_token: '')
confirmed_user = User.confirm_by_token('')
refute user.reload.confirmed?
assert_equal "can't be blank", confirmed_user.errors[:confirmation_token].join
end
test 'should return a new record with errors when a nil token is given and a record exists on the database' do
user = create_user(confirmation_token: nil)
confirmed_user = User.confirm_by_token(nil)
refute user.reload.confirmed?
assert_equal "can't be blank", confirmed_user.errors[:confirmation_token].join
end
test 'should generate errors for a user email if user is already confirmed' do
user = create_user
user.confirmed_at = Time.now

View File

@@ -312,7 +312,7 @@ class LockableTest < ActiveSupport::TestCase
end
test 'should return last attempt message if user made next-to-last attempt of password entering' do
swap Devise, last_attempt_warning: true, lock_strategy: :failed_attempts do
swap Devise, last_attempt_warning: true, lock_strategy: :failed_attempts, unlock_strategy: :none do
user = create_user
user.failed_attempts = Devise.maximum_attempts - 2
assert_equal :invalid, user.unauthenticated_message
@@ -321,7 +321,7 @@ class LockableTest < ActiveSupport::TestCase
assert_equal :last_attempt, user.unauthenticated_message
user.failed_attempts = Devise.maximum_attempts
assert_equal :locked, user.unauthenticated_message
assert_equal :'locked.none', user.unauthenticated_message
end
end
@@ -336,7 +336,22 @@ class LockableTest < ActiveSupport::TestCase
test 'should return locked message if user was programatically locked' do
user = create_user
user.lock_access!
assert_equal :locked, user.unauthenticated_message
swap Devise, unlock_strategy: :none do
assert_equal :'locked.none', user.unauthenticated_message
end
swap Devise, unlock_strategy: :both do
assert_equal :'locked.both', user.unauthenticated_message
end
swap Devise, unlock_strategy: :email do
assert_equal :'locked.email', user.unauthenticated_message
end
swap Devise, unlock_strategy: :time do
assert_equal :'locked.time', user.unauthenticated_message
end
end
test 'unlock_strategy_enabled? should return true for both, email, and time strategies if :both is used' do

View File

@@ -60,6 +60,39 @@ class TrackableTest < ActiveSupport::TestCase
assert_not user.update_tracked_fields!(request)
end
test "update_tracked_fields! runs when isn't a new record and the validations are ok" do
user = create_user
user.stubs(:active_for_authentication?).returns(true)
request = mock
request.stubs(:remote_ip).returns("127.0.0.1")
request.stubs(:env).returns('devise.skip_trackable' => nil)
assert user.update_tracked_fields!(request)
end
test "update_tracked_fields! should not run when skip trackable is turned on" do
user = create_user
user.stubs(:active_for_authentication?).returns(true)
request = mock
request.stubs(:remote_ip).returns("127.0.0.1")
request.stubs(:env).returns('devise.skip_trackable' => 1)
assert_not user.update_tracked_fields!(request)
end
test "update_tracked_fields! should not run when the user is not active for authentication" do
user = create_user
user.stubs(:active_for_authentication?).returns(false)
request = mock
request.stubs(:remote_ip).returns("127.0.0.1")
request.stubs(:env).returns('devise.skip_trackable' => nil)
assert_not user.update_tracked_fields!(request)
end
test 'extract_ip_from should be overridable' do
class UserWithOverride < User
protected

View File

@@ -14,13 +14,7 @@ else
end
class ActiveSupport::TestCase
if Devise::Test.rails5_and_up?
self.use_transactional_tests = true
else
# Let `after_commit` work with transactional fixtures, however this is not needed for Rails 5.
require 'test_after_commit'
self.use_transactional_fixtures = true
end
self.use_transactional_tests = true
self.use_instantiated_fixtures = false
end

View File

@@ -5,7 +5,7 @@ require 'shared_user'
class User < ActiveRecord::Base
include Shim
include SharedUser
include ActiveModel::Serializers::Xml if Devise::Test.rails5_and_up?
include ActiveModel::Serializers::Xml
validates :sign_in_count, presence: true

View File

@@ -22,10 +22,6 @@ class HomeController < ApplicationController
end
def unauthenticated
if Devise::Test.rails5_and_up?
render body: "unauthenticated", status: :unauthorized
else
render text: "unauthenticated", status: :unauthorized
end
render body: "unauthenticated", status: :unauthorized
end
end

View File

@@ -11,6 +11,6 @@ class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
user = User.to_adapter.find_first(email: 'user@test.com')
user.remember_me = true
sign_in user
render (Devise::Test.rails5_and_up? ? :body : :text) => ""
render body: ""
end
end

View File

@@ -15,7 +15,7 @@ class UsersController < ApplicationController
end
def update_form
render (Devise::Test.rails5_and_up? ? :body : :text) => 'Update'
render body: 'Update'
end
def accept
@@ -23,11 +23,11 @@ class UsersController < ApplicationController
end
def exhibit
render (Devise::Test.rails5_and_up? ? :body : :text) => current_user ? "User is authenticated" : "User is not authenticated"
render body: current_user ? "User is authenticated" : "User is not authenticated"
end
def expire
user_session['last_request_at'] = 31.minutes.ago.utc
render (Devise::Test.rails5_and_up? ? :body : :text) => 'User will be expired on next request'
render body: 'User will be expired on next request'
end
end

View File

@@ -33,12 +33,6 @@ module RailsApp
# config.assets.enabled = false
config.action_mailer.default_url_options = { host: "localhost", port: 3000 }
rails_version = Gem::Version.new(Rails.version)
if DEVISE_ORM == :active_record &&
rails_version >= Gem::Version.new('4.2.0') &&
rails_version < Gem::Version.new('5.1.0')
config.active_record.raise_in_transactional_callbacks = true
end
# This was used to break devise in some situations
config.to_prepare do

View File

@@ -7,7 +7,6 @@ end
module Devise
module Test
# Detection for minor differences between Rails versions in tests.
def self.rails6?
Rails.version.start_with? '6'
end
@@ -23,14 +22,6 @@ module Devise
def self.rails51?
Rails.version.start_with? '5.1'
end
def self.rails5_and_up?
Rails::VERSION::MAJOR >= 5
end
def self.rails5?
Rails.version.start_with? '5'
end
end
end

View File

@@ -22,13 +22,7 @@ RailsApp::Application.configure do
# config.action_dispatch.rack_cache = true
# Disable Rails's static asset server (Apache or nginx will already do this).
if Devise::Test.rails5_and_up?
config.public_file_server.enabled = false
elsif Rails.version >= "4.2.0"
config.serve_static_files = false
else
config.serve_static_assets = false
end
config.public_file_server.enabled = false
# Compress JavaScripts and CSS.
config.assets.js_compressor = :uglifier

View File

@@ -16,16 +16,8 @@ RailsApp::Application.configure do
# Disable serving static files from the `/public` folder by default since
# Apache or NGINX already handles this.
if Devise::Test.rails5_and_up?
config.public_file_server.enabled = true
config.public_file_server.headers = {'Cache-Control' => 'public, max-age=3600'}
elsif Rails.version >= "4.2.0"
config.serve_static_files = true
config.static_cache_control = "public, max-age=3600"
else
config.serve_static_assets = true
config.static_cache_control = "public, max-age=3600"
end
config.public_file_server.enabled = true
config.public_file_server.headers = {'Cache-Control' => 'public, max-age=3600'}
# Show full error reports and disable caching.
config.consider_all_requests_local = true

View File

@@ -1,10 +1,6 @@
# frozen_string_literal: true
superclass = ActiveRecord::Migration
# TODO: Inherit from the 5.0 Migration class directly when we drop support for Rails 4.
superclass = ActiveRecord::Migration[5.0] if superclass.respond_to?(:[])
class CreateTables < superclass
class CreateTables < ActiveRecord::Migration[5.0]
def self.up
create_table :users do |t|
t.string :username

View File

@@ -204,8 +204,7 @@ class CustomizedRoutingTest < ActionController::TestCase
end
test 'map with format false for sessions' do
expected_params = {controller: 'devise/sessions', action: 'new'}
expected_params[:format] = false if Devise::Test.rails5_and_up?
expected_params = {controller: 'devise/sessions', action: 'new', format: false}
assert_recognizes(expected_params, {path: '/htmlonly_admin/sign_in', method: :get})
assert_raise ExpectedRoutingError do
@@ -214,8 +213,7 @@ class CustomizedRoutingTest < ActionController::TestCase
end
test 'map with format false for passwords' do
expected_params = {controller: 'devise/passwords', action: 'create'}
expected_params[:format] = false if Devise::Test.rails5_and_up?
expected_params = {controller: 'devise/passwords', action: 'create', format: false}
assert_recognizes(expected_params, {path: '/htmlonly_admin/password', method: :post})
assert_raise ExpectedRoutingError do
@@ -224,8 +222,7 @@ class CustomizedRoutingTest < ActionController::TestCase
end
test 'map with format false for registrations' do
expected_params = {controller: 'devise/registrations', action: 'new'}
expected_params[:format] = false if Devise::Test.rails5_and_up?
expected_params = {controller: 'devise/registrations', action: 'new', format: false}
assert_recognizes(expected_params, {path: '/htmlonly_admin/sign_up', method: :get})
assert_raise ExpectedRoutingError do
@@ -234,8 +231,7 @@ class CustomizedRoutingTest < ActionController::TestCase
end
test 'map with format false for confirmations' do
expected_params = {controller: 'devise/confirmations', action: 'show'}
expected_params[:format] = false if Devise::Test.rails5_and_up?
expected_params = {controller: 'devise/confirmations', action: 'show', format: false}
assert_recognizes(expected_params, {path: '/htmlonly_users/confirmation', method: :get})
assert_raise ExpectedRoutingError do
@@ -244,8 +240,7 @@ class CustomizedRoutingTest < ActionController::TestCase
end
test 'map with format false for unlocks' do
expected_params = {controller: 'devise/unlocks', action: 'show'}
expected_params[:format] = false if Devise::Test.rails5_and_up?
expected_params = {controller: 'devise/unlocks', action: 'show', format: false}
assert_recognizes(expected_params, {path: '/htmlonly_users/unlock', method: :get})
assert_raise ExpectedRoutingError do

View File

@@ -44,38 +44,12 @@ class Rails52SecretKeyBase
def config
OpenStruct.new(secret_key_base: nil)
end
def secret_key_base
'secret_key_base'
end
end
class Rails41Secrets
def secrets
OpenStruct.new(secret_key_base: 'secrets')
end
def config
OpenStruct.new(secret_key_base: nil)
end
end
class Rails41Config
def secrets
OpenStruct.new(secret_key_base: nil)
end
def config
OpenStruct.new(secret_key_base: 'config')
end
end
class Rails40Config
def config
OpenStruct.new(secret_key_base: 'config')
end
end
class SecretKeyFinderTest < ActiveSupport::TestCase
test "rails 5.2 uses credentials when they're available" do
secret_key_finder = Devise::SecretKeyFinder.new(Rails52Credentials.new)
@@ -100,22 +74,4 @@ class SecretKeyFinderTest < ActiveSupport::TestCase
assert_equal 'secret_key_base', secret_key_finder.find
end
test "rails 4.1 uses secrets" do
secret_key_finder = Devise::SecretKeyFinder.new(Rails41Secrets.new)
assert_equal 'secrets', secret_key_finder.find
end
test "rails 4.1 uses config when secrets are empty" do
secret_key_finder = Devise::SecretKeyFinder.new(Rails41Config.new)
assert_equal 'config', secret_key_finder.find
end
test "rails 4.0 uses config" do
secret_key_finder = Devise::SecretKeyFinder.new(Rails40Config.new)
assert_equal 'config', secret_key_finder.find
end
end

View File

@@ -6,21 +6,11 @@ module Devise
# xhr get_via_redirect post_via_redirect
# ).each do |method|
%w( get post put ).each do |method|
if Devise::Test.rails5_and_up?
define_method(method) do |url, options={}|
if options.empty?
super url
else
super url, options
end
end
else
define_method(method) do |url, options={}|
if options[:xhr]==true
xml_http_request __method__, url, options[:params] || {}, options[:headers]
else
super url, options[:params] || {}, options[:headers]
end
define_method(method) do |url, options={}|
if options.empty?
super url
else
super url, options
end
end
end
@@ -31,21 +21,11 @@ module Devise
# xhr get_via_redirect post_via_redirect
# ).each do |method|
%w( get post put ).each do |method|
if Devise::Test.rails5_and_up?
define_method(method) do |action, options={}|
if options.empty?
super action
else
super action, options
end
end
else
define_method(method) do |action, options={}|
if options[:xhr]==true
xml_http_request __method__, action, options[:params] || {}, options[:headers]
else
super action, options[:params] || {}, options[:headers]
end
define_method(method) do |action, options={}|
if options.empty?
super action
else
super action, options
end
end
end

View File

@@ -178,10 +178,8 @@ class TestControllerHelpersTest < Devise::ControllerTestCase
@request = if Devise::Test.rails51? || Devise::Test.rails52_and_up?
ActionController::TestRequest.create(Class.new) # needs a "controller class"
elsif Devise::Test.rails5?
ActionController::TestRequest.create
else
ActionController::TestRequest.new
ActionController::TestRequest.create
end
new_warden_proxy = warden