semaphore/routes/_actions/pushSubscription.js

90 lines
3.3 KiB
JavaScript

import { getSubscription, deleteSubscription, postSubscription, putSubscription } from '../_api/pushSubscription'
import { store } from '../_store/store'
import { urlBase64ToUint8Array } from '../_utils/base64'
const dummyApplicationServerKey = 'BImgAz4cF_yvNFp8uoBJCaGpCX4d0atNIFMHfBvAAXCyrnn9IMAFQ10DW_ZvBCzGeR4fZI5FnEi2JVcRE-L88jY='
export async function updatePushSubscriptionForInstance (instanceName) {
const { loggedInInstances, pushSubscription } = store.get()
const accessToken = loggedInInstances[instanceName].access_token
if (pushSubscription === null) {
return
}
const registration = await navigator.serviceWorker.ready
const subscription = await registration.pushManager.getSubscription()
if (subscription === null) {
store.set({ pushSubscription: null })
store.save()
return
}
try {
const backendSubscription = await getSubscription(instanceName, accessToken)
// Check if applicationServerKey changed (need to get another subscription from the browser)
if (btoa(urlBase64ToUint8Array(backendSubscription.server_key).buffer) !== btoa(subscription.options.applicationServerKey)) {
await subscription.unsubscribe()
await deleteSubscription(instanceName, accessToken)
await updateAlerts(instanceName, pushSubscription.alerts)
} else {
store.set({ pushSubscription: backendSubscription })
store.save()
}
} catch (e) {
// TODO: Better way to detect 404
if (e.message.startsWith('404:')) {
await subscription.unsubscribe()
store.set({ pushSubscription: null })
store.save()
}
}
}
export async function updateAlerts (instanceName, alerts) {
const { loggedInInstances } = store.get()
const accessToken = loggedInInstances[instanceName].access_token
const registration = await navigator.serviceWorker.ready
let subscription = await registration.pushManager.getSubscription()
if (subscription === null) {
// We need applicationServerKey in order to register a push subscription
// but the API doesn't expose it as a constant (as it should).
// So we need to register a subscription with a dummy applicationServerKey,
// send it to the backend saves it and return applicationServerKey, which
// we use to register a new subscription.
// https://github.com/tootsuite/mastodon/issues/8785
subscription = await registration.pushManager.subscribe({
applicationServerKey: urlBase64ToUint8Array(dummyApplicationServerKey),
userVisibleOnly: true
})
let backendSubscription = await postSubscription(instanceName, accessToken, subscription, alerts)
await subscription.unsubscribe()
subscription = await registration.pushManager.subscribe({
applicationServerKey: urlBase64ToUint8Array(backendSubscription.server_key),
userVisibleOnly: true
})
backendSubscription = await postSubscription(instanceName, accessToken, subscription, alerts)
store.set({ pushSubscription: backendSubscription })
store.save()
} else {
try {
const backendSubscription = await putSubscription(instanceName, accessToken, alerts)
store.set({ pushSubscription: backendSubscription })
store.save()
} catch (e) {
const backendSubscription = await postSubscription(instanceName, accessToken, subscription, alerts)
store.set({ pushSubscription: backendSubscription })
store.save()
}
}
}