diff --git a/app/models/concerns/pages_core/authenticable_user.rb b/app/models/concerns/pages_core/authenticable_user.rb index 37f32bbd..49597ddb 100644 --- a/app/models/concerns/pages_core/authenticable_user.rb +++ b/app/models/concerns/pages_core/authenticable_user.rb @@ -17,13 +17,18 @@ module AuthenticableUser } ) - before_save :update_session_token + after_initialize { |u| u.session_token ||= u.class.random_session_token } + before_validation :update_session_token end module ClassMethods def authenticate(email, password:) User.find_by(email:).try(:authenticate, password) end + + def random_session_token + SecureRandom.hex(32) + end end def can_login? @@ -49,10 +54,10 @@ def use_recovery_code!(code) private def update_session_token - return unless !session_token? || password_digest_changed? || + return unless password_digest_changed? || otp_enabled_changed? - self.session_token = SecureRandom.hex(32) + self.session_token = self.class.random_session_token end end end diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 89845d91..fe5225d3 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -78,4 +78,24 @@ it { is_expected.to be(false) } end end + + describe "session_token" do + subject(:session_token) { user.session_token } + + let(:user) { create(:user, :otp) } + + it { is_expected.to be_present } + + it "changes when password is changed" do + previous = user.session_token + user.update(password: "new password") + expect(session_token).not_to eq(previous) + end + + it "changes when OTP status is changed" do + previous = user.session_token + user.update(otp_enabled: false) + expect(session_token).not_to eq(previous) + end + end end