soiz1's picture
Upload 150 files
bee6636 verified
import { iswindow } from "..";
import { SCRAMJETCLIENT } from "../../symbols";
import { ProxyCtx, ScramjetClient } from "../client";
// we don't want to end up overriding a property on window that's derived from a prototype until we've proxied the prototype
export const order = 3;
export default function (client: ScramjetClient, self: typeof window) {
// an automated approach to cleaning the documentProxy from dom functions
// it will trigger an illegal invocation if you pass the proxy to c++ code, we gotta hotswap it out with the real one
// admittedly this is pretty slow. worth investigating if there's ways to get back some of the lost performance
for (const target of [self]) {
for (const prop in target) {
try {
const value = target[prop];
if (typeof value === "function") {
client.RawProxy(target, prop, {
apply(ctx) {
unproxy(ctx, client);
},
});
}
} catch {}
}
}
if (!iswindow) return;
for (const target of [
self.Node.prototype,
self.MutationObserver.prototype,
self.document,
self.MouseEvent.prototype,
self.Range.prototype,
]) {
for (const prop in target) {
try {
const value = target[prop];
if (typeof value === "function") {
client.RawProxy(target, prop, {
apply(ctx) {
unproxy(ctx, client);
},
});
}
} catch {}
}
}
client.Proxy("IntersectionObserver", {
construct(ctx) {
unproxy(ctx, client);
if (typeof ctx.args[1] === "object" && "root" in ctx.args[1])
if (ctx.args[1].root === client.documentProxy)
ctx.args[1].root = self.document;
},
});
// this is probably not how stuff should be done but you cant run defineProperty on the window proxy so...
client.Proxy("Object.defineProperty", {
apply(ctx) {
unproxy(ctx, client);
},
});
client.Proxy("Object.getOwnPropertyDescriptor", {
apply(ctx) {
const desc = ctx.call();
if (!desc) return;
if (desc.get) {
client.RawProxy(desc, "get", {
apply(ctx) {
// value of this in the getter needs to be corrected
unproxy(ctx, client);
},
});
}
if (desc.set) {
client.RawProxy(desc, "set", {
apply(ctx) {
unproxy(ctx, client);
},
});
}
// i don't think we have to care about value but it's worth looking into
ctx.return(desc);
},
});
client.Proxy("Function.prototype.bind", {
apply(ctx) {
if (
(ctx.args[0] instanceof Window && ctx.args[0] !== client.globalProxy) ||
(ctx.args[0] instanceof Document &&
ctx.args[0] !== client.documentProxy)
) {
const client = ctx.args[0][SCRAMJETCLIENT];
console.log(ctx.this);
ctx.this = new Proxy(ctx.this, {
apply(target, that, args) {
if (that === client.globalProxy) that = client.global;
if (that === client.documentProxy) that = client.global.document;
for (const i in args) {
if (args[i] === client.globalProxy) args[i] = client.global;
if (args[i] === client.documentProxy)
args[i] = client.global.document;
}
return Reflect.apply(target, that, args);
},
});
}
},
});
}
export function unproxy(ctx: ProxyCtx, client: ScramjetClient) {
const self = client.global;
if (ctx.this === client.globalProxy) ctx.this = self;
if (ctx.this === client.documentProxy) ctx.this = self.document;
for (const i in ctx.args) {
if (ctx.args[i] === client.globalProxy) ctx.args[i] = self;
if (ctx.args[i] === client.documentProxy) ctx.args[i] = self.document;
}
}