From aedf260551e42e42b0449540aed861e421528aa9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roman=20Kr=C4=8Dek?= Date: Wed, 3 Sep 2025 10:17:20 +0200 Subject: [PATCH 1/3] Fixed problem where auth is bypassed --- src/service-worker.ts | 58 ++++++++++++++++++++----------------------- 1 file changed, 27 insertions(+), 31 deletions(-) diff --git a/src/service-worker.ts b/src/service-worker.ts index acd0f71..c4c77d2 100644 --- a/src/service-worker.ts +++ b/src/service-worker.ts @@ -31,55 +31,51 @@ self.addEventListener('activate', (event) => { }); self.addEventListener('fetch', (event) => { - // ignore POST requests etc if (event.request.method !== 'GET') return; + // --- START: MODIFICATION TO PREVENT CACHING PRIVATE ROUTES --- + const url = new URL(event.request.url); + + // If the request is for a private route, always fetch from the network. + // This ensures that server-side authentication checks are not bypassed by the cache. + if (url.pathname.startsWith('/private')) { + event.respondWith(fetch(event.request)); + return; + } + // --- END: MODIFICATION --- + async function respond() { const url = new URL(event.request.url); - - // Skip caching for auth routes - if (url.pathname.startsWith('/auth/')) { - return fetch(event.request); - } + const cache = await self.caches.open(CACHE); - const cache = await caches.open(CACHE); - - // `build`/`files` can always be served from the cache + // `build`/`prerendered` pages are cached on install. + // If the page exists in the cache, serve it directly. if (ASSETS.includes(url.pathname)) { - const response = await cache.match(url.pathname); - - if (response) { - return response; + const cachedResponse = await cache.match(url.pathname); + if (cachedResponse) { + return cachedResponse; } } - // for everything else, try the network first, but - // fall back to the cache if we're offline + // For everything else, try to get it from the network. try { const response = await fetch(event.request); - // if we're offline, fetch can return a value that is not a Response - // instead of throwing - and we can't pass this non-Response to respondWith - if (!(response instanceof Response)) { - throw new Error('invalid response from fetch'); - } - - if (response.status === 200) { + // If the request is for a file from the build directory, cache it. + if (response.status === 200 && url.pathname.startsWith(`/${build[0]}/`)) { cache.put(event.request, response.clone()); } return response; - } catch (err) { - const response = await cache.match(event.request); - - if (response) { - return response; + } catch (error) { + // If the network is unavailable, fall back to the cache. + const cachedResponse = await cache.match(event.request); + if (cachedResponse) { + return cachedResponse; } - - // if there's no cache, then just error out - // as there is nothing we can do to respond to this request - throw err; } + + return new Response('Not found', { status: 404 }); } event.respondWith(respond()); -- 2.49.1 From 238d2eebc5f66a1731f7b5c2d56d6948f4360d7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roman=20Kr=C4=8Dek?= Date: Wed, 3 Sep 2025 10:22:59 +0200 Subject: [PATCH 2/3] Fix worker reloads --- package.json | 2 +- src/service-worker.ts | 103 +++++++++++++++++++++++++++++++++++++++++- 2 files changed, 103 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 4e9b0f9..3e4d2d5 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "scan-wave", "private": true, - "version": "0.0.1", + "version": "0.0.2", "type": "module", "scripts": { "dev": "vite dev", diff --git a/src/service-worker.ts b/src/service-worker.ts index c4c77d2..42eaaa8 100644 --- a/src/service-worker.ts +++ b/src/service-worker.ts @@ -1,4 +1,105 @@ -/// +/// +import { build, files, version } from '$service-worker'; + +// Create a unique cache name for this deployment +const CACHE = `cache-${version}`; + +const ASSETS = [ + ...build, // the app itself + ...files // everything in `static` +]; + +self.addEventListener('install', (event) => { + console.log('[Service Worker] Install'); + // Create a new cache and add all files to it + async function addFilesToCache() { + const cache = await caches.open(CACHE); + await cache.addAll(ASSETS); + } + + event.waitUntil(addFilesToCache()); + + // Tell the new service worker to activate immediately + self.skipWaiting(); +}); + +self.addEventListener('activate', (event) => { + console.log('[Service Worker] Activate'); + // Remove previous cached data from disk + async function deleteOldCaches() { + for (const key of await caches.keys()) { + if (key !== CACHE) await caches.delete(key); + } + } + + event.waitUntil(deleteOldCaches()); + + // Tell the active service worker to take control of the page immediately + self.clients.claim(); +}); + +self.addEventListener('fetch', (event) => { + if (event.request.method !== 'GET') return; + + // --- START: MODIFICATION TO PREVENT CACHING PRIVATE ROUTES --- + const url = new URL(event.request.url); + + // If the request is for a private route, always fetch from the network. + // This ensures that server-side authentication checks are not bypassed by the cache. + if (url.pathname.startsWith('/private')) { + event.respondWith(fetch(event.request)); + return; + } + // --- END: MODIFICATION --- + + async function respond() { + const url = new URL(event.request.url); + const cache = await self.caches.open(CACHE); + + // `build`/`prerendered` pages are cached on install. + // If the page exists in the cache, serve it directly. + if (ASSETS.includes(url.pathname)) { + const cachedResponse = await cache.match(url.pathname); + if (cachedResponse) { + return cachedResponse; + } + } + + // For everything else, try to get it from the network. + try { + const response = await fetch(event.request); + + // If the request is for a file from the build directory, cache it. + if (response.status === 200 && build.length > 0 && url.pathname.startsWith(`/${build[0]}/`)) { + cache.put(event.request, response.clone()); + } + + return response; + } catch { + // If the network is unavailable, fall back to the cache. + const cachedResponse = await cache.match(event.request); + if (cachedResponse) { + return cachedResponse; + } + } + + return new Response('Not found', { status: 404 }); + } + + event.respondWith(respond()); +}); +, (event) => { + // Create a new cache and add all files to it + async function addFilesToCache() { + const cache = await self.caches.open(CACHE); + await cache.addAll(ASSETS); + } + + event.waitUntil(addFilesToCache()); + + // Tell the new service worker to activate immediately + self.skipWaiting(); +});="@sveltejs/kit" /> import { build, files, version } from '$service-worker'; // Create a unique cache name for this deployment -- 2.49.1 From e616165a77b9b0dcc778077093c078bb679329e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roman=20Kr=C4=8Dek?= Date: Wed, 3 Sep 2025 10:38:30 +0200 Subject: [PATCH 3/3] Fix service worker mess --- src/service-worker.ts | 212 ++++++++++-------------------------------- 1 file changed, 50 insertions(+), 162 deletions(-) diff --git a/src/service-worker.ts b/src/service-worker.ts index 42eaaa8..efa9528 100644 --- a/src/service-worker.ts +++ b/src/service-worker.ts @@ -1,183 +1,71 @@ -/// +/// +/// import { build, files, version } from '$service-worker'; -// Create a unique cache name for this deployment -const CACHE = `cache-${version}`; +declare const self: ServiceWorkerGlobalScope; +const CACHE = `cache-${version}`; const ASSETS = [ - ...build, // the app itself - ...files // everything in `static` + ...build, + ...files ]; -self.addEventListener('install', (event) => { - console.log('[Service Worker] Install'); - // Create a new cache and add all files to it - async function addFilesToCache() { - const cache = await caches.open(CACHE); - await cache.addAll(ASSETS); - } +self.addEventListener('install', (event: ExtendableEvent) => { + const addFilesToCache = async () => { + const cache = await caches.open(CACHE); + await cache.addAll(ASSETS); + }; - event.waitUntil(addFilesToCache()); + console.log("[SW] Installing new service worker"); - // Tell the new service worker to activate immediately - self.skipWaiting(); + event.waitUntil(addFilesToCache()); + self.skipWaiting(); }); -self.addEventListener('activate', (event) => { - console.log('[Service Worker] Activate'); - // Remove previous cached data from disk - async function deleteOldCaches() { - for (const key of await caches.keys()) { - if (key !== CACHE) await caches.delete(key); - } - } +self.addEventListener('activate', (event: ExtendableEvent) => { + const deleteOldCaches = async () => { + for (const key of await caches.keys()) { + if (key !== CACHE) await caches.delete(key); + console.log("[SW] Removing old service worker") + } + }; - event.waitUntil(deleteOldCaches()); - - // Tell the active service worker to take control of the page immediately - self.clients.claim(); + event.waitUntil(deleteOldCaches()); + self.clients.claim(); }); -self.addEventListener('fetch', (event) => { - if (event.request.method !== 'GET') return; +self.addEventListener('fetch', (event: FetchEvent) => { + if (event.request.method !== 'GET') return; - // --- START: MODIFICATION TO PREVENT CACHING PRIVATE ROUTES --- - const url = new URL(event.request.url); + const url = new URL(event.request.url); - // If the request is for a private route, always fetch from the network. - // This ensures that server-side authentication checks are not bypassed by the cache. - if (url.pathname.startsWith('/private')) { - event.respondWith(fetch(event.request)); - return; - } - // --- END: MODIFICATION --- + // Never cache private routes + if (url.pathname.startsWith('/private')) { + event.respondWith(fetch(event.request)); + return; + } - async function respond() { - const url = new URL(event.request.url); - const cache = await self.caches.open(CACHE); + const respond = async () => { + const cache = await caches.open(CACHE); - // `build`/`prerendered` pages are cached on install. - // If the page exists in the cache, serve it directly. - if (ASSETS.includes(url.pathname)) { - const cachedResponse = await cache.match(url.pathname); - if (cachedResponse) { - return cachedResponse; - } - } + if (ASSETS.includes(url.pathname)) { + const cached = await cache.match(url.pathname); + if (cached) return cached; + } - // For everything else, try to get it from the network. - try { - const response = await fetch(event.request); + try { + const response = await fetch(event.request); + if (response.status === 200 && build.length > 0 && url.pathname.startsWith(`/${build[0]}/`)) { + cache.put(event.request, response.clone()); + } + return response; + } catch { + const cached = await cache.match(event.request); + if (cached) return cached; + } - // If the request is for a file from the build directory, cache it. - if (response.status === 200 && build.length > 0 && url.pathname.startsWith(`/${build[0]}/`)) { - cache.put(event.request, response.clone()); - } + return new Response('Not found', { status: 404 }); + }; - return response; - } catch { - // If the network is unavailable, fall back to the cache. - const cachedResponse = await cache.match(event.request); - if (cachedResponse) { - return cachedResponse; - } - } - - return new Response('Not found', { status: 404 }); - } - - event.respondWith(respond()); + event.respondWith(respond()); }); -, (event) => { - // Create a new cache and add all files to it - async function addFilesToCache() { - const cache = await self.caches.open(CACHE); - await cache.addAll(ASSETS); - } - - event.waitUntil(addFilesToCache()); - - // Tell the new service worker to activate immediately - self.skipWaiting(); -});="@sveltejs/kit" /> -import { build, files, version } from '$service-worker'; - -// Create a unique cache name for this deployment -const CACHE = `cache-${version}`; - -const ASSETS = [ - ...build, // the app itself - ...files // everything in `static` -]; - -self.addEventListener('install', (event) => { - // Create a new cache and add all files to it - async function addFilesToCache() { - const cache = await caches.open(CACHE); - await cache.addAll(ASSETS); - } - - event.waitUntil(addFilesToCache()); -}); - -self.addEventListener('activate', (event) => { - // Remove previous cached data from disk - async function deleteOldCaches() { - for (const key of await caches.keys()) { - if (key !== CACHE) await caches.delete(key); - } - } - - event.waitUntil(deleteOldCaches()); -}); - -self.addEventListener('fetch', (event) => { - if (event.request.method !== 'GET') return; - - // --- START: MODIFICATION TO PREVENT CACHING PRIVATE ROUTES --- - const url = new URL(event.request.url); - - // If the request is for a private route, always fetch from the network. - // This ensures that server-side authentication checks are not bypassed by the cache. - if (url.pathname.startsWith('/private')) { - event.respondWith(fetch(event.request)); - return; - } - // --- END: MODIFICATION --- - - async function respond() { - const url = new URL(event.request.url); - const cache = await self.caches.open(CACHE); - - // `build`/`prerendered` pages are cached on install. - // If the page exists in the cache, serve it directly. - if (ASSETS.includes(url.pathname)) { - const cachedResponse = await cache.match(url.pathname); - if (cachedResponse) { - return cachedResponse; - } - } - - // For everything else, try to get it from the network. - try { - const response = await fetch(event.request); - - // If the request is for a file from the build directory, cache it. - if (response.status === 200 && url.pathname.startsWith(`/${build[0]}/`)) { - cache.put(event.request, response.clone()); - } - - return response; - } catch (error) { - // If the network is unavailable, fall back to the cache. - const cachedResponse = await cache.match(event.request); - if (cachedResponse) { - return cachedResponse; - } - } - - return new Response('Not found', { status: 404 }); - } - - event.respondWith(respond()); -}); \ No newline at end of file -- 2.49.1