From 5ff1d15b36e8cb96bb9ec4ff59ccf614aea72cdd Mon Sep 17 00:00:00 2001 From: Simon Larsen Date: Wed, 16 Jul 2025 20:19:37 +0100 Subject: [PATCH] feat: Add VAPID configuration for web push notifications --- Common/UI/Config.ts | 3 +++ .../Components/NotificationMethods/Push.tsx | 23 +++++++++++++++++-- .../Public/oneuptime/templates/_helpers.tpl | 6 +++++ HelmChart/Public/oneuptime/values.yaml | 7 ++++++ PUSH_NOTIFICATIONS.md | 5 ++-- config.example.env | 6 +++++ docker-compose.base.yml | 6 ++++- 7 files changed, 50 insertions(+), 6 deletions(-) diff --git a/Common/UI/Config.ts b/Common/UI/Config.ts index 5d8d2fdf57..5cb1364732 100644 --- a/Common/UI/Config.ts +++ b/Common/UI/Config.ts @@ -49,6 +49,9 @@ export const HOST: string = env("HOST") || ""; export const BILLING_ENABLED: boolean = env("BILLING_ENABLED") === "true"; export const BILLING_PUBLIC_KEY: string = env("BILLING_PUBLIC_KEY") || ""; +// VAPID Configuration for Push Notifications +export const VAPID_PUBLIC_KEY: string = env("VAPID_PUBLIC_KEY") || ""; + export const VERSION: Version = new Version(env("VERSION") || "1.0.0"); export const APP_HOSTNAME: Hostname = Hostname.fromString(HOST); diff --git a/Dashboard/src/Components/NotificationMethods/Push.tsx b/Dashboard/src/Components/NotificationMethods/Push.tsx index 07568bd697..fd94f4fff2 100644 --- a/Dashboard/src/Components/NotificationMethods/Push.tsx +++ b/Dashboard/src/Components/NotificationMethods/Push.tsx @@ -11,7 +11,7 @@ import FormFieldSchemaType from "Common/UI/Components/Forms/Types/FormFieldSchem import ConfirmModal from "Common/UI/Components/Modal/ConfirmModal"; import ModelTable from "Common/UI/Components/ModelTable/ModelTable"; import FieldType from "Common/UI/Components/Types/FieldType"; -import { APP_API_URL } from "Common/UI/Config"; +import { APP_API_URL, VAPID_PUBLIC_KEY } from "Common/UI/Config"; import API from "Common/UI/Utils/API/API"; import User from "Common/UI/Utils/User"; import UserPush from "Common/Models/DatabaseModels/UserPush"; @@ -54,10 +54,29 @@ const Push: () => JSX.Element = (): ReactElement => { // Register service worker const swRegistration = await navigator.serviceWorker.register("/dashboard/sw.js"); + // Wait for service worker to be ready + await navigator.serviceWorker.ready; + + // Ensure the service worker is active + if (!swRegistration.active) { + // If service worker is installing, wait for it to become active + if (swRegistration.installing) { + await new Promise((resolve) => { + swRegistration.installing!.addEventListener('statechange', function() { + if (this.state === 'activated') { + resolve(undefined); + } + }); + }); + } else { + throw new Error("Service worker failed to activate"); + } + } + // Get push subscription const subscription = await swRegistration.pushManager.subscribe({ userVisibleOnly: true, - applicationServerKey: process.env["REACT_APP_VAPID_PUBLIC_KEY"] || "", + applicationServerKey: VAPID_PUBLIC_KEY || "", }); // Create device registration through API diff --git a/HelmChart/Public/oneuptime/templates/_helpers.tpl b/HelmChart/Public/oneuptime/templates/_helpers.tpl index 364d101fff..f0c1e3607c 100644 --- a/HelmChart/Public/oneuptime/templates/_helpers.tpl +++ b/HelmChart/Public/oneuptime/templates/_helpers.tpl @@ -54,6 +54,12 @@ Usage: value: {{ $.Values.analytics.key }} - name: ANALYTICS_HOST value: {{ $.Values.analytics.host }} +- name: VAPID_PUBLIC_KEY + value: {{ $.Values.vapid.publicKey }} +- name: VAPID_PRIVATE_KEY + value: {{ $.Values.vapid.privateKey }} +- name: VAPID_SUBJECT + value: {{ $.Values.vapid.subject }} - name: SERVER_ACCOUNTS_HOSTNAME value: {{ $.Release.Name }}-accounts.{{ $.Release.Namespace }}.svc.{{ $.Values.global.clusterDomain }} - name: SERVER_SERVER_MONITOR_INGEST_HOSTNAME diff --git a/HelmChart/Public/oneuptime/values.yaml b/HelmChart/Public/oneuptime/values.yaml index 3c84012f03..cb34f3bb18 100644 --- a/HelmChart/Public/oneuptime/values.yaml +++ b/HelmChart/Public/oneuptime/values.yaml @@ -171,6 +171,13 @@ analytics: host: key: +# VAPID Configuration for Web Push Notifications +# Generate VAPID keys using: npx web-push generate-vapid-keys +vapid: + publicKey: + privateKey: + subject: mailto:support@oneuptime.com + internalSmtp: enabled: true incomingEmailDomain: diff --git a/PUSH_NOTIFICATIONS.md b/PUSH_NOTIFICATIONS.md index 5625171c3e..ebad8c9178 100644 --- a/PUSH_NOTIFICATIONS.md +++ b/PUSH_NOTIFICATIONS.md @@ -56,11 +56,10 @@ VAPID_SUBJECT=mailto:support@oneuptime.com # Firebase Configuration (for mobile) FIREBASE_SERVICE_ACCOUNT={"type":"service_account",...} - -# Frontend Configuration -REACT_APP_VAPID_PUBLIC_KEY=your_vapid_public_key ``` +**Note:** The VAPID public key is automatically exposed to the frontend through the configuration system. You no longer need to set `REACT_APP_VAPID_PUBLIC_KEY` manually. + ### Database Migration The UserPush table will be automatically created when the service starts due to TypeORM's synchronization. diff --git a/config.example.env b/config.example.env index f6f51caef4..9c598d4ed1 100644 --- a/config.example.env +++ b/config.example.env @@ -263,6 +263,12 @@ NOTIFICATION_SLACK_WEBHOOK_ON_DELETED_PROJECT= # This webhook notifies slack when the subscription is updated. NOTIFICATION_SLACK_WEBHOOK_ON_SUBSCRIPTION_UPDATE= +# VAPID keys for Web Push Notifications +# Generate using: npx web-push generate-vapid-keys +VAPID_PUBLIC_KEY= +VAPID_PRIVATE_KEY= +VAPID_SUBJECT=mailto:support@oneuptime.com + # Copilot Environment Variables COPILOT_ONEUPTIME_URL=http://localhost COPILOT_ONEUPTIME_REPOSITORY_SECRET_KEY= diff --git a/docker-compose.base.yml b/docker-compose.base.yml index 5a86c0a590..5b6ce7d69f 100644 --- a/docker-compose.base.yml +++ b/docker-compose.base.yml @@ -22,6 +22,10 @@ x-common-variables: &common-variables ANALYTICS_KEY: ${ANALYTICS_KEY} ANALYTICS_HOST: ${ANALYTICS_HOST} + # VAPID keys for Web Push Notifications + VAPID_PUBLIC_KEY: ${VAPID_PUBLIC_KEY} + VAPID_SUBJECT: ${VAPID_SUBJECT} + ALLOWED_ACTIVE_MONITOR_COUNT_IN_FREE_PLAN: ${ALLOWED_ACTIVE_MONITOR_COUNT_IN_FREE_PLAN} SERVER_ACCOUNTS_HOSTNAME: accounts @@ -76,7 +80,7 @@ x-common-server-variables: &common-server-variables <<: *common-variables ONEUPTIME_SECRET: ${ONEUPTIME_SECRET} - + VAPID_PRIVATE_KEY: ${VAPID_PRIVATE_KEY} DATABASE_PORT: ${DATABASE_PORT} DATABASE_USERNAME: ${DATABASE_USERNAME} DATABASE_PASSWORD: ${DATABASE_PASSWORD}