mirror of
https://github.com/MercuryWorkshop/scramjet.git
synced 2025-05-12 22:10:01 -04:00
refactor: delete codecs/ & self.$scramjet
This commit is contained in:
parent
f8d33a207e
commit
337134bcdc
22 changed files with 148 additions and 206 deletions
|
@ -49,17 +49,18 @@ fn get_config(scramjet: &Object) -> Config {
|
||||||
let codec = &get_obj(scramjet, "codec");
|
let codec = &get_obj(scramjet, "codec");
|
||||||
let config = &get_obj(scramjet, "config");
|
let config = &get_obj(scramjet, "config");
|
||||||
let flags = &get_obj(config, "flags");
|
let flags = &get_obj(config, "flags");
|
||||||
|
let globals = &get_obj(config, "globals");
|
||||||
|
|
||||||
Config {
|
Config {
|
||||||
prefix: get_str(config, "prefix"),
|
prefix: get_str(config, "prefix"),
|
||||||
encode: create_encode_function(get_obj(codec, "encode")),
|
encode: create_encode_function(get_obj(codec, "encode")),
|
||||||
|
|
||||||
wrapfn: get_str(config, "wrapfn"),
|
wrapfn: get_str(globals, "wrapfn"),
|
||||||
importfn: get_str(config, "importfn"),
|
importfn: get_str(globals, "importfn"),
|
||||||
rewritefn: get_str(config, "rewritefn"),
|
rewritefn: get_str(globals, "rewritefn"),
|
||||||
metafn: get_str(config, "metafn"),
|
metafn: get_str(globals, "metafn"),
|
||||||
setrealmfn: get_str(config, "setrealmfn"),
|
setrealmfn: get_str(globals, "setrealmfn"),
|
||||||
pushsourcemapfn: get_str(config, "pushsourcemapfn"),
|
pushsourcemapfn: get_str(globals, "pushsourcemapfn"),
|
||||||
|
|
||||||
do_sourcemaps: get_bool(flags, "sourcemaps"),
|
do_sourcemaps: get_bool(flags, "sourcemaps"),
|
||||||
capture_errors: get_bool(flags, "captureErrors"),
|
capture_errors: get_bool(flags, "captureErrors"),
|
||||||
|
|
|
@ -419,7 +419,7 @@ fn expression_span(e: &Expression) -> Span {
|
||||||
}
|
}
|
||||||
|
|
||||||
// js MUST not be able to get a reference to any of these because sbx
|
// js MUST not be able to get a reference to any of these because sbx
|
||||||
const UNSAFE_GLOBALS: [&str; 9] = [
|
const UNSAFE_GLOBALS: [&str; 10] = [
|
||||||
"window",
|
"window",
|
||||||
"self",
|
"self",
|
||||||
"globalThis",
|
"globalThis",
|
||||||
|
|
|
@ -15,9 +15,7 @@ export default defineConfig({
|
||||||
entry: {
|
entry: {
|
||||||
shared: join(__dirname, "src/shared/index.ts"),
|
shared: join(__dirname, "src/shared/index.ts"),
|
||||||
worker: join(__dirname, "src/worker/index.ts"),
|
worker: join(__dirname, "src/worker/index.ts"),
|
||||||
thread: join(__dirname, "src/thread/thread.ts"),
|
|
||||||
client: join(__dirname, "src/client/index.ts"),
|
client: join(__dirname, "src/client/index.ts"),
|
||||||
codecs: join(__dirname, "src/codecs/index.ts"),
|
|
||||||
controller: join(__dirname, "src/controller/index.ts"),
|
controller: join(__dirname, "src/controller/index.ts"),
|
||||||
sync: join(__dirname, "src/sync.ts"),
|
sync: join(__dirname, "src/sync.ts"),
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
// entrypoint for scramjet.client.js
|
// entrypoint for scramjet.client.js
|
||||||
|
|
||||||
|
import { loadCodecs } from "../scramjet";
|
||||||
import { SCRAMJETCLIENT } from "../symbols";
|
import { SCRAMJETCLIENT } from "../symbols";
|
||||||
import { ScramjetClient } from "./client";
|
import { ScramjetClient } from "./client";
|
||||||
import { ScramjetServiceWorkerRuntime } from "./swruntime";
|
import { ScramjetServiceWorkerRuntime } from "./swruntime";
|
||||||
|
@ -19,6 +20,8 @@ export class ScramjetContextInit extends Event {
|
||||||
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 in <Partial<typeof self>>self)) {
|
if (!(SCRAMJETCLIENT in <Partial<typeof self>>self)) {
|
||||||
|
loadCodecs();
|
||||||
|
|
||||||
const client = new ScramjetClient(self);
|
const client = new ScramjetClient(self);
|
||||||
|
|
||||||
if (self.COOKIE) client.loadcookies(self.COOKIE);
|
if (self.COOKIE) client.loadcookies(self.COOKIE);
|
||||||
|
|
|
@ -4,7 +4,7 @@ import { config, rewriteJs } from "../../shared";
|
||||||
export default function (client: ScramjetClient, self: Self) {
|
export default function (client: ScramjetClient, self: Self) {
|
||||||
// used for proxying *direct eval*
|
// used for proxying *direct eval*
|
||||||
// eval("...") -> eval($scramjet$rewrite("..."))
|
// eval("...") -> eval($scramjet$rewrite("..."))
|
||||||
Object.defineProperty(self, config.rewritefn, {
|
Object.defineProperty(self, config.globals.rewritefn, {
|
||||||
value: function (js: any) {
|
value: function (js: any) {
|
||||||
if (typeof js !== "string") return js;
|
if (typeof js !== "string") return js;
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ import { rewriteUrl } from "../../shared/rewriters/url";
|
||||||
export default function (client: ScramjetClient, self: Self) {
|
export default function (client: ScramjetClient, self: Self) {
|
||||||
const Function = client.natives.Function;
|
const Function = client.natives.Function;
|
||||||
|
|
||||||
self[config.importfn] = function (base: string) {
|
self[config.globals.importfn] = function (base: string) {
|
||||||
return function (url: string) {
|
return function (url: string) {
|
||||||
const resolved = new URL(url, base).href;
|
const resolved = new URL(url, base).href;
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@ export default function (client: ScramjetClient, self: Self) {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
self[config.metafn] = function (base: string) {
|
self[config.globals.metafn] = function (base: string) {
|
||||||
return {
|
return {
|
||||||
url: base,
|
url: base,
|
||||||
resolve: function (url: string) {
|
resolve: function (url: string) {
|
||||||
|
|
|
@ -60,7 +60,7 @@ 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, config.wrapfn, {
|
Object.defineProperty(self, config.globals.wrapfn, {
|
||||||
value: client.wrapfn,
|
value: client.wrapfn,
|
||||||
writable: false,
|
writable: false,
|
||||||
configurable: false,
|
configurable: false,
|
||||||
|
@ -81,7 +81,7 @@ export default function (client: ScramjetClient, self: typeof globalThis) {
|
||||||
// ((t)=>$scramjet$tryset(location,"+=",t)||location+=t)(...);
|
// ((t)=>$scramjet$tryset(location,"+=",t)||location+=t)(...);
|
||||||
// it has to be a discrete function because there's always the possibility that "location" is a local variable
|
// it has to be a discrete function because there's always the possibility that "location" is a local variable
|
||||||
// we have to use an IIFE to avoid duplicating side-effects in the getter
|
// we have to use an IIFE to avoid duplicating side-effects in the getter
|
||||||
Object.defineProperty(self, config.trysetfn, {
|
Object.defineProperty(self, config.globals.trysetfn, {
|
||||||
value: function (lhs: any, op: string, rhs: any) {
|
value: function (lhs: any, op: string, rhs: any) {
|
||||||
if (lhs instanceof Location) {
|
if (lhs instanceof Location) {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
|
|
|
@ -1,79 +0,0 @@
|
||||||
// for some reason eslint was parsing the type inside of the function params as a variable
|
|
||||||
export interface Codec {
|
|
||||||
// eslint-disable-next-line
|
|
||||||
encode: (str: string | undefined) => string;
|
|
||||||
// eslint-disable-next-line
|
|
||||||
decode: (str: string | undefined) => string;
|
|
||||||
}
|
|
||||||
|
|
||||||
const none = {
|
|
||||||
encode: (str: string | undefined) => str,
|
|
||||||
decode: (str: string | undefined) => str,
|
|
||||||
};
|
|
||||||
|
|
||||||
const plain = {
|
|
||||||
encode: (str: string | undefined) => {
|
|
||||||
if (!str) return str;
|
|
||||||
|
|
||||||
return encodeURIComponent(str);
|
|
||||||
},
|
|
||||||
decode: (str: string | undefined) => {
|
|
||||||
if (!str) return str;
|
|
||||||
|
|
||||||
return decodeURIComponent(str);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const xor = {
|
|
||||||
encode: (str: string | undefined, key: number = 2) => {
|
|
||||||
if (!str) return str;
|
|
||||||
|
|
||||||
let result = "";
|
|
||||||
for (let i = 0; i < str.length; i++) {
|
|
||||||
result += i % key ? String.fromCharCode(str.charCodeAt(i) ^ key) : str[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
return encodeURIComponent(result);
|
|
||||||
},
|
|
||||||
decode: (str: string | undefined, key: number = 2) => {
|
|
||||||
if (!str) return str;
|
|
||||||
|
|
||||||
const [input, ...search] = str.split("?");
|
|
||||||
let result = "";
|
|
||||||
const decoded = decodeURIComponent(input);
|
|
||||||
for (let i = 0; i < decoded.length; i++) {
|
|
||||||
result +=
|
|
||||||
i % key ? String.fromCharCode(decoded.charCodeAt(i) ^ key) : decoded[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
return result + (search.length ? "?" + search.join("?") : "");
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const base64 = {
|
|
||||||
encode: (str: string | undefined) => {
|
|
||||||
if (!str) return str;
|
|
||||||
|
|
||||||
return decodeURIComponent(btoa(str));
|
|
||||||
},
|
|
||||||
decode: (str: string | undefined) => {
|
|
||||||
if (!str) return str;
|
|
||||||
|
|
||||||
return atob(str);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
if (typeof self.$scramjet === "undefined") {
|
|
||||||
//@ts-expect-error really dumb workaround
|
|
||||||
self.$scramjet = {};
|
|
||||||
}
|
|
||||||
self.$scramjet.codecs = {
|
|
||||||
none,
|
|
||||||
plain,
|
|
||||||
xor,
|
|
||||||
base64,
|
|
||||||
};
|
|
||||||
|
|
||||||
if ("document" in self && document.currentScript) {
|
|
||||||
document.currentScript.remove();
|
|
||||||
}
|
|
|
@ -1,30 +1,32 @@
|
||||||
import { ScramjetConfig } from "../types";
|
import { ScramjetConfig } from "../types";
|
||||||
import { Codec } from "../codecs";
|
import { Codec } from "../codecs";
|
||||||
import { ScramjetFrame } from "./frame";
|
import { ScramjetFrame } from "./frame";
|
||||||
|
import { $scramjet, loadCodecs } from "../scramjet";
|
||||||
|
|
||||||
export class ScramjetController {
|
export class ScramjetController {
|
||||||
config: ScramjetConfig;
|
|
||||||
private store: IDBDatabase;
|
private store: IDBDatabase;
|
||||||
codec: Codec;
|
|
||||||
|
|
||||||
constructor(config: ScramjetConfig) {
|
constructor(config: Partial<ScramjetConfig>) {
|
||||||
|
// sane ish defaults
|
||||||
const defaultConfig: Partial<ScramjetConfig> = {
|
const defaultConfig: Partial<ScramjetConfig> = {
|
||||||
prefix: "/scramjet/",
|
prefix: "/scramjet/",
|
||||||
codec: "plain",
|
|
||||||
wrapfn: "$scramjet$wrap",
|
globals: {
|
||||||
trysetfn: "$scramjet$tryset",
|
wrapfn: "$scramjet$wrap",
|
||||||
importfn: "$scramjet$import",
|
trysetfn: "$scramjet$tryset",
|
||||||
rewritefn: "$scramjet$rewrite",
|
importfn: "$scramjet$import",
|
||||||
metafn: "$scramjet$meta",
|
rewritefn: "$scramjet$rewrite",
|
||||||
setrealmfn: "$scramjet$setrealm",
|
metafn: "$scramjet$meta",
|
||||||
pushsourcemapfn: "$scramjet$pushsourcemap",
|
setrealmfn: "$scramjet$setrealm",
|
||||||
wasm: "/scramjet.wasm.js",
|
pushsourcemapfn: "$scramjet$pushsourcemap",
|
||||||
shared: "/scramjet.shared.js",
|
},
|
||||||
worker: "/scramjet.worker.js",
|
files: {
|
||||||
thread: "/scramjet.thread.js",
|
wasm: "/scramjet.wasm.js",
|
||||||
client: "/scramjet.client.js",
|
shared: "/scramjet.shared.js",
|
||||||
codecs: "/scramjet.codecs.js",
|
worker: "/scramjet.worker.js",
|
||||||
sync: "/scramjet.sync.js",
|
client: "/scramjet.client.js",
|
||||||
|
sync: "/scramjet.sync.js",
|
||||||
|
},
|
||||||
flags: {
|
flags: {
|
||||||
serviceworkers: false,
|
serviceworkers: false,
|
||||||
naiiveRewriter: false,
|
naiiveRewriter: false,
|
||||||
|
@ -34,6 +36,12 @@ export class ScramjetController {
|
||||||
scramitize: false,
|
scramitize: false,
|
||||||
sourcemaps: false,
|
sourcemaps: false,
|
||||||
},
|
},
|
||||||
|
codec: {
|
||||||
|
encode: `if (!url) return url;
|
||||||
|
return encodeURIComponent(url);`,
|
||||||
|
decode: `if (!url) return url;
|
||||||
|
return decodeURIComponent(url);`,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const deepMerge = (target: any, source: any): any => {
|
const deepMerge = (target: any, source: any): any => {
|
||||||
|
@ -46,12 +54,11 @@ export class ScramjetController {
|
||||||
return Object.assign(target || {}, source);
|
return Object.assign(target || {}, source);
|
||||||
};
|
};
|
||||||
|
|
||||||
this.config = deepMerge(defaultConfig, config);
|
$scramjet.config = deepMerge(defaultConfig, config);
|
||||||
}
|
}
|
||||||
|
|
||||||
async init(serviceWorkerPath: string): Promise<ServiceWorkerRegistration> {
|
async init(serviceWorkerPath: string): Promise<ServiceWorkerRegistration> {
|
||||||
await import(/* webpackIgnore: true */ this.config.codecs);
|
loadCodecs();
|
||||||
this.codec = self.$scramjet.codecs[this.config.codec];
|
|
||||||
|
|
||||||
await this.openIDB();
|
await this.openIDB();
|
||||||
|
|
||||||
|
@ -72,7 +79,7 @@ export class ScramjetController {
|
||||||
encodeUrl(url: string | URL): string {
|
encodeUrl(url: string | URL): string {
|
||||||
if (url instanceof URL) url = url.toString();
|
if (url instanceof URL) url = url.toString();
|
||||||
|
|
||||||
return this.config.prefix + this.codec.encode(url);
|
return $scramjet.config.prefix + $scramjet.codec.encode(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
async openIDB(): Promise<IDBDatabase> {
|
async openIDB(): Promise<IDBDatabase> {
|
||||||
|
@ -102,7 +109,7 @@ export class ScramjetController {
|
||||||
}
|
}
|
||||||
const tx = this.store.transaction("config", "readwrite");
|
const tx = this.store.transaction("config", "readwrite");
|
||||||
const store = tx.objectStore("config");
|
const store = tx.objectStore("config");
|
||||||
const req = store.put(this.config, "config");
|
const req = store.put($scramjet.config, "config");
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
req.onsuccess = resolve;
|
req.onsuccess = resolve;
|
||||||
|
@ -111,8 +118,8 @@ export class ScramjetController {
|
||||||
}
|
}
|
||||||
|
|
||||||
async modifyConfig(config: ScramjetConfig) {
|
async modifyConfig(config: ScramjetConfig) {
|
||||||
this.config = Object.assign({}, this.config, config);
|
$scramjet.config = Object.assign({}, $scramjet.config, config);
|
||||||
this.codec = self.$scramjet.codecs[this.config.codec];
|
loadCodecs();
|
||||||
|
|
||||||
await this.#saveConfig();
|
await this.#saveConfig();
|
||||||
}
|
}
|
||||||
|
|
3
src/global.d.ts
vendored
3
src/global.d.ts
vendored
|
@ -5,4 +5,7 @@ declare const dbg: {
|
||||||
debug: (message: string, ...args: any[]) => void;
|
debug: (message: string, ...args: any[]) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
declare const COMMITHASH: string;
|
||||||
|
declare const VERSION: string;
|
||||||
|
|
||||||
declare type Self = Window & typeof globalThis;
|
declare type Self = Window & typeof globalThis;
|
||||||
|
|
26
src/scramjet.ts
Normal file
26
src/scramjet.ts
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
import { ScramjetConfig } from "./types";
|
||||||
|
|
||||||
|
if (!("$scramjet" in self)) {
|
||||||
|
// @ts-expect-error ts stuff
|
||||||
|
self.$scramjet = {
|
||||||
|
version: {
|
||||||
|
build: COMMITHASH,
|
||||||
|
version: VERSION,
|
||||||
|
},
|
||||||
|
codec: {},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export const $scramjet = self.$scramjet;
|
||||||
|
|
||||||
|
const nativeFunction = Function;
|
||||||
|
export function loadCodecs() {
|
||||||
|
$scramjet.codec.encode = nativeFunction(
|
||||||
|
"url",
|
||||||
|
$scramjet.config.codec.encode
|
||||||
|
) as any;
|
||||||
|
$scramjet.codec.decode = nativeFunction(
|
||||||
|
"url",
|
||||||
|
$scramjet.config.codec.decode
|
||||||
|
) as any;
|
||||||
|
}
|
|
@ -1,3 +1,5 @@
|
||||||
|
import { $scramjet } from "./scramjet";
|
||||||
|
|
||||||
export const {
|
export const {
|
||||||
util: { BareClient, ScramjetHeaders, BareMuxConnection },
|
util: { BareClient, ScramjetHeaders, BareMuxConnection },
|
||||||
url: { rewriteUrl, unrewriteUrl, rewriteBlob, unrewriteBlob },
|
url: { rewriteUrl, unrewriteUrl, rewriteBlob, unrewriteBlob },
|
||||||
|
@ -13,6 +15,6 @@ export const {
|
||||||
htmlRules,
|
htmlRules,
|
||||||
},
|
},
|
||||||
CookieStore,
|
CookieStore,
|
||||||
} = self.$scramjet.shared;
|
} = $scramjet.shared;
|
||||||
|
|
||||||
export const config = self.$scramjet.config;
|
export const config = $scramjet.config;
|
||||||
|
|
|
@ -14,8 +14,9 @@ import { parseDomain } from "parse-domain";
|
||||||
import { ScramjetHeaders } from "./headers";
|
import { ScramjetHeaders } from "./headers";
|
||||||
import { CookieStore } from "./cookie";
|
import { CookieStore } from "./cookie";
|
||||||
import { htmlRules, unrewriteHtml } from "./rewriters/html";
|
import { htmlRules, unrewriteHtml } from "./rewriters/html";
|
||||||
|
import { $scramjet } from "../scramjet";
|
||||||
|
|
||||||
self.$scramjet.shared = {
|
$scramjet.shared = {
|
||||||
util: {
|
util: {
|
||||||
parseDomain,
|
parseDomain,
|
||||||
BareClient,
|
BareClient,
|
||||||
|
|
|
@ -6,6 +6,7 @@ import { rewriteCss } from "./css";
|
||||||
import { rewriteJs } from "./js";
|
import { rewriteJs } from "./js";
|
||||||
import { CookieStore } from "../cookie";
|
import { CookieStore } from "../cookie";
|
||||||
import { unrewriteBlob } from "../../shared/rewriters/url";
|
import { unrewriteBlob } from "../../shared/rewriters/url";
|
||||||
|
import { $scramjet } from "../../scramjet";
|
||||||
|
|
||||||
export function rewriteHtml(
|
export function rewriteHtml(
|
||||||
html: string,
|
html: string,
|
||||||
|
@ -43,8 +44,7 @@ export function rewriteHtml(
|
||||||
const dump = JSON.stringify(cookieStore.dump());
|
const dump = JSON.stringify(cookieStore.dump());
|
||||||
const injected = `
|
const injected = `
|
||||||
self.COOKIE = ${dump};
|
self.COOKIE = ${dump};
|
||||||
self.$scramjet.config = ${JSON.stringify(self.$scramjet.config)};
|
self.$scramjet.config = ${JSON.stringify($scramjet.config)};
|
||||||
self.$scramjet.codec = self.$scramjet.codecs[self.$scramjet.config.codec];
|
|
||||||
if ("document" in self && document.currentScript) {
|
if ("document" in self && document.currentScript) {
|
||||||
document.currentScript.remove();
|
document.currentScript.remove();
|
||||||
}
|
}
|
||||||
|
@ -53,11 +53,10 @@ export function rewriteHtml(
|
||||||
const script = (src) => new Element("script", { src });
|
const script = (src) => new Element("script", { src });
|
||||||
|
|
||||||
head.children.unshift(
|
head.children.unshift(
|
||||||
script(self.$scramjet.config["wasm"]),
|
script($scramjet.config.files.wasm),
|
||||||
script(self.$scramjet.config["codecs"]),
|
script($scramjet.config.files.shared),
|
||||||
script("data:application/javascript;base64," + btoa(injected)),
|
script("data:application/javascript;base64," + btoa(injected)),
|
||||||
script(self.$scramjet.config["shared"]),
|
script($scramjet.config.files.client)
|
||||||
script(self.$scramjet.config["client"])
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@ import {
|
||||||
rewrite_js,
|
rewrite_js,
|
||||||
rewrite_js_from_arraybuffer,
|
rewrite_js_from_arraybuffer,
|
||||||
} from "../../../rewriter/out/rewriter.js";
|
} from "../../../rewriter/out/rewriter.js";
|
||||||
|
import { $scramjet } from "../../scramjet";
|
||||||
|
|
||||||
initSync({
|
initSync({
|
||||||
module: new WebAssembly.Module(
|
module: new WebAssembly.Module(
|
||||||
|
@ -19,7 +20,7 @@ init();
|
||||||
Error.stackTraceLimit = 50;
|
Error.stackTraceLimit = 50;
|
||||||
|
|
||||||
export function rewriteJs(js: string | ArrayBuffer, meta: URLMeta) {
|
export function rewriteJs(js: string | ArrayBuffer, meta: URLMeta) {
|
||||||
if (self.$scramjet.config.flags.naiiveRewriter) {
|
if ($scramjet.config.flags.naiiveRewriter) {
|
||||||
const text = typeof js === "string" ? js : new TextDecoder().decode(js);
|
const text = typeof js === "string" ? js : new TextDecoder().decode(js);
|
||||||
|
|
||||||
return rewriteJsNaiive(text);
|
return rewriteJsNaiive(text);
|
||||||
|
@ -27,14 +28,12 @@ export function rewriteJs(js: string | ArrayBuffer, meta: URLMeta) {
|
||||||
|
|
||||||
const before = performance.now();
|
const before = performance.now();
|
||||||
if (typeof js === "string") {
|
if (typeof js === "string") {
|
||||||
js = new TextDecoder().decode(
|
js = new TextDecoder().decode(rewrite_js(js, meta.base.href, $scramjet));
|
||||||
rewrite_js(js, meta.base.href, self.$scramjet)
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
js = rewrite_js_from_arraybuffer(
|
js = rewrite_js_from_arraybuffer(
|
||||||
new Uint8Array(js),
|
new Uint8Array(js),
|
||||||
meta.base.href,
|
meta.base.href,
|
||||||
self.$scramjet
|
$scramjet
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
const after = performance.now();
|
const after = performance.now();
|
||||||
|
@ -56,7 +55,7 @@ export function rewriteJsNaiive(js: string | ArrayBuffer) {
|
||||||
}
|
}
|
||||||
|
|
||||||
return `
|
return `
|
||||||
with (${self.$scramjet.config.wrapfn}(globalThis)) {
|
with (${$scramjet.config.globals.wrapfn}(globalThis)) {
|
||||||
|
|
||||||
${js}
|
${js}
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { $scramjet } from "../../scramjet";
|
||||||
import { rewriteJs } from "./js";
|
import { rewriteJs } from "./js";
|
||||||
|
|
||||||
export type URLMeta = {
|
export type URLMeta = {
|
||||||
|
@ -31,9 +32,9 @@ export function rewriteUrl(url: string | URL, meta: URLMeta) {
|
||||||
if (url.startsWith("javascript:")) {
|
if (url.startsWith("javascript:")) {
|
||||||
return "javascript:" + rewriteJs(url.slice("javascript:".length), meta);
|
return "javascript:" + rewriteJs(url.slice("javascript:".length), meta);
|
||||||
} else if (url.startsWith("blob:")) {
|
} else if (url.startsWith("blob:")) {
|
||||||
return location.origin + self.$scramjet.config.prefix + url;
|
return location.origin + $scramjet.config.prefix + url;
|
||||||
} else if (url.startsWith("data:")) {
|
} else if (url.startsWith("data:")) {
|
||||||
return location.origin + self.$scramjet.config.prefix + url;
|
return location.origin + $scramjet.config.prefix + url;
|
||||||
} else if (url.startsWith("mailto:") || url.startsWith("about:")) {
|
} else if (url.startsWith("mailto:") || url.startsWith("about:")) {
|
||||||
return url;
|
return url;
|
||||||
} else {
|
} else {
|
||||||
|
@ -43,8 +44,8 @@ export function rewriteUrl(url: string | URL, meta: URLMeta) {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
location.origin +
|
location.origin +
|
||||||
self.$scramjet.config.prefix +
|
$scramjet.config.prefix +
|
||||||
self.$scramjet.codec.encode(new URL(url, base).href)
|
$scramjet.codec.encode(new URL(url, base).href)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -54,7 +55,7 @@ export function unrewriteUrl(url: string | URL) {
|
||||||
url = url.href;
|
url = url.href;
|
||||||
}
|
}
|
||||||
|
|
||||||
const prefixed = location.origin + self.$scramjet.config.prefix;
|
const prefixed = location.origin + $scramjet.config.prefix;
|
||||||
|
|
||||||
if (url.startsWith("javascript:")) {
|
if (url.startsWith("javascript:")) {
|
||||||
//TODO
|
//TODO
|
||||||
|
@ -69,8 +70,8 @@ export function unrewriteUrl(url: string | URL) {
|
||||||
} else if (url.startsWith("mailto:") || url.startsWith("about:")) {
|
} else if (url.startsWith("mailto:") || url.startsWith("about:")) {
|
||||||
return url;
|
return url;
|
||||||
} else if (tryCanParseURL(url)) {
|
} else if (tryCanParseURL(url)) {
|
||||||
return self.$scramjet.codec.decode(
|
return $scramjet.codec.decode(
|
||||||
url.slice((location.origin + self.$scramjet.config.prefix).length)
|
url.slice((location.origin + $scramjet.config.prefix).length)
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return url;
|
return url;
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { $scramjet } from "../../scramjet";
|
||||||
import { rewriteJs } from "./js";
|
import { rewriteJs } from "./js";
|
||||||
import { URLMeta } from "./url";
|
import { URLMeta } from "./url";
|
||||||
|
|
||||||
|
@ -9,22 +10,11 @@ export function rewriteWorkers(
|
||||||
) {
|
) {
|
||||||
let str = "";
|
let str = "";
|
||||||
|
|
||||||
str += `self.$scramjet = {}; self.$scramjet.config = ${JSON.stringify(self.$scramjet.config)};
|
for (const script of clientscripts) {
|
||||||
`;
|
if (type === "module") {
|
||||||
str += "";
|
str += `import "${$scramjet.config.files[script]}"\n`;
|
||||||
if (type === "module") {
|
} else {
|
||||||
str += `import "${self.$scramjet.config["codecs"]}"
|
str += `importScripts("${$scramjet.config.files[script]}");\n`;
|
||||||
self.$scramjet.codec = self.$scramjet.codecs[self.$scramjet.config.codec];
|
|
||||||
`;
|
|
||||||
for (const script of clientscripts) {
|
|
||||||
str += `import "${self.$scramjet.config[script]}"\n`;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
str += `importScripts("${self.$scramjet.config["codecs"]}");
|
|
||||||
self.$scramjet.codec = self.$scramjet.codecs[self.$scramjet.config.codec];
|
|
||||||
`;
|
|
||||||
for (const script of clientscripts) {
|
|
||||||
str += `importScripts("${self.$scramjet.config[script]}");\n`;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
46
src/types.d.ts
vendored
46
src/types.d.ts
vendored
|
@ -36,23 +36,28 @@ type ScramjetFlags = {
|
||||||
|
|
||||||
interface ScramjetConfig {
|
interface ScramjetConfig {
|
||||||
prefix: string;
|
prefix: string;
|
||||||
codec: string;
|
globals: {
|
||||||
wrapfn: string;
|
wrapfn: string;
|
||||||
trysetfn: string;
|
trysetfn: string;
|
||||||
importfn: string;
|
importfn: string;
|
||||||
rewritefn: string;
|
rewritefn: string;
|
||||||
metafn: string;
|
metafn: string;
|
||||||
setrealmfn: string;
|
setrealmfn: string;
|
||||||
pushsourcemapfn: string;
|
pushsourcemapfn: string;
|
||||||
wasm: string;
|
};
|
||||||
shared: string;
|
files: {
|
||||||
worker: string;
|
wasm: string;
|
||||||
thread: string;
|
shared: string;
|
||||||
client: string;
|
worker: string;
|
||||||
codecs: string;
|
client: string;
|
||||||
sync: string;
|
sync: string;
|
||||||
|
};
|
||||||
flags: ScramjetFlags;
|
flags: ScramjetFlags;
|
||||||
siteflags?: Record<string, ScramjetFlags>;
|
siteflags: Record<string, ScramjetFlags>;
|
||||||
|
codec: {
|
||||||
|
encode: string;
|
||||||
|
decode: string;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
|
@ -85,13 +90,10 @@ declare global {
|
||||||
CookieStore: typeof CookieStore;
|
CookieStore: typeof CookieStore;
|
||||||
};
|
};
|
||||||
config: ScramjetConfig;
|
config: ScramjetConfig;
|
||||||
codecs: {
|
codec: {
|
||||||
none: Codec;
|
encode: (url: string) => string;
|
||||||
plain: Codec;
|
decode: (url: string) => string;
|
||||||
base64: Codec;
|
|
||||||
xor: Codec;
|
|
||||||
};
|
};
|
||||||
codec: Codec;
|
|
||||||
};
|
};
|
||||||
COOKIE: string;
|
COOKIE: string;
|
||||||
WASM: string;
|
WASM: string;
|
||||||
|
|
|
@ -16,6 +16,7 @@ import {
|
||||||
} from "../shared";
|
} from "../shared";
|
||||||
|
|
||||||
import type { URLMeta } from "../shared/rewriters/url";
|
import type { URLMeta } from "../shared/rewriters/url";
|
||||||
|
import { $scramjet } from "../scramjet";
|
||||||
|
|
||||||
function newmeta(url: URL): URLMeta {
|
function newmeta(url: URL): URLMeta {
|
||||||
return {
|
return {
|
||||||
|
@ -115,7 +116,7 @@ export async function swfetch(
|
||||||
|
|
||||||
if (
|
if (
|
||||||
client &&
|
client &&
|
||||||
new URL(client.url).pathname.startsWith(self.$scramjet.config.prefix)
|
new URL(client.url).pathname.startsWith($scramjet.config.prefix)
|
||||||
) {
|
) {
|
||||||
// TODO: i was against cors emulation but we might actually break stuff if we send full origin/referrer always
|
// TODO: i was against cors emulation but we might actually break stuff if we send full origin/referrer always
|
||||||
const clientURL = new URL(unrewriteUrl(client.url));
|
const clientURL = new URL(unrewriteUrl(client.url));
|
||||||
|
|
|
@ -3,22 +3,23 @@ import { swfetch } from "./fetch";
|
||||||
import { ScramjetThreadpool } from "./threadpool";
|
import { ScramjetThreadpool } from "./threadpool";
|
||||||
import type BareClient from "@mercuryworkshop/bare-mux";
|
import type BareClient from "@mercuryworkshop/bare-mux";
|
||||||
import { ScramjetConfig } from "../types";
|
import { ScramjetConfig } from "../types";
|
||||||
|
import { $scramjet, loadCodecs } from "../scramjet";
|
||||||
|
|
||||||
export class ScramjetServiceWorker extends EventTarget {
|
export class ScramjetServiceWorker extends EventTarget {
|
||||||
client: BareClient;
|
client: BareClient;
|
||||||
config: typeof self.$scramjet.config;
|
config: ScramjetConfig;
|
||||||
threadpool: ScramjetThreadpool;
|
threadpool: ScramjetThreadpool;
|
||||||
|
|
||||||
syncPool: Record<number, (val?: any) => void> = {};
|
syncPool: Record<number, (val?: any) => void> = {};
|
||||||
synctoken = 0;
|
synctoken = 0;
|
||||||
|
|
||||||
cookieStore = new self.$scramjet.shared.CookieStore();
|
cookieStore = new $scramjet.shared.CookieStore();
|
||||||
|
|
||||||
serviceWorkers: FakeServiceWorker[] = [];
|
serviceWorkers: FakeServiceWorker[] = [];
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
this.client = new self.$scramjet.shared.util.BareClient();
|
this.client = new $scramjet.shared.util.BareClient();
|
||||||
|
|
||||||
this.threadpool = new ScramjetThreadpool();
|
this.threadpool = new ScramjetThreadpool();
|
||||||
|
|
||||||
|
@ -40,19 +41,6 @@ export class ScramjetServiceWorker extends EventTarget {
|
||||||
async loadConfig() {
|
async loadConfig() {
|
||||||
if (this.config) return;
|
if (this.config) return;
|
||||||
|
|
||||||
// const store = new IDBMap("config", {
|
|
||||||
// prefix: "scramjet",
|
|
||||||
// });
|
|
||||||
|
|
||||||
// if (store.has("config")) {
|
|
||||||
// const config = await store.get("config");
|
|
||||||
// this.config = config;
|
|
||||||
// self.$scramjet.config = config;
|
|
||||||
// self.$scramjet.codec = self.$scramjet.codecs[config.codec];
|
|
||||||
// }
|
|
||||||
|
|
||||||
// Recreate the above code using the stock IDB API
|
|
||||||
|
|
||||||
const request = indexedDB.open("$scramjet", 1);
|
const request = indexedDB.open("$scramjet", 1);
|
||||||
|
|
||||||
return new Promise<void>((resolve, reject) => {
|
return new Promise<void>((resolve, reject) => {
|
||||||
|
@ -64,8 +52,9 @@ export class ScramjetServiceWorker extends EventTarget {
|
||||||
|
|
||||||
config.onsuccess = () => {
|
config.onsuccess = () => {
|
||||||
this.config = config.result;
|
this.config = config.result;
|
||||||
self.$scramjet.config = config.result;
|
$scramjet.config = config.result;
|
||||||
self.$scramjet.codec = self.$scramjet.codecs[config.result.codec];
|
|
||||||
|
loadCodecs();
|
||||||
|
|
||||||
resolve();
|
resolve();
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
importScripts(
|
importScripts(
|
||||||
"/scram/scramjet.wasm.js",
|
"/scram/scramjet.wasm.js",
|
||||||
"/scram/scramjet.codecs.js",
|
|
||||||
"/scram/scramjet.shared.js",
|
"/scram/scramjet.shared.js",
|
||||||
"/scram/scramjet.worker.js"
|
"/scram/scramjet.worker.js"
|
||||||
);
|
);
|
||||||
|
|
16
static/ui.js
16
static/ui.js
|
@ -1,11 +1,11 @@
|
||||||
const scramjet = new ScramjetController({
|
const scramjet = new ScramjetController({
|
||||||
wasm: "/scram/scramjet.wasm.js",
|
files: {
|
||||||
codecs: "/scram/scramjet.codecs.js",
|
wasm: "/scram/scramjet.wasm.js",
|
||||||
worker: "/scram/scramjet.worker.js",
|
worker: "/scram/scramjet.worker.js",
|
||||||
thread: "/scram/scramjet.thread.js",
|
client: "/scram/scramjet.client.js",
|
||||||
client: "/scram/scramjet.client.js",
|
shared: "/scram/scramjet.shared.js",
|
||||||
shared: "/scram/scramjet.shared.js",
|
sync: "/scram/scramjet.sync.js",
|
||||||
sync: "/scram/scramjet.sync.js",
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
scramjet.init("./sw.js");
|
scramjet.init("./sw.js");
|
||||||
|
@ -148,7 +148,7 @@ function App() {
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<div>
|
<div>
|
||||||
<h1>Percury Unblocker</h1>
|
<h1>scramjet</h1>
|
||||||
<p>surf the unblocked and mostly buggy web</p>
|
<p>surf the unblocked and mostly buggy web</p>
|
||||||
|
|
||||||
<div class=${[flex, "cfg"]}>
|
<div class=${[flex, "cfg"]}>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue