Reorganize functions in push registerer so they make logical sense

environments/review-main-yi2y9f/deployments/4918^2
Alex Gleason 2024-10-15 16:08:14 -05:00
rodzic 59b3df9641
commit d0211c8af1
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 7211D1F99744FBB7
2 zmienionych plików z 68 dodań i 60 usunięć

Wyświetl plik

@ -2,67 +2,15 @@
import { HTTPError } from 'soapbox/api/HTTPError';
import { MastodonClient } from 'soapbox/api/MastodonClient';
import { WebPushSubscription, webPushSubscriptionSchema } from 'soapbox/schemas/web-push';
import { decode as decodeBase64 } from 'soapbox/utils/base64';
/** Taken from https://www.npmjs.com/package/web-push */
function urlBase64ToUint8Array(base64String: string): Uint8Array {
const padding = '='.repeat((4 - base64String.length % 4) % 4);
const base64 = (base64String + padding)
.replace(/-/g, '+')
.replace(/_/g, '/');
return decodeBase64(base64);
}
async function getBackendSubscription(api: MastodonClient): Promise<WebPushSubscription | null> {
try {
const response = await api.get('/api/v1/push/subscription');
const data = await response.json();
return webPushSubscriptionSchema.parse(data);
} catch (e) {
if (e instanceof HTTPError && e.response.status === 404) {
return null;
} else {
throw e;
}
}
}
async function sendSubscriptionToBackend(api: MastodonClient, subscription: PushSubscription): Promise<WebPushSubscription> {
const params = {
subscription: subscription.toJSON(),
};
const response = await api.post('/api/v1/push/subscription', params);
const data = await response.json();
return webPushSubscriptionSchema.parse(data);
}
async function createSubscription(vapidKey: string): Promise<PushSubscription> {
const registration = await navigator.serviceWorker.ready;
return registration.pushManager.subscribe({
userVisibleOnly: true,
applicationServerKey: urlBase64ToUint8Array(vapidKey),
});
}
async function getOrCreateSubscription(vapidKey: string): Promise<{ subscription: PushSubscription; created: boolean }> {
const registration = await navigator.serviceWorker.ready;
const subscription = await registration.pushManager.getSubscription();
if (subscription) {
return { subscription, created: false };
} else {
const subscription = await createSubscription(vapidKey);
return { subscription, created: true };
}
}
import { decodeBase64Url } from 'soapbox/utils/base64';
// Last one checks for payload support: https://web-push-book.gauntface.com/chapter-06/01-non-standards-browsers/#no-payload
const supportsPushNotifications = ('serviceWorker' in navigator && 'PushManager' in window && 'getKey' in PushSubscription.prototype);
/**
* Register web push notifications.
* This function creates a subscription if one hasn't been created already, and syncronizes it with the backend.
*/
export async function registerPushNotifications(api: MastodonClient, vapidKey: string) {
if (!supportsPushNotifications) {
console.warn('Your browser does not support Web Push Notifications.');
@ -91,6 +39,56 @@ export async function registerPushNotifications(api: MastodonClient, vapidKey: s
}
}
/** Get an existing subscription object from the browser if it exists, or ask the browser to create one. */
async function getOrCreateSubscription(vapidKey: string): Promise<{ subscription: PushSubscription; created: boolean }> {
const registration = await navigator.serviceWorker.ready;
const subscription = await registration.pushManager.getSubscription();
if (subscription) {
return { subscription, created: false };
} else {
const subscription = await createSubscription(vapidKey);
return { subscription, created: true };
}
}
/** Request a subscription object from the web browser. */
async function createSubscription(vapidKey: string): Promise<PushSubscription> {
const registration = await navigator.serviceWorker.ready;
return registration.pushManager.subscribe({
userVisibleOnly: true,
applicationServerKey: decodeBase64Url(vapidKey),
});
}
/** Fetch the API for an existing subscription saved in the backend, if any. */
async function getBackendSubscription(api: MastodonClient): Promise<WebPushSubscription | null> {
try {
const response = await api.get('/api/v1/push/subscription');
const data = await response.json();
return webPushSubscriptionSchema.parse(data);
} catch (e) {
if (e instanceof HTTPError && e.response.status === 404) {
return null;
} else {
throw e;
}
}
}
/** Publish a new subscription to the backend. */
async function sendSubscriptionToBackend(api: MastodonClient, subscription: PushSubscription): Promise<WebPushSubscription> {
const params = {
subscription: subscription.toJSON(),
};
const response = await api.post('/api/v1/push/subscription', params);
const data = await response.json();
return webPushSubscriptionSchema.parse(data);
}
/** Check if the VAPID key and endpoint of the subscription match the data in the backend. */
function subscriptionMatchesBackend(subscription: PushSubscription, backend: WebPushSubscription): boolean {
const { applicationServerKey } = subscription.options;
@ -103,7 +101,7 @@ function subscriptionMatchesBackend(subscription: PushSubscription, backend: Web
return false;
}
const backendKeyBytes: Uint8Array = urlBase64ToUint8Array(backend.server_key);
const backendKeyBytes: Uint8Array = decodeBase64Url(backend.server_key);
const subscriptionKeyBytes: Uint8Array = new Uint8Array(applicationServerKey);
return backendKeyBytes.toString() === subscriptionKeyBytes.toString();

Wyświetl plik

@ -1,4 +1,4 @@
export const decode = (base64: string) => {
export function decodeBase64(base64: string): Uint8Array {
const rawData = window.atob(base64);
const outputArray = new Uint8Array(rawData.length);
@ -7,4 +7,14 @@ export const decode = (base64: string) => {
}
return outputArray;
};
}
/** Taken from https://www.npmjs.com/package/web-push */
export function decodeBase64Url(base64String: string): Uint8Array {
const padding = '='.repeat((4 - base64String.length % 4) % 4);
const base64 = (base64String + padding)
.replace(/-/g, '+')
.replace(/_/g, '/');
return decodeBase64(base64);
}