diff --git a/README.md b/README.md index 3c362cf..f17d8e9 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ check back in 3 months when scramjet supports 23% of what UV supports TODO - Finish HTML rewriting - - \ tag rewriting: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/meta + - ~~\ tag rewriting: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/meta~~ - Build script imports for scramjet scripts in DomHandler AST - example stringified output: @@ -15,13 +15,13 @@ TODO - `` rewriting - Make an array of all possible import values and pass the array onto the JS rewriter, then rewrite all the URLs inside of it - Fix URL rewriting - - Pass the full the full url object arround instead of just the origin and if the url is relative append it to the url path before adding it to the origin + - ~~Pass the full the full url object arround instead of just the origin and if the url is relative append it to the url path before adding it to the origin~~ - Finish JS rewriting - Only thing rewritten currently are imports and exports - Check imports/exports for values contained in the `importmap` array, don't rewrite the node value if present - Fix CSS rewriting - CSS rewriting only rewrites the `url()` function, but `@import` rules can import urls using just a string: https://developer.mozilla.org/en-US/docs/Web/CSS/@import -- Rewrite `Link` header: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Link +- ~~Rewrite `Link` header: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Link~~ - Write client APIs - `__scope$()` function for JS rewriting - Location object diff --git a/src/bundle/rewriters/css.ts b/src/bundle/rewriters/css.ts index 9a3ed6c..c9829c4 100644 --- a/src/bundle/rewriters/css.ts +++ b/src/bundle/rewriters/css.ts @@ -1,6 +1,6 @@ import { encodeUrl } from "./url" -export function rewriteCss(css: string, origin?: string) { +export function rewriteCss(css: string, origin?: URL) { css = css.replace(/(?<=url\("?'?)[^"'][\S]*[^"'](?="?'?\);?)/g, (match) => encodeUrl(match, origin)); return "/* intercepted by scramjet 🐳 */" + css; diff --git a/src/bundle/rewriters/headers.ts b/src/bundle/rewriters/headers.ts index 3c0c4d2..020e1e6 100644 --- a/src/bundle/rewriters/headers.ts +++ b/src/bundle/rewriters/headers.ts @@ -26,11 +26,13 @@ const urlHeaders = [ "referer" ]; -export function rewriteHeaders(rawHeaders: BareHeaders, origin?: string) { +export function rewriteHeaders(rawHeaders: BareHeaders, origin?: URL) { const headers = {}; + for (const key in rawHeaders) { headers[key.toLowerCase()] = rawHeaders[key]; } + cspHeaders.forEach((header) => { delete headers[header]; }); @@ -38,7 +40,11 @@ export function rewriteHeaders(rawHeaders: BareHeaders, origin?: string) { urlHeaders.forEach((header) => { if (headers[header]) headers[header] = encodeUrl(headers[header] as string, origin); - }) + }); + + if (headers["link"]) { + headers["link"] = headers["link"].replace(/<(.*?)>/gi, (match) => encodeUrl(match, origin)); + } return headers; } \ No newline at end of file diff --git a/src/bundle/rewriters/html.ts b/src/bundle/rewriters/html.ts index 11bc0e5..1f924eb 100644 --- a/src/bundle/rewriters/html.ts +++ b/src/bundle/rewriters/html.ts @@ -9,7 +9,7 @@ import { rewriteJs } from "./js"; // html nodes to rewrite // meta -export function rewriteHtml(html: string, origin?: string) { +export function rewriteHtml(html: string, origin?: URL) { const handler = new DomHandler((err, dom) => dom); const parser = new Parser(handler); @@ -19,7 +19,7 @@ export function rewriteHtml(html: string, origin?: string) { return render(traverseParsedHtml(handler.root, origin)); } -function traverseParsedHtml(node, origin?: string) { +function traverseParsedHtml(node, origin?: URL) { /* csp attributes */ if (hasAttrib(node, "nonce")) delete node.attribs.nonce; if (hasAttrib(node, "integrity")) delete node.attribs.integrity; @@ -39,6 +39,13 @@ function traverseParsedHtml(node, origin?: string) { if (node.name === "style" && node.children[0] !== undefined) node.children[0].data = rewriteCss(node.children[0].data, origin); if (node.name === "script" && /(application|text)\/javascript|importmap|undefined/.test(node.attribs.type) && node.children[0] !== undefined) node.children[0].data = rewriteJs(node.children[0].data, origin); + if (node.name === "meta" && hasAttrib(node, "http-equiv")) { + if (node.attribs["http-equiv"] === "content-security-policy") { + return; + } else if (node.attribs["http-equiv"] === "refresh") { + node.attribs.content = node.attribs.content.split(";url=").map((elem, index) => index === 1 ? encodeUrl(elem) : elem).join(";url="); + } + } if (node.childNodes) { for (const childNode in node.childNodes) { @@ -50,7 +57,7 @@ function traverseParsedHtml(node, origin?: string) { } // stole from osana lmao -export function rewriteSrcset(srcset: string, origin?: string) { +export function rewriteSrcset(srcset: string, origin?: URL) { const urls = srcset.split(/ [0-9]+x,? ?/g); if (!urls) return ""; const sufixes = srcset.match(/ [0-9]+x,? ?/g); diff --git a/src/bundle/rewriters/js.ts b/src/bundle/rewriters/js.ts index cdb3fd9..c7677c5 100644 --- a/src/bundle/rewriters/js.ts +++ b/src/bundle/rewriters/js.ts @@ -5,7 +5,7 @@ import { encodeUrl } from "./url"; // i am a cat. i like to be petted. i like to be fed. i like to be -export function rewriteJs(js: string, origin?: string) { +export function rewriteJs(js: string, origin?: URL) { const ast = parse(js, { module: true }); diff --git a/src/bundle/rewriters/url.ts b/src/bundle/rewriters/url.ts index 94efde7..c7f8d11 100644 --- a/src/bundle/rewriters/url.ts +++ b/src/bundle/rewriters/url.ts @@ -1,25 +1,19 @@ import { rewriteJs } from "./js"; -function canParseUrl(url: string, origin?: string) { - if (URL.canParse) { - console.log(URL.canParse(url, origin) + "\n" + url + "\n" + origin); +function canParseUrl(url: string, origin?: URL) { + try { + new URL(url, origin); - return URL.canParse(url, origin); - } else { - try { - new URL(url, origin); - - return true; - } catch { - return false; - } + return true; + } catch { + return false; } } // something is broken with this but i didn't debug it -export function encodeUrl(url: string, origin?: string) { +export function encodeUrl(url: string, origin?: URL) { if (!origin) { - origin = self.__scramjet$config.codec.decode(location.href.slice((location.origin + self.__scramjet$config.prefix).length)); + origin = new URL(self.__scramjet$config.codec.decode(location.href.slice((location.origin + self.__scramjet$config.prefix).length))); } if (url.startsWith("javascript:")) { diff --git a/src/worker/index.ts b/src/worker/index.ts index 3900350..2eaafd9 100644 --- a/src/worker/index.ts +++ b/src/worker/index.ts @@ -41,13 +41,13 @@ self.ScramjetServiceWorker = class ScramjetServiceWorker { switch (request.destination) { case "iframe": case "document": - responseBody = self.__scramjet$bundle.rewriters.rewriteHtml(await response.text(), url.origin); + responseBody = self.__scramjet$bundle.rewriters.rewriteHtml(await response.text(), origin); break; case "script": - responseBody = self.__scramjet$bundle.rewriters.rewriteJs(await response.text(), url.origin); + responseBody = self.__scramjet$bundle.rewriters.rewriteJs(await response.text(), origin); break; case "style": - responseBody = self.__scramjet$bundle.rewriters.rewriteCss(await response.text(), url.origin); + responseBody = self.__scramjet$bundle.rewriters.rewriteCss(await response.text(), origin); break; case "sharedworker": break;