mirror of
https://github.com/wekan/wekan.git
synced 2026-11-07 11:02:33 -05:00
Member Settings / Notification Settings / "Browser notifications on this device": the browser asks for permission and gives a push subscription, and from then on every notification the member gets in WeKan - the same recipients, watching and muted kinds as the tray and e-mail - also pops up from that browser even with WeKan closed; a click opens the card. Turn it on per browser and device, up to ten per account. web-push 3.6.7 (pinned) sends it with this WeKan's own VAPID key pair, made once and kept in a server-only collection; only the public key leaves the server. A subscription's endpoint is chosen by the browser and POSTed to by the server, so it is accepted only over https and only at the push services browsers use - an internal address or another site is refused when saved and again before every send. Gone subscriptions are forgotten. The service worker opens only paths of this WeKan. Not offered on Sandstorm. models/lib/webPush.js decides; tests/webPush.test.cjs covers the push services, internal and look-alike hosts, foreign click targets and the bound; server/lib/tests/webPush.tests.js runs in Meteor (passing): one key pair, only the public key out, an internal endpoint refused. With the webhook activity picker (c3321926ab) and the all-boards activity feed (656af74b2c), this completes both issues. The new strings are English placeholders until the next translation pass. Thanks to saurabharch, hingerl and xet7 ! Fixes #2026, Fixes #1377.
37 lines
1.4 KiB
JavaScript
37 lines
1.4 KiB
JavaScript
// #2026 / #1377: turning browser push on and off on this device
|
|
// (server/webPush.js). The service worker is public/pwa-service-worker.js.
|
|
import { Meteor } from 'meteor/meteor';
|
|
|
|
const { base64urlToBytes } = require('/models/lib/passkeys');
|
|
|
|
export function webPushSupported() {
|
|
return typeof window !== 'undefined' && 'serviceWorker' in navigator && 'PushManager' in window
|
|
&& 'Notification' in window && !Meteor.settings?.public?.sandstorm;
|
|
}
|
|
|
|
async function registration() {
|
|
return navigator.serviceWorker.ready;
|
|
}
|
|
|
|
export async function webPushEnabledHere() {
|
|
if (!webPushSupported()) return false;
|
|
const reg = await registration();
|
|
return !!(await reg.pushManager.getSubscription());
|
|
}
|
|
|
|
export async function enableWebPush() {
|
|
if ((await Notification.requestPermission()) !== 'granted') throw new Meteor.Error('web-push-denied');
|
|
const publicKey = await Meteor.callAsync('webPushPublicKey');
|
|
const reg = await registration();
|
|
const sub = await reg.pushManager.subscribe({ userVisibleOnly: true, applicationServerKey: base64urlToBytes(publicKey) });
|
|
await Meteor.callAsync('webPushSubscribe', sub.toJSON());
|
|
}
|
|
|
|
export async function disableWebPush() {
|
|
const reg = await registration();
|
|
const sub = await reg.pushManager.getSubscription();
|
|
if (!sub) return;
|
|
await Meteor.callAsync('webPushUnsubscribe', sub.endpoint);
|
|
await sub.unsubscribe();
|
|
}
|