scramjet/src/shared/rewriters/url.ts

82 lines
2.2 KiB
TypeScript

import { $scramjet } from "../../scramjet";
import { rewriteJs } from "./js";
export type URLMeta = {
origin: URL;
base: URL;
};
function tryCanParseURL(url: string, origin?: string | URL): URL | null {
try {
return new URL(url, origin);
} catch {
return null;
}
}
export function rewriteBlob(url: string, meta: URLMeta) {
const blob = new URL(url.substring("blob:".length));
return "blob:" + meta.origin.origin + blob.pathname;
}
export function unrewriteBlob(url: string) {
const blob = new URL(url.substring("blob:".length));
return "blob:" + location.origin + blob.pathname;
}
export function rewriteUrl(url: string | URL, meta: URLMeta) {
if (url instanceof URL) url = url.toString();
if (url.startsWith("javascript:")) {
return (
"javascript:" +
rewriteJs(url.slice("javascript:".length), "(javascript: url)", meta)
);
} else if (url.startsWith("blob:")) {
return location.origin + $scramjet.config.prefix + url;
} else if (url.startsWith("data:")) {
return location.origin + $scramjet.config.prefix + url;
} else if (url.startsWith("mailto:") || url.startsWith("about:")) {
return url;
} else {
let base = meta.base.href;
if (base.startsWith("about:")) base = unrewriteUrl(self.location.href); // jank!!!!! weird jank!!!
const realUrl = tryCanParseURL(url, base);
if (!realUrl) return url;
return (
location.origin +
$scramjet.config.prefix +
$scramjet.codec.encode(realUrl.href)
);
}
}
export function unrewriteUrl(url: string | URL) {
if (url instanceof URL) url = url.toString();
const prefixed = location.origin + $scramjet.config.prefix;
if (url.startsWith("javascript:")) {
//TODO
return url;
} else if (url.startsWith("blob:")) {
// realistically this shouldn't happen
return url;
} else if (url.startsWith(prefixed + "blob:")) {
return url.substring(prefixed.length);
} else if (url.startsWith(prefixed + "data:")) {
return url.substring(prefixed.length);
} else if (url.startsWith("mailto:") || url.startsWith("about:")) {
return url;
} else if (tryCanParseURL(url)) {
return $scramjet.codec.decode(
url.slice((location.origin + $scramjet.config.prefix).length)
);
} else {
return url;
}
}