58 lines
2.1 KiB
Plaintext
58 lines
2.1 KiB
Plaintext
|
import { isRemotePath } from "@astrojs/internal-helpers/path";
|
||
|
function matchPattern(url, remotePattern) {
|
||
|
return matchProtocol(url, remotePattern.protocol) && matchHostname(url, remotePattern.hostname, true) && matchPort(url, remotePattern.port) && matchPathname(url, remotePattern.pathname, true);
|
||
|
}
|
||
|
function matchPort(url, port) {
|
||
|
return !port || port === url.port;
|
||
|
}
|
||
|
function matchProtocol(url, protocol) {
|
||
|
return !protocol || protocol === url.protocol.slice(0, -1);
|
||
|
}
|
||
|
function matchHostname(url, hostname, allowWildcard) {
|
||
|
if (!hostname) {
|
||
|
return true;
|
||
|
} else if (!allowWildcard || !hostname.startsWith("*")) {
|
||
|
return hostname === url.hostname;
|
||
|
} else if (hostname.startsWith("**.")) {
|
||
|
const slicedHostname = hostname.slice(2);
|
||
|
return slicedHostname !== url.hostname && url.hostname.endsWith(slicedHostname);
|
||
|
} else if (hostname.startsWith("*.")) {
|
||
|
const slicedHostname = hostname.slice(1);
|
||
|
const additionalSubdomains = url.hostname.replace(slicedHostname, "").split(".").filter(Boolean);
|
||
|
return additionalSubdomains.length === 1;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
function matchPathname(url, pathname, allowWildcard) {
|
||
|
if (!pathname) {
|
||
|
return true;
|
||
|
} else if (!allowWildcard || !pathname.endsWith("*")) {
|
||
|
return pathname === url.pathname;
|
||
|
} else if (pathname.endsWith("/**")) {
|
||
|
const slicedPathname = pathname.slice(0, -2);
|
||
|
return slicedPathname !== url.pathname && url.pathname.startsWith(slicedPathname);
|
||
|
} else if (pathname.endsWith("/*")) {
|
||
|
const slicedPathname = pathname.slice(0, -1);
|
||
|
const additionalPathChunks = url.pathname.replace(slicedPathname, "").split("/").filter(Boolean);
|
||
|
return additionalPathChunks.length === 1;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
function isRemoteAllowed(src, {
|
||
|
domains = [],
|
||
|
remotePatterns = []
|
||
|
}) {
|
||
|
if (!isRemotePath(src))
|
||
|
return false;
|
||
|
const url = new URL(src);
|
||
|
return domains.some((domain) => matchHostname(url, domain)) || remotePatterns.some((remotePattern) => matchPattern(url, remotePattern));
|
||
|
}
|
||
|
export {
|
||
|
isRemoteAllowed,
|
||
|
matchHostname,
|
||
|
matchPathname,
|
||
|
matchPattern,
|
||
|
matchPort,
|
||
|
matchProtocol
|
||
|
};
|