Files
once-campfire/test/models/user_test.rb
T
Jeremy Daer 6cab924097 Remove push subscriptions on a password change, and post them again
A push subscription belongs to the user, not a session, so a device
signed out by a password change kept getting notifications. Changing
the password now removes every subscription along with the sessions,
in the same transaction.

A browser still signed in keeps its own subscription in its service
worker, so the notifications controller posts it once per session: the
bell names the session by a digest of its id, never its token, and the
browser remembers the last one it posted for. That post never
unsubscribes the browser when the server refuses it.

A request that authenticated just before the change could put a
subscription back after it. The create action now checks the session
still exists and saves in one immediate transaction, after validating
the endpoint outside it.
2026-10-19 12:39:03 -07:00

114 lines
4.2 KiB
Ruby

require "test_helper"
class UserTest < ActiveSupport::TestCase
test "user does not prevent very long passwords" do
users(:david).update(password: "secret" * 50)
assert users(:david).valid?
end
test "creating users grants membership to the open rooms" do
assert_difference -> { Membership.count }, +Rooms::Open.count do
create_new_user
end
end
test "memberships granted to the open rooms are like any other" do
freeze_time
user = create_new_user
assert_equal Rooms::Open.ids.sort, user.memberships.pluck(:room_id).sort
user.memberships.each do |membership|
assert membership.involved_in_mentions?
assert_equal Time.current, membership.created_at
assert_equal Time.current, membership.updated_at
end
end
test "deactivating a user deletes push subscriptions, searches, memberships for non-direct rooms, and changes their email address" do
assert_difference -> { Membership.count }, -users(:david).memberships.without_direct_rooms.count do
assert_difference -> { Push::Subscription.count }, -users(:david).push_subscriptions.count do
assert_difference -> { Search.count }, -users(:david).searches.count do
SecureRandom.stubs(:uuid).returns("2e7de450-cf04-4fa8-9b02-ff5ab2d733e7")
users(:david).deactivate
assert_equal "david-deactivated-2e7de450-cf04-4fa8-9b02-ff5ab2d733e7@37signals.com", users(:david).reload.email_address
end
end
end
end
test "deactivating a user deletes their sessions" do
assert_changes -> { users(:david).sessions.count }, from: 1, to: 0 do
users(:david).deactivate
end
end
test "changing the password signs out every session, the current one included" do
Current.session = users(:david).sessions.start!(user_agent: "This device", ip_address: "127.0.0.1")
assert_changes -> { users(:david).sessions.count }, to: 0 do
users(:david).update!(password: "a new secret123456")
end
end
test "changing the password closes the account's live connections" do
remote_connections = mock
remote_connections.expects(:disconnect).with(reconnect: true)
ActionCable.server.stubs(:remote_connections).returns(mock.tap { |m| m.expects(:where).with(current_user: users(:david)).returns(remote_connections) })
users(:david).update!(password: "a new secret123456")
end
test "changing the password closes live connections even when the user is saved again before commit" do
remote_connections = mock
remote_connections.expects(:disconnect).with(reconnect: true)
ActionCable.server.stubs(:remote_connections).returns(mock.tap { |m| m.expects(:where).with(current_user: users(:david)).returns(remote_connections) })
User.transaction do
users(:david).update!(password: "a new secret123456")
users(:david).update!(name: "Dave")
end
end
test "a password change that rolls back keeps every session and connection" do
ActionCable.server.expects(:remote_connections).never
assert_no_changes -> { users(:david).sessions.count } do
User.transaction do
users(:david).update!(password: "a new secret123456")
raise ActiveRecord::Rollback
end
end
end
test "changing the password removes every push subscription of the user" do
assert users(:david).push_subscriptions.any?
users(:david).update!(password: "a new secret123456")
assert_empty users(:david).push_subscriptions.reload
assert users(:jason).push_subscriptions.any?
end
test "a password change that rolls back keeps push subscriptions" do
assert_no_changes -> { users(:david).push_subscriptions.count } do
User.transaction do
users(:david).update!(password: "a new secret123456")
raise ActiveRecord::Rollback
end
end
end
test "changing other details keeps every session" do
ActionCable.server.expects(:remote_connections).never
assert_no_changes -> { [ users(:david).sessions.count, users(:david).push_subscriptions.count ] } do
users(:david).update!(name: "Dave", email_address: "dave@37signals.com")
end
end
private
def create_new_user
User.create!(name: "User", email_address: "user@example.com", password: "secret123456")
end
end