mirror of
https://github.com/basecamp/once-campfire.git
synced 2026-10-29 08:54:09 +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
@@ -4,8 +4,10 @@ import { pageIsTurboPreview } from "helpers/turbo_helpers"
|
||||
import { onNextEventLoopTick } from "helpers/timing_helpers"
|
||||
import { getCookie, setCookie } from "lib/cookie"
|
||||
|
||||
const PUSH_SUBSCRIPTION_SYNCED_KEY = "push-subscription-synced-session"
|
||||
|
||||
export default class extends Controller {
|
||||
static values = { subscriptionsUrl: String }
|
||||
static values = { subscriptionsUrl: String, session: String }
|
||||
static targets = [ "notAllowedNotice", "bell", "details" ]
|
||||
static classes = [ "attention" ]
|
||||
|
||||
@@ -25,6 +27,8 @@ export default class extends Controller {
|
||||
this.#showBellAlert()
|
||||
}
|
||||
}
|
||||
|
||||
this.#resyncPushSubscriptionOncePerSession()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -109,6 +113,21 @@ export default class extends Controller {
|
||||
if (!response.ok) subscription.unsubscribe()
|
||||
}
|
||||
|
||||
// A password change removes the account's subscriptions, the one this browser holds included. Post it again
|
||||
// once per session, so a browser that's still signed in keeps getting notifications. A failure here leaves the
|
||||
// browser's own subscription alone: the next session tries again.
|
||||
async #resyncPushSubscriptionOncePerSession() {
|
||||
if (this.#allowed && this.sessionValue && localStorage.getItem(PUSH_SUBSCRIPTION_SYNCED_KEY) !== this.sessionValue) {
|
||||
const registration = await this.#serviceWorkerRegistration
|
||||
const subscription = await registration?.pushManager?.getSubscription()
|
||||
|
||||
if (Notification.permission === "granted" && subscription) {
|
||||
await post(this.subscriptionsUrlValue, { body: this.#extractJsonPayloadAsString(subscription), responseKind: "turbo-stream" })
|
||||
localStorage.setItem(PUSH_SUBSCRIPTION_SYNCED_KEY, this.sessionValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async #requestPermissionAndSubscribe(registration) {
|
||||
const permission = await Notification.requestPermission()
|
||||
if (permission === "granted") this.#subscribe(registration)
|
||||
|
||||
Reference in new issue
Block a user