mirror of
https://github.com/heartcombo/devise.git
synced 2026-01-10 08:08:00 -05:00
Compare commits
9 Commits
v4.0.0.rc1
...
v3.5.5
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8cbdeb54a5 | ||
|
|
14affc8a55 | ||
|
|
eb0f0b662f | ||
|
|
1516a0ae6d | ||
|
|
c92996646a | ||
|
|
ba5dd0a41a | ||
|
|
f63be5039a | ||
|
|
f25562fd4b | ||
|
|
2a2fd806a8 |
11
CHANGELOG.md
11
CHANGELOG.md
@@ -1,4 +1,13 @@
|
||||
### Unreleased
|
||||
### 3.5.5 - 2016-22-01
|
||||
|
||||
* bug fixes
|
||||
* Bring back remember_expired? implementation
|
||||
* Ensure timeouts are not triggered if remember me is being used
|
||||
|
||||
### 3.5.4 - 2016-18-01
|
||||
|
||||
* bug fixes
|
||||
* Store creation timestamps on remember cookies
|
||||
|
||||
### 3.5.3 - 2015-12-10
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
PATH
|
||||
remote: .
|
||||
specs:
|
||||
devise (3.5.3)
|
||||
devise (3.5.5)
|
||||
bcrypt (~> 3.0)
|
||||
orm_adapter (~> 0.1)
|
||||
railties (>= 3.2.6, < 5)
|
||||
@@ -139,8 +139,8 @@ GEM
|
||||
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 (3.2.0)
|
||||
rack (~> 1.0)
|
||||
@@ -180,4 +180,4 @@ DEPENDENCIES
|
||||
webrat (= 0.7.3)
|
||||
|
||||
BUNDLED WITH
|
||||
1.10.6
|
||||
1.11.2
|
||||
|
||||
@@ -116,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
|
||||
|
||||
@@ -9,11 +9,18 @@ module Devise
|
||||
Rails.configuration.session_options.slice(:path, :domain, :secure)
|
||||
end
|
||||
|
||||
def remember_me_is_active?(resource)
|
||||
return false unless resource.respond_to?(:remember_me)
|
||||
scope = Devise::Mapping.find_scope!(resource)
|
||||
cookie = cookies.signed[remember_key(resource, scope)]
|
||||
resource.class.serialized_in_cookie?(resource, *cookie)
|
||||
end
|
||||
|
||||
# Remembers the given resource by setting up a cookie
|
||||
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
|
||||
|
||||
|
||||
@@ -19,9 +19,10 @@ Warden::Manager.after_set_user do |record, warden, options|
|
||||
|
||||
proxy = Devise::Hooks::Proxy.new(warden)
|
||||
|
||||
if record.timedout?(last_request_at) && !env['devise.skip_timeout']
|
||||
if record.timedout?(last_request_at) &&
|
||||
!env['devise.skip_timeout'] &&
|
||||
!proxy.remember_me_is_active?(record)
|
||||
Devise.sign_out_all_scopes ? proxy.sign_out : proxy.sign_out(scope)
|
||||
|
||||
throw :warden, scope: scope, message: :timeout
|
||||
end
|
||||
|
||||
|
||||
@@ -254,7 +254,7 @@ module Devise
|
||||
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
|
||||
|
||||
@@ -83,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
|
||||
|
||||
@@ -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,19 +57,18 @@ 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)
|
||||
remember_created_at.nil?
|
||||
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
|
||||
@@ -102,29 +101,21 @@ module Devise
|
||||
def after_remembered
|
||||
end
|
||||
|
||||
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)
|
||||
serialize_from_cookie_with_or_without_record(nil, args)
|
||||
end
|
||||
|
||||
# Check if the given record is the one serialized in cookie
|
||||
def serialized_in_cookie?(record, *args)
|
||||
!!serialize_from_cookie_with_or_without_record(record, args)
|
||||
end
|
||||
|
||||
# Generate a token checking if one does not already exist in the database.
|
||||
@@ -135,6 +126,29 @@ module Devise
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def serialize_from_cookie_with_or_without_record(record, 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)) && (id == record.to_key) &&
|
||||
(generated_at > (record.remember_created_at || Time.now).utc) &&
|
||||
Devise.secure_compare(record.rememberable_value, token)
|
||||
record
|
||||
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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
module Devise
|
||||
VERSION = "3.5.3".freeze
|
||||
VERSION = "3.5.5".freeze
|
||||
end
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -175,7 +175,7 @@ class SessionTimeoutTest < ActionDispatch::IntegrationTest
|
||||
assert warden.authenticated?(:user)
|
||||
end
|
||||
|
||||
test 'does not crashes when the last_request_at is a String' do
|
||||
test 'does not crash when the last_request_at is a String' do
|
||||
user = sign_in_as_user
|
||||
|
||||
get edit_form_user_path(user, last_request_at: Time.now.utc.to_s)
|
||||
|
||||
@@ -486,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
|
||||
|
||||
@@ -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,13 +34,45 @@ 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 '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
|
||||
@@ -93,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!
|
||||
@@ -125,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
|
||||
|
||||
Reference in New Issue
Block a user