mirror of
https://github.com/heartcombo/devise.git
synced 2022-11-09 12:18:31 -05:00
Fix some unlockable bugs.
This commit is contained in:
parent
97b7ba8659
commit
2a082f3e4c
7 changed files with 48 additions and 53 deletions
|
@ -1,4 +1,5 @@
|
||||||
class Devise::UnlocksController < ApplicationController
|
class Devise::UnlocksController < ApplicationController
|
||||||
|
prepend_before_filter :ensure_email_as_unlock_strategy
|
||||||
prepend_before_filter :require_no_authentication
|
prepend_before_filter :require_no_authentication
|
||||||
include Devise::Controllers::InternalHelpers
|
include Devise::Controllers::InternalHelpers
|
||||||
|
|
||||||
|
@ -31,4 +32,10 @@ class Devise::UnlocksController < ApplicationController
|
||||||
render_with_scope :new
|
render_with_scope :new
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
protected
|
||||||
|
|
||||||
|
def ensure_email_as_unlock_strategy
|
||||||
|
raise ActionController::UnknownAction unless resource_class.unlock_strategy_enabled?(:email)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -57,15 +57,9 @@ module Devise
|
||||||
::Devise::Mailer.confirmation_instructions(self).deliver
|
::Devise::Mailer.confirmation_instructions(self).deliver
|
||||||
end
|
end
|
||||||
|
|
||||||
# Remove confirmation date and send confirmation instructions, to ensure
|
# Resend confirmation token. This method does not need to generate a new token.
|
||||||
# after sending these instructions the user won't be able to sign in without
|
|
||||||
# confirming it's account
|
|
||||||
def resend_confirmation_token
|
def resend_confirmation_token
|
||||||
unless_confirmed do
|
unless_confirmed { send_confirmation_instructions }
|
||||||
generate_confirmation_token
|
|
||||||
save(:validate => false)
|
|
||||||
send_confirmation_instructions
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Overwrites active? from Devise::Models::Activatable for confirmation
|
# Overwrites active? from Devise::Models::Activatable for confirmation
|
||||||
|
|
|
@ -23,9 +23,10 @@ module Devise
|
||||||
|
|
||||||
# Lock an user setting it's locked_at to actual time.
|
# Lock an user setting it's locked_at to actual time.
|
||||||
def lock_access!
|
def lock_access!
|
||||||
|
return true if access_locked?
|
||||||
self.locked_at = Time.now
|
self.locked_at = Time.now
|
||||||
|
|
||||||
if unlock_strategy_enabled?(:email)
|
if self.class.unlock_strategy_enabled?(:email)
|
||||||
generate_unlock_token
|
generate_unlock_token
|
||||||
send_unlock_instructions
|
send_unlock_instructions
|
||||||
end
|
end
|
||||||
|
@ -55,11 +56,7 @@ module Devise
|
||||||
|
|
||||||
# Resend the unlock instructions if the user is locked.
|
# Resend the unlock instructions if the user is locked.
|
||||||
def resend_unlock_token
|
def resend_unlock_token
|
||||||
if_access_locked do
|
if_access_locked { send_unlock_instructions }
|
||||||
generate_unlock_token unless unlock_token.present?
|
|
||||||
save(:validate => false)
|
|
||||||
send_unlock_instructions
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Overwrites active? from Devise::Models::Activatable for locking purposes
|
# Overwrites active? from Devise::Models::Activatable for locking purposes
|
||||||
|
@ -82,10 +79,7 @@ module Devise
|
||||||
self.failed_attempts = 0
|
self.failed_attempts = 0
|
||||||
else
|
else
|
||||||
self.failed_attempts += 1
|
self.failed_attempts += 1
|
||||||
if failed_attempts > self.class.maximum_attempts
|
lock_access! if failed_attempts > self.class.maximum_attempts
|
||||||
lock_access!
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
save(:validate => false) if changed?
|
save(:validate => false) if changed?
|
||||||
result
|
result
|
||||||
|
@ -100,7 +94,7 @@ module Devise
|
||||||
|
|
||||||
# Tells if the lock is expired if :time unlock strategy is active
|
# Tells if the lock is expired if :time unlock strategy is active
|
||||||
def lock_expired?
|
def lock_expired?
|
||||||
if unlock_strategy_enabled?(:time)
|
if self.class.unlock_strategy_enabled?(:time)
|
||||||
locked_at && locked_at < self.class.unlock_in.ago
|
locked_at && locked_at < self.class.unlock_in.ago
|
||||||
else
|
else
|
||||||
false
|
false
|
||||||
|
@ -118,11 +112,6 @@ module Devise
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Is the unlock enabled for the given unlock strategy?
|
|
||||||
def unlock_strategy_enabled?(strategy)
|
|
||||||
[:both, strategy].include?(self.class.unlock_strategy)
|
|
||||||
end
|
|
||||||
|
|
||||||
module ClassMethods
|
module ClassMethods
|
||||||
# Attempt to find a user by it's email. If a record is found, send new
|
# Attempt to find a user by it's email. If a record is found, send new
|
||||||
# unlock instructions to it. If not user is found, returns a new user
|
# unlock instructions to it. If not user is found, returns a new user
|
||||||
|
@ -144,6 +133,11 @@ module Devise
|
||||||
lockable
|
lockable
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Is the unlock enabled for the given unlock strategy?
|
||||||
|
def unlock_strategy_enabled?(strategy)
|
||||||
|
[:both, strategy].include?(self.unlock_strategy)
|
||||||
|
end
|
||||||
|
|
||||||
Devise::Models.config(self, :maximum_attempts, :unlock_strategy, :unlock_in)
|
Devise::Models.config(self, :maximum_attempts, :unlock_strategy, :unlock_in)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -36,6 +36,15 @@ class LockTest < ActionController::IntegrationTest
|
||||||
assert_equal 0, ActionMailer::Base.deliveries.size
|
assert_equal 0, ActionMailer::Base.deliveries.size
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test 'unlocked pages should not be available if email strategy is disabled' do
|
||||||
|
visit new_user_unlock_path
|
||||||
|
swap Devise, :unlock_strategy => :time do
|
||||||
|
assert_raise AbstractController::ActionNotFound do
|
||||||
|
visit new_user_unlock_path
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
test 'user with invalid unlock token should not be able to unlock an account' do
|
test 'user with invalid unlock token should not be able to unlock an account' do
|
||||||
visit_user_unlock_with_token('invalid_token')
|
visit_user_unlock_with_token('invalid_token')
|
||||||
|
|
||||||
|
@ -60,7 +69,6 @@ class LockTest < ActionController::IntegrationTest
|
||||||
test "sign in user automatically after unlocking it's account" do
|
test "sign in user automatically after unlocking it's account" do
|
||||||
user = create_user(:locked => true)
|
user = create_user(:locked => true)
|
||||||
visit_user_unlock_with_token(user.unlock_token)
|
visit_user_unlock_with_token(user.unlock_token)
|
||||||
|
|
||||||
assert warden.authenticated?(:user)
|
assert warden.authenticated?(:user)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -71,6 +79,16 @@ class LockTest < ActionController::IntegrationTest
|
||||||
assert_not warden.authenticated?(:user)
|
assert_not warden.authenticated?(:user)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "user should not send a new e-mail if already locked" do
|
||||||
|
user = create_user(:locked => true)
|
||||||
|
user.update_attribute(:failed_attempts, User.maximum_attempts + 1)
|
||||||
|
ActionMailer::Base.deliveries.clear
|
||||||
|
|
||||||
|
sign_in_as_user(:password => "invalid")
|
||||||
|
assert_contain 'Invalid email or password.'
|
||||||
|
assert ActionMailer::Base.deliveries.empty?
|
||||||
|
end
|
||||||
|
|
||||||
test 'error message is configurable by resource name' do
|
test 'error message is configurable by resource name' do
|
||||||
store_translations :en, :devise => {
|
store_translations :en, :devise => {
|
||||||
:sessions => { :admin => { :locked => "You are locked!" } }
|
:sessions => { :admin => { :locked => "You are locked!" } }
|
||||||
|
|
|
@ -11,15 +11,6 @@ class ConfirmableTest < ActiveSupport::TestCase
|
||||||
assert_not_nil create_user.confirmation_token
|
assert_not_nil create_user.confirmation_token
|
||||||
end
|
end
|
||||||
|
|
||||||
test 'should regenerate confirmation token each time' do
|
|
||||||
user = create_user
|
|
||||||
3.times do
|
|
||||||
token = user.confirmation_token
|
|
||||||
user.resend_confirmation_token
|
|
||||||
assert_not_equal token, user.confirmation_token
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
test 'should never generate the same confirmation token for different users' do
|
test 'should never generate the same confirmation token for different users' do
|
||||||
confirmation_tokens = []
|
confirmation_tokens = []
|
||||||
3.times do
|
3.times do
|
||||||
|
@ -137,13 +128,6 @@ class ConfirmableTest < ActiveSupport::TestCase
|
||||||
assert_equal "not found", confirmation_user.errors[:email].join
|
assert_equal "not found", confirmation_user.errors[:email].join
|
||||||
end
|
end
|
||||||
|
|
||||||
test 'should generate a confirmation token before send the confirmation instructions email' do
|
|
||||||
user = create_user
|
|
||||||
token = user.confirmation_token
|
|
||||||
confirmation_user = User.send_confirmation_instructions(:email => user.email)
|
|
||||||
assert_not_equal token, user.reload.confirmation_token
|
|
||||||
end
|
|
||||||
|
|
||||||
test 'should send email instructions for the user confirm it\'s email' do
|
test 'should send email instructions for the user confirm it\'s email' do
|
||||||
user = create_user
|
user = create_user
|
||||||
assert_email_sent do
|
assert_email_sent do
|
||||||
|
|
|
@ -37,7 +37,7 @@ class LockableTest < ActiveSupport::TestCase
|
||||||
assert_equal 0, user.reload.failed_attempts
|
assert_equal 0, user.reload.failed_attempts
|
||||||
end
|
end
|
||||||
|
|
||||||
test "should verify wheter a user is locked or not" do
|
test "should verify whether a user is locked or not" do
|
||||||
user = create_user
|
user = create_user
|
||||||
assert_not user.access_locked?
|
assert_not user.access_locked?
|
||||||
user.lock_access!
|
user.lock_access!
|
||||||
|
@ -64,6 +64,14 @@ class LockableTest < ActiveSupport::TestCase
|
||||||
assert 0, user.reload.failed_attempts
|
assert 0, user.reload.failed_attempts
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "should not lock a locked account" do
|
||||||
|
user = create_user
|
||||||
|
user.lock_access!
|
||||||
|
assert_no_difference "ActionMailer::Base.deliveries.size" do
|
||||||
|
user.lock_access!
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
test 'should not unlock an unlocked user' do
|
test 'should not unlock an unlocked user' do
|
||||||
user = create_user
|
user = create_user
|
||||||
assert_not user.unlock_access!
|
assert_not user.unlock_access!
|
||||||
|
@ -101,16 +109,6 @@ class LockableTest < ActiveSupport::TestCase
|
||||||
assert_not_nil user.unlock_token
|
assert_not_nil user.unlock_token
|
||||||
end
|
end
|
||||||
|
|
||||||
test 'should not regenerate unlock token if it already exists' do
|
|
||||||
user = create_user
|
|
||||||
user.lock!
|
|
||||||
3.times do
|
|
||||||
token = user.unlock_token
|
|
||||||
user.resend_unlock_token
|
|
||||||
assert_equal token, user.unlock_token
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
test "should never generate the same unlock token for different users" do
|
test "should never generate the same unlock token for different users" do
|
||||||
unlock_tokens = []
|
unlock_tokens = []
|
||||||
3.times do
|
3.times do
|
||||||
|
|
|
@ -33,7 +33,7 @@ class ActionDispatch::IntegrationTest
|
||||||
user = create_user(options)
|
user = create_user(options)
|
||||||
get new_user_session_path unless options[:visit] == false
|
get new_user_session_path unless options[:visit] == false
|
||||||
fill_in 'email', :with => 'user@test.com'
|
fill_in 'email', :with => 'user@test.com'
|
||||||
fill_in 'password', :with => '123456'
|
fill_in 'password', :with => options[:password] || '123456'
|
||||||
check 'remember me' if options[:remember_me] == true
|
check 'remember me' if options[:remember_me] == true
|
||||||
yield if block_given?
|
yield if block_given?
|
||||||
click_button 'Sign In'
|
click_button 'Sign In'
|
||||||
|
|
Loading…
Reference in a new issue