Skip to content

Commit 5502587

Browse files
committed
chore: attempt to override url pathname
1 parent e227ea7 commit 5502587

File tree

4 files changed

+49
-7
lines changed

4 files changed

+49
-7
lines changed
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { describe, expect, it } from "vitest";
2+
3+
import { getPathnameWithDots } from "./getPathnameWithDots";
4+
5+
describe("getPathnameWithDots", () => {
6+
const origin = "http://d1234.cloudfront.net";
7+
8+
it("should return if there's no pathname", () => {
9+
expect(getPathnameWithDots(origin)).toBe("/");
10+
expect(getPathnameWithDots(`${origin}/`)).toBe("/");
11+
});
12+
13+
it("should return if there's no '/./' or '/../' in pathname", () => {
14+
const expectedPathname = `/foo/bar/index.html`;
15+
expect(getPathnameWithDots(`${origin}${expectedPathname}`)).toBe(expectedPathname);
16+
});
17+
18+
it.each(["/./", "/../"])("should include '%s' in pathname if it exists", (folderName) => {
19+
const expectedPathname = `/foo${folderName}bar/index.html`;
20+
expect(getPathnameWithDots(`${origin}${expectedPathname}`)).toBe(expectedPathname);
21+
expect(getPathnameWithDots(`${origin}${expectedPathname}?foo=bar`)).toBe(expectedPathname);
22+
expect(getPathnameWithDots(`${origin}${expectedPathname}#foo=bar`)).toBe(expectedPathname);
23+
});
24+
});
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/**
2+
* Returns pathname with `/./` and `/../` allowed by S3 Objects
3+
*
4+
* @param urlString string provided for generating the URL.
5+
*/
6+
export const getPathnameWithDots = (urlString: string) => {
7+
const url = new URL(urlString);
8+
9+
if (url.pathname === "/") return url.pathname;
10+
11+
if (!urlString.includes("/./") && !urlString.includes("/../")) return url.pathname;
12+
13+
const startIndex = url.origin.length;
14+
const endIndex = urlString.includes("?")
15+
? urlString.indexOf("?")
16+
: urlString.includes("#")
17+
? urlString.indexOf("#")
18+
: urlString.length;
19+
return urlString.substring(startIndex, endIndex);
20+
};

packages/cloudfront-signer/src/sign.spec.ts

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -369,14 +369,9 @@ describe("getSignedUrl", () => {
369369

370370
describe("should not normalize the URL", () => {
371371
it.each([".", ".."])("with '%s'", (folderName) => {
372-
const urlWithFolderName = `https://d111111abcdef8.cloudfront.net/public-content/${folderName}/private-content/private.jpeg`;
372+
const urlWithFolderName = `https://d1234.cloudfront.net/public-content/${folderName}/private-content/private.jpeg`;
373373
const policy = JSON.stringify({ Statement: [{ Resource: urlWithFolderName }] });
374-
const result = getSignedUrl({
375-
keyPairId,
376-
privateKey,
377-
policy,
378-
passphrase,
379-
});
374+
const result = getSignedUrl({ keyPairId, privateKey, policy, passphrase });
380375
const signature = createSignature(policy);
381376
expect(result.startsWith(urlWithFolderName)).toBeTruthy();
382377
const signatureQueryParam = denormalizeBase64(signature);

packages/cloudfront-signer/src/sign.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import { createSign } from "crypto";
22

3+
import { getPathnameWithDots } from "./getPathnameWithDots";
4+
35
/**
46
* Input type to getSignedUrl and getSignedCookies.
57
* @public
@@ -137,6 +139,7 @@ export function getSignedUrl({
137139
}
138140

139141
const newURL = new URL(baseUrl!);
142+
newURL.pathname = getPathnameWithDots(baseUrl!);
140143
newURL.search = Array.from(newURL.searchParams.entries())
141144
.concat(Object.entries(cloudfrontSignBuilder.createCloudfrontAttribute()))
142145
.filter(([, value]) => value !== undefined)

0 commit comments

Comments
 (0)