mirror of
https://github.com/MercuryWorkshop/scramjet.git
synced 2025-05-13 22:40:01 -04:00
fix buggy impl of innerHTML and outerHTML
This commit is contained in:
parent
00e11793aa
commit
33bcfaedab
2 changed files with 90 additions and 78 deletions
|
@ -48,7 +48,7 @@ export default function (client: ScramjetClient, self: typeof window) {
|
||||||
for (const element of attrObject[attr]) {
|
for (const element of attrObject[attr]) {
|
||||||
const descriptor = nativeGetOwnPropertyDescriptor(
|
const descriptor = nativeGetOwnPropertyDescriptor(
|
||||||
element.prototype,
|
element.prototype,
|
||||||
attr
|
attr,
|
||||||
);
|
);
|
||||||
Object.defineProperty(element.prototype, attr, {
|
Object.defineProperty(element.prototype, attr, {
|
||||||
get() {
|
get() {
|
||||||
|
@ -75,7 +75,7 @@ export default function (client: ScramjetClient, self: typeof window) {
|
||||||
base: new URL(client.url.origin),
|
base: new URL(client.url.origin),
|
||||||
origin: new URL(client.url.origin),
|
origin: new URL(client.url.origin),
|
||||||
} as URLMeta,
|
} as URLMeta,
|
||||||
true
|
true,
|
||||||
);
|
);
|
||||||
} else if (["srcset", "imagesrcset"].includes(attr)) {
|
} else if (["srcset", "imagesrcset"].includes(attr)) {
|
||||||
value = rewriteSrcset(value, client.meta);
|
value = rewriteSrcset(value, client.meta);
|
||||||
|
@ -174,10 +174,15 @@ export default function (client: ScramjetClient, self: typeof window) {
|
||||||
ctx.set(newval);
|
ctx.set(newval);
|
||||||
},
|
},
|
||||||
get(ctx) {
|
get(ctx) {
|
||||||
if (
|
if (ctx.this instanceof self.HTMLScriptElement) {
|
||||||
ctx.this instanceof self.HTMLScriptElement ||
|
return atob(
|
||||||
ctx.this instanceof self.HTMLStyleElement
|
client.natives["Element.prototype.getAttribute"].call(
|
||||||
) {
|
ctx.this,
|
||||||
|
"data-scramjet-script-source-src",
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (ctx.this instanceof self.HTMLStyleElement) {
|
||||||
return ctx.get();
|
return ctx.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -264,7 +269,7 @@ export default function (client: ScramjetClient, self: typeof window) {
|
||||||
ctx.args[0],
|
ctx.args[0],
|
||||||
client.cookieStore,
|
client.cookieStore,
|
||||||
client.meta,
|
client.meta,
|
||||||
false
|
false,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -276,7 +281,7 @@ export default function (client: ScramjetClient, self: typeof window) {
|
||||||
ctx.args[0],
|
ctx.args[0],
|
||||||
client.cookieStore,
|
client.cookieStore,
|
||||||
client.meta,
|
client.meta,
|
||||||
true
|
true,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -287,7 +292,7 @@ export default function (client: ScramjetClient, self: typeof window) {
|
||||||
ctx.args[0],
|
ctx.args[0],
|
||||||
client.cookieStore,
|
client.cookieStore,
|
||||||
client.meta,
|
client.meta,
|
||||||
false
|
false,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -10,7 +10,7 @@ export function rewriteHtml(
|
||||||
html: string,
|
html: string,
|
||||||
cookieStore: CookieStore,
|
cookieStore: CookieStore,
|
||||||
meta: URLMeta,
|
meta: URLMeta,
|
||||||
fromTop: boolean = false
|
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);
|
||||||
|
@ -56,7 +56,7 @@ export function rewriteHtml(
|
||||||
script(self.$scramjet.config["codecs"]),
|
script(self.$scramjet.config["codecs"]),
|
||||||
script("data:application/javascript;base64," + btoa(injected)),
|
script("data:application/javascript;base64," + btoa(injected)),
|
||||||
script(self.$scramjet.config["shared"]),
|
script(self.$scramjet.config["shared"]),
|
||||||
script(self.$scramjet.config["client"])
|
script(self.$scramjet.config["client"]),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -78,6 +78,12 @@ export function unrewriteHtml(html: string) {
|
||||||
function traverse(node: ChildNode) {
|
function traverse(node: ChildNode) {
|
||||||
if ("attribs" in node) {
|
if ("attribs" in node) {
|
||||||
for (const key in node.attribs) {
|
for (const key in node.attribs) {
|
||||||
|
if (key == "data-scramjet-script-source-src") {
|
||||||
|
if (node.children[0] && "data" in node.children[0])
|
||||||
|
node.children[0].data = atob(node.attribs[key]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (key.startsWith("data-scramjet-")) {
|
if (key.startsWith("data-scramjet-")) {
|
||||||
node.attribs[key.slice(13)] = node.attribs[key];
|
node.attribs[key.slice(13)] = node.attribs[key];
|
||||||
delete node.attribs[key];
|
delete node.attribs[key];
|
||||||
|
@ -101,80 +107,80 @@ export const htmlRules: {
|
||||||
[key: string]: "*" | string[] | ((...any: any[]) => string | null);
|
[key: string]: "*" | string[] | ((...any: any[]) => string | null);
|
||||||
fn: (value: string, meta: URLMeta, cookieStore: CookieStore) => string | null;
|
fn: (value: string, meta: URLMeta, cookieStore: CookieStore) => string | null;
|
||||||
}[] = [
|
}[] = [
|
||||||
{
|
{
|
||||||
fn: (value: string, meta: URLMeta) => {
|
fn: (value: string, meta: URLMeta) => {
|
||||||
return encodeUrl(value, meta);
|
return encodeUrl(value, meta);
|
||||||
|
},
|
||||||
|
|
||||||
|
// url rewrites
|
||||||
|
src: [
|
||||||
|
"embed",
|
||||||
|
"script",
|
||||||
|
"img",
|
||||||
|
"image",
|
||||||
|
"iframe",
|
||||||
|
"source",
|
||||||
|
"video",
|
||||||
|
"audio",
|
||||||
|
"input",
|
||||||
|
"track",
|
||||||
|
],
|
||||||
|
href: ["a", "link", "area"],
|
||||||
|
data: ["object"],
|
||||||
|
action: ["form"],
|
||||||
|
formaction: ["button", "input", "textarea", "submit"],
|
||||||
|
poster: ["video"],
|
||||||
|
"xlink:href": ["image"],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
fn: () => null,
|
||||||
|
|
||||||
// url rewrites
|
// csp stuff that must be deleted
|
||||||
src: [
|
nonce: "*",
|
||||||
"embed",
|
integrity: ["script", "link"],
|
||||||
"script",
|
csp: ["iframe"],
|
||||||
"img",
|
|
||||||
"image",
|
|
||||||
"iframe",
|
|
||||||
"source",
|
|
||||||
"video",
|
|
||||||
"audio",
|
|
||||||
"input",
|
|
||||||
"track",
|
|
||||||
],
|
|
||||||
href: ["a", "link", "area"],
|
|
||||||
data: ["object"],
|
|
||||||
action: ["form"],
|
|
||||||
formaction: ["button", "input", "textarea", "submit"],
|
|
||||||
poster: ["video"],
|
|
||||||
"xlink:href": ["image"],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
fn: () => null,
|
|
||||||
|
|
||||||
// csp stuff that must be deleted
|
|
||||||
nonce: "*",
|
|
||||||
integrity: ["script", "link"],
|
|
||||||
csp: ["iframe"],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
fn: (value: string, meta: URLMeta) => rewriteSrcset(value, meta),
|
|
||||||
|
|
||||||
// srcset
|
|
||||||
srcset: ["img", "source"],
|
|
||||||
imagesrcset: ["link"],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
fn: (value: string, meta: URLMeta, cookieStore: CookieStore) =>
|
|
||||||
rewriteHtml(
|
|
||||||
value,
|
|
||||||
cookieStore,
|
|
||||||
{
|
|
||||||
// for srcdoc origin is the origin of the page that the iframe is on. base and path get dropped
|
|
||||||
origin: new URL(meta.origin.origin),
|
|
||||||
base: new URL(meta.origin.origin),
|
|
||||||
},
|
|
||||||
true
|
|
||||||
),
|
|
||||||
|
|
||||||
// srcdoc
|
|
||||||
srcdoc: ["iframe"],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
fn: (value: string, meta: URLMeta) => rewriteCss(value, meta),
|
|
||||||
style: "*",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
fn: (value: string) => {
|
|
||||||
if (["_parent", "_top", "_unfencedTop"].includes(value)) return "_self";
|
|
||||||
},
|
},
|
||||||
target: ["a", "base"],
|
{
|
||||||
},
|
fn: (value: string, meta: URLMeta) => rewriteSrcset(value, meta),
|
||||||
];
|
|
||||||
|
// srcset
|
||||||
|
srcset: ["img", "source"],
|
||||||
|
imagesrcset: ["link"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fn: (value: string, meta: URLMeta, cookieStore: CookieStore) =>
|
||||||
|
rewriteHtml(
|
||||||
|
value,
|
||||||
|
cookieStore,
|
||||||
|
{
|
||||||
|
// for srcdoc origin is the origin of the page that the iframe is on. base and path get dropped
|
||||||
|
origin: new URL(meta.origin.origin),
|
||||||
|
base: new URL(meta.origin.origin),
|
||||||
|
},
|
||||||
|
true,
|
||||||
|
),
|
||||||
|
|
||||||
|
// srcdoc
|
||||||
|
srcdoc: ["iframe"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fn: (value: string, meta: URLMeta) => rewriteCss(value, meta),
|
||||||
|
style: "*",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fn: (value: string) => {
|
||||||
|
if (["_parent", "_top", "_unfencedTop"].includes(value)) return "_self";
|
||||||
|
},
|
||||||
|
target: ["a", "base"],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
// i need to add the attributes in during rewriting
|
// i need to add the attributes in during rewriting
|
||||||
|
|
||||||
function traverseParsedHtml(
|
function traverseParsedHtml(
|
||||||
node: any,
|
node: any,
|
||||||
cookieStore: CookieStore,
|
cookieStore: CookieStore,
|
||||||
meta: URLMeta
|
meta: URLMeta,
|
||||||
) {
|
) {
|
||||||
if (node.name === "base" && node.attribs.href !== undefined) {
|
if (node.name === "base" && node.attribs.href !== undefined) {
|
||||||
meta.base = new URL(node.attribs.href, meta.origin);
|
meta.base = new URL(node.attribs.href, meta.origin);
|
||||||
|
@ -207,11 +213,12 @@ function traverseParsedHtml(
|
||||||
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
|
||||||
) {
|
) {
|
||||||
let js = node.children[0].data;
|
let js = node.children[0].data;
|
||||||
|
node.attribs[`data-scramjet-script-source-src`] = btoa(js);
|
||||||
const htmlcomment = /<!--[\s\S]*?-->/g;
|
const htmlcomment = /<!--[\s\S]*?-->/g;
|
||||||
js = js.replace(htmlcomment, "");
|
js = js.replace(htmlcomment, "");
|
||||||
node.children[0].data = rewriteJs(js, meta);
|
node.children[0].data = rewriteJs(js, meta);
|
||||||
|
@ -238,7 +245,7 @@ function traverseParsedHtml(
|
||||||
node.childNodes[childNode] = traverseParsedHtml(
|
node.childNodes[childNode] = traverseParsedHtml(
|
||||||
node.childNodes[childNode],
|
node.childNodes[childNode],
|
||||||
cookieStore,
|
cookieStore,
|
||||||
meta
|
meta,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue