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;
	}
}