mirror of
https://github.com/MercuryWorkshop/scramjet.git
synced 2025-05-13 22:40:01 -04:00
properly rewrite postmessage
This commit is contained in:
parent
34c3cc5094
commit
c2d147442e
9 changed files with 134 additions and 17 deletions
|
@ -25,7 +25,7 @@ export default function (client: ScramjetClient) {
|
||||||
get(ctx) {
|
get(ctx) {
|
||||||
const realwin = ctx.get() as Window;
|
const realwin = ctx.get() as Window;
|
||||||
|
|
||||||
if (ScramjetClient.SCRAMJET in realwin.self) {
|
if (realwin && ScramjetClient.SCRAMJET in realwin.self) {
|
||||||
return realwin.self[ScramjetClient.SCRAMJET].windowProxy;
|
return realwin.self[ScramjetClient.SCRAMJET].windowProxy;
|
||||||
} else {
|
} else {
|
||||||
// the opener has to have been already hooked, so if we reach here then it's a real window
|
// the opener has to have been already hooked, so if we reach here then it's a real window
|
||||||
|
|
|
@ -1,8 +1,28 @@
|
||||||
import { ScramjetClient } from "../client";
|
import { ScramjetClient } from "../client";
|
||||||
|
|
||||||
export default function (client: ScramjetClient, self: typeof window) {
|
export default function (client: ScramjetClient) {
|
||||||
client.Proxy("window.postMessage", {
|
client.Proxy("window.postMessage", {
|
||||||
apply(ctx) {
|
apply(ctx) {
|
||||||
|
// so we need to send the real origin here, since the recieving window can't possibly know.
|
||||||
|
// except, remember that this code is being ran in a different realm than the invoker, so if we ask our `client` it may give us the wrong origin
|
||||||
|
// but, the first argument given will be polluted with the real realm
|
||||||
|
|
||||||
|
// this obtains a reference to the Function object of the real realm
|
||||||
|
const {
|
||||||
|
constructor: { constructor: Function },
|
||||||
|
} = ctx.args[0];
|
||||||
|
|
||||||
|
// and finally, invoking the stolen Function will execute inside the caller's realm
|
||||||
|
const callerGlobalThis: Self = Function("return globalThis")();
|
||||||
|
const callerClient: ScramjetClient =
|
||||||
|
callerGlobalThis[ScramjetClient.SCRAMJET];
|
||||||
|
|
||||||
|
ctx.args[0] = {
|
||||||
|
$scramjet$origin: callerClient.url.origin,
|
||||||
|
$scramjet$data: ctx.args[0],
|
||||||
|
};
|
||||||
|
|
||||||
|
// * origin because obviously
|
||||||
if (typeof ctx.args[1] === "string") ctx.args[1] = "*";
|
if (typeof ctx.args[1] === "string") ctx.args[1] = "*";
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -2,6 +2,16 @@
|
||||||
|
|
||||||
import { ScramjetClient } from "./client";
|
import { ScramjetClient } from "./client";
|
||||||
|
|
||||||
|
export const iswindow = "window" in self;
|
||||||
|
export const isworker = "WorkerGlobalScope" in self;
|
||||||
|
export const issw = "ServiceWorkerGlobalScope" in self;
|
||||||
|
export const isdedicated = "DedicatedWorkerGlobalScope" in self;
|
||||||
|
export const isshared = "SharedWorkerGlobalScope" in self;
|
||||||
|
|
||||||
|
export const wrapfn = "$scramjet$wrap";
|
||||||
|
export const trysetfn = "$scramjet$tryset";
|
||||||
|
export const importfn = "$scramjet$import";
|
||||||
|
|
||||||
dbg.log("scrammin");
|
dbg.log("scrammin");
|
||||||
// if it already exists, that means the handlers have probably already been setup by the parent document
|
// if it already exists, that means the handlers have probably already been setup by the parent document
|
||||||
if (!(ScramjetClient.SCRAMJET in self)) {
|
if (!(ScramjetClient.SCRAMJET in self)) {
|
||||||
|
|
81
src/client/shared/event.ts
Normal file
81
src/client/shared/event.ts
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
import { iswindow } from "..";
|
||||||
|
import { ScramjetClient } from "../client";
|
||||||
|
|
||||||
|
const realOnEvent = Symbol.for("scramjet original onevent function");
|
||||||
|
|
||||||
|
export default function (client: ScramjetClient, self: Self) {
|
||||||
|
const handlers = {
|
||||||
|
message: {
|
||||||
|
origin() {
|
||||||
|
return this.data.$scramjet$origin;
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return this.data.$scramjet$data;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
function wraplistener(listener: (...args: any) => any) {
|
||||||
|
return new Proxy(listener, {
|
||||||
|
apply(target, thisArg, argArray) {
|
||||||
|
const realEvent: Event = argArray[0];
|
||||||
|
|
||||||
|
// we only need to handle events dispatched from the browser
|
||||||
|
if (realEvent.isTrusted) {
|
||||||
|
const type = realEvent.type;
|
||||||
|
|
||||||
|
if (type in handlers) {
|
||||||
|
let handler = handlers[type];
|
||||||
|
argArray[0] = new Proxy(realEvent, {
|
||||||
|
get(_target, prop, reciever) {
|
||||||
|
if (prop in handler) {
|
||||||
|
return handler[prop].call(_target);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Reflect.get(target, prop, reciever);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return listener.apply(self, argArray);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
client.Proxy("EventTarget.prototype.addEventListener", {
|
||||||
|
apply(ctx) {
|
||||||
|
ctx.args[1] = wraplistener(ctx.args[1]);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!iswindow) return;
|
||||||
|
|
||||||
|
const targets = [self.window, self.HTMLElement.prototype];
|
||||||
|
|
||||||
|
for (const target of targets) {
|
||||||
|
const keys = Reflect.ownKeys(target);
|
||||||
|
|
||||||
|
for (const key of keys) {
|
||||||
|
if (typeof key === "string" && key.startsWith("on")) {
|
||||||
|
const descriptor = Object.getOwnPropertyDescriptor(target, key);
|
||||||
|
if (!descriptor.get || !descriptor.set || !descriptor.configurable)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// these are the `onmessage`, `onclick`, etc. properties
|
||||||
|
client.RawTrap(target, key, {
|
||||||
|
get(ctx) {
|
||||||
|
if (this[realOnEvent]) return this[realOnEvent];
|
||||||
|
|
||||||
|
return ctx.get();
|
||||||
|
},
|
||||||
|
set(ctx, value: any) {
|
||||||
|
this[realOnEvent] = value;
|
||||||
|
|
||||||
|
ctx.set(wraplistener(value));
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
import { encodeUrl } from "../shared";
|
import { encodeUrl } from "../shared";
|
||||||
import { importfn } from "./wrap";
|
import { importfn } from "../";
|
||||||
|
|
||||||
export default function (client, self) {
|
export default function (client, self) {
|
||||||
self[importfn] = function (base) {
|
self[importfn] = function (base) {
|
||||||
|
|
|
@ -1,21 +1,16 @@
|
||||||
|
import { iswindow, isworker, trysetfn, wrapfn } from "..";
|
||||||
import { ScramjetClient } from "../client";
|
import { ScramjetClient } from "../client";
|
||||||
|
|
||||||
export const iswindow = "window" in self;
|
|
||||||
export const isworker = "WorkerGlobalScope" in self;
|
|
||||||
export const issw = "ServiceWorkerGlobalScope" in self;
|
|
||||||
export const isdedicated = "DedicatedWorkerGlobalScope" in self;
|
|
||||||
export const isshared = "SharedWorkerGlobalScope" in self;
|
|
||||||
|
|
||||||
export const wrapfn = "$scramjet$wrap";
|
|
||||||
export const trysetfn = "$scramjet$tryset";
|
|
||||||
export const importfn = "$scramjet$import";
|
|
||||||
|
|
||||||
export default function (client: ScramjetClient, self: typeof globalThis) {
|
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
|
// 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 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!
|
// this presents some issues (see element.ts), but makes us a good bit faster at runtime!
|
||||||
Object.defineProperty(self, wrapfn, {
|
Object.defineProperty(self, wrapfn, {
|
||||||
value: function (identifier: any) {
|
value: function (identifier: any, args: any) {
|
||||||
|
if (args && typeof args === "object" && args.length === 0)
|
||||||
|
for (const arg of args) {
|
||||||
|
argdbg(arg);
|
||||||
|
}
|
||||||
if (iswindow && identifier instanceof self.Window) {
|
if (iswindow && identifier instanceof self.Window) {
|
||||||
return client.windowProxy;
|
return client.windowProxy;
|
||||||
} else if (iswindow && identifier instanceof self.parent.self.Window) {
|
} else if (iswindow && identifier instanceof self.parent.self.Window) {
|
||||||
|
@ -75,4 +70,15 @@ export default function (client: ScramjetClient, self: typeof globalThis) {
|
||||||
writable: false,
|
writable: false,
|
||||||
configurable: false,
|
configurable: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function argdbg(arg) {
|
||||||
|
switch (typeof arg) {
|
||||||
|
case "string":
|
||||||
|
if (arg.includes("scramjet")) debugger;
|
||||||
|
break;
|
||||||
|
case "object":
|
||||||
|
for (let ar of arg) argdbg(ar);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { encodeUrl } from "../shared/rewriters/url";
|
import { encodeUrl } from "../shared/rewriters/url";
|
||||||
import { ScramjetClient } from "./client";
|
import { ScramjetClient } from "./client";
|
||||||
import { wrapfn } from "./shared/wrap";
|
import { wrapfn } from ".";
|
||||||
|
|
||||||
export function createWindowProxy(
|
export function createWindowProxy(
|
||||||
client: ScramjetClient,
|
client: ScramjetClient,
|
||||||
|
|
2
src/global.d.ts
vendored
2
src/global.d.ts
vendored
|
@ -4,3 +4,5 @@ declare const dbg: {
|
||||||
error: (message: string, ...args: any[]) => void;
|
error: (message: string, ...args: any[]) => void;
|
||||||
debug: (message: string, ...args: any[]) => void;
|
debug: (message: string, ...args: any[]) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
declare type Self = Window & typeof globalThis;
|
||||||
|
|
2
src/types.d.ts
vendored
2
src/types.d.ts
vendored
|
@ -51,5 +51,3 @@ declare global {
|
||||||
WASM: string;
|
WASM: string;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type Self = Window & typeof globalThis;
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue