From d3a6f9f836e35932a950e40ba69eff63d7db7eed Mon Sep 17 00:00:00 2001 From: "Fred K. Schott" Date: Thu, 31 Aug 2023 11:05:39 -0700 Subject: [PATCH] add leading and trailing slash sanitization for params (#8276) * add leading and trailing slash sanitization for params * chore: fix lint * refactor: use shared trimSlashes util --------- Co-authored-by: Nate Moore Co-authored-by: Nate Moore --- .changeset/chilled-hornets-press.md | 5 ++ packages/astro/src/core/routing/params.ts | 5 +- .../units/routing/route-sanitization.test.js | 66 +++++++++++++++++++ 3 files changed, 75 insertions(+), 1 deletion(-) create mode 100644 .changeset/chilled-hornets-press.md create mode 100644 packages/astro/test/units/routing/route-sanitization.test.js diff --git a/.changeset/chilled-hornets-press.md b/.changeset/chilled-hornets-press.md new file mode 100644 index 0000000000..5283117fe5 --- /dev/null +++ b/.changeset/chilled-hornets-press.md @@ -0,0 +1,5 @@ +--- +'astro': patch +--- + +Sanitize route params for leading and trailing slashes diff --git a/packages/astro/src/core/routing/params.ts b/packages/astro/src/core/routing/params.ts index fc05c9696a..d2856563e0 100644 --- a/packages/astro/src/core/routing/params.ts +++ b/packages/astro/src/core/routing/params.ts @@ -1,5 +1,6 @@ import type { GetStaticPathsItem, Params, RouteData } from '../../@types/astro'; import { validateGetStaticPathsParameter } from './validation.js'; +import { trimSlashes } from '../path.js'; /** * given an array of params like `['x', 'y', 'z']` for @@ -32,7 +33,9 @@ export function stringifyParams(params: GetStaticPathsItem['params'], route: Rou const validatedParams = Object.entries(params).reduce((acc, next) => { validateGetStaticPathsParameter(next, route.component); const [key, value] = next; - acc[key] = value?.toString(); + if (value !== undefined) { + acc[key] = typeof value === 'string' ? trimSlashes(value) : value.toString() + } return acc; }, {} as Params); diff --git a/packages/astro/test/units/routing/route-sanitization.test.js b/packages/astro/test/units/routing/route-sanitization.test.js new file mode 100644 index 0000000000..3bddeb92ae --- /dev/null +++ b/packages/astro/test/units/routing/route-sanitization.test.js @@ -0,0 +1,66 @@ +import { + createBasicSettings, + createFs, + createRequestAndResponse, + defaultLogger, +} from '../test-utils.js'; +import { fileURLToPath } from 'node:url'; +import { expect } from 'chai'; +import { createContainer } from '../../../dist/core/dev/container.js'; +import * as cheerio from 'cheerio'; +import testAdapter from '../../test-adapter.js'; + +const root = new URL('../../fixtures/alias/', import.meta.url); +const fileSystem = { +'/src/pages/[...testSlashTrim].astro': ` + --- + export function getStaticPaths() { + return [ + { + params: { + testSlashTrim: "/a-route-param-with-leading-trailing-slash/", + }, + }, + ]; + } + --- +

Success!

+`, +}; + +describe('Route sanitization', () => { + let container; + let settings; + + before(async () => { + const fs = createFs(fileSystem, root); + settings = await createBasicSettings({ + root: fileURLToPath(root), + trailingSlash: 'never', + output: 'hybrid', + adapter: testAdapter(), + }); + container = await createContainer({ + fs, + settings, + logger: defaultLogger, + }); + }); + + after(async () => { + await container.close(); + }); + + describe('Request', () => { + it('should correctly match a route param with a trailing slash', async () => { + const { req, res, text } = createRequestAndResponse({ + method: 'GET', + url: '/a-route-param-with-leading-trailing-slash', + }); + container.handle(req, res); + const html = await text(); + const $ = cheerio.load(html); + expect($('p').text()).to.equal('Success!'); + }); + }); +});