Fix #4555: Invalidate sessions for deleted users
Fix three exploits that allowed one to keep using their account after it was deleted: * It was possible to use session cookies from another computer to login after you deleted your account. * It was possible to use API keys to make API requests after you deleted your account. * It was possible to request a password reset, delete your account, then use the password reset link to change your password and login to your deleted account.
This commit is contained in:
@@ -150,10 +150,6 @@ class User < ApplicationRecord
|
||||
|
||||
accepts_nested_attributes_for :email_address, reject_if: :all_blank, allow_destroy: true
|
||||
|
||||
# UserDeletion#rename renames deleted users to `user_<1234>~`. Tildes
|
||||
# are appended if the username is taken.
|
||||
scope :deleted, -> { where("name ~ 'user_[0-9]+~*'") }
|
||||
scope :undeleted, -> { where("name !~ 'user_[0-9]+~*'") }
|
||||
scope :admins, -> { where(level: Levels::ADMIN) }
|
||||
scope :banned, -> { bit_prefs_match(:is_banned, true) }
|
||||
|
||||
@@ -161,6 +157,8 @@ class User < ApplicationRecord
|
||||
scope :has_private_favorites, -> { bit_prefs_match(:enable_private_favorites, true) }
|
||||
scope :has_public_favorites, -> { bit_prefs_match(:enable_private_favorites, false) }
|
||||
|
||||
deletable
|
||||
|
||||
module BanMethods
|
||||
def unban!
|
||||
self.is_banned = false
|
||||
@@ -224,16 +222,22 @@ class User < ApplicationRecord
|
||||
self.bcrypt_password_hash = BCrypt::Password.create(hash_password(new_password))
|
||||
end
|
||||
|
||||
# @return [User, Boolean] Return the user if the signed user ID is correct, or false if it isn't.
|
||||
def authenticate_login_key(signed_user_id)
|
||||
return false if is_deleted?
|
||||
signed_user_id.present? && id == Danbooru::MessageVerifier.new(:login).verify(signed_user_id) && self
|
||||
end
|
||||
|
||||
# @return [Array<(User, ApiKey)>, Boolean] Return a (User, ApiKey) pair if the API key is correct, or false if it isn't.
|
||||
def authenticate_api_key(key)
|
||||
return false if is_deleted?
|
||||
api_key = api_keys.find_by(key: key)
|
||||
api_key.present? && ActiveSupport::SecurityUtils.secure_compare(api_key.key, key) && [self, api_key]
|
||||
end
|
||||
|
||||
# @return [User, Boolean] Return the user if the password is correct, or false if it isn't.
|
||||
def authenticate_password(password)
|
||||
return false if is_deleted?
|
||||
BCrypt::Password.new(bcrypt_password_hash) == hash_password(password) && self
|
||||
end
|
||||
|
||||
@@ -300,10 +304,6 @@ class User < ApplicationRecord
|
||||
User.level_string(value || level)
|
||||
end
|
||||
|
||||
def is_deleted?
|
||||
name.match?(/\Auser_[0-9]+~*\z/)
|
||||
end
|
||||
|
||||
def is_anonymous?
|
||||
level == Levels::ANONYMOUS
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user