53 lines
1.7 KiB
TypeScript
53 lines
1.7 KiB
TypeScript
import { NextResponse } from 'next/server';
|
|
import type { NextRequest } from 'next/server';
|
|
|
|
export function middleware(request: NextRequest) {
|
|
const response = NextResponse.next();
|
|
|
|
// Security Headers
|
|
const headers = response.headers;
|
|
|
|
// Prevent clickjacking
|
|
headers.set('X-Frame-Options', 'SAMEORIGIN');
|
|
|
|
// XSS Protection (legacy but still useful)
|
|
headers.set('X-XSS-Protection', '1; mode=block');
|
|
|
|
// Prevent MIME type sniffing
|
|
headers.set('X-Content-Type-Options', 'nosniff');
|
|
|
|
// Referrer Policy
|
|
headers.set('Referrer-Policy', 'strict-origin-when-cross-origin');
|
|
|
|
// Permissions Policy (restrict features)
|
|
headers.set('Permissions-Policy', 'camera=(), microphone=(), geolocation=()');
|
|
|
|
// Content Security Policy
|
|
const csp = [
|
|
"default-src 'self'",
|
|
"script-src 'self' 'unsafe-inline' 'unsafe-eval' https://plausible.elpatron.me", // Next.js requires unsafe-inline/eval
|
|
"style-src 'self' 'unsafe-inline'", // Allow inline styles
|
|
"img-src 'self' data: blob:",
|
|
"font-src 'self' data:",
|
|
"connect-src 'self' https://openrouter.ai https://gotify.example.com https://plausible.elpatron.me",
|
|
"media-src 'self' blob:",
|
|
"frame-ancestors 'self'",
|
|
].join('; ');
|
|
headers.set('Content-Security-Policy', csp);
|
|
|
|
return response;
|
|
}
|
|
|
|
// Apply middleware to all routes
|
|
export const config = {
|
|
matcher: [
|
|
/*
|
|
* Match all request paths except for the ones starting with:
|
|
* - _next/static (static files)
|
|
* - _next/image (image optimization files)
|
|
* - favicon.ico (favicon file)
|
|
*/
|
|
'/((?!_next/static|_next/image|favicon.ico).*)',
|
|
],
|
|
};
|