refactor(push): load VAPID key from server at runtime

This commit is contained in:
2026-01-13 12:14:17 +01:00
parent 3a50bb5299
commit 3a16705614
4 changed files with 36 additions and 20 deletions

View File

@@ -12,10 +12,6 @@ COPY . .
# Use a temporary DB for generation # Use a temporary DB for generation
ENV DATABASE_URL="file:./temp.db" ENV DATABASE_URL="file:./temp.db"
# Build arguments for public env vars
ARG NEXT_PUBLIC_VAPID_PUBLIC_KEY
ENV NEXT_PUBLIC_VAPID_PUBLIC_KEY=$NEXT_PUBLIC_VAPID_PUBLIC_KEY
RUN npx prisma generate RUN npx prisma generate
RUN npm run build RUN npm run build

View File

@@ -73,10 +73,8 @@ docker-compose up -d --build
Mit **Docker CLI**: Mit **Docker CLI**:
```bash ```bash
# Image bauen (Beachte: Public Vars müssen beim Build da sein!) # Image bauen
docker build \ docker build -t cat-sitting-planner .
--build-arg NEXT_PUBLIC_VAPID_PUBLIC_KEY="DEIN_PUBLIC_KEY" \
-t cat-sitting-planner .
# Container starten # Container starten
# Container starten # Container starten

View File

@@ -43,3 +43,7 @@ export async function unsubscribeUser(endpoint: string) {
return { success: true }; return { success: true };
} }
export async function getVapidPublicKey() {
return process.env.NEXT_PUBLIC_VAPID_PUBLIC_KEY;
}

View File

@@ -3,7 +3,7 @@
import { useState, useEffect } from "react" import { useState, useEffect } from "react"
import { Bell, BellOff, Loader2, AlertTriangle } from "lucide-react" import { Bell, BellOff, Loader2, AlertTriangle } from "lucide-react"
import { toast } from "sonner" import { toast } from "sonner"
import { subscribeUser, unsubscribeUser } from "@/app/actions/subscription" import { subscribeUser, unsubscribeUser, getVapidPublicKey } from "@/app/actions/subscription"
import { Button } from "@/components/ui/button" import { Button } from "@/components/ui/button"
function urlBase64ToUint8Array(base64String: string) { function urlBase64ToUint8Array(base64String: string) {
@@ -31,12 +31,24 @@ export function PushSubscriptionSettings({ planId }: { planId: string }) {
const [subscription, setSubscription] = useState<PushSubscription | null>(null) const [subscription, setSubscription] = useState<PushSubscription | null>(null)
const [loading, setLoading] = useState(false) const [loading, setLoading] = useState(false)
const [debugInfo, setDebugInfo] = useState<string | null>(null) const [debugInfo, setDebugInfo] = useState<string | null>(null)
const [vapidKey, setVapidKey] = useState<string | null>(null)
useEffect(() => { useEffect(() => {
async function checkSupport() {
const checks = [] const checks = []
if (!('serviceWorker' in navigator)) checks.push("No Service Worker support") if (!('serviceWorker' in navigator)) checks.push("No Service Worker support")
if (!('PushManager' in window)) checks.push("No PushManager support") if (!('PushManager' in window)) checks.push("No PushManager support")
if (!process.env.NEXT_PUBLIC_VAPID_PUBLIC_KEY) checks.push("Missing VAPID Key")
try {
const key = await getVapidPublicKey()
if (!key) {
checks.push("Missing VAPID Key (Server)")
} else {
setVapidKey(key)
}
} catch (e) {
checks.push("Failed to fetch VAPID Key")
}
if (checks.length === 0) { if (checks.length === 0) {
setIsSupported(true) setIsSupported(true)
@@ -45,6 +57,8 @@ export function PushSubscriptionSettings({ planId }: { planId: string }) {
console.warn("Push not supported:", checks.join(", ")) console.warn("Push not supported:", checks.join(", "))
setDebugInfo(checks.join(", ")) setDebugInfo(checks.join(", "))
} }
}
checkSupport()
}, []) }, [])
async function registerServiceWorker() { async function registerServiceWorker() {
@@ -59,6 +73,10 @@ export function PushSubscriptionSettings({ planId }: { planId: string }) {
} }
async function subscribe() { async function subscribe() {
if (!vapidKey) {
toast.error("VAPID Key missing")
return
}
setLoading(true) setLoading(true)
setDebugInfo(null) setDebugInfo(null)
try { try {
@@ -84,7 +102,7 @@ export function PushSubscriptionSettings({ planId }: { planId: string }) {
const sub = await registration.pushManager.subscribe({ const sub = await registration.pushManager.subscribe({
userVisibleOnly: true, userVisibleOnly: true,
applicationServerKey: urlBase64ToUint8Array(process.env.NEXT_PUBLIC_VAPID_PUBLIC_KEY!) applicationServerKey: urlBase64ToUint8Array(vapidKey)
}) })
console.log("Subscribed locally:", sub) console.log("Subscribed locally:", sub)