From 5f77342d8dc5ec69b737fa4d6f1139817b86784d Mon Sep 17 00:00:00 2001 From: velzie Date: Fri, 30 Aug 2024 16:59:52 -0400 Subject: [PATCH] ScramjetClient.SCRAMJET -> SCRAMJETCLIENT --- src/client/client.ts | 9 +++++---- src/client/dom/element.ts | 11 ++++++----- src/client/dom/open.ts | 11 +++++------ src/client/index.ts | 3 ++- src/client/shared/event.ts | 3 ++- src/client/shared/wrap.ts | 11 ++++++----- src/controller/frame.ts | 33 +++++++++++++++++++++++++++++++++ src/controller/index.ts | 31 +++---------------------------- src/shared/rewriters/html.ts | 6 ++++++ src/symbols.ts | 3 +++ src/types.d.ts | 11 +++++++++++ 11 files changed, 82 insertions(+), 50 deletions(-) create mode 100644 src/controller/frame.ts create mode 100644 src/symbols.ts diff --git a/src/client/client.ts b/src/client/client.ts index 84e6b63..39da1b9 100644 --- a/src/client/client.ts +++ b/src/client/client.ts @@ -1,3 +1,4 @@ +import { SCRAMJETCLIENT } from "../symbols"; import { createDocumentProxy } from "./document"; import { createGlobalProxy } from "./global"; import { getOwnPropertyDescriptorHandler } from "./helpers"; @@ -43,8 +44,6 @@ export type Trap = { }; export class ScramjetClient { - static SCRAMJET = Symbol.for("scramjet client global"); - documentProxy: any; globalProxy: any; locationProxy: any; @@ -76,7 +75,7 @@ export class ScramjetClient { this.locationProxy = createLocationProxy(this, global); this.globalProxy = createGlobalProxy(this, global); - global[ScramjetClient.SCRAMJET] = this; + global[SCRAMJETCLIENT] = this; } loadcookies(cookiestr: string) { @@ -175,6 +174,7 @@ export class ScramjetClient { if (handler.apply) { h.apply = function (fn: any, thisArg: any, argArray: any[]) { let returnValue: any = null; + let earlyreturn = false; const ctx: ProxyCtx = { fn, @@ -182,6 +182,7 @@ export class ScramjetClient { args: argArray, newTarget: null, return: (r: any) => { + earlyreturn = true; returnValue = r; }, }; @@ -213,7 +214,7 @@ export class ScramjetClient { delete Error.prepareStackTrace; - if (returnValue) { + if (earlyreturn) { return returnValue; } diff --git a/src/client/dom/element.ts b/src/client/dom/element.ts index 4fd7fa7..a45b129 100644 --- a/src/client/dom/element.ts +++ b/src/client/dom/element.ts @@ -1,3 +1,4 @@ +import { SCRAMJETCLIENT } from "../../symbols"; import { ScramjetClient } from "../client"; import { nativeGetOwnPropertyDescriptor } from "../natives"; import { config, decodeUrl, htmlRules, unrewriteHtml } from "../shared"; @@ -127,8 +128,8 @@ export default function (client: ScramjetClient, self: typeof window) { get(ctx) { const realwin = ctx.get() as Window; - if (ScramjetClient.SCRAMJET in realwin.self) { - return realwin.self[ScramjetClient.SCRAMJET].globalProxy.window; + if (SCRAMJETCLIENT in realwin.self) { + return realwin.self[SCRAMJETCLIENT].globalProxy.window; } else { // hook the iframe const newclient = new ScramjetClient(realwin.self); @@ -145,8 +146,8 @@ export default function (client: ScramjetClient, self: typeof window) { client.descriptors["HTMLIFrameElement.prototype.contentWindow"].get; const realwin = contentwindow.apply(ctx.this); - if (ScramjetClient.SCRAMJET in realwin.self) { - return realwin.self[ScramjetClient.SCRAMJET].documentProxy; + if (SCRAMJETCLIENT in realwin.self) { + return realwin.self[SCRAMJETCLIENT].documentProxy; } else { const newclient = new ScramjetClient(realwin.self); newclient.hook(); @@ -175,7 +176,7 @@ export default function (client: ScramjetClient, self: typeof window) { let doc = ctx.get() as Document | null; if (!doc) return null; - let scram: ScramjetClient = doc[ScramjetClient.SCRAMJET]; + let scram: ScramjetClient = doc[SCRAMJETCLIENT]; if (!scram) return doc; // ?? return scram.documentProxy; diff --git a/src/client/dom/open.ts b/src/client/dom/open.ts index 7691f7e..6b72c1c 100644 --- a/src/client/dom/open.ts +++ b/src/client/dom/open.ts @@ -1,5 +1,6 @@ import { encodeUrl } from "../shared"; import { ScramjetClient } from "../client"; +import { SCRAMJETCLIENT } from "../../symbols"; export default function (client: ScramjetClient) { client.Proxy("window.open", { @@ -13,10 +14,8 @@ export default function (client: ScramjetClient) { if (!realwin) return ctx.return(realwin); - if (ScramjetClient.SCRAMJET in realwin.self) { - return ctx.return( - realwin.self[ScramjetClient.SCRAMJET].globalProxy.window - ); + if (SCRAMJETCLIENT in realwin.self) { + return ctx.return(realwin.self[SCRAMJETCLIENT].globalProxy.window); } else { const newclient = new ScramjetClient(realwin.self); // hook the opened window @@ -32,8 +31,8 @@ export default function (client: ScramjetClient) { get(ctx) { const realwin = ctx.get() as Window; - if (realwin && ScramjetClient.SCRAMJET in realwin.self) { - return realwin.self[ScramjetClient.SCRAMJET].globalProxy; + if (realwin && SCRAMJETCLIENT in realwin.self) { + return realwin.self[SCRAMJETCLIENT].globalProxy; } else { // the opener has to have been already hooked, so if we reach here then it's a real window return undefined; diff --git a/src/client/index.ts b/src/client/index.ts index 7de8dd5..6f2fff2 100644 --- a/src/client/index.ts +++ b/src/client/index.ts @@ -1,5 +1,6 @@ // entrypoint for scramjet.client.js +import { SCRAMJETCLIENT } from "../symbols"; import { ScramjetClient } from "./client"; import { ScramjetServiceWorkerRuntime } from "./swruntime"; @@ -13,7 +14,7 @@ export const isemulatedsw = dbg.log("scrammin"); // if it already exists, that means the handlers have probably already been setup by the parent document -if (!(ScramjetClient.SCRAMJET in self)) { +if (!(SCRAMJETCLIENT in >self)) { const client = new ScramjetClient(self); if (self.COOKIE) client.loadcookies(self.COOKIE); diff --git a/src/client/shared/event.ts b/src/client/shared/event.ts index e2d2114..cc891bf 100644 --- a/src/client/shared/event.ts +++ b/src/client/shared/event.ts @@ -1,4 +1,5 @@ import { iswindow } from ".."; +import { SCRAMJETCLIENT } from "../../symbols"; import { ScramjetClient } from "../client"; import { getOwnPropertyDescriptorHandler } from "../helpers"; import { nativeGetOwnPropertyDescriptor } from "../natives"; @@ -22,7 +23,7 @@ export default function (client: ScramjetClient, self: Self) { return this.ports; }, source() { - let scram: ScramjetClient = this.source[ScramjetClient.SCRAMJET]; + let scram: ScramjetClient = this.source[SCRAMJETCLIENT]; if (scram) return scram.globalProxy; diff --git a/src/client/shared/wrap.ts b/src/client/shared/wrap.ts index cb8aa9b..561e3c2 100644 --- a/src/client/shared/wrap.ts +++ b/src/client/shared/wrap.ts @@ -1,4 +1,5 @@ import { iswindow, isworker } from ".."; +import { SCRAMJETCLIENT } from "../../symbols"; import { ScramjetClient } from "../client"; import { config } from "../shared"; @@ -15,9 +16,9 @@ export default function (client: ScramjetClient, self: typeof globalThis) { if (iswindow && identifier instanceof self.Window) { return client.globalProxy; } else if (iswindow && identifier instanceof self.parent.self.Window) { - if (ScramjetClient.SCRAMJET in self.parent.self) { + if (SCRAMJETCLIENT 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].globalProxy; + return self.parent.self[SCRAMJETCLIENT].globalProxy; } else { // ... then we should pretend we aren't nested and return the current window return client.globalProxy; @@ -31,13 +32,13 @@ export default function (client: ScramjetClient, self: typeof globalThis) { if (test === current) break; // there is no parent, actual or emulated. // ... then `test` represents a window outside of the proxy context, and therefore `current` is the topmost window in the proxy context - if (!(ScramjetClient.SCRAMJET in test)) break; + if (!(SCRAMJETCLIENT in test)) break; // test is also insde a proxy, so we should continue up the chain current = test; } - return current[ScramjetClient.SCRAMJET].globalProxy.window; + return current[SCRAMJETCLIENT].globalProxy.window; } else if ( (iswindow && identifier instanceof self.Location) || (isworker && identifier instanceof self.WorkerLocation) @@ -89,7 +90,7 @@ export default function (client: ScramjetClient, self: typeof globalThis) { } } self.$scramerr = function scramerr(e) { - // console.warn("CAUGHT ERROR", e); + console.warn("CAUGHT ERROR", e); }; self.$scramdbg = function scramdbg(args, t) { diff --git a/src/controller/frame.ts b/src/controller/frame.ts new file mode 100644 index 0000000..8ad4b18 --- /dev/null +++ b/src/controller/frame.ts @@ -0,0 +1,33 @@ +import { ScramjetController } from "."; +import type { ScramjetClient } from "../client/client"; +import { SCRAMJETCLIENT, SCRAMJETFRAME } from "../symbols"; + +export class ScramjetFrame extends EventTarget { + constructor( + private controller: ScramjetController, + public frame: HTMLIFrameElement + ) { + super(); + frame[SCRAMJETFRAME] = this; + } + + get client(): ScramjetClient { + return this.frame.contentWindow.window[SCRAMJETCLIENT]; + } + + go(url: string | URL) { + if (url instanceof URL) url = url.toString(); + + dbg.log("navigated to", url); + + this.frame.src = this.controller.encodeUrl(url); + } + + back() { + this.frame.contentWindow?.history.back(); + } + + forward() { + this.frame.contentWindow?.history.forward(); + } +} diff --git a/src/controller/index.ts b/src/controller/index.ts index 1d55a96..be0308c 100644 --- a/src/controller/index.ts +++ b/src/controller/index.ts @@ -1,6 +1,8 @@ import IDBMap from "@webreflection/idb-map"; import { ScramjetConfig } from "../types"; import { Codec } from "../codecs"; +import type { ScramjetClient } from "../client/client"; +import { ScramjetFrame } from "./frame"; export class ScramjetController { config: ScramjetConfig; @@ -24,7 +26,7 @@ export class ScramjetController { client: "/scramjet.client.js", codecs: "/scramjet.codecs.js", flags: { - serviceworkers: true, + serviceworkers: false, }, }; @@ -74,31 +76,4 @@ export class ScramjetController { } } -class ScramjetFrame extends EventTarget { - static SCRAMJETFRAME = Symbol.for("scramjet frame handle"); - constructor( - private controller: ScramjetController, - public frame: HTMLIFrameElement - ) { - super(); - frame[ScramjetFrame.SCRAMJETFRAME] = this; - } - - go(url: string | URL) { - if (url instanceof URL) url = url.toString(); - - dbg.log("navigated to", url); - - this.frame.src = this.controller.encodeUrl(url); - } - - back() { - this.frame.contentWindow?.history.back(); - } - - forward() { - this.frame.contentWindow?.history.forward(); - } -} - window.ScramjetController = ScramjetController; diff --git a/src/shared/rewriters/html.ts b/src/shared/rewriters/html.ts index f05db2c..c05a2d0 100644 --- a/src/shared/rewriters/html.ts +++ b/src/shared/rewriters/html.ts @@ -150,6 +150,12 @@ export const htmlRules: { fn: (value: string, origin?: URL) => rewriteCss(value, origin), style: "*", }, + { + fn: (value: string) => { + if (["_parent", "_top", "_unfencedTop"].includes(value)) return "_self"; + }, + target: ["a"], + }, ]; // i need to add the attributes in during rewriting diff --git a/src/symbols.ts b/src/symbols.ts new file mode 100644 index 0000000..5505d8b --- /dev/null +++ b/src/symbols.ts @@ -0,0 +1,3 @@ +// see types.d.ts for what these mean +export const SCRAMJETCLIENT = Symbol.for("scramjet client global"); +export const SCRAMJETFRAME = Symbol.for("scramjet frame handle"); diff --git a/src/types.d.ts b/src/types.d.ts index a6e4135..9301af7 100644 --- a/src/types.d.ts +++ b/src/types.d.ts @@ -15,6 +15,9 @@ import { BareClient } from "@mercuryworkshop/bare-mux"; import { parseDomain } from "parse-domain"; import { ScramjetHeaders } from "./shared/headers"; import { CookieStore } from "./shared/cookie"; +import { SCRAMJETCLIENT, SCRAMJETFRAME } from "./symbols"; +import { ScramjetClient } from "./client/client"; +import { ScramjetFrame } from "./controller/frame"; type ScramjetFlags = { serviceworkers: boolean; @@ -75,5 +78,13 @@ declare global { COOKIE: string; WASM: string; ScramjetController: typeof ScramjetController; + + // the scramjet client belonging to a window + [SCRAMJETCLIENT]: ScramjetClient; + } + + interface HTMLIFrameElement { + // the event target belonging to an