@cloudflare/pages-shared 0.8.0 → 0.8.2
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.
|
@@ -7,10 +7,11 @@ const escapeRegex = (str: string) => {
|
|
|
7
7
|
return str.replace(ESCAPE_REGEX_CHARACTERS, "\\$&");
|
|
8
8
|
};
|
|
9
9
|
|
|
10
|
-
// Placeholder names must begin with a colon, be alphanumeric and optionally contain underscores.
|
|
10
|
+
// Placeholder names must begin with a colon then a letter, be alphanumeric and optionally contain underscores.
|
|
11
11
|
// e.g. :place_123_holder
|
|
12
|
-
const HOST_PLACEHOLDER_REGEX =
|
|
13
|
-
|
|
12
|
+
const HOST_PLACEHOLDER_REGEX =
|
|
13
|
+
/(?<=^https:\\\/\\\/[^/]*?):([A-Za-z]\w*)(?=\\)/g;
|
|
14
|
+
const PLACEHOLDER_REGEX = /:([A-Za-z]\w*)/g;
|
|
14
15
|
|
|
15
16
|
export type Replacements = Record<string, string>;
|
|
16
17
|
|
|
@@ -67,11 +68,22 @@ export const generateRulesMatcher = <T>(
|
|
|
67
68
|
][];
|
|
68
69
|
|
|
69
70
|
return ({ request }: { request: Request }) => {
|
|
70
|
-
const { pathname,
|
|
71
|
+
const { pathname, hostname } = new URL(request.url);
|
|
71
72
|
|
|
72
73
|
return compiledRules
|
|
73
74
|
.map(([{ crossHost, regExp }, match]) => {
|
|
74
|
-
|
|
75
|
+
// This, rather confusingly, means that although we enforce `https://` protocols in
|
|
76
|
+
// the rules of `_headers`/`_redirects`, we don't actually respect that at all at runtime.
|
|
77
|
+
// When processing a request against an absolute URL rule, we rewrite the protocol to `https://`.
|
|
78
|
+
// This has the benefit of ensuring attackers can't specify a different protocol
|
|
79
|
+
// to circumvent a developer's security rules (e.g. CORS), but it isn't obvious behavior.
|
|
80
|
+
// We should consider different syntax in the future for developers when they specify rules.
|
|
81
|
+
// For example, `*://example.com/path`, `://example.com/path` or `//example.com/`.
|
|
82
|
+
// Though we'd need to be careful with that last one
|
|
83
|
+
// as that would currently be read as a relative URL.
|
|
84
|
+
// Perhaps, if we ever move the `_headers`/`_redirects` files to acting ahead of Functions,
|
|
85
|
+
// this might be a good time for this change.
|
|
86
|
+
const test = crossHost ? `https://${hostname}${pathname}` : pathname;
|
|
75
87
|
const result = regExp.exec(test);
|
|
76
88
|
if (result) {
|
|
77
89
|
return replacerFn(match, result.groups || {});
|
|
@@ -50,7 +50,7 @@ export function parseRedirects(input: string): ParsedRedirects {
|
|
|
50
50
|
|
|
51
51
|
const [str_from, str_to, str_status = "302"] = tokens as RedirectLine;
|
|
52
52
|
|
|
53
|
-
const fromResult = validateUrl(str_from, true, false, false);
|
|
53
|
+
const fromResult = validateUrl(str_from, true, true, false, false);
|
|
54
54
|
if (fromResult[0] === undefined) {
|
|
55
55
|
invalid.push({
|
|
56
56
|
line,
|
|
@@ -88,7 +88,7 @@ export function parseRedirects(input: string): ParsedRedirects {
|
|
|
88
88
|
}
|
|
89
89
|
}
|
|
90
90
|
|
|
91
|
-
const toResult = validateUrl(str_to, false, true, true);
|
|
91
|
+
const toResult = validateUrl(str_to, false, false, true, true);
|
|
92
92
|
if (toResult[0] === undefined) {
|
|
93
93
|
invalid.push({
|
|
94
94
|
line,
|
|
@@ -11,11 +11,13 @@ export const extractPathname = (
|
|
|
11
11
|
};
|
|
12
12
|
|
|
13
13
|
const URL_REGEX = /^https:\/\/+(?<host>[^/]+)\/?(?<path>.*)/;
|
|
14
|
+
const HOST_WITH_PORT_REGEX = /.*:\d+$/;
|
|
14
15
|
const PATH_REGEX = /^\//;
|
|
15
16
|
|
|
16
17
|
export const validateUrl = (
|
|
17
18
|
token: string,
|
|
18
19
|
onlyRelative = false,
|
|
20
|
+
disallowPorts = false,
|
|
19
21
|
includeSearch = false,
|
|
20
22
|
includeHash = false
|
|
21
23
|
): [undefined, string] | [string, undefined] => {
|
|
@@ -27,6 +29,13 @@ export const validateUrl = (
|
|
|
27
29
|
`Only relative URLs are allowed. Skipping absolute URL ${token}.`,
|
|
28
30
|
];
|
|
29
31
|
|
|
32
|
+
if (disallowPorts && host.groups.host.match(HOST_WITH_PORT_REGEX)) {
|
|
33
|
+
return [
|
|
34
|
+
undefined,
|
|
35
|
+
`Specifying ports is not supported. Skipping absolute URL ${token}.`,
|
|
36
|
+
];
|
|
37
|
+
}
|
|
38
|
+
|
|
30
39
|
return [
|
|
31
40
|
`https://${host.groups.host}${extractPathname(
|
|
32
41
|
host.groups.path,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cloudflare/pages-shared",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.2",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "https://github.com/cloudflare/workers-sdk.git",
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"test:ci": "vitest run"
|
|
19
19
|
},
|
|
20
20
|
"dependencies": {
|
|
21
|
-
"miniflare": "3.
|
|
21
|
+
"miniflare": "3.20230814.1"
|
|
22
22
|
},
|
|
23
23
|
"devDependencies": {
|
|
24
24
|
"@cloudflare/workers-tsconfig": "*",
|