convert to estraverse and minor cleanup

This commit is contained in:
Avad3 2024-07-13 10:08:30 -04:00
parent bc9a16720e
commit 29bbda0700
8 changed files with 66 additions and 126 deletions

View file

@ -28,6 +28,7 @@
"@mercuryworkshop/libcurl-transport": "^1.3.6", "@mercuryworkshop/libcurl-transport": "^1.3.6",
"@tomphttp/bare-server-node": "^2.0.3", "@tomphttp/bare-server-node": "^2.0.3",
"@types/eslint": "^8.56.10", "@types/eslint": "^8.56.10",
"@types/estraverse": "^5.1.7",
"@types/serviceworker": "^0.0.85", "@types/serviceworker": "^0.0.85",
"@typescript-eslint/eslint-plugin": "^6.21.0", "@typescript-eslint/eslint-plugin": "^6.21.0",
"@typescript-eslint/parser": "^6.21.0", "@typescript-eslint/parser": "^6.21.0",
@ -44,11 +45,11 @@
"dependencies": { "dependencies": {
"@mercuryworkshop/bare-mux": "^2.0.2", "@mercuryworkshop/bare-mux": "^2.0.2",
"@webreflection/idb-map": "^0.3.1", "@webreflection/idb-map": "^0.3.1",
"astravel": "^0.6.1",
"astring": "^1.8.6", "astring": "^1.8.6",
"dom-serializer": "^2.0.0", "dom-serializer": "^2.0.0",
"domhandler": "^5.0.3", "domhandler": "^5.0.3",
"domutils": "^3.1.0", "domutils": "^3.1.0",
"estraverse": "^5.3.0",
"htmlparser2": "^9.1.0", "htmlparser2": "^9.1.0",
"meriyah": "^4.4.2" "meriyah": "^4.4.2"
} }

21
pnpm-lock.yaml generated
View file

@ -14,9 +14,6 @@ importers:
'@webreflection/idb-map': '@webreflection/idb-map':
specifier: ^0.3.1 specifier: ^0.3.1
version: 0.3.1 version: 0.3.1
astravel:
specifier: ^0.6.1
version: 0.6.1
astring: astring:
specifier: ^1.8.6 specifier: ^1.8.6
version: 1.8.6 version: 1.8.6
@ -29,6 +26,9 @@ importers:
domutils: domutils:
specifier: ^3.1.0 specifier: ^3.1.0
version: 3.1.0 version: 3.1.0
estraverse:
specifier: ^5.3.0
version: 5.3.0
htmlparser2: htmlparser2:
specifier: ^9.1.0 specifier: ^9.1.0
version: 9.1.0 version: 9.1.0
@ -54,6 +54,9 @@ importers:
'@types/eslint': '@types/eslint':
specifier: ^8.56.10 specifier: ^8.56.10
version: 8.56.10 version: 8.56.10
'@types/estraverse':
specifier: ^5.1.7
version: 5.1.7
'@types/serviceworker': '@types/serviceworker':
specifier: ^0.0.85 specifier: ^0.0.85
version: 0.0.85 version: 0.0.85
@ -410,6 +413,9 @@ packages:
'@types/eslint@8.56.10': '@types/eslint@8.56.10':
resolution: {integrity: sha512-Shavhk87gCtY2fhXDctcfS3e6FdxWkCx1iUZ9eEUbh7rTqlZT0/IzOkCOVt0fCjcFuZ9FPYfuezTBImfHCDBGQ==} resolution: {integrity: sha512-Shavhk87gCtY2fhXDctcfS3e6FdxWkCx1iUZ9eEUbh7rTqlZT0/IzOkCOVt0fCjcFuZ9FPYfuezTBImfHCDBGQ==}
'@types/estraverse@5.1.7':
resolution: {integrity: sha512-JRVtdKYZz7VkNp7hMC/WKoiZ8DS3byw20ZGoMZ1R8eBrBPIY7iBaDAS1zcrnXQCwK44G4vbXkimeU7R0VLG8UQ==}
'@types/estree@1.0.5': '@types/estree@1.0.5':
resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==} resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==}
@ -561,9 +567,6 @@ packages:
resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==}
engines: {node: '>=8'} engines: {node: '>=8'}
astravel@0.6.1:
resolution: {integrity: sha512-ZIkgWFIV0Yo423Vqalz7VcF+BAiISvSgplnkV2abPGACPFKofsWTcvr9SFyYM/t/vMZWqmdP/Eze6ATX7r84Dg==}
astring@1.8.6: astring@1.8.6:
resolution: {integrity: sha512-ISvCdHdlTDlH5IpxQJIex7BWBywFWgjJSVdwst+/iQCoEYnyOaQ95+X1JGshuBjGp6nxKUy1jMgE3zPqN7fQdg==} resolution: {integrity: sha512-ISvCdHdlTDlH5IpxQJIex7BWBywFWgjJSVdwst+/iQCoEYnyOaQ95+X1JGshuBjGp6nxKUy1jMgE3zPqN7fQdg==}
hasBin: true hasBin: true
@ -1692,6 +1695,10 @@ snapshots:
'@types/estree': 1.0.5 '@types/estree': 1.0.5
'@types/json-schema': 7.0.15 '@types/json-schema': 7.0.15
'@types/estraverse@5.1.7':
dependencies:
'@types/estree': 1.0.5
'@types/estree@1.0.5': {} '@types/estree@1.0.5': {}
'@types/json-schema@7.0.15': {} '@types/json-schema@7.0.15': {}
@ -1853,8 +1860,6 @@ snapshots:
array-union@2.1.0: {} array-union@2.1.0: {}
astravel@0.6.1: {}
astring@1.8.6: {} astring@1.8.6: {}
async-exit-hook@2.0.1: {} async-exit-hook@2.0.1: {}

View file

@ -29,7 +29,7 @@ function traverseParsedHtml(node, origin?: URL) {
} }
/* url attributes */ /* url attributes */
for (const urlAttr of ["src", "href", "data", "action"]) { for (const urlAttr of ["src", "href", "data", "action", "formaction"]) {
if (hasAttrib(node, urlAttr) && !isScramjetFile(node.attribs[urlAttr])) { if (hasAttrib(node, urlAttr) && !isScramjetFile(node.attribs[urlAttr])) {
const value = node.attribs[urlAttr]; const value = node.attribs[urlAttr];
node.attribs[`data-${urlAttr}`] = value; node.attribs[`data-${urlAttr}`] = value;

View file

@ -1,7 +1,7 @@
import { parseModule } from "meriyah"; import { parseModule } from "meriyah";
import { generate } from "astring"; import { generate } from "astring";
import { makeTraveler } from "astravel";
import { encodeUrl } from "./url"; import { encodeUrl } from "./url";
import { replace } from "estraverse";
// i am a cat. i like to be petted. i like to be fed. i like to be // i am a cat. i like to be petted. i like to be fed. i like to be
@ -18,10 +18,7 @@ import { encodeUrl } from "./url";
export function rewriteJs(js: string, origin?: URL) { export function rewriteJs(js: string, origin?: URL) {
try { try {
const ast = parseModule(js, { const ast = parseModule(js);
module: true,
webcompat: true
});
// const identifierList = [ // const identifierList = [
// "window", // "window",
@ -33,30 +30,20 @@ export function rewriteJs(js: string, origin?: URL) {
// "" // ""
// ] // ]
const customTraveler = makeTraveler({ replace(ast, {
ImportDeclaration: (node) => { enter: (node, parent) => {
if (["ImportDeclaration", "ImportExpression", "ExportAllDeclaration", "ExportNamedDeclaration"].includes(node.type) && node.source) {
node.source.value = encodeUrl(node.source.value, origin); node.source.value = encodeUrl(node.source.value, origin);
}
return node;
}, },
ImportExpression: (node) => { fallback: "iteration"
node.source.value = encodeUrl(node.source.value, origin); })
},
ExportAllDeclaration: (node) => {
node.source.value = encodeUrl(node.source.value, origin);
},
ExportNamedDeclaration: (node) => {
if (node.source) node.source.value = encodeUrl(node.source.value, origin);
},
});
customTraveler.go(ast);
return generate(ast); return generate(ast);
} catch { } catch (err) {
console.log(js); throw new Error(err);
return js;
} }
} }

View file

@ -16,8 +16,11 @@ jsProperties.forEach((prop) => {
const propDescriptor = Object.getOwnPropertyDescriptor(CSSStyleDeclaration.prototype, prop); const propDescriptor = Object.getOwnPropertyDescriptor(CSSStyleDeclaration.prototype, prop);
Object.defineProperty(CSSStyleDeclaration.prototype, prop, { Object.defineProperty(CSSStyleDeclaration.prototype, prop, {
get() {
return propDescriptor.get.call(this);
},
set(v) { set(v) {
propDescriptor.set.call(this, rewriteCss(v)); return propDescriptor.set.call(this, rewriteCss(v));
}, },
}) })
}); });

View file

@ -1,25 +1,6 @@
import { encodeUrl, rewriteCss, rewriteHtml, rewriteJs, rewriteSrcset } from "../bundle"; import { encodeUrl, rewriteCss, rewriteHtml, rewriteJs, rewriteSrcset } from "../bundle";
// object const attrObject = {
// iframe
// embed
// link
// style
// script
// img
// source
// form
// meta
// area
// base
// body
// input
// audio
// button
// track
// video
const attribs = {
"nonce": [HTMLElement], "nonce": [HTMLElement],
"integrity": [HTMLScriptElement, HTMLLinkElement], "integrity": [HTMLScriptElement, HTMLLinkElement],
"csp": [HTMLIFrameElement], "csp": [HTMLIFrameElement],
@ -30,64 +11,56 @@ const attribs = {
"formaction": [HTMLButtonElement, HTMLInputElement], "formaction": [HTMLButtonElement, HTMLInputElement],
"srcdoc": [HTMLIFrameElement], "srcdoc": [HTMLIFrameElement],
"srcset": [HTMLImageElement, HTMLSourceElement], "srcset": [HTMLImageElement, HTMLSourceElement],
"imagesrcset": [HTMLLinkElement], "imagesrcset": [HTMLLinkElement]
"style": [HTMLElement]
} }
Object.keys(attribs).forEach((attrib: string) => { const attrs = Object.keys(attrObject);
attribs[attrib].forEach((element) => {
const descriptor = Object.getOwnPropertyDescriptor(element.prototype, attrib); for (const attr of attrs) {
Object.defineProperty(element.prototype, attrib, { for (const element of attrObject[attr]) {
const descriptor = Object.getOwnPropertyDescriptor(element.prototype, attr);
Object.defineProperty(element.prototype, attr, {
get() { get() {
return this.dataset[attrib]; return this.dataset[attr];
}, },
set(value) { set(value) {
this.dataset[attrib] = value; this.dataset[attr] = value;
if (/nonce|integrity|csp/.test(attrib)) { if (/nonce|integrity|csp/.test(attr)) {
this.removeAttribute(attrib); return;
} else if (/src|href|data|action|formaction/.test(attrib)) { } else if (/src|href|data|action|formaction/.test(attr)) {
// @ts-expect-error // @ts-expect-error
if (value instanceof TrustedScriptURL) { if (value instanceof TrustedScriptURL) {
return; return;
} }
value = encodeUrl(value); value = encodeUrl(value);
} else if (attrib === "srcdoc") { } else if (attr === "srcdoc") {
value = rewriteHtml(value); value = rewriteHtml(value);
} else if (/(image)?srcset/.test(attrib)) { } else if (/(image)?srcset/.test(attr)) {
value = rewriteSrcset(value); value = rewriteSrcset(value);
} else if (attrib === "style") {
value = rewriteCss(value);
} }
descriptor.set.call(this, value); descriptor.set.call(this, value);
}, },
}); });
}) }
}); }
HTMLElement.prototype.getAttribute = new Proxy(Element.prototype.getAttribute, { Element.prototype.getAttribute = new Proxy(Element.prototype.getAttribute, {
apply(target, thisArg, argArray) { apply(target, thisArg, argArray) {
console.log(thisArg); if (attrs.includes(argArray[0]) && thisArg.dataset[argArray[0]]) {
if (Object.keys(attribs).includes(argArray[0])) { return thisArg.dataset[argArray[0]];
argArray[0] = `data-${argArray[0]}`;
} }
return Reflect.apply(target, thisArg, argArray); return Reflect.apply(target, thisArg, argArray);
}, },
}); });
// setAttribute proxy is currently broken Element.prototype.setAttribute = new Proxy(Element.prototype.setAttribute, {
HTMLElement.prototype.setAttribute = new Proxy(Element.prototype.setAttribute, {
apply(target, thisArg, argArray) { apply(target, thisArg, argArray) {
if (thisArg.dataset["scramjet"]) { if (attrs.includes(argArray[0])) {
return; thisArg.dataset[argArray[0]] = argArray[1];
}
console.log(argArray[1])
if (Object.keys(attribs).includes(argArray[0])) {
thisArg.dataset[`_${argArray[0]}`] = argArray[1];
if (/nonce|integrity|csp/.test(argArray[0])) { if (/nonce|integrity|csp/.test(argArray[0])) {
return; return;
} else if (/src|href|data|action|formaction/.test(argArray[0])) { } else if (/src|href|data|action|formaction/.test(argArray[0])) {
@ -108,21 +81,17 @@ HTMLElement.prototype.setAttribute = new Proxy(Element.prototype.setAttribute, {
const innerHTML = Object.getOwnPropertyDescriptor(Element.prototype, "innerHTML"); const innerHTML = Object.getOwnPropertyDescriptor(Element.prototype, "innerHTML");
Object.defineProperty(HTMLElement.prototype, "innerHTML", { Object.defineProperty(Element.prototype, "innerHTML", {
set(value) { set(value) {
if (this instanceof HTMLScriptElement) {
// @ts-expect-error // @ts-expect-error
if (!(value instanceof TrustedScript)) { if (this instanceof HTMLScriptElement && !(value instanceof TrustedScript)) {
value = rewriteJs(value); value = rewriteJs(value);
}
} else if (this instanceof HTMLStyleElement) { } else if (this instanceof HTMLStyleElement) {
value = rewriteCss(value); value = rewriteCss(value);
} else {
// @ts-expect-error // @ts-expect-error
if (!(value instanceof TrustedHTML)) { } else if (!(value instanceof TrustedHTML)) {
value = rewriteHtml(value); value = rewriteHtml(value);
} }
}
return innerHTML.set.call(this, value); return innerHTML.set.call(this, value);
}, },

View file

@ -7,7 +7,7 @@ import "./requests/websocket.ts"
import "./element.ts"; import "./element.ts";
import "./storage.ts"; import "./storage.ts";
import "./css.ts"; import "./css.ts";
import "./worker.ts" import "./worker.ts";
declare global { declare global {
interface Window { interface Window {

View file

@ -1,25 +0,0 @@
export default class Clone {
el: HTMLElement;
copy: HTMLElement
constructor(element: HTMLElement) {
this.el = element;
this.copy = document.createElement(element.tagName);
for (const attr of element.getAttributeNames()) {
this.copy.setAttribute(attr, element.getAttribute(attr));
}
if (element.innerHTML) {
this.copy.innerHTML = element.innerHTML;
}
}
insertCopy() {
this.el.insertAdjacentElement("afterend", this.copy);
}
removeElement() {
this.el.remove();
}
}