mirror of
https://github.com/MercuryWorkshop/scramjet.git
synced 2025-05-14 06:50:01 -04:00
fix postmessage stuff a little more
This commit is contained in:
parent
4ae8dafccb
commit
f48ecdb2b9
3 changed files with 86 additions and 82 deletions
|
@ -1,81 +0,0 @@
|
||||||
import { iswindow } from "..";
|
|
||||||
import { SCRAMJETCLIENT } from "../../symbols";
|
|
||||||
import { ScramjetClient } from "../client";
|
|
||||||
import { POLLUTANT } from "../shared/realm";
|
|
||||||
|
|
||||||
export default function (client: ScramjetClient) {
|
|
||||||
client.Proxy("window.postMessage", {
|
|
||||||
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
|
|
||||||
// if we were given any object that came from the real realm we can use that to get the real origin
|
|
||||||
// and this works in every case EXCEPT for the fact that all three arguments can be strings which are copied instead of cloned
|
|
||||||
// so we have to use `$setrealm` which will pollute this with an object from the real realm
|
|
||||||
|
|
||||||
let pollutant;
|
|
||||||
|
|
||||||
if (typeof ctx.args[0] === "object" && ctx.args[0] !== null) {
|
|
||||||
pollutant = ctx.args[0]; // try to use the first object we can find because it's more reliable
|
|
||||||
} else if (typeof ctx.args[2] === "object" && ctx.args[2] !== null) {
|
|
||||||
pollutant = ctx.args[2]; // next try to use transfer
|
|
||||||
} else if (
|
|
||||||
POLLUTANT in ctx.this &&
|
|
||||||
typeof ctx.this[POLLUTANT] === "object" &&
|
|
||||||
ctx.this[POLLUTANT] !== null
|
|
||||||
) {
|
|
||||||
pollutant = ctx.this[POLLUTANT]; // lastly try to use the object from $setrealm
|
|
||||||
} else {
|
|
||||||
pollutant = {}; // give up
|
|
||||||
}
|
|
||||||
|
|
||||||
// and now we can steal Function from the caller's realm
|
|
||||||
const {
|
|
||||||
constructor: { constructor: Function },
|
|
||||||
} = pollutant;
|
|
||||||
|
|
||||||
// invoking stolen function will give us the caller's globalThis, remember scramjet has already proxied it!!!
|
|
||||||
const callerGlobalThisProxied: Self = Function("return globalThis")();
|
|
||||||
const callerClient = callerGlobalThisProxied[SCRAMJETCLIENT];
|
|
||||||
|
|
||||||
// this WOULD be enough but the source argument of MessageEvent has to return the caller's window
|
|
||||||
// and if we just call it normally it would be coming from here, which WILL NOT BE THE CALLER'S because the accessor is from the parent
|
|
||||||
// so with the stolen function we wrap postmessage so the source will truly be the caller's window (remember that function is scramjet's!!!)
|
|
||||||
const wrappedPostMessage = Function(
|
|
||||||
"data",
|
|
||||||
"origin",
|
|
||||||
"transfer",
|
|
||||||
"this(data, origin, transfer)"
|
|
||||||
);
|
|
||||||
|
|
||||||
ctx.args[0] = {
|
|
||||||
$scramjet$messagetype: "window",
|
|
||||||
$scramjet$origin: callerClient.url.origin,
|
|
||||||
$scramjet$data: ctx.args[0],
|
|
||||||
};
|
|
||||||
|
|
||||||
// * origin because obviously
|
|
||||||
if (typeof ctx.args[1] === "string") ctx.args[1] = "*";
|
|
||||||
|
|
||||||
ctx.return(
|
|
||||||
wrappedPostMessage.call(ctx.fn, ctx.args[0], ctx.args[1], ctx.args[2])
|
|
||||||
);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const toproxy = [
|
|
||||||
"Worker.prototype.postMessage",
|
|
||||||
"MessagePort.prototype.postMessage",
|
|
||||||
];
|
|
||||||
if (!iswindow) toproxy.push("self.postMessage"); // only do the generic version if we're in a worker
|
|
||||||
|
|
||||||
client.Proxy(toproxy, {
|
|
||||||
apply(ctx) {
|
|
||||||
// origin/source doesn't need to be preserved - it's null in the message event
|
|
||||||
|
|
||||||
ctx.args[0] = {
|
|
||||||
$scramjet$messagetype: "worker",
|
|
||||||
$scramjet$data: ctx.args[0],
|
|
||||||
};
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
82
src/client/shared/postmessage.ts
Normal file
82
src/client/shared/postmessage.ts
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
import { iswindow } from "..";
|
||||||
|
import { SCRAMJETCLIENT } from "../../symbols";
|
||||||
|
import { ScramjetClient } from "../client";
|
||||||
|
import { POLLUTANT } from "../shared/realm";
|
||||||
|
|
||||||
|
export default function (client: ScramjetClient) {
|
||||||
|
if (iswindow)
|
||||||
|
client.Proxy("window.postMessage", {
|
||||||
|
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
|
||||||
|
// if we were given any object that came from the real realm we can use that to get the real origin
|
||||||
|
// and this works in every case EXCEPT for the fact that all three arguments can be strings which are copied instead of cloned
|
||||||
|
// so we have to use `$setrealm` which will pollute this with an object from the real realm
|
||||||
|
|
||||||
|
let pollutant;
|
||||||
|
|
||||||
|
if (typeof ctx.args[0] === "object" && ctx.args[0] !== null) {
|
||||||
|
pollutant = ctx.args[0]; // try to use the first object we can find because it's more reliable
|
||||||
|
} else if (typeof ctx.args[2] === "object" && ctx.args[2] !== null) {
|
||||||
|
pollutant = ctx.args[2]; // next try to use transfer
|
||||||
|
} else if (
|
||||||
|
POLLUTANT in ctx.this &&
|
||||||
|
typeof ctx.this[POLLUTANT] === "object" &&
|
||||||
|
ctx.this[POLLUTANT] !== null
|
||||||
|
) {
|
||||||
|
pollutant = ctx.this[POLLUTANT]; // lastly try to use the object from $setrealm
|
||||||
|
} else {
|
||||||
|
pollutant = {}; // give up
|
||||||
|
}
|
||||||
|
|
||||||
|
// and now we can steal Function from the caller's realm
|
||||||
|
const {
|
||||||
|
constructor: { constructor: Function },
|
||||||
|
} = pollutant;
|
||||||
|
|
||||||
|
// invoking stolen function will give us the caller's globalThis, remember scramjet has already proxied it!!!
|
||||||
|
const callerGlobalThisProxied: Self = Function("return globalThis")();
|
||||||
|
const callerClient = callerGlobalThisProxied[SCRAMJETCLIENT];
|
||||||
|
|
||||||
|
// this WOULD be enough but the source argument of MessageEvent has to return the caller's window
|
||||||
|
// and if we just call it normally it would be coming from here, which WILL NOT BE THE CALLER'S because the accessor is from the parent
|
||||||
|
// so with the stolen function we wrap postmessage so the source will truly be the caller's window (remember that function is scramjet's!!!)
|
||||||
|
const wrappedPostMessage = Function(
|
||||||
|
"data",
|
||||||
|
"origin",
|
||||||
|
"transfer",
|
||||||
|
"this(data, origin, transfer)"
|
||||||
|
);
|
||||||
|
|
||||||
|
ctx.args[0] = {
|
||||||
|
$scramjet$messagetype: "window",
|
||||||
|
$scramjet$origin: callerClient.url.origin,
|
||||||
|
$scramjet$data: ctx.args[0],
|
||||||
|
};
|
||||||
|
|
||||||
|
// * origin because obviously
|
||||||
|
if (typeof ctx.args[1] === "string") ctx.args[1] = "*";
|
||||||
|
|
||||||
|
ctx.return(
|
||||||
|
wrappedPostMessage.call(ctx.fn, ctx.args[0], ctx.args[1], ctx.args[2])
|
||||||
|
);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const toproxy = [
|
||||||
|
"Worker.prototype.postMessage",
|
||||||
|
"MessagePort.prototype.postMessage",
|
||||||
|
];
|
||||||
|
if (!iswindow) toproxy.push("self.postMessage"); // only do the generic version if we're in a worker
|
||||||
|
|
||||||
|
client.Proxy(toproxy, {
|
||||||
|
apply(ctx) {
|
||||||
|
// origin/source doesn't need to be preserved - it's null in the message event
|
||||||
|
|
||||||
|
ctx.args[0] = {
|
||||||
|
$scramjet$messagetype: "worker",
|
||||||
|
$scramjet$data: ctx.args[0],
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
|
@ -3,6 +3,8 @@ import { encodeUrl } from "../../shared/rewriters/url";
|
||||||
import type { MessageC2W } from "../../worker";
|
import type { MessageC2W } from "../../worker";
|
||||||
import { ScramjetClient } from "../client";
|
import { ScramjetClient } from "../client";
|
||||||
|
|
||||||
|
const workerpostmessage = Worker.prototype.postMessage;
|
||||||
|
|
||||||
export default function (client: ScramjetClient, self: typeof globalThis) {
|
export default function (client: ScramjetClient, self: typeof globalThis) {
|
||||||
client.Proxy("Worker", {
|
client.Proxy("Worker", {
|
||||||
construct({ args, call }) {
|
construct({ args, call }) {
|
||||||
|
@ -36,7 +38,8 @@ export default function (client: ScramjetClient, self: typeof globalThis) {
|
||||||
|
|
||||||
(async () => {
|
(async () => {
|
||||||
const port = await conn.getInnerPort();
|
const port = await conn.getInnerPort();
|
||||||
worker.postMessage(
|
workerpostmessage.call(
|
||||||
|
worker,
|
||||||
{
|
{
|
||||||
$scramjet$type: "baremuxinit",
|
$scramjet$type: "baremuxinit",
|
||||||
port,
|
port,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue