mirror of
https://github.com/MercuryWorkshop/scramjet.git
synced 2025-05-13 22:40:01 -04:00
long awaited html/element rewrite merge
This commit is contained in:
parent
6f51642afb
commit
8e191b45ab
8 changed files with 184 additions and 183 deletions
|
@ -1,6 +1,7 @@
|
||||||
|
import { createDocumentProxy } from "./document";
|
||||||
|
import { createGlobalProxy } from "./global";
|
||||||
import { createLocationProxy } from "./location";
|
import { createLocationProxy } from "./location";
|
||||||
import { CookieStore, decodeUrl } from "./shared";
|
import { CookieStore, decodeUrl } from "./shared";
|
||||||
import { createDocumentProxy, createGlobalProxy } from "./window";
|
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
interface Window {
|
interface Window {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { ScramjetClient } from "../client";
|
import { ScramjetClient } from "../client";
|
||||||
import { config, decodeUrl } from "../shared";
|
import { config, decodeUrl, htmlRules } from "../shared";
|
||||||
import {
|
import {
|
||||||
encodeUrl,
|
encodeUrl,
|
||||||
rewriteCss,
|
rewriteCss,
|
||||||
|
@ -48,16 +48,10 @@ export default function (client: ScramjetClient, self: typeof window) {
|
||||||
return decodeUrl(descriptor.get.call(this));
|
return decodeUrl(descriptor.get.call(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.$origattrs[attr]) {
|
|
||||||
return this.$origattrs[attr];
|
|
||||||
}
|
|
||||||
|
|
||||||
return descriptor.get.call(this);
|
return descriptor.get.call(this);
|
||||||
},
|
},
|
||||||
|
|
||||||
set(value) {
|
set(value) {
|
||||||
this.$origattrs[attr] = value;
|
|
||||||
|
|
||||||
if (["nonce", "integrity", "csp"].includes(attr)) {
|
if (["nonce", "integrity", "csp"].includes(attr)) {
|
||||||
return;
|
return;
|
||||||
} else if (
|
} else if (
|
||||||
|
@ -65,7 +59,7 @@ export default function (client: ScramjetClient, self: typeof window) {
|
||||||
) {
|
) {
|
||||||
value = encodeUrl(value);
|
value = encodeUrl(value);
|
||||||
} else if (attr === "srcdoc") {
|
} else if (attr === "srcdoc") {
|
||||||
value = rewriteHtml(value, client.cookieStore);
|
value = rewriteHtml(value, client.cookieStore, undefined, true);
|
||||||
} else if (["srcset", "imagesrcset"].includes(attr)) {
|
} else if (["srcset", "imagesrcset"].includes(attr)) {
|
||||||
value = rewriteSrcset(value);
|
value = rewriteSrcset(value);
|
||||||
}
|
}
|
||||||
|
@ -76,56 +70,35 @@ export default function (client: ScramjetClient, self: typeof window) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.Element.prototype.$origattrs = {};
|
client.Proxy("Element.prototype.setAttribute", {
|
||||||
|
apply(ctx) {
|
||||||
|
const [name, value] = ctx.args;
|
||||||
|
|
||||||
self.Element.prototype.getAttribute = new Proxy(
|
const rule = htmlRules.find((rule) => {
|
||||||
self.Element.prototype.getAttribute,
|
let r = rule[name];
|
||||||
{
|
if (!r) return false;
|
||||||
apply(target, thisArg, argArray) {
|
if (r === "*") return true;
|
||||||
if (
|
if (typeof r === "function") return false; // this can't happen but ts
|
||||||
attrs.includes(argArray[0]) &&
|
|
||||||
thisArg.hasAttribute(`data-${argArray[0]}`)
|
return r.includes(ctx.this.tagName.toLowerCase());
|
||||||
) {
|
});
|
||||||
return thisArg.getAttribute(`data-${argArray[0]}`);
|
|
||||||
|
if (rule) {
|
||||||
|
ctx.args[1] = rule.fn(value, client.url, client.cookieStore);
|
||||||
|
ctx.fn.call(ctx.this, `data-scramjet-${ctx.args[0]}`, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (attrs.includes(argArray[0]) && thisArg.$origattrs[argArray[0]]) {
|
|
||||||
return thisArg.$origattrs[argArray[0]];
|
|
||||||
}
|
|
||||||
|
|
||||||
return Reflect.apply(target, thisArg, argArray);
|
|
||||||
},
|
},
|
||||||
}
|
});
|
||||||
);
|
|
||||||
|
|
||||||
self.Element.prototype.setAttribute = new Proxy(
|
client.Proxy("Element.prototype.getAttribute", {
|
||||||
self.Element.prototype.setAttribute,
|
apply(ctx) {
|
||||||
{
|
const [name] = ctx.args;
|
||||||
apply(target, thisArg, argArray) {
|
|
||||||
if (attrs.includes(argArray[0])) {
|
|
||||||
thisArg.$origattrs[argArray[0]] = argArray[1];
|
|
||||||
if (["nonce", "integrity", "csp"].includes(argArray[0])) {
|
|
||||||
return;
|
|
||||||
} else if (
|
|
||||||
["src", "data", "href", "action", "formaction"].includes(
|
|
||||||
argArray[0]
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
argArray[1] = encodeUrl(argArray[1]);
|
|
||||||
} else if (argArray[0] === "srcdoc") {
|
|
||||||
// TODO: this will rewrite with the wrong url in mind for iframes!!
|
|
||||||
argArray[1] = rewriteHtml(argArray[1], client.cookieStore);
|
|
||||||
} else if (["srcset", "imagesrcset"].includes(argArray[0])) {
|
|
||||||
argArray[1] = rewriteSrcset(argArray[1]);
|
|
||||||
} else if (argArray[1] === "style") {
|
|
||||||
argArray[1] = rewriteCss(argArray[1]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Reflect.apply(target, thisArg, argArray);
|
if (ctx.fn.call(ctx.this, `data-scramjet-${name}`)) {
|
||||||
|
ctx.return(ctx.fn.call(ctx.this, `data-scramjet-${name}`));
|
||||||
|
}
|
||||||
},
|
},
|
||||||
}
|
});
|
||||||
);
|
|
||||||
|
|
||||||
const innerHTML = Object.getOwnPropertyDescriptor(
|
const innerHTML = Object.getOwnPropertyDescriptor(
|
||||||
self.Element.prototype,
|
self.Element.prototype,
|
||||||
|
|
|
@ -4,7 +4,6 @@ import { decodeUrl, rewriteCss } from "../shared";
|
||||||
export default function (client: ScramjetClient, self: typeof window) {
|
export default function (client: ScramjetClient, self: typeof window) {
|
||||||
client.Proxy("FontFace", {
|
client.Proxy("FontFace", {
|
||||||
construct(ctx) {
|
construct(ctx) {
|
||||||
dbg.log("FontFace", ctx.args);
|
|
||||||
ctx.args[1] = rewriteCss(ctx.args[1]);
|
ctx.args[1] = rewriteCss(ctx.args[1]);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
export const {
|
export const {
|
||||||
util: { isScramjetFile, BareClient },
|
util: { BareClient },
|
||||||
url: { encodeUrl, decodeUrl },
|
url: { encodeUrl, decodeUrl },
|
||||||
rewrite: {
|
rewrite: {
|
||||||
rewriteCss,
|
rewriteCss,
|
||||||
|
@ -8,6 +8,7 @@ export const {
|
||||||
rewriteJs,
|
rewriteJs,
|
||||||
rewriteHeaders,
|
rewriteHeaders,
|
||||||
rewriteWorkers,
|
rewriteWorkers,
|
||||||
|
htmlRules,
|
||||||
},
|
},
|
||||||
CookieStore,
|
CookieStore,
|
||||||
} = self.$scramjet.shared;
|
} = self.$scramjet.shared;
|
||||||
|
|
|
@ -4,15 +4,14 @@ import { rewriteHtml, rewriteSrcset } from "./rewriters/html";
|
||||||
import { rewriteJs } from "./rewriters/js";
|
import { rewriteJs } from "./rewriters/js";
|
||||||
import { rewriteHeaders } from "./rewriters/headers";
|
import { rewriteHeaders } from "./rewriters/headers";
|
||||||
import { rewriteWorkers } from "./rewriters/worker";
|
import { rewriteWorkers } from "./rewriters/worker";
|
||||||
import { isScramjetFile } from "./rewriters/html";
|
|
||||||
import { BareClient } from "@mercuryworkshop/bare-mux";
|
import { BareClient } from "@mercuryworkshop/bare-mux";
|
||||||
import { parseDomain } from "parse-domain";
|
import { parseDomain } from "parse-domain";
|
||||||
import { ScramjetHeaders } from "./headers";
|
import { ScramjetHeaders } from "./headers";
|
||||||
import { CookieStore } from "./cookie";
|
import { CookieStore } from "./cookie";
|
||||||
|
import { htmlRules } from "./rewriters/html";
|
||||||
|
|
||||||
self.$scramjet.shared = {
|
self.$scramjet.shared = {
|
||||||
util: {
|
util: {
|
||||||
isScramjetFile,
|
|
||||||
parseDomain,
|
parseDomain,
|
||||||
BareClient,
|
BareClient,
|
||||||
ScramjetHeaders,
|
ScramjetHeaders,
|
||||||
|
@ -28,6 +27,7 @@ self.$scramjet.shared = {
|
||||||
rewriteJs,
|
rewriteJs,
|
||||||
rewriteHeaders,
|
rewriteHeaders,
|
||||||
rewriteWorkers,
|
rewriteWorkers,
|
||||||
|
htmlRules,
|
||||||
},
|
},
|
||||||
CookieStore,
|
CookieStore,
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,116 +1,178 @@
|
||||||
import { ElementType, Parser } from "htmlparser2";
|
import { ElementType, Parser } from "htmlparser2";
|
||||||
import { DomHandler, Element, Text } from "domhandler";
|
import { ChildNode, DomHandler, Element, Node, Text } from "domhandler";
|
||||||
import { hasAttrib } from "domutils";
|
|
||||||
import render from "dom-serializer";
|
import render from "dom-serializer";
|
||||||
import { encodeUrl } from "./url";
|
import { encodeUrl } from "./url";
|
||||||
import { rewriteCss } from "./css";
|
import { rewriteCss } from "./css";
|
||||||
import { rewriteJs } from "./js";
|
import { rewriteJs } from "./js";
|
||||||
import { CookieStore } from "../cookie";
|
import { CookieStore } from "../cookie";
|
||||||
|
|
||||||
export function isScramjetFile(src: string) {
|
|
||||||
let bool = false;
|
|
||||||
["wasm", "codecs", "client", "shared", "worker"].forEach((file) => {
|
|
||||||
if (src === self.$scramjet.config[file]) bool = true;
|
|
||||||
});
|
|
||||||
|
|
||||||
return bool;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function rewriteHtml(
|
export function rewriteHtml(
|
||||||
html: string,
|
html: string,
|
||||||
cookieStore: CookieStore,
|
cookieStore: CookieStore,
|
||||||
origin?: URL
|
origin?: URL,
|
||||||
|
fromTop: boolean = false
|
||||||
) {
|
) {
|
||||||
const handler = new DomHandler((err, dom) => dom);
|
const handler = new DomHandler((err, dom) => dom);
|
||||||
const parser = new Parser(handler);
|
const parser = new Parser(handler);
|
||||||
|
|
||||||
parser.write(html);
|
parser.write(html);
|
||||||
parser.end();
|
parser.end();
|
||||||
|
traverseParsedHtml(handler.root, cookieStore, origin);
|
||||||
|
|
||||||
return render(traverseParsedHtml(handler.root, cookieStore, origin));
|
function findhead(node) {
|
||||||
|
if (node.type === ElementType.Tag && node.name === "head") {
|
||||||
|
return node as Element;
|
||||||
|
} else if (node.childNodes) {
|
||||||
|
for (const child of node.childNodes) {
|
||||||
|
const head = findhead(child);
|
||||||
|
if (head) return head;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fromTop) {
|
||||||
|
let head = findhead(handler.root);
|
||||||
|
if (!head) {
|
||||||
|
head = new Element("head", {}, []);
|
||||||
|
handler.root.children.unshift(head);
|
||||||
|
}
|
||||||
|
|
||||||
|
const dump = JSON.stringify(cookieStore.dump());
|
||||||
|
const injected = `
|
||||||
|
self.COOKIE = ${dump};
|
||||||
|
self.$scramjet.config = ${JSON.stringify(self.$scramjet.config)};
|
||||||
|
self.$scramjet.codec = self.$scramjet.codecs[self.$scramjet.config.codec];
|
||||||
|
if ("document" in self && document.currentScript) {
|
||||||
|
document.currentScript.remove();
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
head.children.unshift(
|
||||||
|
new Element("script", {
|
||||||
|
src: self.$scramjet.config["wasm"],
|
||||||
|
}),
|
||||||
|
new Element("script", {
|
||||||
|
src: self.$scramjet.config["codecs"],
|
||||||
|
}),
|
||||||
|
new Element("script", {
|
||||||
|
src: "data:application/javascript;base64," + btoa(injected),
|
||||||
|
}),
|
||||||
|
new Element("script", {
|
||||||
|
src: self.$scramjet.config["shared"],
|
||||||
|
}),
|
||||||
|
new Element("script", {
|
||||||
|
src: self.$scramjet.config["client"],
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return render(handler.root);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const htmlRules: {
|
||||||
|
[key: string]: "*" | string[] | Function;
|
||||||
|
fn: (
|
||||||
|
value: string,
|
||||||
|
origin: URL | null,
|
||||||
|
cookieStore: CookieStore
|
||||||
|
) => string | null;
|
||||||
|
}[] = [
|
||||||
|
{
|
||||||
|
fn: (value: string, origin: URL) => {
|
||||||
|
if (["_parent", "_top", "_unfencedTop"].includes(value)) return "_self";
|
||||||
|
|
||||||
|
console.log(value, origin);
|
||||||
|
return encodeUrl(value, origin);
|
||||||
|
},
|
||||||
|
|
||||||
|
// url rewrites
|
||||||
|
src: [
|
||||||
|
"embed",
|
||||||
|
"script",
|
||||||
|
"img",
|
||||||
|
"iframe",
|
||||||
|
"source",
|
||||||
|
"video",
|
||||||
|
"audio",
|
||||||
|
"input",
|
||||||
|
"track",
|
||||||
|
],
|
||||||
|
href: ["a", "link", "base", "area"],
|
||||||
|
data: ["object"],
|
||||||
|
action: ["form"],
|
||||||
|
formaction: ["button", "input", "textarea", "submit"],
|
||||||
|
poster: ["video"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fn: () => null,
|
||||||
|
|
||||||
|
// csp stuff that must be deleted
|
||||||
|
nonce: "*",
|
||||||
|
integrity: ["script", "link"],
|
||||||
|
csp: ["iframe"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fn: (value: string, origin?: URL) => rewriteSrcset(value, origin),
|
||||||
|
|
||||||
|
// srcset
|
||||||
|
srcset: ["img", "source"],
|
||||||
|
imagesrcset: ["link"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fn: (value: string, origin: URL, cookieStore: CookieStore) =>
|
||||||
|
rewriteHtml(value, cookieStore, origin, true),
|
||||||
|
|
||||||
|
// srcdoc
|
||||||
|
srcdoc: ["iframe"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fn: (value: string, origin?: URL) => rewriteCss(value, origin),
|
||||||
|
style: "*",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
// i need to add the attributes in during rewriting
|
// i need to add the attributes in during rewriting
|
||||||
|
|
||||||
function traverseParsedHtml(node, cookieStore: CookieStore, origin?: URL) {
|
function traverseParsedHtml(node: any, cookieStore: CookieStore, origin?: URL) {
|
||||||
/* csp attributes */
|
if (node.attribs)
|
||||||
for (const cspAttr of ["nonce", "integrity", "csp"]) {
|
for (const rule of htmlRules) {
|
||||||
if (hasAttrib(node, cspAttr)) {
|
for (const attr in rule) {
|
||||||
node.attribs[`data-${cspAttr}`] = node.attribs[cspAttr];
|
const sel = rule[attr];
|
||||||
delete node.attribs[cspAttr];
|
if (typeof sel === "function") continue;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* url attributes */
|
if (sel === "*" || sel.includes(node.name)) {
|
||||||
for (const urlAttr of ["src", "href", "action", "formaction", "poster"]) {
|
if (node.attribs[attr] !== undefined) {
|
||||||
if (
|
const value = node.attribs[attr];
|
||||||
hasAttrib(node, urlAttr) &&
|
let v = rule.fn(value, origin, cookieStore);
|
||||||
!isScramjetFile(node.attribs[urlAttr]) &&
|
|
||||||
[
|
if (v === null) delete node.attribs[attr];
|
||||||
"iframe",
|
else {
|
||||||
"embed",
|
node.attribs[attr] = v;
|
||||||
"script",
|
node.attribs[`data-scramjet-${attr}`] = value;
|
||||||
"a",
|
|
||||||
"img",
|
|
||||||
"link",
|
|
||||||
"object",
|
|
||||||
"form",
|
|
||||||
"media",
|
|
||||||
"source",
|
|
||||||
"video",
|
|
||||||
].includes(node.name)
|
|
||||||
) {
|
|
||||||
if (["_parent", "_top", "_unfencedTop"].includes(node.attribs["target"]))
|
|
||||||
node.attribs["target"] = "_self";
|
|
||||||
const value = node.attribs[urlAttr];
|
|
||||||
node.attribs[`data-${urlAttr}`] = value;
|
|
||||||
node.attribs[urlAttr] = encodeUrl(value, origin);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* other */
|
|
||||||
for (const srcsetAttr of ["srcset", "imagesrcset"]) {
|
|
||||||
if (hasAttrib(node, srcsetAttr)) {
|
|
||||||
const value = node.attribs[srcsetAttr];
|
|
||||||
node.attribs[`data-${srcsetAttr}`] = value;
|
|
||||||
node.attribs[srcsetAttr] = rewriteSrcset(value, origin);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (node.name === "meta" && hasAttrib(node, "http-equiv")) {
|
|
||||||
const content = node.attribs.content;
|
|
||||||
|
|
||||||
const regex =
|
|
||||||
/(https?:\/\/(?:www\.|(?!www))[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}|www\.[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}|https?:\/\/(?:www\.|(?!www))[a-zA-Z0-9]+\.[^\s]{2,}|www\.[a-zA-Z0-9]+\.[^\s]{2,})/;
|
|
||||||
|
|
||||||
if (regex.test(content)) {
|
|
||||||
const url = content.match(regex)[0];
|
|
||||||
|
|
||||||
node.attribs.content = content.replace(url, encodeUrl(url, origin));
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (hasAttrib(node, "srcdoc"))
|
|
||||||
node.attribs.srcdoc = rewriteHtml(node.attribs.srcdoc, cookieStore, origin);
|
|
||||||
if (hasAttrib(node, "style"))
|
|
||||||
node.attribs.style = rewriteCss(node.attribs.style, origin);
|
|
||||||
|
|
||||||
if (node.name === "style" && node.children[0] !== undefined)
|
if (node.name === "style" && node.children[0] !== undefined)
|
||||||
node.children[0].data = rewriteCss(node.children[0].data, origin);
|
node.children[0].data = rewriteCss(node.children[0].data, origin);
|
||||||
|
|
||||||
if (
|
if (
|
||||||
node.name === "script" &&
|
node.name === "script" &&
|
||||||
/(application|text)\/javascript|module|importmap|undefined/.test(
|
/(application|text)\/javascript|module|importmap|undefined/.test(
|
||||||
node.attribs.type
|
node.attribs.type
|
||||||
) &&
|
) &&
|
||||||
node.children[0] !== undefined &&
|
node.children[0] !== undefined
|
||||||
!node.attribs["data-scramjet"]
|
|
||||||
) {
|
) {
|
||||||
let js = node.children[0].data;
|
let js = node.children[0].data;
|
||||||
const htmlcomment = /<!--[\s\S]*?-->/g;
|
const htmlcomment = /<!--[\s\S]*?-->/g;
|
||||||
js = js.replace(htmlcomment, "");
|
js = js.replace(htmlcomment, "");
|
||||||
node.children[0].data = rewriteJs(js, origin);
|
node.children[0].data = rewriteJs(js, origin);
|
||||||
}
|
}
|
||||||
if (node.name === "meta" && hasAttrib(node, "http-equiv")) {
|
|
||||||
|
if (node.name === "meta" && node.attribs["http-equiv"] != undefined) {
|
||||||
if (node.attribs["http-equiv"] === "content-security-policy") {
|
if (node.attribs["http-equiv"] === "content-security-policy") {
|
||||||
node = {};
|
node = {};
|
||||||
} else if (
|
} else if (
|
||||||
|
@ -124,50 +186,6 @@ function traverseParsedHtml(node, cookieStore: CookieStore, origin?: URL) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (node.name === "head") {
|
|
||||||
const scripts = [];
|
|
||||||
|
|
||||||
const dump = JSON.stringify(cookieStore.dump());
|
|
||||||
|
|
||||||
scripts.push(
|
|
||||||
new Element("script", {
|
|
||||||
src: self.$scramjet.config["wasm"],
|
|
||||||
"data-scramjet": "true",
|
|
||||||
})
|
|
||||||
);
|
|
||||||
const codecs = new Element("script", {
|
|
||||||
src: self.$scramjet.config["codecs"],
|
|
||||||
"data-scramjet": "true",
|
|
||||||
});
|
|
||||||
const config = new Element("script", {
|
|
||||||
src:
|
|
||||||
"data:application/javascript;base64," +
|
|
||||||
btoa(
|
|
||||||
`
|
|
||||||
self.COOKIE = ${dump};
|
|
||||||
self.$scramjet.config = ${JSON.stringify(self.$scramjet.config)};
|
|
||||||
self.$scramjet.codec = self.$scramjet.codecs[self.$scramjet.config.codec];
|
|
||||||
if ("document" in self && document.currentScript) {
|
|
||||||
document.currentScript.remove();
|
|
||||||
}
|
|
||||||
`
|
|
||||||
),
|
|
||||||
"data-scramjet": "true",
|
|
||||||
});
|
|
||||||
const shared = new Element("script", {
|
|
||||||
src: self.$scramjet.config["shared"],
|
|
||||||
"data-scramjet": "true",
|
|
||||||
});
|
|
||||||
const client = new Element("script", {
|
|
||||||
src: self.$scramjet.config["client"],
|
|
||||||
"data-scramjet": "true",
|
|
||||||
});
|
|
||||||
|
|
||||||
scripts.push(codecs, config, shared, client);
|
|
||||||
|
|
||||||
node.children.unshift(...scripts);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (node.childNodes) {
|
if (node.childNodes) {
|
||||||
for (const childNode in node.childNodes) {
|
for (const childNode in node.childNodes) {
|
||||||
node.childNodes[childNode] = traverseParsedHtml(
|
node.childNodes[childNode] = traverseParsedHtml(
|
||||||
|
|
10
src/types.d.ts
vendored
10
src/types.d.ts
vendored
|
@ -1,17 +1,20 @@
|
||||||
import { ScramjetController } from "./bootsrapper/index";
|
import { ScramjetController } from "./bootsrapper/index";
|
||||||
import { encodeUrl, decodeUrl } from "./shared/rewriters/url";
|
import { encodeUrl, decodeUrl } from "./shared/rewriters/url";
|
||||||
import { rewriteCss } from "./shared/rewriters/css";
|
import { rewriteCss } from "./shared/rewriters/css";
|
||||||
import { rewriteHtml, rewriteSrcset } from "./shared/rewriters/html";
|
import { htmlRules, rewriteHtml, rewriteSrcset } from "./shared/rewriters/html";
|
||||||
import { rewriteJs } from "./shared/rewriters/js";
|
import { rewriteJs } from "./shared/rewriters/js";
|
||||||
import { rewriteHeaders } from "./shared/rewriters/headers";
|
import { rewriteHeaders } from "./shared/rewriters/headers";
|
||||||
import { rewriteWorkers } from "./shared/rewriters/worker";
|
import { rewriteWorkers } from "./shared/rewriters/worker";
|
||||||
import { isScramjetFile } from "./shared/rewriters/html";
|
|
||||||
import type { Codec } from "./codecs";
|
import type { Codec } from "./codecs";
|
||||||
import { BareClient } from "@mercuryworkshop/bare-mux";
|
import { BareClient } from "@mercuryworkshop/bare-mux";
|
||||||
import { parseDomain } from "parse-domain";
|
import { parseDomain } from "parse-domain";
|
||||||
import { ScramjetHeaders } from "./shared/headers";
|
import { ScramjetHeaders } from "./shared/headers";
|
||||||
import { CookieStore } from "./shared/cookie";
|
import { CookieStore } from "./shared/cookie";
|
||||||
|
|
||||||
|
type ScramjetFlags = {
|
||||||
|
serviceworkers: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
interface ScramjetConfig {
|
interface ScramjetConfig {
|
||||||
prefix: string;
|
prefix: string;
|
||||||
codec: string;
|
codec: string;
|
||||||
|
@ -26,6 +29,7 @@ interface ScramjetConfig {
|
||||||
thread: string;
|
thread: string;
|
||||||
client: string;
|
client: string;
|
||||||
codecs: string;
|
codecs: string;
|
||||||
|
flags: ScramjetFlags;
|
||||||
}
|
}
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
|
@ -43,11 +47,11 @@ declare global {
|
||||||
rewriteJs: typeof rewriteJs;
|
rewriteJs: typeof rewriteJs;
|
||||||
rewriteHeaders: typeof rewriteHeaders;
|
rewriteHeaders: typeof rewriteHeaders;
|
||||||
rewriteWorkers: typeof rewriteWorkers;
|
rewriteWorkers: typeof rewriteWorkers;
|
||||||
|
htmlRules: typeof htmlRules;
|
||||||
};
|
};
|
||||||
util: {
|
util: {
|
||||||
BareClient: typeof BareClient;
|
BareClient: typeof BareClient;
|
||||||
ScramjetHeaders: typeof ScramjetHeaders;
|
ScramjetHeaders: typeof ScramjetHeaders;
|
||||||
isScramjetFile: typeof isScramjetFile;
|
|
||||||
parseDomain: typeof parseDomain;
|
parseDomain: typeof parseDomain;
|
||||||
};
|
};
|
||||||
CookieStore: typeof CookieStore;
|
CookieStore: typeof CookieStore;
|
||||||
|
|
|
@ -165,7 +165,12 @@ async function handleResponse(
|
||||||
case "iframe":
|
case "iframe":
|
||||||
case "document":
|
case "document":
|
||||||
if (responseHeaders["content-type"]?.startsWith("text/html")) {
|
if (responseHeaders["content-type"]?.startsWith("text/html")) {
|
||||||
responseBody = rewriteHtml(await response.text(), cookieStore, url);
|
responseBody = rewriteHtml(
|
||||||
|
await response.text(),
|
||||||
|
cookieStore,
|
||||||
|
url,
|
||||||
|
true
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
responseBody = response.body;
|
responseBody = response.body;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue