diff --git a/src/util/PathUtil.ts b/src/util/PathUtil.ts index 3cad06ff9..f09a10dce 100644 --- a/src/util/PathUtil.ts +++ b/src/util/PathUtil.ts @@ -155,16 +155,31 @@ export function toCanonicalUriPath(path: string): string { encodeURIComponent(decodeURIComponent(part))); } +// Characters not allowed in a Windows file path +const forbiddenSymbols = { + '<': '%3C', + '>': '%3E', + ':': '%3A', + '"': '%22', + '|': '%7C', + '?': '%3F', + // `*` does not get converted by `encodeUriComponent` + '*': '%2A', +} as const; +const forbiddenRegex = new RegExp(`[${Object.keys(forbiddenSymbols).join('')}]`, 'ug'); /** * This function is used when converting a URI to a file path. Decodes all components of a URI path, * with the exception of encoded slash characters, as this would lead to unexpected file locations * being targeted (resulting in erroneous behaviour of the file based backend). + * Characters that would result in an illegal file path remain percent encoded. * * @param path - The path to decode the URI path components of. * @returns A decoded copy of the provided URI path (ignoring encoded slash characters). */ export function decodeUriPathComponents(path: string): string { - return transformPathComponents(path, decodeURIComponent); + return transformPathComponents(path, (part): string => decodeURIComponent(part) + // The characters replaced below result in illegal Windows file paths so need to be encoded + .replace(forbiddenRegex, (val): string => forbiddenSymbols[val as keyof typeof forbiddenSymbols])); } /** diff --git a/test/unit/util/PathUtil.test.ts b/test/unit/util/PathUtil.test.ts index 4eb681a26..01816bb76 100644 --- a/test/unit/util/PathUtil.test.ts +++ b/test/unit/util/PathUtil.test.ts @@ -96,7 +96,7 @@ describe('PathUtil', (): void => { describe('#toCanonicalUriPath', (): void => { it('encodes only the necessary parts.', (): void => { - expect(toCanonicalUriPath('/a%20path&/name')).toBe('/a%20path%26/name'); + expect(toCanonicalUriPath('/a%20path&*/name')).toBe('/a%20path%26*/name'); }); it('leaves the query string untouched.', (): void => { @@ -138,6 +138,11 @@ describe('PathUtil', (): void => { expect(decodeUriPathComponents('/a%25252Fb')).toBe('/a%25252Fb'); expect(decodeUriPathComponents('/a%2525252Fb')).toBe('/a%2525252Fb'); }); + + it('ensures illegal path characters are encoded.', async(): Promise => { + expect(decodeUriPathComponents('/a {