wrangler 2.0.12 → 2.0.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +2 -2
- package/src/__tests__/jest.setup.ts +30 -0
- package/src/__tests__/kv.test.ts +2 -23
- package/src/__tests__/publish.test.ts +2 -1
- package/src/__tests__/user.test.ts +1 -0
- package/src/generate-auth-url.ts +33 -0
- package/src/generate-random-state.ts +16 -0
- package/src/index.tsx +1 -2
- package/src/kv.ts +1 -1
- package/src/open-in-browser.ts +1 -3
- package/src/parse.ts +0 -19
- package/src/user.tsx +12 -24
- package/templates/static-asset-facade.js +1 -1
- package/wrangler-dist/cli.js +325 -287
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wrangler",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.14",
|
|
4
4
|
"author": "wrangler@cloudflare.com",
|
|
5
5
|
"description": "Command-line interface for all things Cloudflare Workers",
|
|
6
6
|
"bin": {
|
|
@@ -99,7 +99,7 @@
|
|
|
99
99
|
"timeago.js": "^4.0.2",
|
|
100
100
|
"tmp-promise": "^3.0.3",
|
|
101
101
|
"ts-dedent": "^2.2.0",
|
|
102
|
-
"undici": "^5.
|
|
102
|
+
"undici": "^5.5.1",
|
|
103
103
|
"update-check": "^1.5.4",
|
|
104
104
|
"ws": "^8.5.0",
|
|
105
105
|
"yargs": "^17.4.1"
|
|
@@ -75,3 +75,33 @@ jest.mock("../dev/dev", () => {
|
|
|
75
75
|
// Make sure that we don't accidentally try to open a browser window when running tests.
|
|
76
76
|
// We will actually provide a mock implementation for `openInBrowser()` within relevant tests.
|
|
77
77
|
jest.mock("../open-in-browser");
|
|
78
|
+
|
|
79
|
+
// Mock the functions involved in getAuthURL so we don't take snapshots of the constantly changing URL.
|
|
80
|
+
jest.mock("../generate-auth-url", () => {
|
|
81
|
+
return {
|
|
82
|
+
generateRandomState: jest.fn().mockImplementation(() => "MOCK_STATE_PARAM"),
|
|
83
|
+
generateAuthUrl: jest
|
|
84
|
+
.fn()
|
|
85
|
+
.mockImplementation(({ authUrl, clientId, callbackUrl, scopes }) => {
|
|
86
|
+
return (
|
|
87
|
+
authUrl +
|
|
88
|
+
`?response_type=code&` +
|
|
89
|
+
`client_id=${encodeURIComponent(clientId)}&` +
|
|
90
|
+
`redirect_uri=${encodeURIComponent(callbackUrl)}&` +
|
|
91
|
+
// we add offline_access manually for every request
|
|
92
|
+
`scope=${encodeURIComponent(
|
|
93
|
+
[...scopes, "offline_access"].join(" ")
|
|
94
|
+
)}&` +
|
|
95
|
+
`state=MOCK_STATE_PARAM&` +
|
|
96
|
+
`code_challenge=${encodeURIComponent("MOCK_CODE_CHALLENGE")}&` +
|
|
97
|
+
`code_challenge_method=S256`
|
|
98
|
+
);
|
|
99
|
+
}),
|
|
100
|
+
};
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
jest.mock("../generate-random-state", () => {
|
|
104
|
+
return {
|
|
105
|
+
generateRandomState: jest.fn().mockImplementation(() => "MOCK_STATE_PARAM"),
|
|
106
|
+
};
|
|
107
|
+
});
|
package/src/__tests__/kv.test.ts
CHANGED
|
@@ -448,11 +448,10 @@ describe("wrangler", () => {
|
|
|
448
448
|
});
|
|
449
449
|
|
|
450
450
|
it("should put a key with a value loaded from a given path", async () => {
|
|
451
|
-
|
|
452
|
-
writeFileSync("foo.txt", buf);
|
|
451
|
+
writeFileSync("foo.txt", "file-contents", "utf-8");
|
|
453
452
|
const requests = mockKeyPutRequest("some-namespace-id", {
|
|
454
453
|
key: "my-key",
|
|
455
|
-
value:
|
|
454
|
+
value: "file-contents",
|
|
456
455
|
});
|
|
457
456
|
await runWrangler(
|
|
458
457
|
"kv:key put my-key --namespace-id some-namespace-id --path foo.txt"
|
|
@@ -464,26 +463,6 @@ describe("wrangler", () => {
|
|
|
464
463
|
expect(requests.count).toEqual(1);
|
|
465
464
|
});
|
|
466
465
|
|
|
467
|
-
it("should put a key with a binary value loaded from a given path", async () => {
|
|
468
|
-
const buf = Buffer.from(
|
|
469
|
-
"iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAACXBIWXMAAAsTAAALEwEAmpwYAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAiSURBVHgB7coxEQAACMPAgH/PgAM6dGwu49fA/deIBXrgAj2cAhIFT4QxAAAAAElFTkSuQmCC",
|
|
470
|
-
"base64"
|
|
471
|
-
);
|
|
472
|
-
writeFileSync("test.png", buf);
|
|
473
|
-
const requests = mockKeyPutRequest("another-namespace-id", {
|
|
474
|
-
key: "my-key",
|
|
475
|
-
value: buf,
|
|
476
|
-
});
|
|
477
|
-
await runWrangler(
|
|
478
|
-
"kv:key put my-key --namespace-id another-namespace-id --path test.png"
|
|
479
|
-
);
|
|
480
|
-
expect(std.out).toMatchInlineSnapshot(
|
|
481
|
-
`"Writing the contents of test.png to the key \\"my-key\\" on namespace another-namespace-id."`
|
|
482
|
-
);
|
|
483
|
-
expect(std.err).toMatchInlineSnapshot(`""`);
|
|
484
|
-
expect(requests.count).toEqual(1);
|
|
485
|
-
});
|
|
486
|
-
|
|
487
466
|
it("should error if no key is provided", async () => {
|
|
488
467
|
await expect(
|
|
489
468
|
runWrangler("kv:key put")
|
|
@@ -66,7 +66,6 @@ describe("publish", () => {
|
|
|
66
66
|
writeWorkerSource();
|
|
67
67
|
mockSubDomainRequest();
|
|
68
68
|
mockUploadWorkerRequest();
|
|
69
|
-
|
|
70
69
|
mockOAuthServerCallback();
|
|
71
70
|
const accessTokenRequest = mockGrantAccessToken({ respondWith: "ok" });
|
|
72
71
|
mockGrantAuthorization({ respondWith: "success" });
|
|
@@ -79,6 +78,7 @@ describe("publish", () => {
|
|
|
79
78
|
|
|
80
79
|
expect(std.out).toMatchInlineSnapshot(`
|
|
81
80
|
"Attempting to login via OAuth...
|
|
81
|
+
Opening a link in your default browser: https://dash.cloudflare.com/oauth2/auth?response_type=code&client_id=54d11594-84e4-41aa-b438-e81b8fa78ee7&redirect_uri=http%3A%2F%2Flocalhost%3A8976%2Foauth%2Fcallback&scope=account%3Aread%20user%3Aread%20workers%3Awrite%20workers_kv%3Awrite%20workers_routes%3Awrite%20workers_scripts%3Awrite%20workers_tail%3Aread%20pages%3Awrite%20zone%3Aread%20offline_access&state=MOCK_STATE_PARAM&code_challenge=MOCK_CODE_CHALLENGE&code_challenge_method=S256
|
|
82
82
|
Successfully logged in.
|
|
83
83
|
Uploaded test-name (TIMINGS)
|
|
84
84
|
Published test-name (TIMINGS)
|
|
@@ -108,6 +108,7 @@ describe("publish", () => {
|
|
|
108
108
|
|
|
109
109
|
expect(std.out).toMatchInlineSnapshot(`
|
|
110
110
|
"Attempting to login via OAuth...
|
|
111
|
+
Opening a link in your default browser: https://dash.cloudflare.com/oauth2/auth?response_type=code&client_id=54d11594-84e4-41aa-b438-e81b8fa78ee7&redirect_uri=http%3A%2F%2Flocalhost%3A8976%2Foauth%2Fcallback&scope=account%3Aread%20user%3Aread%20workers%3Awrite%20workers_kv%3Awrite%20workers_routes%3Awrite%20workers_scripts%3Awrite%20workers_tail%3Aread%20pages%3Awrite%20zone%3Aread%20offline_access&state=MOCK_STATE_PARAM&code_challenge=MOCK_CODE_CHALLENGE&code_challenge_method=S256
|
|
111
112
|
Successfully logged in.
|
|
112
113
|
Uploaded test-name (TIMINGS)
|
|
113
114
|
Published test-name (TIMINGS)
|
|
@@ -46,6 +46,7 @@ describe("User", () => {
|
|
|
46
46
|
|
|
47
47
|
expect(std.out).toMatchInlineSnapshot(`
|
|
48
48
|
"Attempting to login via OAuth...
|
|
49
|
+
Opening a link in your default browser: https://dash.cloudflare.com/oauth2/auth?response_type=code&client_id=54d11594-84e4-41aa-b438-e81b8fa78ee7&redirect_uri=http%3A%2F%2Flocalhost%3A8976%2Foauth%2Fcallback&scope=account%3Aread%20user%3Aread%20workers%3Awrite%20workers_kv%3Awrite%20workers_routes%3Awrite%20workers_scripts%3Awrite%20workers_tail%3Aread%20pages%3Awrite%20zone%3Aread%20offline_access&state=MOCK_STATE_PARAM&code_challenge=MOCK_CODE_CHALLENGE&code_challenge_method=S256
|
|
49
50
|
Successfully logged in."
|
|
50
51
|
`);
|
|
51
52
|
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
interface GenerateAuthUrlProps {
|
|
2
|
+
authUrl: string;
|
|
3
|
+
clientId: string;
|
|
4
|
+
callbackUrl: string;
|
|
5
|
+
scopes: string[];
|
|
6
|
+
stateQueryParam: string;
|
|
7
|
+
codeChallenge: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* generateAuthUrl was extracted from getAuthURL in user.tsx
|
|
12
|
+
* to make it possible to mock the generated URL
|
|
13
|
+
*/
|
|
14
|
+
export const generateAuthUrl = ({
|
|
15
|
+
authUrl,
|
|
16
|
+
clientId,
|
|
17
|
+
callbackUrl,
|
|
18
|
+
scopes,
|
|
19
|
+
stateQueryParam,
|
|
20
|
+
codeChallenge,
|
|
21
|
+
}: GenerateAuthUrlProps) => {
|
|
22
|
+
return (
|
|
23
|
+
authUrl +
|
|
24
|
+
`?response_type=code&` +
|
|
25
|
+
`client_id=${encodeURIComponent(clientId)}&` +
|
|
26
|
+
`redirect_uri=${encodeURIComponent(callbackUrl)}&` +
|
|
27
|
+
// we add offline_access manually for every request
|
|
28
|
+
`scope=${encodeURIComponent([...scopes, "offline_access"].join(" "))}&` +
|
|
29
|
+
`state=${stateQueryParam}&` +
|
|
30
|
+
`code_challenge=${encodeURIComponent(codeChallenge)}&` +
|
|
31
|
+
`code_challenge_method=S256`
|
|
32
|
+
);
|
|
33
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { webcrypto as crypto } from "node:crypto";
|
|
2
|
+
import { PKCE_CHARSET } from "./user";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Generates random state to be passed for anti-csrf.
|
|
6
|
+
* extracted from user.tsx to make it possible to
|
|
7
|
+
* mock the generated URL
|
|
8
|
+
*/
|
|
9
|
+
export function generateRandomState(lengthOfState: number): string {
|
|
10
|
+
const output = new Uint32Array(lengthOfState);
|
|
11
|
+
// @ts-expect-error crypto's types aren't there yet
|
|
12
|
+
crypto.getRandomValues(output);
|
|
13
|
+
return Array.from(output)
|
|
14
|
+
.map((num: number) => PKCE_CHARSET[num % PKCE_CHARSET.length])
|
|
15
|
+
.join("");
|
|
16
|
+
}
|
package/src/index.tsx
CHANGED
|
@@ -48,7 +48,6 @@ import {
|
|
|
48
48
|
parsePackageJSON,
|
|
49
49
|
parseTOML,
|
|
50
50
|
readFileSync,
|
|
51
|
-
readFileSyncToBuffer,
|
|
52
51
|
} from "./parse";
|
|
53
52
|
import publish from "./publish";
|
|
54
53
|
import { createR2Bucket, deleteR2Bucket, listR2Buckets } from "./r2";
|
|
@@ -2273,7 +2272,7 @@ function createCLIParser(argv: string[]) {
|
|
|
2273
2272
|
const namespaceId = getKVNamespaceId(args, config);
|
|
2274
2273
|
// One of `args.path` and `args.value` must be defined
|
|
2275
2274
|
const value = args.path
|
|
2276
|
-
?
|
|
2275
|
+
? readFileSync(args.path)
|
|
2277
2276
|
: // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
2278
2277
|
args.value!;
|
|
2279
2278
|
|
package/src/kv.ts
CHANGED
package/src/open-in-browser.ts
CHANGED
|
@@ -10,10 +10,8 @@ import { logger } from "./logger";
|
|
|
10
10
|
* @param url the URL to point the browser at
|
|
11
11
|
*/
|
|
12
12
|
export default async function openInBrowser(url: string): Promise<void> {
|
|
13
|
-
const errorMessage = `Failed to open ${url} in a browser`;
|
|
14
|
-
|
|
15
13
|
const childProcess = await open(url);
|
|
16
14
|
childProcess.on("error", () => {
|
|
17
|
-
logger.warn(
|
|
15
|
+
logger.warn("Failed to open");
|
|
18
16
|
});
|
|
19
17
|
}
|
package/src/parse.ts
CHANGED
|
@@ -139,25 +139,6 @@ export function parseJSON<T>(input: string, file?: string): T {
|
|
|
139
139
|
}
|
|
140
140
|
}
|
|
141
141
|
|
|
142
|
-
/**
|
|
143
|
-
* Reads a file into a node Buffer.
|
|
144
|
-
*/
|
|
145
|
-
export function readFileSyncToBuffer(file: string): Buffer {
|
|
146
|
-
try {
|
|
147
|
-
return fs.readFileSync(file);
|
|
148
|
-
} catch (err) {
|
|
149
|
-
const { message } = err as Error;
|
|
150
|
-
throw new ParseError({
|
|
151
|
-
text: `Could not read file: ${file}`,
|
|
152
|
-
notes: [
|
|
153
|
-
{
|
|
154
|
-
text: message.replace(file, resolve(file)),
|
|
155
|
-
},
|
|
156
|
-
],
|
|
157
|
-
});
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
|
|
161
142
|
/**
|
|
162
143
|
* Reads a file and parses it based on its type.
|
|
163
144
|
*/
|
package/src/user.tsx
CHANGED
|
@@ -223,6 +223,8 @@ import { fetch } from "undici";
|
|
|
223
223
|
import { getCloudflareApiBaseUrl } from "./cfetch";
|
|
224
224
|
import { purgeConfigCaches } from "./config-cache";
|
|
225
225
|
import { getEnvironmentVariableFactory } from "./environment-variables";
|
|
226
|
+
import { generateAuthUrl } from "./generate-auth-url";
|
|
227
|
+
import { generateRandomState } from "./generate-random-state";
|
|
226
228
|
import { logger } from "./logger";
|
|
227
229
|
import openInBrowser from "./open-in-browser";
|
|
228
230
|
import { parseTOML, readFileSync } from "./parse";
|
|
@@ -591,7 +593,7 @@ const RECOMMENDED_STATE_LENGTH = 32;
|
|
|
591
593
|
/**
|
|
592
594
|
* Character set to generate code verifier defined in rfc7636.
|
|
593
595
|
*/
|
|
594
|
-
const PKCE_CHARSET =
|
|
596
|
+
export const PKCE_CHARSET =
|
|
595
597
|
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~";
|
|
596
598
|
|
|
597
599
|
/**
|
|
@@ -641,17 +643,14 @@ export async function getAuthURL(scopes = ScopeKeys): Promise<string> {
|
|
|
641
643
|
stateQueryParam,
|
|
642
644
|
});
|
|
643
645
|
|
|
644
|
-
return (
|
|
645
|
-
AUTH_URL
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
`code_challenge=${encodeURIComponent(codeChallenge)}&` +
|
|
653
|
-
`code_challenge_method=S256`
|
|
654
|
-
);
|
|
646
|
+
return generateAuthUrl({
|
|
647
|
+
authUrl: AUTH_URL,
|
|
648
|
+
clientId: CLIENT_ID,
|
|
649
|
+
callbackUrl: CALLBACK_URL,
|
|
650
|
+
scopes,
|
|
651
|
+
stateQueryParam,
|
|
652
|
+
codeChallenge,
|
|
653
|
+
});
|
|
655
654
|
}
|
|
656
655
|
|
|
657
656
|
type TokenResponse =
|
|
@@ -863,18 +862,6 @@ async function generatePKCECodes(): Promise<PKCECodes> {
|
|
|
863
862
|
return { codeChallenge, codeVerifier };
|
|
864
863
|
}
|
|
865
864
|
|
|
866
|
-
/**
|
|
867
|
-
* Generates random state to be passed for anti-csrf.
|
|
868
|
-
*/
|
|
869
|
-
function generateRandomState(lengthOfState: number): string {
|
|
870
|
-
const output = new Uint32Array(lengthOfState);
|
|
871
|
-
// @ts-expect-error crypto's types aren't there yet
|
|
872
|
-
crypto.getRandomValues(output);
|
|
873
|
-
return Array.from(output)
|
|
874
|
-
.map((num: number) => PKCE_CHARSET[num % PKCE_CHARSET.length])
|
|
875
|
-
.join("");
|
|
876
|
-
}
|
|
877
|
-
|
|
878
865
|
/**
|
|
879
866
|
* Writes a a wrangler config file (auth credentials) to disk,
|
|
880
867
|
* and updates the user auth state with the new credentials.
|
|
@@ -1013,6 +1000,7 @@ export async function login(props?: LoginProps): Promise<boolean> {
|
|
|
1013
1000
|
server.listen(8976);
|
|
1014
1001
|
});
|
|
1015
1002
|
|
|
1003
|
+
logger.log(`Opening a link in your default browser: ${urlToOpen}`);
|
|
1016
1004
|
await openInBrowser(urlToOpen);
|
|
1017
1005
|
|
|
1018
1006
|
return Promise.race([timerPromise, loginPromise]);
|
|
@@ -35,7 +35,7 @@ export default {
|
|
|
35
35
|
} catch (e) {
|
|
36
36
|
console.error(e);
|
|
37
37
|
// if an error is thrown then serve from actual worker
|
|
38
|
-
return worker.fetch(request);
|
|
38
|
+
return worker.fetch(request, env, ctx);
|
|
39
39
|
// TODO: throw here if worker is not available
|
|
40
40
|
// (which implies it may be a service-worker)
|
|
41
41
|
}
|