Files
ApiCore/ApiCore-Frontend/src/proxy.ts
T
Nick.RosenloecherandClaude Opus 5.5 2395576c88 feat(t5): App-Icons, Manifest und Offline-Cache v5 (T5a A9)
- Honigzelle auf Tinte als Master-SVG; scripts/generate-icons.mjs erzeugt
  any/maskable 192/512, Monochrom 512, drei Shortcut-Icons, Apple-Icon und
  favicon.ico (16/32/48, ICO-Container von Hand) byte-gleich bei jedem Lauf.
- manifest.ts exakt nach Spec 12.3, Farben gleich dem hellen --background.
- Service Worker: SHELL_CACHE apicore-shell-v5, Icons im Shell-Cache; ein
  fehlendes Icon hält das Vorladen der Seiten nicht auf.
- Proxy-Matcher: nur echte Icon-Dateien (icons/*.png) ohne
  Sicherheits-Header, Punkte maskiert.
- BrandMark-Deckel mittig (linke Kante 18.8).

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-10-16 17:51:41 +02:00

79 lines
3.2 KiB
TypeScript

import { NextResponse } from "next/server";
// There used to be a cookie-based redirect-to-/login check here, gated on
// the "refreshToken" cookie. It could never work: that cookie is set by the
// BACKEND's own origin (a different domain, apicorebackend.* vs apicore.*),
// scoped to /api/v1/auth - the browser never sends it on requests to the
// frontend, so this proxy (running on the frontend's origin) can never see
// it. The check always evaluated "no session", harmless while this file
// sat in the wrong directory and never ran at all, but once relocated so
// Next.js actually picked it up, it started force-redirecting every visit
// to /settings, /apiaries, /colonies, /queens straight back to /login,
// regardless of whether the user was genuinely logged in - login state for
// this app is only observable client-side (in-memory access token,
// cross-origin refresh cookie), which is exactly what
// src/app/(app)/layout.tsx already correctly redirects on. Removed rather
// than patched: there is no way to make a cross-origin cookie visible to
// this server without weakening the cookie itself (e.g. dropping its path
// scope), which isn't worth it for a redirect the client already handles.
// Deliberately computed here, not in next.config.ts: that file's headers()
// is resolved once at build time and frozen into the standalone output, so
// process.env.API_URL there is whatever was (or wasn't) set during the
// Docker build - never the container's actual runtime value. Proxy runs the
// Node.js runtime fresh on every request, so this reads the real deployed
// API_URL correctly instead of silently falling back to localhost forever.
function apiOrigin(): string {
try {
return new URL(process.env.API_URL ?? "http://localhost:3001").origin;
} catch {
return "";
}
}
function cspHeader(): string {
return `
default-src 'self';
script-src 'self' 'unsafe-inline';
style-src 'self' 'unsafe-inline';
img-src 'self' blob: data:;
media-src 'self' blob:;
font-src 'self';
connect-src 'self' ${apiOrigin()};
object-src 'none';
base-uri 'self';
form-action 'self';
frame-ancestors 'self';
upgrade-insecure-requests;
`
.replace(/\s{2,}/g, " ")
.trim();
}
function withSecurityHeaders(response: NextResponse): NextResponse {
response.headers.set("Content-Security-Policy", cspHeader());
response.headers.set("X-Frame-Options", "SAMEORIGIN");
response.headers.set("X-Content-Type-Options", "nosniff");
response.headers.set("Referrer-Policy", "no-referrer");
response.headers.set(
"Strict-Transport-Security",
"max-age=31536000; includeSubDomains",
);
return response;
}
export function proxy() {
return withSecurityHeaders(NextResponse.next());
}
// Static files without security headers: build assets, the worker, the
// manifest and the app icons (public/icons/*.png, src/app/apple-icon.png).
// Dots are escaped and file names end at `$`, so no page that merely starts
// like one of them (`/iconsx`, `/favicon.icox`, `/icons/x/y`) loses its
// headers; manifest.spec checks it.
export const config = {
matcher: [
"/((?!_next/static/|_next/image$|favicon\\.ico$|sw\\.js$|manifest\\.webmanifest$|icon\\.svg$|apple-icon\\.png$|icons/[\\w-]+\\.png$).*)",
],
};