Skip to content

Commit

Permalink
fix: Refresh JWT in wrangler pages publish when it expires (#1199)
Browse files Browse the repository at this point in the history
  • Loading branch information
sidharthachatterjee authored Jun 8, 2022
1 parent bafa5ac commit e64812e
Show file tree
Hide file tree
Showing 3 changed files with 117 additions and 4 deletions.
5 changes: 5 additions & 0 deletions .changeset/small-olives-confess.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"wrangler": patch
---

fix: Refresh JWT in wrangler pages publish when it expires
99 changes: 98 additions & 1 deletion packages/wrangler/src/__tests__/pages.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ function assertLater(fn: () => void) {
}

function mockGetToken(jwt: string) {
setMockResponse(
return setMockResponse(
"/accounts/:accountId/pages/projects/foo/upload-token",
async ([_url, accountId]) => {
assertLater(() => {
Expand Down Expand Up @@ -488,6 +488,103 @@ describe("pages", () => {
`);
});

it("should refetch a JWT if it expires while uploading", async () => {
writeFileSync("logo.txt", "foobar");

const cancelMockGetToken = mockGetToken("<<funfetti-auth-jwt>>");

setMockResponse(
"/pages/assets/check-missing",
"POST",
async (_, init) => {
const body = JSON.parse(init.body as string) as { hashes: string[] };
assertLater(() => {
expect(init.headers).toMatchObject({
Authorization: "Bearer <<funfetti-auth-jwt>>",
});
expect(body).toMatchObject({
hashes: ["1a98fb08af91aca4a7df1764a2c4ddb0"],
});
});
return body.hashes;
}
);

// Accumulate multiple requests then assert afterwards
const requests: RequestInit[] = [];
setMockRawResponse("/pages/assets/upload", "POST", async (_, init) => {
requests.push(init);

// Fail just the first request
if (requests.length < 2) {
cancelMockGetToken();
mockGetToken("<<funfetti-auth-jwt2>>");
return createFetchResult(null, false, [
{
code: 8000013,
message: "Authorization failed",
},
]);
} else {
return createFetchResult(null, true);
}
});

setMockResponse(
"/accounts/:accountId/pages/projects/foo/deployments",
async ([_url, accountId], init) => {
assertLater(() => {
expect(accountId).toEqual("some-account-id");
expect(init.method).toEqual("POST");
const body = init.body as FormData;
const manifest = JSON.parse(body.get("manifest") as string);
expect(manifest).toMatchInlineSnapshot(`
Object {
"/logo.txt": "1a98fb08af91aca4a7df1764a2c4ddb0",
}
`);
});

return {
url: "https://abcxyz.foo.pages.dev/",
};
}
);

await runWrangler("pages publish . --project-name=foo");

// Assert two requests
expect(requests.length).toBe(2);

expect(requests[0].headers).toMatchObject({
Authorization: "Bearer <<funfetti-auth-jwt>>",
});

expect(requests[1].headers).toMatchObject({
Authorization: "Bearer <<funfetti-auth-jwt2>>",
});

for (const init of requests) {
const body = JSON.parse(init.body as string) as UploadPayloadFile[];
expect(body).toMatchObject([
{
key: "1a98fb08af91aca4a7df1764a2c4ddb0",
value: Buffer.from("foobar").toString("base64"),
metadata: {
contentType: "text/plain",
},
base64: true,
},
]);
}

expect(std.out).toMatchInlineSnapshot(`
"✨ Success! Uploaded 1 files (TIMINGS)
✨ Deployment complete! Take a peek over at https://abcxyz.foo.pages.dev/"
`);
});

it("should try to use multiple buckets (up to the max concurrency)", async () => {
writeFileSync("logo.txt", "foobar");
writeFileSync("logo.png", "foobar");
Expand Down
17 changes: 14 additions & 3 deletions packages/wrangler/src/pages.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1139,9 +1139,15 @@ const createDeployment: CommandModule<

const files = [...fileMap.values()];

const { jwt } = await fetchResult<{ jwt: string }>(
`/accounts/${accountId}/pages/projects/${projectName}/upload-token`
);
async function fetchJwt(): Promise<string> {
return (
await fetchResult<{ jwt: string }>(
`/accounts/${accountId}/pages/projects/${projectName}/upload-token`
)
).jwt;
}

let jwt = await fetchJwt();

const start = Date.now();

Expand Down Expand Up @@ -1237,6 +1243,11 @@ const createDeployment: CommandModule<
await new Promise((resolve) =>
setTimeout(resolve, attempts++ * 1000)
);

if ((e as { code: number }).code === 8000013) {
// Looks like the JWT expired, fetch another one
jwt = await fetchJwt();
}
return doUpload();
} else {
throw e;
Expand Down

0 comments on commit e64812e

Please sign in to comment.