mirror of
https://github.com/MercuryWorkshop/scramjet.git
synced 2025-05-13 14:30:02 -04:00
refactor window and document proxies
This commit is contained in:
parent
f3f1a2ed41
commit
6f51642afb
9 changed files with 99 additions and 99 deletions
|
@ -1,6 +1,6 @@
|
|||
import { createLocationProxy } from "./location";
|
||||
import { CookieStore, decodeUrl } from "./shared";
|
||||
import { createDocumentProxy, createWindowProxy } from "./window";
|
||||
import { createDocumentProxy, createGlobalProxy } from "./window";
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
|
@ -43,11 +43,11 @@ export class ScramjetClient {
|
|||
static SCRAMJET = Symbol.for("scramjet client global");
|
||||
|
||||
documentProxy: any;
|
||||
windowProxy: any;
|
||||
globalProxy: any;
|
||||
locationProxy: any;
|
||||
serviceWorker: ServiceWorkerContainer;
|
||||
|
||||
nativeDescriptors: Record<string, PropertyDescriptor> = {};
|
||||
descriptors: Record<string, PropertyDescriptor> = {};
|
||||
natives: Record<string, any> = {};
|
||||
|
||||
cookieStore = new CookieStore();
|
||||
|
@ -69,7 +69,7 @@ export class ScramjetClient {
|
|||
}
|
||||
|
||||
this.locationProxy = createLocationProxy(this, global);
|
||||
this.windowProxy = createWindowProxy(this, global);
|
||||
this.globalProxy = createGlobalProxy(this, global);
|
||||
|
||||
global[ScramjetClient.SCRAMJET] = this;
|
||||
}
|
||||
|
@ -124,7 +124,7 @@ export class ScramjetClient {
|
|||
const prop = split.pop();
|
||||
const target = split.reduce((a, b) => a?.[b], this.global);
|
||||
const original = Reflect.get(target, prop);
|
||||
this.natives[prop] = original;
|
||||
this.natives[name] = original;
|
||||
|
||||
this.RawProxy(target, prop, handler);
|
||||
}
|
||||
|
@ -206,7 +206,7 @@ export class ScramjetClient {
|
|||
const target = split.reduce((a, b) => a?.[b], this.global);
|
||||
|
||||
const original = Object.getOwnPropertyDescriptor(target, prop);
|
||||
this.nativeDescriptors[name] = original;
|
||||
this.descriptors[name] = original;
|
||||
|
||||
return this.RawTrap(target, prop, descriptor);
|
||||
}
|
||||
|
|
30
src/client/document.ts
Normal file
30
src/client/document.ts
Normal file
|
@ -0,0 +1,30 @@
|
|||
import { encodeUrl } from "../shared/rewriters/url";
|
||||
import { ScramjetClient } from "./client";
|
||||
|
||||
export function createDocumentProxy(
|
||||
client: ScramjetClient,
|
||||
self: typeof globalThis
|
||||
) {
|
||||
return new Proxy(self.document, {
|
||||
get(target, prop) {
|
||||
if (prop === "location") {
|
||||
return client.locationProxy;
|
||||
}
|
||||
|
||||
if (prop === "defaultView") {
|
||||
return client.globalProxy;
|
||||
}
|
||||
|
||||
const value = Reflect.get(target, prop);
|
||||
return value;
|
||||
},
|
||||
set(target, prop, newValue) {
|
||||
if (prop === "location") {
|
||||
location.href = encodeUrl(newValue);
|
||||
return;
|
||||
}
|
||||
|
||||
return Reflect.set(target, prop, newValue);
|
||||
},
|
||||
});
|
||||
}
|
|
@ -157,7 +157,7 @@ export default function (client: ScramjetClient, self: typeof window) {
|
|||
const newclient = new ScramjetClient(realwin.self);
|
||||
newclient.hook();
|
||||
|
||||
return newclient.windowProxy;
|
||||
return newclient.globalProxy;
|
||||
}
|
||||
},
|
||||
});
|
||||
|
|
|
@ -20,7 +20,7 @@ export default function (client: ScramjetClient) {
|
|||
// hook the opened window
|
||||
newclient.hook();
|
||||
|
||||
return ctx.return(newclient.windowProxy);
|
||||
return ctx.return(newclient.globalProxy);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
|
55
src/client/global.ts
Normal file
55
src/client/global.ts
Normal file
|
@ -0,0 +1,55 @@
|
|||
import { encodeUrl } from "./shared";
|
||||
import { ScramjetClient } from "./client";
|
||||
import { indirectEval } from "./shared/eval";
|
||||
import { config } from "./shared";
|
||||
|
||||
export function createGlobalProxy(
|
||||
client: ScramjetClient,
|
||||
self: typeof globalThis
|
||||
): typeof globalThis {
|
||||
return new Proxy(self, {
|
||||
get(target, prop) {
|
||||
if (prop === "location") return client.locationProxy;
|
||||
|
||||
if (
|
||||
typeof prop === "string" &&
|
||||
["window", "top", "self", "globalThis", "parent", "document"].includes(
|
||||
prop
|
||||
)
|
||||
)
|
||||
return self[config.wrapfn](self[prop]);
|
||||
|
||||
if (prop === "$scramjet") return;
|
||||
|
||||
if (prop === "eval") return indirectEval.bind(client);
|
||||
|
||||
const value = Reflect.get(target, prop);
|
||||
|
||||
return value;
|
||||
},
|
||||
|
||||
set(target, prop, value) {
|
||||
if (prop === "location") {
|
||||
location.href = encodeUrl(value);
|
||||
return;
|
||||
}
|
||||
|
||||
return Reflect.set(target, prop, value);
|
||||
},
|
||||
has(target, prop) {
|
||||
if (prop === "$scramjet") return false;
|
||||
return Reflect.has(target, prop);
|
||||
},
|
||||
ownKeys(target) {
|
||||
return Reflect.ownKeys(target).filter((key) => key !== "$scramjet");
|
||||
},
|
||||
defineProperty(target, property, attributes) {
|
||||
if (!attributes.get && !attributes.set) {
|
||||
attributes.writable = true;
|
||||
}
|
||||
attributes.configurable = true;
|
||||
|
||||
return Reflect.defineProperty(target, property, attributes);
|
||||
},
|
||||
});
|
||||
}
|
|
@ -22,7 +22,7 @@ export default function (client: ScramjetClient, self: Self) {
|
|||
source() {
|
||||
let scram: ScramjetClient = this.source[ScramjetClient.SCRAMJET];
|
||||
|
||||
if (scram) return scram.windowProxy;
|
||||
if (scram) return scram.globalProxy;
|
||||
|
||||
return this.source;
|
||||
},
|
||||
|
|
|
@ -45,11 +45,11 @@ export default function (client: ScramjetClient, self: typeof window) {
|
|||
|
||||
export function unproxy(ctx: ProxyCtx, client: ScramjetClient) {
|
||||
const self = client.global;
|
||||
if (ctx.this === client.windowProxy) ctx.this = self;
|
||||
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.documentProxy) ctx.args[i] = self.document;
|
||||
if (ctx.args[i] === client.windowProxy) ctx.args[i] = self;
|
||||
if (ctx.args[i] === client.globalProxy) ctx.args[i] = self;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,14 +13,14 @@ export default function (client: ScramjetClient, self: typeof globalThis) {
|
|||
argdbg(arg);
|
||||
}
|
||||
if (iswindow && identifier instanceof self.Window) {
|
||||
return client.windowProxy;
|
||||
return client.globalProxy;
|
||||
} else if (iswindow && identifier instanceof self.parent.self.Window) {
|
||||
if (ScramjetClient.SCRAMJET in self.parent.self) {
|
||||
// ... then we're in a subframe, and the parent frame is also in a proxy context, so we should return its proxy
|
||||
return self.parent.self[ScramjetClient.SCRAMJET].windowProxy;
|
||||
} else {
|
||||
// ... then we should pretend we aren't nested and return the current window
|
||||
return client.windowProxy;
|
||||
return client.globalProxy;
|
||||
}
|
||||
} else if (iswindow && identifier instanceof self.top.self.Window) {
|
||||
// instead of returning top, we need to return the uppermost parent that's inside a scramjet context
|
||||
|
@ -46,7 +46,7 @@ export default function (client: ScramjetClient, self: typeof globalThis) {
|
|||
} else if (iswindow && identifier instanceof self.Document) {
|
||||
return client.documentProxy;
|
||||
} else if (isworker && identifier instanceof self.WorkerGlobalScope) {
|
||||
return client.windowProxy;
|
||||
return client.globalProxy;
|
||||
}
|
||||
|
||||
return identifier;
|
||||
|
|
|
@ -1,85 +0,0 @@
|
|||
import { encodeUrl } from "./shared";
|
||||
import { ScramjetClient } from "./client";
|
||||
import { indirectEval } from "./shared/eval";
|
||||
import { config } from "./shared";
|
||||
|
||||
export function createWindowProxy(
|
||||
client: ScramjetClient,
|
||||
self: typeof globalThis
|
||||
): typeof globalThis {
|
||||
return new Proxy(self, {
|
||||
get(target, prop) {
|
||||
const propIsString = typeof prop === "string";
|
||||
if (prop === "location") return client.locationProxy;
|
||||
|
||||
if (
|
||||
propIsString &&
|
||||
["window", "top", "self", "globalThis", "parent"].includes(prop)
|
||||
)
|
||||
return self[config.wrapfn](self[prop]);
|
||||
|
||||
if (prop === "$scramjet") return;
|
||||
|
||||
if (prop === "eval") return indirectEval.bind(client);
|
||||
|
||||
const value = Reflect.get(target, prop);
|
||||
|
||||
return value;
|
||||
},
|
||||
|
||||
set(target, prop, newValue) {
|
||||
// ensures that no apis are overwritten
|
||||
if (
|
||||
typeof prop === "string" &&
|
||||
["window", "top", "parent", "self", "globalThis", "location"].includes(
|
||||
prop
|
||||
)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return Reflect.set(target, prop, newValue);
|
||||
},
|
||||
defineProperty(target, property, attributes) {
|
||||
if (!attributes.get && !attributes.set) {
|
||||
attributes.writable = true;
|
||||
}
|
||||
attributes.configurable = true;
|
||||
|
||||
return Reflect.defineProperty(target, property, attributes);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export function createDocumentProxy(
|
||||
client: ScramjetClient,
|
||||
self: typeof globalThis
|
||||
) {
|
||||
return new Proxy(self.document || {}, {
|
||||
get(target, prop) {
|
||||
const propIsString = typeof prop === "string";
|
||||
|
||||
if (propIsString && prop === "location") {
|
||||
return client.locationProxy;
|
||||
}
|
||||
|
||||
if (propIsString && prop === "defaultView") {
|
||||
return client.windowProxy;
|
||||
}
|
||||
|
||||
const value = Reflect.get(target, prop);
|
||||
|
||||
return value;
|
||||
},
|
||||
set(target, prop, newValue) {
|
||||
if (typeof prop === "string" && prop === "location") {
|
||||
//@ts-ignore
|
||||
location = new URL(encodeUrl(newValue));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
return Reflect.set(target, prop, newValue);
|
||||
},
|
||||
});
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue