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

21
pnpm-lock.yaml generated
View file

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

View file

@ -29,7 +29,7 @@ function traverseParsedHtml(node, origin?: URL) {
}
/* 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])) {
const value = node.attribs[urlAttr];
node.attribs[`data-${urlAttr}`] = value;

View file

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

View file

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

View file

@ -7,7 +7,7 @@ import "./requests/websocket.ts"
import "./element.ts";
import "./storage.ts";
import "./css.ts";
import "./worker.ts"
import "./worker.ts";
declare global {
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();
}
}