From dfdcf278dfc2cb9170c716b967f27d818402b0b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Luquet?= Date: Wed, 29 Apr 2026 11:06:34 +0200 Subject: [PATCH] fix(webpush): use base64url encoding for push subscription tokens Use subscription.toJSON() instead of manually encoding ArrayBuffer keys with btoa(), which produced standard base64 (with +, / and = padding) instead of base64url (-, _ and no padding) as required by the Web Push standard and ejabberd. Fixes both the register and disable flows in useWebPush and NotificationsSettings. --- .../NotificationsSettings.tsx | 18 +++++------------- apps/fluux/src/hooks/useWebPush.ts | 19 +++++-------------- 2 files changed, 10 insertions(+), 27 deletions(-) diff --git a/apps/fluux/src/components/settings-components/NotificationsSettings.tsx b/apps/fluux/src/components/settings-components/NotificationsSettings.tsx index de576d10..9b9d42bc 100644 --- a/apps/fluux/src/components/settings-components/NotificationsSettings.tsx +++ b/apps/fluux/src/components/settings-components/NotificationsSettings.tsx @@ -49,13 +49,6 @@ async function openNotificationSettings(): Promise { } } -function arrayBufferToBase64(buffer: ArrayBuffer): string { - const bytes = new Uint8Array(buffer) - let binary = '' - bytes.forEach((b) => (binary += String.fromCharCode(b))) - return btoa(binary) -} - async function disableWebPush(client: any): Promise { try { const { webPushServices } = connectionStore.getState() @@ -66,13 +59,12 @@ async function disableWebPush(client: any): Promise { const subscription = await swReg.pushManager.getSubscription() if (!subscription) return - const p256dhKey = subscription.getKey('p256dh') - const authKey = subscription.getKey('auth') - if (!p256dhKey || !authKey) return + const json = subscription.toJSON() + const p256dh = json.keys?.p256dh + const auth = json.keys?.auth + if (!p256dh || !auth) return - const p256dh = arrayBufferToBase64(p256dhKey) - const auth = arrayBufferToBase64(authKey) - const notificationId = `${subscription.endpoint}#${p256dh}#${auth}` + const notificationId = `${json.endpoint ?? subscription.endpoint}#${p256dh}#${auth}` await client.webPush.disableSubscription(service.appId, 'webpush', notificationId) connectionStore.getState().setWebPushEnabled(false) diff --git a/apps/fluux/src/hooks/useWebPush.ts b/apps/fluux/src/hooks/useWebPush.ts index f576636d..c5fe8f35 100644 --- a/apps/fluux/src/hooks/useWebPush.ts +++ b/apps/fluux/src/hooks/useWebPush.ts @@ -61,17 +61,15 @@ async function registerPush( console.log('[WebPush] New subscription created, endpoint:', subscription.endpoint) } - const endpoint = subscription.endpoint - const p256dhKey = subscription.getKey('p256dh') - const authKey = subscription.getKey('auth') - if (!p256dhKey || !authKey) { + const json = subscription.toJSON() + const endpoint = json.endpoint ?? subscription.endpoint + const p256dh = json.keys?.p256dh + const auth = json.keys?.auth + if (!p256dh || !auth) { console.error('[WebPush] Missing subscription keys') return } - const p256dh = arrayBufferToBase64(p256dhKey) - const auth = arrayBufferToBase64(authKey) - console.log('[WebPush] Registering with XMPP server, endpoint:', endpoint) await client.webPush.registerSubscription(endpoint, p256dh, auth, service.appId) console.log('[WebPush] Registration complete!') @@ -151,10 +149,3 @@ function urlBase64ToUint8Array(base64String: string): Uint8Array { const rawData = atob(base64) return Uint8Array.from(rawData, (char) => char.charCodeAt(0)) } - -function arrayBufferToBase64(buffer: ArrayBuffer): string { - const bytes = new Uint8Array(buffer) - let binary = '' - bytes.forEach((b) => (binary += String.fromCharCode(b))) - return btoa(binary) -}