All checks were successful
Build & Deploy / 🔍 Prepare (push) Successful in 11s
Build & Deploy / 🧪 QA (push) Successful in 1m28s
Build & Deploy / 🏗️ Build (push) Successful in 7m17s
Build & Deploy / 🚀 Deploy (push) Successful in 26s
Build & Deploy / 🧪 Smoke Test (push) Successful in 1m4s
Build & Deploy / ⚡ Lighthouse (push) Successful in 2m40s
Build & Deploy / 🔔 Notify (push) Successful in 1s
- Fixed invalid Traefik rule syntax in docker-compose.yml (was using raw hostname) - Updated middleware.ts to explicitly allow localized paths - Ensures whitelist for OG images/health checks is recognized
102 lines
3.3 KiB
TypeScript
102 lines
3.3 KiB
TypeScript
import createMiddleware from 'next-intl/middleware';
|
|
import { NextRequest, NextResponse } from 'next/server';
|
|
|
|
// Create the internationalization middleware
|
|
const intlMiddleware = createMiddleware({
|
|
// A list of all locales that are supported
|
|
locales: ['en', 'de'],
|
|
|
|
// Used when no locale matches
|
|
defaultLocale: 'en',
|
|
});
|
|
|
|
export default function middleware(request: NextRequest) {
|
|
const { method, url, headers } = request;
|
|
const { pathname } = request.nextUrl;
|
|
|
|
// Explicit bypass for infrastructure routes to avoid locale redirects/interception
|
|
if (
|
|
pathname.startsWith('/stats') ||
|
|
pathname.startsWith('/errors') ||
|
|
pathname.startsWith('/health') ||
|
|
pathname.includes('/api/og') ||
|
|
pathname.includes('opengraph-image') ||
|
|
pathname.endsWith('sitemap.xml') ||
|
|
pathname.endsWith('manifest.webmanifest')
|
|
) {
|
|
return NextResponse.next();
|
|
}
|
|
|
|
// Build header object for logging
|
|
const headerObj: Record<string, string> = {};
|
|
headers.forEach((value, key) => {
|
|
headerObj[key] = value;
|
|
});
|
|
|
|
// Defensive URL correction for internal container leakage (0.0.0.0, klz-app, localhost)
|
|
// This prevents hydration mismatches and host poisoning in generated links/metadata.
|
|
const urlObj = new URL(url);
|
|
const internalHosts = ['0.0.0.0', 'klz-app', 'localhost', '127.0.0.1'];
|
|
|
|
let effectiveRequest = request;
|
|
if (internalHosts.includes(urlObj.hostname)) {
|
|
const proto = headers.get('x-forwarded-proto') || 'https';
|
|
// Prioritize x-forwarded-host (passed by Traefik) over the local Host header
|
|
const hostHeader =
|
|
headers.get('x-forwarded-host') || headers.get('host') || 'testing.klz-cables.com';
|
|
|
|
urlObj.protocol = proto;
|
|
|
|
effectiveRequest = new NextRequest(urlObj, {
|
|
headers: request.headers,
|
|
method: request.method,
|
|
body: request.body,
|
|
});
|
|
|
|
console.log(
|
|
`🛡️ Proxy: Fixed internal URL leak: ${url} -> ${urlObj.toString()} | Proto: ${proto} | Host: ${hostHeader}`,
|
|
);
|
|
}
|
|
|
|
try {
|
|
// Apply internationalization middleware
|
|
const response = intlMiddleware(effectiveRequest);
|
|
|
|
// Upgrade 307 (Temporary Redirect) to 308 (Permanent Redirect)
|
|
// This improves compatibility with scanners (Website Carbon, PageSpeed) and SEO.
|
|
if (response.status === 307) {
|
|
const location = response.headers.get('Location');
|
|
if (location) {
|
|
const url = new URL(location, request.url);
|
|
return Response.redirect(url, 308);
|
|
}
|
|
}
|
|
|
|
// Allow iframe embedding from recorder domains
|
|
const referer = headers.get('referer') || '';
|
|
const recorderDomains = ['recorder.localhost', 'recorder.mintel.me'];
|
|
const isRecorderRequest = recorderDomains.some((domain) => referer.includes(domain));
|
|
|
|
if (isRecorderRequest) {
|
|
response.headers.delete('x-frame-options');
|
|
response.headers.delete('content-security-policy');
|
|
response.headers.set('Access-Control-Allow-Origin', '*');
|
|
}
|
|
|
|
return response;
|
|
} catch (error) {
|
|
console.error(
|
|
`Request failed: method=${method} url=${url} headers=${JSON.stringify(headerObj)}`,
|
|
error,
|
|
);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
export const config = {
|
|
matcher: [
|
|
'/((?!api|_next/static|_next/image|favicon.ico|manifest.webmanifest|.*\\.(?:svg|png|jpg|jpeg|gif|webp|pdf|txt|vcf|xml)$).*)',
|
|
'/(de|en)/:path*',
|
|
],
|
|
};
|