73 lines
2.9 KiB
JavaScript
73 lines
2.9 KiB
JavaScript
/** @type {import('next').NextConfig} */
|
||
|
||
// MultiToolApp-Plattform (module-plan.md):
|
||
// HUB_URL – Basis-URL des Hubs (JWKS-Abruf für Token-Validierung)
|
||
// HUB_BASE_PATH – Pfad, unter dem der Hub diese App routet (z. B. /apps/kalender).
|
||
// Setzt Next.js basePath → alle Routen hängen darunter.
|
||
// Ohne HUB_BASE_PATH läuft die App standalone (basePath: '').
|
||
const hubUrl = (process.env.HUB_URL ?? '').replace(/\/$/, '');
|
||
const hubBasePath = (process.env.HUB_BASE_PATH ?? '').replace(/\/$/, '');
|
||
|
||
const nextConfig = {
|
||
// Standalone-Ausgabe für einen schlanken Docker-Container
|
||
output: 'standalone',
|
||
reactStrictMode: true,
|
||
// Proxy-Modus: App läuft unter /apps/<slug> innerhalb der Hub-Domain.
|
||
// basePath '' (falsy) = Standalone-Betrieb ohne Pfad-Präfix.
|
||
...(hubBasePath ? { basePath: hubBasePath } : {}),
|
||
// Manifest-Route: /.well-known/app-manifest → /api/manifest
|
||
// (Next.js App Router routed keine Dot-Ordner; mit beforeFiles-Phase
|
||
// fangen wir den Pfad ab, bevor basePath zuschlägt.)
|
||
async rewrites() {
|
||
return {
|
||
beforeFiles: [
|
||
{
|
||
source: '/.well-known/app-manifest',
|
||
destination: '/api/manifest',
|
||
},
|
||
],
|
||
};
|
||
},
|
||
// Security-Header (Next.js setzt keine davon by default):
|
||
// - X-Content-Type-Options: verhindert MIME-Sniffing
|
||
// - Referrer-Policy: keine URLs/Token an Dritte leaken
|
||
// - Permissions-Policy: Browser-Features, die die App nicht nutzt
|
||
// - CSP: Skripte nur 'self' + Inline (Next.js Hydration-Snippet);
|
||
// style-src 'unsafe-inline' ist fuer Tailwind noetig.
|
||
// - frame-ancestors: nur der Hub darf einbetten (statt X-Frame-Options,
|
||
// das Subdomain-Embedding blockieren wuerde – platform-plan.md §4).
|
||
async headers() {
|
||
return [
|
||
{
|
||
source: '/:path*',
|
||
headers: [
|
||
{ key: 'X-Content-Type-Options', value: 'nosniff' },
|
||
{ key: 'Referrer-Policy', value: 'strict-origin-when-cross-origin' },
|
||
{
|
||
key: 'Permissions-Policy',
|
||
value: 'camera=(), microphone=(), geolocation=()',
|
||
},
|
||
{
|
||
key: 'Content-Security-Policy',
|
||
value: [
|
||
"default-src 'self'",
|
||
"script-src 'self' 'unsafe-inline'",
|
||
"style-src 'self' 'unsafe-inline'",
|
||
"img-src 'self' data:",
|
||
"font-src 'self'",
|
||
// JWKS-Abruf vom Hub (Token-Validierung in /auth/hub)
|
||
hubUrl ? `connect-src 'self' ${hubUrl}` : "connect-src 'self'",
|
||
// Proxy-Modus: kein Framing mehr nötig – aber der Hub darf
|
||
// weiterhin einbetten (Rückwärtskompatibilität).
|
||
hubUrl ? `frame-ancestors ${hubUrl}` : "frame-ancestors 'none'",
|
||
"base-uri 'self'",
|
||
"form-action 'self'",
|
||
].join('; '),
|
||
},
|
||
],
|
||
},
|
||
];
|
||
},
|
||
};
|
||
|
||
export default nextConfig; |