File size: 3,647 Bytes
bee6636 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 |
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;
}
}
|