mirror of
https://github.com/basecamp/once-campfire.git
synced 2026-10-29 00:44:05 +09:00
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.
From #371.
(cherry picked from commit 6cab924097)
This commit is contained in:
1 parent
417f087964
commit
93718f7408
9 files changed
+201
-16
No files matched your search
@@ -5,17 +5,14 @@ class Users::PushSubscriptionsController < ApplicationController
|
||||
end
|
||||
|
||||
def create
|
||||
if subscription = @push_subscriptions.find_by(push_subscription_params)
|
||||
# Existing endpoints must pass current validations
|
||||
if subscription.valid?
|
||||
subscription.touch
|
||||
head :ok
|
||||
else
|
||||
head :unprocessable_entity
|
||||
end
|
||||
subscription = @push_subscriptions.find_or_initialize_by(push_subscription_params)
|
||||
subscription.user_agent = request.user_agent if subscription.new_record?
|
||||
|
||||
# Existing endpoints must pass current validations too
|
||||
if subscription.valid?
|
||||
head save_while_signed_in(subscription) ? :ok : :unauthorized
|
||||
else
|
||||
subscription = @push_subscriptions.create push_subscription_params.merge(user_agent: request.user_agent)
|
||||
head subscription.persisted? ? :ok : :unprocessable_entity
|
||||
head :unprocessable_entity
|
||||
end
|
||||
end
|
||||
|
||||
@@ -29,6 +26,16 @@ class Users::PushSubscriptionsController < ApplicationController
|
||||
@push_subscriptions = Current.user.push_subscriptions
|
||||
end
|
||||
|
||||
# A password change ends every session and subscription. A request that authenticated just before it mustn't
|
||||
# put one back, so the session is checked under the same write lock as the save. Validation, which looks up
|
||||
# the endpoint's address, runs before taking the lock.
|
||||
def save_while_signed_in(subscription)
|
||||
Push::Subscription.transaction do
|
||||
Session.exists?(Current.session.id) &&
|
||||
(subscription.new_record? ? subscription.save!(validate: false) : subscription.touch)
|
||||
end
|
||||
end
|
||||
|
||||
def push_subscription_params
|
||||
params.require(:push_subscription).permit(:endpoint, :p256dh_key, :auth_key)
|
||||
end
|
||||
|
||||
Reference in new issue
Block a user