From bcd54e8232e49aaafcb109ee565581052e911e4b Mon Sep 17 00:00:00 2001 From: zhongliang02 Date: Thu, 7 Nov 2024 10:55:52 +0800 Subject: [PATCH] Revert "fix dynamic routes bypass (#24)" This reverts commit 51111705a3a686af0331046ef745d381e515b604. --- packages/validators/src/__tests__/url.test.ts | 12 ----------- packages/validators/src/url/utils.ts | 20 ++++++++++++++----- 2 files changed, 15 insertions(+), 17 deletions(-) diff --git a/packages/validators/src/__tests__/url.test.ts b/packages/validators/src/__tests__/url.test.ts index 87bb612..b11ef3f 100644 --- a/packages/validators/src/__tests__/url.test.ts +++ b/packages/validators/src/__tests__/url.test.ts @@ -143,18 +143,6 @@ describe('UrlValidator with base URL', () => { it('should not allow Next.js dynamic routes', () => { expect(() => validator.parse('/[[x]]javascript:alert(1337)/[y]/[z]?x&y&z')).toThrow(UrlValidationError) }) - - it('should not allow Next.js dynamic routes', () => { - expect(() => - validator.parse('/[[x]x]]https://[y]y]//example.com/[[/[[x]x]]/y?x=[[x]&x]x&%2F[[x=[[/[[x]&y=[y]&y]y='), - ).toThrow(UrlValidationError) - }) - - it('should not allow Next.js dynamic routes', () => { - expect(() => validator.parse('/[[x]x]]javascript:alert(1)%2F%2F/[[/[[x]x]]/y?x=[[x]&x]x&%2F[[x=[[/[[x]')).toThrow( - UrlValidationError, - ) - }) }) describe('UrlValidator with invalid options', () => { diff --git a/packages/validators/src/url/utils.ts b/packages/validators/src/url/utils.ts index 73a141c..4541eac 100644 --- a/packages/validators/src/url/utils.ts +++ b/packages/validators/src/url/utils.ts @@ -1,8 +1,7 @@ import { UrlValidationError } from '@/url/errors' import { UrlValidatorWhitelist } from '@/url/options' -// regex from https://github.com/vercel/next.js/blob/8cb8edb686ec8ddf7e24c69545d11175fcb9df02/packages/next/src/shared/lib/router/utils/is-dynamic.ts#L7 -const DYNAMIC_ROUTE_SEGMENT_REGEX = /\/\[[^/]+?\](?=\/|$)/ +const DYNAMIC_ROUTE_SEGMENT_REGEX = /\[\[?([^\]]+)\]?\]/g const IS_NOT_HOSTNAME_REGEX = /[^.]+\.[^.]+/g export const resolveRelativeUrl = (url: string, baseOrigin?: URL): URL => { @@ -27,8 +26,19 @@ export const resolveRelativeUrl = (url: string, baseOrigin?: URL): URL => { return normalizedUrl } -export const isDynamicRoute = (url: URL): boolean => { - return DYNAMIC_ROUTE_SEGMENT_REGEX.test(url.pathname) +/* As of Next.js 14.2.5, router.push() resolves dynamic routes using query parameters. */ +const resolveNextDynamicRoute = (url: URL): URL => { + const pathname = url.pathname + const query = new URLSearchParams(url.search) + const resolvedPathname = pathname.replace(DYNAMIC_ROUTE_SEGMENT_REGEX, (_, name: string) => { + const value = query.get(name) || '' + query.delete(name) + return value + }) + + const result = new URL(url.href) + result.pathname = resolvedPathname + return result } export const isSafeUrl = (url: URL, whitelist: UrlValidatorWhitelist) => { @@ -49,7 +59,7 @@ export const isSafeUrl = (url: URL, whitelist: UrlValidatorWhitelist) => { } // don't allow dynamic routes - if (isDynamicRoute(url)) { + if (resolveNextDynamicRoute(url).href !== url.href) { return false } return true