Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
134 changes: 68 additions & 66 deletions packages/scramjet/packages/controller/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,74 +1,71 @@
import { type MethodsDefinition, RpcHelper } from "@mercuryworkshop/rpc";
import {
BareResponse,
type ProxyTransport,
} from "@mercuryworkshop/proxy-transports";
import type * as ScramjetGlobal from "@mercuryworkshop/scramjet";

declare const $scramjet: typeof ScramjetGlobal;

export const Plugin = $scramjet.Plugin;

import {
type TransportToController,
type Controllerbound,
type ControllerToTransport,
type SWbound,
type WebSocketMessage,
} from "./types";
import {
BareCompatibleClient,
BareResponse,
type ProxyTransport,
} from "@mercuryworkshop/proxy-transports";

const cookieJar = new $scramjet.CookieJar();
declare const $scramjet: typeof ScramjetGlobal;
export const Plugin = $scramjet.Plugin;

type Config = {
export type Config = {
prefix: string;
scramjetPath: string;
wasmPath: string;
injectPath: string;
scramjetPath: string;
virtualWasmPath: string;
prefix: string;
codec: Record<"encode" | "decode", (input: string) => string>;
};

export const config: Config = {
const config: Config = {
prefix: "/~/sj/",
virtualWasmPath: "scramjet.wasm.js",
injectPath: "/controller/controller.inject.js",
scramjetPath: "/scramjet/scramjet.js",
wasmPath: "/scramjet/scramjet.wasm",
injectPath: "/controller/controller.inject.js",
virtualWasmPath: "scramjet.wasm.js",
codec: {
encode: (url: string) => {
if (!url) return url;

return encodeURIComponent(url);
},
decode: (url: string) => {
if (!url) return url;

return decodeURIComponent(url);
},
},
};

const defaultCfg = {
const scramjetConfig: Partial<ScramjetGlobal.ScramjetConfig> = {
flags: {
...$scramjet.defaultConfig.flags,
allowFailedIntercepts: true,
},
maskedfiles: ["inject.js", "scramjet.wasm.js"],
};

const frames: Record<string, Frame> = {};

let wasmPayload: string | null = null;

function makeId(): string {
return Math.random().toString(36).substring(2, 10);
}

const codecEncode = (url: string) => {
if (!url) return url;

return encodeURIComponent(url);
};

const codecDecode = (url: string) => {
if (!url) return url;

return decodeURIComponent(url);
};
function deepMerge(target: any, source: any): any {
for (const key in source) {
if (key in target) {
Object.assign(source[key], deepMerge(target[key], source[key]));
}
}

type ControllerInit = {
serviceworker: ServiceWorker;
transport: ProxyTransport;
};
return Object.assign(target || {}, source);
}

let wasmPayload: string | null = null;
let wasmAlreadyFetched = false;

async function loadScramjetWasm() {
Expand All @@ -81,12 +78,20 @@ async function loadScramjetWasm() {
wasmAlreadyFetched = true;
}

type ControllerInit = {
serviceworker: ServiceWorker;
transport: ProxyTransport;
config?: Partial<Config>;
scramjetConfig?: Partial<ScramjetGlobal.ScramjetConfig>;
};

export class Controller {
config: Config;
scramjetConfig: ScramjetGlobal.ScramjetConfig;
id: string;
prefix: string;
frames: Frame[] = [];
cookieJar = new $scramjet.CookieJar();
flags: typeof defaultCfg.flags = { ...defaultCfg.flags };
serviceWorkerController: ServiceWorker;
guardServiceWorkerRevive = true;

Expand Down Expand Up @@ -265,9 +270,12 @@ export class Controller {
};

constructor(public init: ControllerInit) {
this.config = deepMerge(config, init.config);
this.scramjetConfig = deepMerge($scramjet.defaultConfig, scramjetConfig);
this.scramjetConfig = deepMerge(this.scramjetConfig, init.scramjetConfig);
this.transport = init.transport;
this.id = makeId();
this.prefix = config.prefix + this.id + "/";
this.prefix = this.config.prefix + this.id + "/";
this.serviceWorkerController = init.serviceworker;

this.ready = Promise.all([
Expand Down Expand Up @@ -321,7 +329,7 @@ export class Controller {
this.serviceWorkerController.postMessage(
{
$controller$init: {
prefix: config.prefix + this.id,
prefix: this.prefix,
id: this.id,
},
},
Expand Down Expand Up @@ -359,10 +367,10 @@ function base64Encode(text: string) {
}

function yieldGetInjectScripts(
cookieJar: ScramjetGlobal.CookieJar,
config: Config,
sjconfig: ScramjetGlobal.ScramjetConfig,
prefix: URL,
cookieJar: ScramjetGlobal.CookieJar,
codecEncode: (input: string) => string,
codecDecode: (input: string) => string
) {
Expand Down Expand Up @@ -390,8 +398,8 @@ function yieldGetInjectScripts(
$scramjetController.load({
config: ${JSON.stringify(config)},
sjconfig: ${JSON.stringify(sjconfig)},
cookies: ${cookieJar.dump()},
prefix: new URL("${prefix.href}"),
cookies: ${cookieJar.dump()},
yieldGetInjectScripts: ${yieldGetInjectScripts.toString()},
codecEncode: ${codecEncode.toString()},
codecDecode: ${codecDecode.toString()},
Expand All @@ -416,30 +424,24 @@ export class Frame {
};

get context(): ScramjetGlobal.ScramjetContext {
const sjcfg = {
...$scramjet.defaultConfig,
flags: this.controller.flags,
maskedfiles: defaultCfg.maskedfiles,
};

return {
cookieJar,
config: this.controller.scramjetConfig,
prefix: new URL(this.prefix, location.href),
config: sjcfg,
cookieJar: this.controller.cookieJar,
interface: {
getInjectScripts: yieldGetInjectScripts(
this.controller.cookieJar,
config,
sjcfg,
this.controller.config,
this.controller.scramjetConfig,
new URL(this.prefix, location.href),
codecEncode,
codecDecode
this.controller.cookieJar,
this.controller.config.codec.encode,
this.controller.config.codec.decode
),
getWorkerInjectScripts: (meta, type, script) => {
let str = "";

str += script(config.scramjetPath);
str += script(this.prefix + config.virtualWasmPath);
str += script(this.controller.config.scramjetPath);
str += script(this.prefix + this.controller.config.virtualWasmPath);
str += script(
"data:text/javascript;charset=utf-8;base64," +
base64Encode(`
Expand All @@ -449,23 +451,23 @@ export class Frame {
setWasm(Uint8Array.from(atob(self.WASM), (c) => c.charCodeAt(0)));
delete self.WASM;

const sjconfig = ${JSON.stringify(sjcfg)};
const sjconfig = ${JSON.stringify(this.controller.scramjetConfig)};
const prefix = new URL("${this.prefix}", location.href);

const context = {
config: sjconfig,
prefix,
interface: {
codecEncode: ${codecEncode.toString()},
codecDecode: ${codecDecode.toString()},
codecEncode: ${this.controller.config.codec.encode.toString()},
codecDecode: ${this.controller.config.codec.decode.toString()},
},
prefix,
config: sjconfig
};

const client = new ScramjetClient(globalThis, {
context,
transport: null,
shouldPassthroughWebsocket: (url) => {
return url === "wss://anura.pro/";
return false;
}
});

Expand All @@ -476,8 +478,8 @@ export class Frame {

return str;
},
codecEncode,
codecDecode,
codecEncode: this.controller.config.codec.encode,
codecDecode: this.controller.config.codec.decode,
},
};
}
Expand Down
41 changes: 17 additions & 24 deletions packages/scramjet/packages/controller/src/inject.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
import { RpcHelper } from "@mercuryworkshop/rpc";
import type {
RawHeaders,
ProxyTransport,
TransferrableResponse,
} from "@mercuryworkshop/proxy-transports";
import { generateClientId } from "@mercuryworkshop/scramjet";
import type {
CookieJar as CookieJarType,
Expand All @@ -6,14 +12,7 @@ import type {
} from "@mercuryworkshop/scramjet";
import type * as ScramjetGlobal from "@mercuryworkshop/scramjet";
declare const $scramjet: typeof ScramjetGlobal;

import type {
RawHeaders,
ProxyTransport,
TransferrableResponse,
} from "@mercuryworkshop/proxy-transports";

import { RpcHelper } from "@mercuryworkshop/rpc";
import type { Config } from "./index";
import type {
ControllerToTransport,
TransportToController,
Expand Down Expand Up @@ -144,26 +143,20 @@ class RemoteTransport implements ProxyTransport {
headers,
});
}

meta() {
return {};
}
}

const sw = navigator.serviceWorker.controller;
const { SCRAMJETCLIENT, ScramjetClient, CookieJar, setWasm } = $scramjet;

type Config = any;
type Init = {
config: Config;
sjconfig: ScramjetConfig;
cookies: string;
prefix: URL;
cookies: string;
yieldGetInjectScripts: (
cookieJar: CookieJarType,
config: Config,
sjconfig: ScramjetConfig,
prefix: URL,
cookieJar: CookieJarType,
codecEncode: (input: string) => string,
codecDecode: (input: string) => string
) => any;
Expand Down Expand Up @@ -240,21 +233,21 @@ class ExecutionContextWrapper {
}

const context: ScramjetGlobal.ScramjetContext = {
config: this.init.sjconfig,
prefix: this.init.prefix,
cookieJar: this.cookieJar,
interface: {
getInjectScripts: this.init.yieldGetInjectScripts(
this.cookieJar,
this.init.config,
this.init.sjconfig,
this.init.prefix,
this.cookieJar,
this.init.codecEncode,
this.init.codecDecode
),
codecEncode: this.init.codecEncode,
codecDecode: this.init.codecDecode,
},
config: this.init.sjconfig,
prefix: this.init.prefix,
cookieJar: this.cookieJar,
};

this.client = new ScramjetClient(this.global, {
Expand All @@ -268,13 +261,13 @@ class ExecutionContextWrapper {
// }
// });
},
shouldPassthroughWebsocket: (url) => {
return url === "wss://anura.pro/";
shouldPassthroughWebsocket: () => {
return false;
},
shouldBlockMessageEvent(i) {
shouldBlockMessageEvent: () => {
return false;
},
hookSubcontext: (frameself, frame) => {
hookSubcontext: (frameself) => {
const context = new ExecutionContextWrapper(frameself, {
...this.init,
// TODO: clientId will change over the lifetime once it recieves syncDocumentInit
Expand Down
2 changes: 1 addition & 1 deletion packages/scramjet/packages/demo/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,7 @@ export const App: Component<
<FlagEditor
inline={true}
onFlagsChange={(flags) => {
Object.assign(controller.flags, flags);
Object.assign(controller.scramjetConfig.flags, flags);
}}
/>
</div>
Expand Down
2 changes: 1 addition & 1 deletion packages/scramjet/packages/demo/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ async function waitForControllerOrReady(timeoutMs = 10000): Promise<void> {

async function mount() {
try {
const root = <App></App>;
const root = <App />;
app.replaceWith(root);
} catch (e) {
let err = e as any;
Expand Down
Loading