mirror of
https://github.com/basecamp/once-campfire.git
synced 2026-10-27 07:56:48 +09:00
A digest cached earlier in the request would let the check pass on a password that has since changed.
29 lines
1.0 KiB
Ruby
29 lines
1.0 KiB
Ruby
class Session < ApplicationRecord
|
|
ACTIVITY_REFRESH_RATE = 1.hour
|
|
|
|
has_secure_token
|
|
|
|
belongs_to :user
|
|
|
|
before_create { self.last_active_at ||= Time.now }
|
|
|
|
validate :user_password_unchanged, on: :create
|
|
|
|
def resume(user_agent:, ip_address:)
|
|
if last_active_at.before?(ACTIVITY_REFRESH_RATE.ago)
|
|
update! user_agent: user_agent, ip_address: ip_address, last_active_at: Time.now
|
|
end
|
|
end
|
|
|
|
private
|
|
# A password change ends every session, so one can't start on a password checked before the change. Validated in
|
|
# the save's transaction, which holds the database's write lock from the start, so a change commits either before
|
|
# this check, and fails it, or after the insert, and ends this session with the others. Read past the query cache,
|
|
# and compared here rather than in the query, which logs its values.
|
|
def user_password_unchanged
|
|
unless User.uncached { User.where(id: user_id).pick(:password_digest) } == user.password_digest
|
|
errors.add :user, :invalid
|
|
end
|
|
end
|
|
end
|