diff --git a/docker-compose.yml b/docker-compose.yml index 3ec20fc2b..89b78d31b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -27,7 +27,8 @@ services: - "traefik.http.routers.${PROJECT_NAME:-klz}.middlewares=${AUTH_MIDDLEWARE:-etib-ratelimit,etib-forward,etib-compress}" # Public Router – paths that bypass Gatekeeper auth (health, SEO, static assets, OG images) - - "traefik.http.routers.${PROJECT_NAME:-klz}-public.rule=(${TRAEFIK_HOST_RULE:-Host(`${TRAEFIK_HOST:-e-tib.com}`) || Host(`staging.${TRAEFIK_HOST:-e-tib.com}`) || Host(`testing.${TRAEFIK_HOST:-e-tib.com}`)}) && PathRegexp(`^/([a-z]{2}/)?(health|login|gatekeeper|uploads|media|assets|robots\\.txt|manifest\\.webmanifest|sitemap(-[0-9]+)?\\.xml|(.*/)?api/og(/.*)?|(.*/)?opengraph-image.*)`)" + - "traefik.http.routers.${PROJECT_NAME:-klz}-public.rule=(${TRAEFIK_HOST_RULE:-Host(`${TRAEFIK_HOST:-e-tib.com}`) || Host(`staging.${TRAEFIK_HOST:-e-tib.com}`) || Host(`testing.${TRAEFIK_HOST:-e-tib.com}`)}) && PathRegexp(`^/([a-z]{2}/)?(health|login|gatekeeper|uploads|media|assets|_next|robots\\.txt|manifest\\.webmanifest|sitemap(-[0-9]+)?\\.xml|(.*/)?api/og(/.*)?|(.*/)?opengraph-image.*)`)" + - "traefik.http.routers.${PROJECT_NAME:-klz}-public.entrypoints=${TRAEFIK_ENTRYPOINT:-web}" - "traefik.http.routers.${PROJECT_NAME:-klz}-public.tls.certresolver=${TRAEFIK_CERT_RESOLVER:-}" - "traefik.http.routers.${PROJECT_NAME:-klz}-public.tls=${TRAEFIK_TLS:-false}" diff --git a/package.json b/package.json index 58baa705b..564a1c7d0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "e-tib-nextjs", - "version": "2.4.56", + "version": "2.4.57", "type": "module", "private": true, "packageManager": "pnpm@10.18.3", diff --git a/proxy.ts b/proxy.ts index fae6aa4f9..39793a3c1 100644 --- a/proxy.ts +++ b/proxy.ts @@ -7,11 +7,12 @@ export default createMiddleware({ }); export const config = { - // Match all pathnames except for + // Match all pathnames except for: // - /api (API routes) // - /stats (Analytics proxy) - // - /_next (Next.js internals) - // - /_static (inside /public) - // - all root files inside /public (e.g. /favicon.ico) - matcher: ['/((?!api|stats|_next|assets|_static|_vercel|[\\w-]+\\.\\w+).*)'] + // - /_next (Next.js internals & image optimizer) + // - /assets, /_static (static files in /public) + // - all files with an extension (e.g. /favicon.ico, .JPG, .png, .webp, .svg) + matcher: ['/((?!api|stats|_next|assets|_static|_vercel|.*\\..*).*)'] }; + diff --git a/tests/proxy-config.test.ts b/tests/proxy-config.test.ts new file mode 100644 index 000000000..1404ea9b3 --- /dev/null +++ b/tests/proxy-config.test.ts @@ -0,0 +1,21 @@ +import { describe, it, expect } from 'vitest'; +import { config } from '../proxy'; + +describe('Proxy Middleware Config Matcher', () => { + const matcherRegex = new RegExp(`^${config.matcher[0]}`); + + + it('matches localized page routes for next-intl processing', () => { + expect(matcherRegex.test('/de')).toBe(true); + expect(matcherRegex.test('/en/contact')).toBe(true); + expect(matcherRegex.test('/karriere')).toBe(true); + }); + + it('excludes static assets with any file extension including uppercase .JPG and subdirectories', () => { + // These should NOT match the middleware (expect test to be false so middleware is bypassed) + expect(matcherRegex.test('/assets/photos/DJI_0048.JPG')).toBe(false); + expect(matcherRegex.test('/assets/videos/web/hero-kabelpflug-poster.jpg')).toBe(false); + expect(matcherRegex.test('/assets/logo-white.png')).toBe(false); + expect(matcherRegex.test('/_next/image')).toBe(false); + }); +});