From 9ae24aa6fb9a1481e367db32824d442ed92c431f Mon Sep 17 00:00:00 2001 From: elpatron Date: Wed, 3 Jun 2026 17:18:49 +0200 Subject: [PATCH] fix: allow microphone access for voice memos in PWA Permissions-Policy blocked getUserMedia; allow microphone on same origin like camera. Co-authored-by: Cursor --- client/nginx.conf | 6 +++--- client/src/components/LiveVoiceCapture.tsx | 4 ++++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/client/nginx.conf b/client/nginx.conf index ac4b841..16d7399 100644 --- a/client/nginx.conf +++ b/client/nginx.conf @@ -7,7 +7,7 @@ server { add_header X-Content-Type-Options "nosniff" always; add_header X-Frame-Options "SAMEORIGIN" always; add_header Referrer-Policy "strict-origin-when-cross-origin" always; - add_header Permissions-Policy "camera=(self), geolocation=(self), microphone=()" always; + add_header Permissions-Policy "camera=(self), geolocation=(self), microphone=(self)" always; add_header Content-Security-Policy "default-src 'self'; script-src 'self' https://plausible.elpatron.me; connect-src 'self' https://plausible.elpatron.me; img-src 'self' data: blob: https://*.tile.openstreetmap.org; style-src 'self' 'unsafe-inline'; font-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'self';" always; # Service worker and app shell must revalidate so PWA updates are detected @@ -17,7 +17,7 @@ server { add_header X-Content-Type-Options "nosniff" always; add_header X-Frame-Options "SAMEORIGIN" always; add_header Referrer-Policy "strict-origin-when-cross-origin" always; - add_header Permissions-Policy "camera=(self), geolocation=(self), microphone=()" always; + add_header Permissions-Policy "camera=(self), geolocation=(self), microphone=(self)" always; add_header Content-Security-Policy "default-src 'self'; script-src 'self' https://plausible.elpatron.me; connect-src 'self' https://plausible.elpatron.me; img-src 'self' data: blob: https://*.tile.openstreetmap.org; style-src 'self' 'unsafe-inline'; font-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'self';" always; } @@ -27,7 +27,7 @@ server { add_header X-Content-Type-Options "nosniff" always; add_header X-Frame-Options "SAMEORIGIN" always; add_header Referrer-Policy "strict-origin-when-cross-origin" always; - add_header Permissions-Policy "camera=(self), geolocation=(self), microphone=()" always; + add_header Permissions-Policy "camera=(self), geolocation=(self), microphone=(self)" always; add_header Content-Security-Policy "default-src 'self'; script-src 'self' https://plausible.elpatron.me; connect-src 'self' https://plausible.elpatron.me; img-src 'self' data: blob: https://*.tile.openstreetmap.org; style-src 'self' 'unsafe-inline'; font-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'self';" always; } diff --git a/client/src/components/LiveVoiceCapture.tsx b/client/src/components/LiveVoiceCapture.tsx index 05ccdc0..63b3f6e 100644 --- a/client/src/components/LiveVoiceCapture.tsx +++ b/client/src/components/LiveVoiceCapture.tsx @@ -116,6 +116,10 @@ export default function LiveVoiceCapture({ const startRecording = async () => { setMicError(null) chunksRef.current = [] + if (!navigator.mediaDevices?.getUserMedia) { + setMicError(t('logs.live_voice_mic_denied')) + return + } try { const stream = await navigator.mediaDevices.getUserMedia({ audio: true }) streamRef.current = stream