implement direct and indirect eval

This commit is contained in:
velzie 2024-07-28 21:45:41 -04:00
parent e6b237c525
commit ec8421be8f
No known key found for this signature in database
GPG key ID: 048413F95F0DDE1F
12 changed files with 171 additions and 101 deletions

View file

@ -1,24 +1,47 @@
import { ScramjetClient, ProxyCtx } from "../client";
import { rewriteJs } from "../shared";
import { config, rewriteJs } from "../shared";
function rewriteFunction(ctx: ProxyCtx) {
for (const i in ctx.args) {
ctx.args[i] = rewriteJs(ctx.args[i]);
}
for (const i in ctx.args) {
ctx.args[i] = rewriteJs(ctx.args[i]);
}
ctx.return(ctx.fn(...ctx.args));
ctx.return(ctx.fn(...ctx.args));
}
export default function (client: ScramjetClient, self: Self) {
client.Proxy("Function", {
apply(ctx) {
rewriteFunction(ctx);
},
client.Proxy("Function", {
apply(ctx) {
rewriteFunction(ctx);
},
construct(ctx) {
rewriteFunction(ctx);
},
});
construct(ctx) {
rewriteFunction(ctx);
},
});
Function.prototype.constructor = Function;
}
Function.prototype.constructor = Function;
// used for proxying *direct eval*
// eval("...") -> eval($scramjet$rewrite("..."))
Object.defineProperty(self, config.rewritefn, {
value: function (js: any) {
if (typeof js !== "string") return js;
const rewritten = rewriteJs(js, client.url);
return rewritten;
},
writable: false,
configurable: false,
});
}
export function indirectEval(this: ScramjetClient, js: any) {
// > If the argument of eval() is not a string, eval() returns the argument unchanged
if (typeof js !== "string") return js;
const indirection = this.global.eval;
return indirection(rewriteJs(js, this.url) as string);
}

View file

@ -1,8 +1,7 @@
import { encodeUrl } from "../shared";
import { importfn } from "../";
import { config, encodeUrl } from "../shared";
export default function (client, self) {
self[importfn] = function (base) {
self[config.importfn] = function (base) {
return function (url) {
const resolved = new URL(url, base).href;

View file

@ -1,11 +1,12 @@
import { iswindow, isworker, trysetfn, wrapfn } from "..";
import { iswindow, isworker } from "..";
import { ScramjetClient } from "../client";
import { config } from "../shared";
export default function (client: ScramjetClient, self: typeof globalThis) {
// the main magic of the proxy. all attempts to access any "banned objects" will be redirected here, and instead served a proxy object
// this contrasts from how other proxies will leave the root object alone and instead attempt to catch every member access
// this presents some issues (see element.ts), but makes us a good bit faster at runtime!
Object.defineProperty(self, wrapfn, {
Object.defineProperty(self, config.wrapfn, {
value: function (identifier: any, args: any) {
if (args && typeof args === "object" && args.length === 0)
for (const arg of args) {
@ -58,7 +59,7 @@ export default function (client: ScramjetClient, self: typeof globalThis) {
// ((t)=>$scramjet$tryset(location,"+=",t)||location+=t)(...);
// it has to be a discrete function because there's always the possibility that "location" is a local variable
// we have to use an IIFE to avoid duplicating side-effects in the getter
Object.defineProperty(self, trysetfn, {
Object.defineProperty(self, config.trysetfn, {
value: function (lhs: any, op: string, rhs: any) {
if (lhs instanceof Location) {
// @ts-ignore