Sign out the account's other sessions when its password changes

Changing the password is how someone shuts out whoever else is signed
in to their account, but every session opened with the old password
stayed valid. Now the others end and their live connections close, as
on sign-out. The session the password was changed from stays signed in.

Changing the password outside a request, as from a console, ends every
session.

From #371. 1.5.2 has no record snapshot or response cache, so the test
that a cached session lookup doesn't outlive the password change is
left out; the rest applies as it is.

(cherry picked from commit c78c3fd7ef)
This commit is contained in:
Jeremy Daer committed 2026-10-19 10:28:55 -07:00
1 parent 9474e70f5a
commit c78f03fda7
4 files changed
+77

No files matched your search

@@ -8,6 +8,8 @@ class Users::ProfilesController < ApplicationController
def update
@user.update user_params
disconnect_remote_connections if @user.saved_change_to_password_digest?
redirect_to user_profile_url, notice: update_notice
end
+7
View File
@@ -20,6 +20,7 @@ class User < ApplicationRecord
has_secure_password validations: false
after_create_commit :grant_membership_to_open_rooms
after_update :sign_out_other_sessions, if: :saved_change_to_password_digest?
scope :ordered, -> { order("LOWER(name)") }
scope :filtered_by, ->(query) { where("name like ?", "%#{query}%") }
@@ -50,6 +51,12 @@ class User < ApplicationRecord
end
private
# A new password is how someone shuts out whoever else got into their account, so it ends the sessions opened
# with the old one. The session it was changed from, if any, stays.
def sign_out_other_sessions
sessions.excluding(Current.session).delete_all
end
# One statement, which SQLite runs under the write lock, so no room is closed between reading the open ones and
# inserting. A room that Room#destroy_later closes is either closed before, and skipped, or after, and takes this
# membership away with the others. A room that granted itself to every user when it was created is skipped too,