"use strict"; const $ = require("jquery"); const storage = require("./localStorage"); const socket = require("./socket"); let pushNotificationsButton; let clientSubscribed = null; let applicationServerKey; module.exports.hasServiceWorker = false; module.exports.configurePushNotifications = (subscribedOnServer, key) => { applicationServerKey = key; // If client has push registration but the server knows nothing about it, // this subscription is broken and client has to register again if (clientSubscribed === true && subscribedOnServer === false) { pushNotificationsButton.attr("disabled", true); navigator.serviceWorker.ready .then((registration) => registration.pushManager.getSubscription()) .then((subscription) => subscription && subscription.unsubscribe()) .then((successful) => { if (successful) { alternatePushButton().removeAttr("disabled"); } }); } }; module.exports.initialize = () => { pushNotificationsButton = $("#pushNotifications"); if (!isAllowedServiceWorkersHost()) { return; } $("#pushNotificationsHttps").hide(); if ("serviceWorker" in navigator) { navigator.serviceWorker.register("service-worker.js").then((registration) => { module.exports.hasServiceWorker = true; if (!registration.pushManager) { return; } return registration.pushManager.getSubscription().then((subscription) => { $("#pushNotificationsUnsupported").hide(); pushNotificationsButton .removeAttr("disabled") .on("click", onPushButton); clientSubscribed = !!subscription; if (clientSubscribed) { alternatePushButton(); } }); }).catch((err) => { $("#pushNotificationsUnsupported span").text(err); }); } }; function onPushButton() { pushNotificationsButton.attr("disabled", true); navigator.serviceWorker.ready.then((registration) => registration.pushManager.getSubscription().then((existingSubscription) => { if (existingSubscription) { socket.emit("push:unregister"); return existingSubscription.unsubscribe(); } return registration.pushManager.subscribe({ applicationServerKey: urlBase64ToUint8Array(applicationServerKey), userVisibleOnly: true, }).then((subscription) => { const rawKey = subscription.getKey ? subscription.getKey("p256dh") : ""; const key = rawKey ? window.btoa(String.fromCharCode.apply(null, new Uint8Array(rawKey))) : ""; const rawAuthSecret = subscription.getKey ? subscription.getKey("auth") : ""; const authSecret = rawAuthSecret ? window.btoa(String.fromCharCode.apply(null, new Uint8Array(rawAuthSecret))) : ""; socket.emit("push:register", { token: storage.get("token"), endpoint: subscription.endpoint, keys: { p256dh: key, auth: authSecret, }, }); return true; }); }).then((successful) => { if (successful) { alternatePushButton().removeAttr("disabled"); } }) ).catch((err) => { $("#pushNotificationsUnsupported") .find("span").text(`An error has occured: ${err}`).end() .show(); }); return false; } function alternatePushButton() { const text = pushNotificationsButton.text(); return pushNotificationsButton .text(pushNotificationsButton.data("text-alternate")) .data("text-alternate", text); } function urlBase64ToUint8Array(base64String) { const padding = "=".repeat((4 - base64String.length % 4) % 4); const base64 = (base64String + padding) .replace(/-/g, "+") .replace(/_/g, "/"); const rawData = window.atob(base64); const outputArray = new Uint8Array(rawData.length); for (let i = 0; i < rawData.length; ++i) { outputArray[i] = rawData.charCodeAt(i); } return outputArray; } function isAllowedServiceWorkersHost() { return location.protocol === "https:" || location.hostname === "localhost" || location.hostname === "127.0.0.1"; }