diff --git a/packages/docusaurus-utils/src/__tests__/index.test.ts b/packages/docusaurus-utils/src/__tests__/index.test.ts index b8ead90d5f..f6a0543207 100644 --- a/packages/docusaurus-utils/src/__tests__/index.test.ts +++ b/packages/docusaurus-utils/src/__tests__/index.test.ts @@ -18,6 +18,7 @@ import { objectWithKeySorted, aliasedSitePath, createExcerpt, + isValidPathname, } from '../index'; describe('load utils', () => { @@ -363,4 +364,20 @@ describe('load utils', () => { expect(createExcerpt(testCase.input)).toEqual(testCase.output); }); }); + + test('isValidPathname', () => { + expect(isValidPathname('/')).toBe(true); + expect(isValidPathname('/hey')).toBe(true); + expect(isValidPathname('/hey/ho')).toBe(true); + expect(isValidPathname('/hey/ho/')).toBe(true); + expect(isValidPathname('/hey/h%C3%B4/')).toBe(true); + expect(isValidPathname('/hey///ho///')).toBe(true); // Unexpected but valid + // + expect(isValidPathname('')).toBe(false); + expect(isValidPathname('hey')).toBe(false); + expect(isValidPathname('/hey/hô')).toBe(false); + expect(isValidPathname('/hey?qs=ho')).toBe(false); + expect(isValidPathname('https://fb.com/hey')).toBe(false); + expect(isValidPathname('//hey')).toBe(false); + }); }); diff --git a/packages/docusaurus-utils/src/index.ts b/packages/docusaurus-utils/src/index.ts index 39879cbb07..8ecc4f9f9f 100644 --- a/packages/docusaurus-utils/src/index.ts +++ b/packages/docusaurus-utils/src/index.ts @@ -12,6 +12,7 @@ import camelCase from 'lodash.camelcase'; import kebabCase from 'lodash.kebabcase'; import escapeStringRegexp from 'escape-string-regexp'; import fs from 'fs-extra'; +import {URL} from 'url'; const fileHash = new Map(); export async function generate( @@ -327,3 +328,14 @@ export function getEditUrl(fileRelativePath: string, editUrl?: string) { ? normalizeUrl([editUrl, posixPath(fileRelativePath)]) : undefined; } + +export function isValidPathname(str: string): boolean { + if (!str.startsWith('/')) { + return false; + } + try { + return new URL(str, 'https://domain.com').pathname === str; + } catch (e) { + return false; + } +}