mirror of
https://github.com/bulwarkmail/webmail.git
synced 2026-10-31 08:13:50 +00:00
fix(push): don't abort enabling push when the browser can't read its subscription
Firefox rejects pushManager.getSubscription() with `AbortError: Error retrieving push subscription` when its local push record is stale or the push service is unreachable. enableWebPush let that reject the whole call, so the onboarding banner showed the browser's bare error and push could never be turned on again - even though subscribing fresh is exactly the recovery. Treat a failed lookup as "no subscription to reuse" and continue to subscribe(), whose error still surfaces when the push service is really unavailable. Same reasoning for unsubscribe() of a mismatched subscription: getting the new subscription is what matters. Claude-Session: https://claude.ai/code/session_019KwXZEwxijHRbfobfXmcK2
This commit is contained in:
@@ -231,6 +231,32 @@ describe('enableWebPush', () => {
|
||||
expect(calls.some((c) => c.url.endsWith('/api/push/register/web'))).toBe(true);
|
||||
});
|
||||
|
||||
it('subscribes anyway when the browser cannot retrieve the existing subscription', async () => {
|
||||
// Firefox rejects the lookup with `AbortError: Error retrieving push
|
||||
// subscription` when its local record is stale; that must not abort enable.
|
||||
const { registration } = installPushBrowser();
|
||||
registration.pushManager.getSubscription.mockRejectedValue(
|
||||
new DOMException('Error retrieving push subscription', 'AbortError'),
|
||||
);
|
||||
installFetch({});
|
||||
|
||||
const result = await enableWebPush({ client: makeClient([]), relayBaseUrl: RELAY });
|
||||
|
||||
expect(registration.pushManager.subscribe).toHaveBeenCalledTimes(1);
|
||||
expect(result.subscriptionId).toBe('push-new');
|
||||
});
|
||||
|
||||
it('still subscribes when unsubscribing the mismatched subscription fails', async () => {
|
||||
const { browserSub, registration } = installPushBrowser();
|
||||
browserSub.options.applicationServerKey = new Uint8Array([9, 9, 9]).buffer;
|
||||
browserSub.unsubscribe.mockRejectedValue(new Error('unsubscribe failed'));
|
||||
installFetch({});
|
||||
|
||||
await enableWebPush({ client: makeClient([]), relayBaseUrl: RELAY });
|
||||
|
||||
expect(registration.pushManager.subscribe).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('replaces a browser subscription whose key the browser does not expose', async () => {
|
||||
const { browserSub, registration } = installPushBrowser();
|
||||
browserSub.options.applicationServerKey = null;
|
||||
|
||||
+9
-2
@@ -424,12 +424,19 @@ export async function enableWebPush(
|
||||
// service on every send - Mozilla answers 401 "VAPID public key mismatch" -
|
||||
// while isWebPushEnabled keeps reporting push as on.
|
||||
const applicationServerKey = urlBase64ToUint8Array(vapidPublicKey);
|
||||
let pushSubscription = await registration.pushManager.getSubscription();
|
||||
// A stale or broken local record makes Firefox reject the lookup itself with
|
||||
// `AbortError: Error retrieving push subscription`, which would abort the
|
||||
// whole enable. There is nothing to reuse in that case, so carry on to
|
||||
// subscribe() and let its own error surface if the push service is really
|
||||
// unreachable.
|
||||
let pushSubscription = await registration.pushManager.getSubscription().catch(() => null);
|
||||
if (
|
||||
pushSubscription
|
||||
&& !sameKey(pushSubscription.options?.applicationServerKey, applicationServerKey)
|
||||
) {
|
||||
await pushSubscription.unsubscribe();
|
||||
// An unsubscribe that fails leaves the old record in place; subscribing
|
||||
// with the right key is what matters, so don't abort the enable for it.
|
||||
await pushSubscription.unsubscribe().catch(() => undefined);
|
||||
pushSubscription = null;
|
||||
}
|
||||
if (!pushSubscription) {
|
||||
|
||||
Reference in New Issue
Block a user