Open Bluebie opened 1 year ago
Debug logs:
{
headers: {
Encryption: 'salt=isPj-BpgoefoCo0zD6CZkQ',
'Crypto-Key': 'dh=BAXyOq64oDKng00hII2X2xnMTVe1d_FVD26oT1his6YaZ6QhSox6jb2ID5CZeX1-YWhO1jQEkTWbvcHcCy_3JJ8; p256ecdsa=BEZCatmRpI460vTmtq3s3Ak9_A9EAFId7IeFlNz3szsgANV1Vlixa7MX4hjU9USzQeUkuUPKicjldA9AjlSZb3I',
'Content-Length': '231',
'Content-Type': 'application/octet-stream',
'Content-Encoding': 'aesgcm',
Authorization: 'WebPush eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiJ9.eyJhdWQiOiJodHRwOi8vd2ViLnB1c2guYXBwbGUuY29tIiwiZXhwIjoxNjcyNDYxNjg0LCJzdWIiOiJtYWlsdG86Zm94QHBob2VuaXgubW9uc3RlciJ9.Tpm1kl9IQfnrTd9szQit3UqfHP8NGDwv2Zqsld-HzowK5-ZY5dprGIloV2xSKhMiOXx91mqnlnN-KTYzZB5-pg',
TTL: '60',
Urgency: 'low'
},
body: ArrayBuffer {
[Uint8Contents]: <a8 43 0f f3 db 3a d8 80 62 af 74 bc 8a a3 90 ae 06 f0 65 35 f4 ec a4 7b 4a c5 54 94 69 35 5a f1 d6 1d a4 c6 f8 a5 ec f2 59 85 3c f1 f9 91 8c 18 25 00 eb 57 bf dc aa 56 22 46 ed f2 ea a0 a6 df 4d c8 fe 1e 98 b8 0a d3 27 c4 ed 7c c5 e3 a1 4c 69 90 bb e8 b1 0c c2 92 46 5f ad 3e 7d 40 03 65 6c f7 bc 96 ... 131 more bytes>,
byteLength: 231
},
endpoint: 'https://web.push.apple.com/QKRk2ENkEtyy-bV6ful3vZQGES24AT-qZke1Mfm6ani6A79nU3JKiTtVxffhgelph7gewQ0Qa9SE03oSDFZUzC1CHlIc--5QCX4JEwOTtbCWwKB2GutvZenkA1xBConxbuxuZB_WE4M0VGS1wbc3NeiD9lprMAjNAZAQ7F77MIw'
}
Push Error to endpoint "https://web.push.apple.com/QKRk2ENkEtyy-bV6ful3vZQGES24AT-qZke1Mfm6ani6A79nU3JKiTtVxffhgelph7gewQ0Qa9SE03oSDFZUzC1CHlIc--5QCX4JEwOTtbCWwKB2GutvZenkA1xBConxbuxuZB_WE4M0VGS1wbc3NeiD9lprMAjNAZAQ7F77MIw": HTTP 403 Forbidden: {"reason":"BadJwtToken"}
from this implementation on sveltekit
///// -- $lib/io/webpush/server.ts
import type { WebPushSubscription } from "$lib/data/push"
import { readSiteConfig } from "$lib/data/site-config"
// @ts-expect-error
import { generatePushHTTPRequest } from "webpush-webcrypto"
import { applicationServerKeys } from "./key"
export async function sendWebPush (subscription: WebPushSubscription, title: string, options: NotificationOptions) {
const siteConfig = await readSiteConfig()
const { headers, body, endpoint } = await generatePushHTTPRequest({
applicationServerKeys,
payload: JSON.stringify({ title, options }),
target: {
endpoint: subscription.config.client.endpoint,
keys: {
p256dh: subscription.config.client.key,
auth: subscription.config.client.auth,
},
},
adminContact: siteConfig.adminContact,
ttl: 60, // * 60 * 24 * 7,
urgency: "low",
})
console.log({ headers, body, endpoint })
const response = await fetch(endpoint, { method: 'POST', headers, body })
if (!response.ok) {
throw new Error(`Push Error to endpoint "${endpoint}": HTTP ${response.status} ${response.statusText}: ${await response.text()}`)
}
}
///// -- endpoint server file:
import { readWebPushSubscription } from "$lib/data/push"
import { sendWebPush } from "$lib/io/webpush/server"
import { json } from "@sveltejs/kit"
import type { RequestHandler } from "./$types"
export const POST: RequestHandler = async ({ request }) => {
const body = await request.json()
const subscription = await readWebPushSubscription(body.endpoint)
const result = await sendWebPush(subscription, body.title, body.config)
return json({ ok: true, result })
}
Unfortunately I don’t have access to a machine running Ventura right now so don’t have easy means to test Safari web push. One quick thought: does your siteConfig.adminContact
have mailto:
at the start of it? My examples don’t, I didn’t realise it was required (I guess Safari is stricter than others), fingers crossed that might be all it is.
Yes, I've tested with and without mailto: prefix. Maybe I can set up a mac and provide remote access if you want to try it out yourself over VNC or something like that?
I just tried validating the JWT token in your example and the validation failed so I think for now I need to work out why that’s failing when others are validating. Will update with anything I find.
In case it's useful, this is how i'm setting up applicationServerKey
// file: ./key.ts
// @ts-expect-error
import { ApplicationServerKeys, setWebCrypto } from "webpush-webcrypto"
setWebCrypto(crypto)
// import.meta.env.VITE_WEB_PUSH_SERVER_KEY='{"publicKey":"BEZCatmRpI460vTmtq3s3Ak9_A9EAFId7IeFlNz3szsgANV1Vlixa7MX4hjU9USzQeUkuUPKicjldA9AjlSZb3I","privateKey":"MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQguBA_G1swtN7ZKsntySPnw8n5Y9L3TS0JtPxb384x2q2hRANCAARGQmrZkaSOOtL05rat7NwJPfwPRABSHeyHhZTc97M7IADVdVZYsWuzF-IY1PVEs0HlJLlDyonI5XQPQI5UmW9y"}'
const cfg = JSON.parse(import.meta.env.VITE_WEB_PUSH_SERVER_KEY)
export const applicationServerKeys = await ApplicationServerKeys.fromJSON(cfg)
and this is the script I used to generate that env value:
import crypto from 'node:crypto'
import { ApplicationServerKeys, setWebCrypto } from "webpush-webcrypto"
setWebCrypto(crypto)
ApplicationServerKeys.generate().then(x => {
x.toJSON().then(x => console.log(JSON.stringify(x)))
})
I have rotated keys just before posting this, but those were the keys used to generate the logs posted earlier
Spent all day trying to track down what's going wrong here, and I'm still feeling lost. Here's what i've learnt along the way:
I don't want to say "just use web_push for now"... but maybe just use web_push for now if it works for you. I will be able to take a look at Safari web pushes in January but not immediately, sorry.
@alastaircoote – this just works as of 2023-12-01
(confirmed with Safari 17.1
on iOS; with mailto:
in adminContact
)
I have your library working well with Chrome and Firefox on macOS Ventura, but Safari's web push endpoints are responding with
HTTP 403 Forbidden
: with body{"reason":"BadJwtToken"}
Apple's doc's indicate this error message could be caused by:
What I've looked at so far: