ScramjetClient.SCRAMJET -> SCRAMJETCLIENT

This commit is contained in:
velzie 2024-08-30 16:59:52 -04:00
parent 2050fa140c
commit 5f77342d8d
No known key found for this signature in database
GPG key ID: 048413F95F0DDE1F
11 changed files with 82 additions and 50 deletions

View file

@ -1,3 +1,4 @@
import { SCRAMJETCLIENT } from "../symbols";
import { createDocumentProxy } from "./document"; import { createDocumentProxy } from "./document";
import { createGlobalProxy } from "./global"; import { createGlobalProxy } from "./global";
import { getOwnPropertyDescriptorHandler } from "./helpers"; import { getOwnPropertyDescriptorHandler } from "./helpers";
@ -43,8 +44,6 @@ export type Trap<T> = {
}; };
export class ScramjetClient { export class ScramjetClient {
static SCRAMJET = Symbol.for("scramjet client global");
documentProxy: any; documentProxy: any;
globalProxy: any; globalProxy: any;
locationProxy: any; locationProxy: any;
@ -76,7 +75,7 @@ export class ScramjetClient {
this.locationProxy = createLocationProxy(this, global); this.locationProxy = createLocationProxy(this, global);
this.globalProxy = createGlobalProxy(this, global); this.globalProxy = createGlobalProxy(this, global);
global[ScramjetClient.SCRAMJET] = this; global[SCRAMJETCLIENT] = this;
} }
loadcookies(cookiestr: string) { loadcookies(cookiestr: string) {
@ -175,6 +174,7 @@ export class ScramjetClient {
if (handler.apply) { if (handler.apply) {
h.apply = function (fn: any, thisArg: any, argArray: any[]) { h.apply = function (fn: any, thisArg: any, argArray: any[]) {
let returnValue: any = null; let returnValue: any = null;
let earlyreturn = false;
const ctx: ProxyCtx = { const ctx: ProxyCtx = {
fn, fn,
@ -182,6 +182,7 @@ export class ScramjetClient {
args: argArray, args: argArray,
newTarget: null, newTarget: null,
return: (r: any) => { return: (r: any) => {
earlyreturn = true;
returnValue = r; returnValue = r;
}, },
}; };
@ -213,7 +214,7 @@ export class ScramjetClient {
delete Error.prepareStackTrace; delete Error.prepareStackTrace;
if (returnValue) { if (earlyreturn) {
return returnValue; return returnValue;
} }

View file

@ -1,3 +1,4 @@
import { SCRAMJETCLIENT } from "../../symbols";
import { ScramjetClient } from "../client"; import { ScramjetClient } from "../client";
import { nativeGetOwnPropertyDescriptor } from "../natives"; import { nativeGetOwnPropertyDescriptor } from "../natives";
import { config, decodeUrl, htmlRules, unrewriteHtml } from "../shared"; import { config, decodeUrl, htmlRules, unrewriteHtml } from "../shared";
@ -127,8 +128,8 @@ export default function (client: ScramjetClient, self: typeof window) {
get(ctx) { get(ctx) {
const realwin = ctx.get() as Window; const realwin = ctx.get() as Window;
if (ScramjetClient.SCRAMJET in realwin.self) { if (SCRAMJETCLIENT in realwin.self) {
return realwin.self[ScramjetClient.SCRAMJET].globalProxy.window; return realwin.self[SCRAMJETCLIENT].globalProxy.window;
} else { } else {
// hook the iframe // hook the iframe
const newclient = new ScramjetClient(realwin.self); const newclient = new ScramjetClient(realwin.self);
@ -145,8 +146,8 @@ export default function (client: ScramjetClient, self: typeof window) {
client.descriptors["HTMLIFrameElement.prototype.contentWindow"].get; client.descriptors["HTMLIFrameElement.prototype.contentWindow"].get;
const realwin = contentwindow.apply(ctx.this); const realwin = contentwindow.apply(ctx.this);
if (ScramjetClient.SCRAMJET in realwin.self) { if (SCRAMJETCLIENT in realwin.self) {
return realwin.self[ScramjetClient.SCRAMJET].documentProxy; return realwin.self[SCRAMJETCLIENT].documentProxy;
} else { } else {
const newclient = new ScramjetClient(realwin.self); const newclient = new ScramjetClient(realwin.self);
newclient.hook(); newclient.hook();
@ -175,7 +176,7 @@ export default function (client: ScramjetClient, self: typeof window) {
let doc = ctx.get() as Document | null; let doc = ctx.get() as Document | null;
if (!doc) return null; if (!doc) return null;
let scram: ScramjetClient = doc[ScramjetClient.SCRAMJET]; let scram: ScramjetClient = doc[SCRAMJETCLIENT];
if (!scram) return doc; // ?? if (!scram) return doc; // ??
return scram.documentProxy; return scram.documentProxy;

View file

@ -1,5 +1,6 @@
import { encodeUrl } from "../shared"; import { encodeUrl } from "../shared";
import { ScramjetClient } from "../client"; import { ScramjetClient } from "../client";
import { SCRAMJETCLIENT } from "../../symbols";
export default function (client: ScramjetClient) { export default function (client: ScramjetClient) {
client.Proxy("window.open", { client.Proxy("window.open", {
@ -13,10 +14,8 @@ export default function (client: ScramjetClient) {
if (!realwin) return ctx.return(realwin); if (!realwin) return ctx.return(realwin);
if (ScramjetClient.SCRAMJET in realwin.self) { if (SCRAMJETCLIENT in realwin.self) {
return ctx.return( return ctx.return(realwin.self[SCRAMJETCLIENT].globalProxy.window);
realwin.self[ScramjetClient.SCRAMJET].globalProxy.window
);
} else { } else {
const newclient = new ScramjetClient(realwin.self); const newclient = new ScramjetClient(realwin.self);
// hook the opened window // hook the opened window
@ -32,8 +31,8 @@ export default function (client: ScramjetClient) {
get(ctx) { get(ctx) {
const realwin = ctx.get() as Window; const realwin = ctx.get() as Window;
if (realwin && ScramjetClient.SCRAMJET in realwin.self) { if (realwin && SCRAMJETCLIENT in realwin.self) {
return realwin.self[ScramjetClient.SCRAMJET].globalProxy; return realwin.self[SCRAMJETCLIENT].globalProxy;
} 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
return undefined; return undefined;

View file

@ -1,5 +1,6 @@
// entrypoint for scramjet.client.js // entrypoint for scramjet.client.js
import { SCRAMJETCLIENT } from "../symbols";
import { ScramjetClient } from "./client"; import { ScramjetClient } from "./client";
import { ScramjetServiceWorkerRuntime } from "./swruntime"; import { ScramjetServiceWorkerRuntime } from "./swruntime";
@ -13,7 +14,7 @@ export const isemulatedsw =
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 in <Partial<typeof self>>self)) {
const client = new ScramjetClient(self); const client = new ScramjetClient(self);
if (self.COOKIE) client.loadcookies(self.COOKIE); if (self.COOKIE) client.loadcookies(self.COOKIE);

View file

@ -1,4 +1,5 @@
import { iswindow } from ".."; import { iswindow } from "..";
import { SCRAMJETCLIENT } from "../../symbols";
import { ScramjetClient } from "../client"; import { ScramjetClient } from "../client";
import { getOwnPropertyDescriptorHandler } from "../helpers"; import { getOwnPropertyDescriptorHandler } from "../helpers";
import { nativeGetOwnPropertyDescriptor } from "../natives"; import { nativeGetOwnPropertyDescriptor } from "../natives";
@ -22,7 +23,7 @@ export default function (client: ScramjetClient, self: Self) {
return this.ports; return this.ports;
}, },
source() { source() {
let scram: ScramjetClient = this.source[ScramjetClient.SCRAMJET]; let scram: ScramjetClient = this.source[SCRAMJETCLIENT];
if (scram) return scram.globalProxy; if (scram) return scram.globalProxy;

View file

@ -1,4 +1,5 @@
import { iswindow, isworker } from ".."; import { iswindow, isworker } from "..";
import { SCRAMJETCLIENT } from "../../symbols";
import { ScramjetClient } from "../client"; import { ScramjetClient } from "../client";
import { config } from "../shared"; import { config } from "../shared";
@ -15,9 +16,9 @@ export default function (client: ScramjetClient, self: typeof globalThis) {
if (iswindow && identifier instanceof self.Window) { if (iswindow && identifier instanceof self.Window) {
return client.globalProxy; return client.globalProxy;
} else if (iswindow && identifier instanceof self.parent.self.Window) { } 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 // ... 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 { } else {
// ... then we should pretend we aren't nested and return the current window // ... then we should pretend we aren't nested and return the current window
return client.globalProxy; 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. 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 // ... 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 // test is also insde a proxy, so we should continue up the chain
current = test; current = test;
} }
return current[ScramjetClient.SCRAMJET].globalProxy.window; return current[SCRAMJETCLIENT].globalProxy.window;
} else if ( } else if (
(iswindow && identifier instanceof self.Location) || (iswindow && identifier instanceof self.Location) ||
(isworker && identifier instanceof self.WorkerLocation) (isworker && identifier instanceof self.WorkerLocation)
@ -89,7 +90,7 @@ export default function (client: ScramjetClient, self: typeof globalThis) {
} }
} }
self.$scramerr = function scramerr(e) { self.$scramerr = function scramerr(e) {
// console.warn("CAUGHT ERROR", e); console.warn("CAUGHT ERROR", e);
}; };
self.$scramdbg = function scramdbg(args, t) { self.$scramdbg = function scramdbg(args, t) {

33
src/controller/frame.ts Normal file
View file

@ -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();
}
}

View file

@ -1,6 +1,8 @@
import IDBMap from "@webreflection/idb-map"; import IDBMap from "@webreflection/idb-map";
import { ScramjetConfig } from "../types"; import { ScramjetConfig } from "../types";
import { Codec } from "../codecs"; import { Codec } from "../codecs";
import type { ScramjetClient } from "../client/client";
import { ScramjetFrame } from "./frame";
export class ScramjetController { export class ScramjetController {
config: ScramjetConfig; config: ScramjetConfig;
@ -24,7 +26,7 @@ export class ScramjetController {
client: "/scramjet.client.js", client: "/scramjet.client.js",
codecs: "/scramjet.codecs.js", codecs: "/scramjet.codecs.js",
flags: { 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; window.ScramjetController = ScramjetController;

View file

@ -150,6 +150,12 @@ export const htmlRules: {
fn: (value: string, origin?: URL) => rewriteCss(value, origin), fn: (value: string, origin?: URL) => rewriteCss(value, origin),
style: "*", style: "*",
}, },
{
fn: (value: string) => {
if (["_parent", "_top", "_unfencedTop"].includes(value)) return "_self";
},
target: ["a"],
},
]; ];
// i need to add the attributes in during rewriting // i need to add the attributes in during rewriting

3
src/symbols.ts Normal file
View file

@ -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");

11
src/types.d.ts vendored
View file

@ -15,6 +15,9 @@ import { BareClient } from "@mercuryworkshop/bare-mux";
import { parseDomain } from "parse-domain"; import { parseDomain } from "parse-domain";
import { ScramjetHeaders } from "./shared/headers"; import { ScramjetHeaders } from "./shared/headers";
import { CookieStore } from "./shared/cookie"; import { CookieStore } from "./shared/cookie";
import { SCRAMJETCLIENT, SCRAMJETFRAME } from "./symbols";
import { ScramjetClient } from "./client/client";
import { ScramjetFrame } from "./controller/frame";
type ScramjetFlags = { type ScramjetFlags = {
serviceworkers: boolean; serviceworkers: boolean;
@ -75,5 +78,13 @@ declare global {
COOKIE: string; COOKIE: string;
WASM: string; WASM: string;
ScramjetController: typeof ScramjetController; ScramjetController: typeof ScramjetController;
// the scramjet client belonging to a window
[SCRAMJETCLIENT]: ScramjetClient;
}
interface HTMLIFrameElement {
// the event target belonging to an <iframe> holding a /prefix/blah url
[SCRAMJETFRAME]: ScramjetFrame;
} }
} }