From 65502e0b0beb97de902bbdce847ab1ede98ada8b Mon Sep 17 00:00:00 2001 From: borja Date: Mon, 13 Oct 2025 21:10:02 +0200 Subject: [PATCH] fix: restringir cabeceras a HTML y robustecer proxy; quitar checkOrigin Co-authored-by: aider (openrouter/openai/gpt-5) --- apps/web/src/hooks.server.ts | 12 ++++++++---- apps/web/svelte.config.js | 1 - proxy.ts | 9 +++++++-- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/apps/web/src/hooks.server.ts b/apps/web/src/hooks.server.ts index a9d7854..e763d87 100644 --- a/apps/web/src/hooks.server.ts +++ b/apps/web/src/hooks.server.ts @@ -70,11 +70,15 @@ export const handle: Handle = async ({ event, resolve }) => { const response = await resolve(event); - // Cabeceras de seguridad básicas + // Cabeceras de seguridad y caché: solo para HTML try { - response.headers.set('X-Frame-Options', 'DENY'); - response.headers.set('Referrer-Policy', 'no-referrer'); - response.headers.set('X-Content-Type-Options', 'nosniff'); + const ct = response.headers.get('content-type') || ''; + if (ct.includes('text/html')) { + response.headers.set('cache-control', 'no-store'); + response.headers.set('X-Frame-Options', 'DENY'); + response.headers.set('Referrer-Policy', 'no-referrer'); + response.headers.set('X-Content-Type-Options', 'nosniff'); + } } catch { // Ignorar si la implementación de Response no permite set() } diff --git a/apps/web/svelte.config.js b/apps/web/svelte.config.js index 2bbd211..6208ddc 100644 --- a/apps/web/svelte.config.js +++ b/apps/web/svelte.config.js @@ -13,7 +13,6 @@ const config = { // See https://svelte.dev/docs/kit/adapters for more information about adapters. adapter: adapter(), csrf: { - checkOrigin: false, trustedOrigins: ['*'] } } diff --git a/proxy.ts b/proxy.ts index 42e58d2..e703cfa 100644 --- a/proxy.ts +++ b/proxy.ts @@ -48,8 +48,13 @@ Bun.serve({ try { console.log(`[proxy] ${req.method} ${url.pathname}${url.search} -> ${routeToBot ? 'bot' : 'web'} ${res.status} (${ms}ms)`); } catch {} - // Devuelve la respuesta tal cual (incluye Set-Cookie, Location, etc.) - return res; + // Devuelve la respuesta (incluye Set-Cookie, Location, etc.), asegurando Content-Type en assets por si faltase + const passthroughHeaders = new Headers(res.headers); + if (!passthroughHeaders.get('content-type')) { + if (url.pathname.endsWith('.js')) passthroughHeaders.set('content-type', 'application/javascript; charset=utf-8'); + if (url.pathname.endsWith('.css')) passthroughHeaders.set('content-type', 'text/css; charset=utf-8'); + } + return new Response(res.body, { status: res.status, headers: passthroughHeaders }); } catch (err) { const msg = err instanceof Error ? err.message : String(err); console.error(`[proxy] ${req.method} ${url.pathname}${url.search} -> ERROR: ${msg}`);