From 27849add07e72180855048e300e59eda51c27885 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 21 Feb 2026 18:55:34 +0000 Subject: [PATCH 1/2] Bump ajv from 6.12.6 to 6.14.0 Bumps [ajv](https://github.com/ajv-validator/ajv) from 6.12.6 to 6.14.0. - [Release notes](https://github.com/ajv-validator/ajv/releases) - [Commits](https://github.com/ajv-validator/ajv/compare/v6.12.6...v6.14.0) --- updated-dependencies: - dependency-name: ajv dependency-version: 6.14.0 dependency-type: indirect ... Signed-off-by: dependabot[bot] --- pnpm-lock.yaml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3f2b1ce65..5553d72aa 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -4196,6 +4196,7 @@ packages: glob@10.5.0: resolution: {integrity: sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==} + deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me hasBin: true glob@13.0.0: @@ -4204,12 +4205,12 @@ packages: glob@7.2.3: resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} - deprecated: Glob versions prior to v9 are no longer supported + deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me glob@8.1.0: resolution: {integrity: sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==} engines: {node: '>=12'} - deprecated: Glob versions prior to v9 are no longer supported + deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me global-dirs@3.0.1: resolution: {integrity: sha512-NBcGGFbBA9s1VzD41QXDG+3++t9Mn5t1FpLdhESY6oKY4gYTFpX4wO3sqGUa0Srjtbfj3szX0RnemmrVRUdULA==} @@ -6758,6 +6759,7 @@ packages: tar@6.2.1: resolution: {integrity: sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==} engines: {node: '>=10'} + deprecated: Old versions of tar are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me terser@5.43.1: resolution: {integrity: sha512-+6erLbBm0+LROX2sPXlUYx/ux5PyE9K/a92Wrt6oA+WDAoFTdpHE5tCYCI5PNzq2y8df4rA+QgHLJuR4jNymsg==} From 25081d690eb619a2b0cb9be54a5d16c3c6db4fb6 Mon Sep 17 00:00:00 2001 From: cryst Date: Mon, 9 Mar 2026 19:56:41 +0000 Subject: [PATCH 2/2] Fix tracker script name route matching --- docker/middleware.ts | 10 +++-- .../__tests__/match-configured-path.test.ts | 17 +++++++++ src/lib/match-configured-path.ts | 38 +++++++++++++++++++ 3 files changed, 61 insertions(+), 4 deletions(-) create mode 100644 src/lib/__tests__/match-configured-path.test.ts create mode 100644 src/lib/match-configured-path.ts diff --git a/docker/middleware.ts b/docker/middleware.ts index 4b189df89..15111884d 100644 --- a/docker/middleware.ts +++ b/docker/middleware.ts @@ -1,4 +1,5 @@ import { type NextRequest, NextResponse } from 'next/server'; +import { matchesConfiguredPath } from '@/lib/match-configured-path'; export const config = { matcher: '/:path*', @@ -7,6 +8,7 @@ export const config = { const TRACKER_PATH = '/script.js'; const COLLECT_PATH = '/api/send'; const LOGIN_PATH = '/login'; +const BASE_PATH = process.env.BASE_PATH || ''; const apiHeaders = { 'Access-Control-Allow-Origin': '*', @@ -27,7 +29,7 @@ function customCollectEndpoint(request: NextRequest) { if (collectEndpoint) { const url = request.nextUrl.clone(); - if (url.pathname.endsWith(collectEndpoint)) { + if (matchesConfiguredPath(url.pathname, collectEndpoint, BASE_PATH)) { url.pathname = COLLECT_PATH; return NextResponse.rewrite(url, { headers: apiHeaders }); } @@ -41,7 +43,7 @@ function customScriptName(request: NextRequest) { const url = request.nextUrl.clone(); const names = scriptName.split(',').map(name => name.trim().replace(/^\/+/, '')); - if (names.find(name => url.pathname.endsWith(name))) { + if (names.find(name => matchesConfiguredPath(url.pathname, name, BASE_PATH))) { url.pathname = TRACKER_PATH; return NextResponse.rewrite(url, { headers: trackerHeaders }); } @@ -51,7 +53,7 @@ function customScriptName(request: NextRequest) { function customScriptUrl(request: NextRequest) { const scriptUrl = process.env.TRACKER_SCRIPT_URL; - if (scriptUrl && request.nextUrl.pathname.endsWith(TRACKER_PATH)) { + if (scriptUrl && matchesConfiguredPath(request.nextUrl.pathname, TRACKER_PATH, BASE_PATH)) { return NextResponse.rewrite(scriptUrl, { headers: trackerHeaders }); } } @@ -59,7 +61,7 @@ function customScriptUrl(request: NextRequest) { function disableLogin(request: NextRequest) { const loginDisabled = process.env.DISABLE_LOGIN; - if (loginDisabled && request.nextUrl.pathname.endsWith(LOGIN_PATH)) { + if (loginDisabled && matchesConfiguredPath(request.nextUrl.pathname, LOGIN_PATH, BASE_PATH)) { return new NextResponse('Access denied', { status: 403 }); } } diff --git a/src/lib/__tests__/match-configured-path.test.ts b/src/lib/__tests__/match-configured-path.test.ts new file mode 100644 index 000000000..f70ba9c1e --- /dev/null +++ b/src/lib/__tests__/match-configured-path.test.ts @@ -0,0 +1,17 @@ +import { matchesConfiguredPath } from '../match-configured-path'; + +test('matches the exact configured path', () => { + expect(matchesConfiguredPath('/d.js', 'd.js')).toBe(true); +}); + +test('does not match unrelated asset paths that only share the suffix', () => { + expect(matchesConfiguredPath('/_next/static/chunks/app/dashboard.js', 'd.js')).toBe(false); +}); + +test('matches paths under the configured base path', () => { + expect(matchesConfiguredPath('/umami/d.js', 'd.js', '/umami')).toBe(true); +}); + +test('normalizes leading slashes in configured paths', () => { + expect(matchesConfiguredPath('/script.js', '/script.js')).toBe(true); +}); diff --git a/src/lib/match-configured-path.ts b/src/lib/match-configured-path.ts new file mode 100644 index 000000000..104319f2d --- /dev/null +++ b/src/lib/match-configured-path.ts @@ -0,0 +1,38 @@ +function normalizePathname(pathname?: string) { + if (!pathname) { + return ''; + } + + return `/${pathname.replace(/^\/+/, '')}`; +} + +function normalizeBasePath(basePath?: string) { + if (!basePath) { + return ''; + } + + return `/${basePath.replace(/^\/+|\/+$/g, '')}`; +} + +export function matchesConfiguredPath( + pathname: string, + configuredPath?: string, + basePath?: string, +) { + const normalizedPathname = normalizePathname(pathname); + const normalizedConfiguredPath = normalizePathname(configuredPath); + + if (!normalizedConfiguredPath) { + return false; + } + + if (normalizedPathname === normalizedConfiguredPath) { + return true; + } + + const normalizedBasePath = normalizeBasePath(basePath); + + return normalizedBasePath + ? normalizedPathname === `${normalizedBasePath}${normalizedConfiguredPath}` + : false; +}