chore: import upstream snapshot with attribution
Deploy (to testing) and Test Playground Preview Worker / Deploy Playground Preview Worker (testing) (push) Has been skipped
Deploy Workers Shared Staging / Deploy Workers Shared Staging (push) Failing after 0s
Prerelease / build (push) Has been skipped
Handle Changesets / Handle Changesets (push) Has been cancelled
Semgrep OSS scan / semgrep-oss (push) Has been cancelled
Deploy (to testing) and Test Playground Preview Worker / Deploy Playground Preview Worker (testing) (push) Has been skipped
Deploy Workers Shared Staging / Deploy Workers Shared Staging (push) Failing after 0s
Prerelease / build (push) Has been skipped
Handle Changesets / Handle Changesets (push) Has been cancelled
Semgrep OSS scan / semgrep-oss (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,76 @@
|
||||
export const extractPathname = (
|
||||
path = "/",
|
||||
includeSearch: boolean,
|
||||
includeHash: boolean
|
||||
): string => {
|
||||
if (!path.startsWith("/")) {
|
||||
path = `/${path}`;
|
||||
}
|
||||
const url = new URL(`//${path}`, "relative://");
|
||||
return `${url.pathname}${includeSearch ? url.search : ""}${
|
||||
includeHash ? url.hash : ""
|
||||
}`;
|
||||
};
|
||||
|
||||
const URL_REGEX = /^https:\/\/+(?<host>[^/]+)\/?(?<path>.*)/;
|
||||
const HOST_WITH_PORT_REGEX = /.*:\d+$/;
|
||||
const PATH_REGEX = /^\//;
|
||||
|
||||
export const validateUrl = (
|
||||
token: string,
|
||||
onlyRelative = false,
|
||||
disallowPorts = false,
|
||||
includeSearch = false,
|
||||
includeHash = false
|
||||
): [undefined, string] | [string, undefined] => {
|
||||
const host = URL_REGEX.exec(token);
|
||||
if (host && host.groups && host.groups.host) {
|
||||
if (onlyRelative) {
|
||||
return [
|
||||
undefined,
|
||||
`Only relative URLs are allowed. Skipping absolute URL ${token}.`,
|
||||
];
|
||||
}
|
||||
|
||||
if (disallowPorts && host.groups.host.match(HOST_WITH_PORT_REGEX)) {
|
||||
return [
|
||||
undefined,
|
||||
`Specifying ports is not supported. Skipping absolute URL ${token}.`,
|
||||
];
|
||||
}
|
||||
|
||||
return [
|
||||
`https://${host.groups.host}${extractPathname(
|
||||
host.groups.path,
|
||||
includeSearch,
|
||||
includeHash
|
||||
)}`,
|
||||
undefined,
|
||||
];
|
||||
} else {
|
||||
if (!token.startsWith("/") && onlyRelative) {
|
||||
token = `/${token}`;
|
||||
}
|
||||
|
||||
const path = PATH_REGEX.exec(token);
|
||||
if (path) {
|
||||
try {
|
||||
return [extractPathname(token, includeSearch, includeHash), undefined];
|
||||
} catch {
|
||||
return [undefined, `Error parsing URL segment ${token}. Skipping.`];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return [
|
||||
undefined,
|
||||
onlyRelative
|
||||
? "URLs should begin with a forward-slash."
|
||||
: 'URLs should either be relative (e.g. begin with a forward-slash), or use HTTPS (e.g. begin with "https://").',
|
||||
];
|
||||
};
|
||||
|
||||
export function urlHasHost(token: string): boolean {
|
||||
const host = URL_REGEX.exec(token);
|
||||
return Boolean(host && host.groups && host.groups.host);
|
||||
}
|
||||
Reference in New Issue
Block a user