diff --git a/src/components/settings/Loader.astro b/src/components/settings/Loader.astro index 233da19..82ba805 100644 --- a/src/components/settings/Loader.astro +++ b/src/components/settings/Loader.astro @@ -25,6 +25,7 @@ */ import { EventHandler } from "@utils/events"; import { SW, createProxyScripts, checkProxyScripts, createBareMuxConn, setTransport } from "@utils/serviceWorker"; + import { Settings } from "@utils/settings"; import { log } from "@utils/index"; const titleText = ` _ _ _ _ ____ _ @@ -45,8 +46,8 @@ } await checkProxyScripts(); const conn = await createBareMuxConn("/baremux/worker.js"); - await setTransport(conn, "libcurl"); window.sw = new SW(conn); + for await (const _ of Settings.initDefaults()) {}; const { serviceWorker, bareMuxConn, sj } = await window.sw.getSWInfo(); log({ type: 'info', bg: true, prefix: true }, `General init completed! \n\nServiceWorker: ${serviceWorker.active?.state} \nBareMuxConn: ${bareMuxConn ? 'Active': 'Not active'} \nScramjetController: ${sj ? 'Active' : 'Not active'}`); } diff --git a/src/pages/[lang]/index.astro b/src/pages/[lang]/index.astro index 4266e86..7f25b04 100644 --- a/src/pages/[lang]/index.astro +++ b/src/pages/[lang]/index.astro @@ -48,6 +48,8 @@ import { VERSION } from "astro:env/client"; import { search, Elements } from "@utils/index"; import { BareClient } from "@mercuryworkshop/bare-mux"; import { defaultStore } from "@utils/storage"; + import { Settings } from "@utils/settings"; + import { setTransport } from "@utils/serviceWorker"; type Suggestion = { phrase: string; @@ -89,14 +91,28 @@ import { VERSION } from "astro:env/client"; copyright.classList.add("hidden"); if (defaultStore.getVal(SettingsVals.proxy.proxy.key) === SettingsVals.proxy.proxy.available.automatic) { switch(SupportedSites[input.value]) { - case "uv": + case "uv": { prox(input.value, "uv"); break; - case "sj": + } + case "sj": { prox(input.value, "sj"); break; - default: + } + default: { prox(input.value, "uv"); + } + } + } + + switch(defaultStore.getVal("proxy") as "uv" | "sj") { + case "uv": { + prox(input.value, "uv"); + break; + } + case "sj": { + prox(input.value, "sj"); + break; } } } diff --git a/src/utils/marketplace.ts b/src/utils/marketplace.ts new file mode 100644 index 0000000..9fe597b --- /dev/null +++ b/src/utils/marketplace.ts @@ -0,0 +1,87 @@ +import { log } from "./index"; +import { StoreManager } from "./storage"; +import { SettingsVals } from "./values"; + +type PluginType = "page" | "serviceWorker"; +type MarketplacePluginType = "plugin-page" | "plugin-sw"; +type PackageType = "theme" | MarketplacePluginType; + +interface Plug { + name: string; + src: string; + type: PluginType; + remove?: boolean; +} +interface SWPagePlugin extends Omit { + host: string; + html: string; + injectTo: "head" | "body"; +} + +type SWPluginFunction = (args: T) => void | unknown; + +type Events = + | "abortpayment" + | "activate" + | "backgroundfetchabort" + | "backgroundfetchclick" + | "backgroundfetchfail" + | "backgroundfetchsuccess" + | "canmakepayment" + | "contentdelete" + | "cookiechange" + | "fetch" + | "install" + | "message" + | "messageerror" + | "notificationclick" + | "notificationclose" + | "paymentrequest" + | "periodicsync" + | "push" + | "pushsubscriptionchange" + | "sync"; + +interface SWPlugin extends Omit { + function: string | SWPluginFunction; + events: Events[]; +} + +interface Theme { + name: string; + payload: string; + video?: string; + bgImage?: string; +}; + +class Marketplace { + //create our own subsidized StoreManager with it's own prefix so the marketplace stuff NEVER touches the other data + #storage: StoreManager<"nebula||marketplace">; + constructor() { + this.#storage = new StoreManager("nebula||marketplace"); + } + async installTheme(theme: Theme) { + const themes = this.#storage.getVal(SettingsVals.marketPlace.themes) + ? JSON.parse(this.#storage.getVal(SettingsVals.marketPlace.themes)) + : []; + if (themes.find((t: any) => t === theme.name)) return log({ type: 'error', bg: false, prefix: false, throw: true }, `${theme.name} is already installed!`) + themes.push(theme.name); + this.#storage.setVal(SettingsVals.marketPlace.themes, JSON.stringify(themes)); + } + + async installPlugin(plugin: Plug) { + const plugins = this.#storage.getVal(SettingsVals.marketPlace.plugins) + ? JSON.parse(this.#storage.getVal(SettingsVals.marketPlace.plugins)) + : []; + + const plug = plugins.find(({ name }: { name: string }) => name === plugin.name); + if (plug && plug.remove === false) return log({ type: 'error', bg: false, prefix: false, throw: true }, `${plugin.name} is already installed!`); + if (plug && plug.remove) { plug.remove = false; return this.#storage.setVal(SettingsVals.marketPlace.plugins, JSON.stringify(plugins)) }; + plugins.push({ name: plugin.name, src: plugin.src, type: plugin.type } as unknown as Plug); + this.#storage.setVal(SettingsVals.marketPlace.plugins, JSON.stringify(plugins)); + } +} + +window.mp = Marketplace + +export { Marketplace } diff --git a/src/utils/serviceWorker.ts b/src/utils/serviceWorker.ts index c9c38d3..7a6ed1a 100644 --- a/src/utils/serviceWorker.ts +++ b/src/utils/serviceWorker.ts @@ -1,6 +1,7 @@ import { BareMuxConnection } from "@mercuryworkshop/bare-mux"; import { defaultStore } from "./storage"; import { SettingsVals, WispServers } from "./values"; +import { log } from "./index"; /** * Creates a script element and returns it for usage or more modification. @@ -76,7 +77,8 @@ const createBareMuxConn = (worker: string): Promise => { const setTransport = (conn: BareMuxConnection, transport?: "libcurl" | "epoxy"): Promise => { const server = defaultStore.getVal(SettingsVals.proxy.wispServer); return new Promise((resolve) => { - console.log(`Set wisp server at: ${server ? WispServers[server]: WispServers.default }`); + log({ type: 'info', bg: false, prefix: false }, `Set transport: ${transport ? transport : "libcurl"}`); + log({ type: 'info', bg: false, prefix: false }, `Set wisp server at: ${server ? WispServers[server]: WispServers.default }`); if (transport === "epoxy") return resolve(conn.setTransport("/epoxy/index.mjs", [ { wisp: server ? WispServers[server] : WispServers.default }])); if (transport === "libcurl") return resolve(conn.setTransport("/libcurl/index.mjs", [ { wisp: server ? WispServers[server] : WispServers.default }])); }); @@ -121,7 +123,7 @@ class SW { const scram = sj(); (async () => await scram.init())(); navigator.serviceWorker.ready.then(async (reg) => { - console.log("Service worker ready and active!"); + log({ type: 'info', prefix: true, bg: false }, 'ServiceWorker ready and active!'); this.#init = { serviceWorker: reg, sj: scram, bareMuxConn: conn }; this.#ready = true; }); diff --git a/src/utils/settings.ts b/src/utils/settings.ts new file mode 100644 index 0000000..d8b69a4 --- /dev/null +++ b/src/utils/settings.ts @@ -0,0 +1,109 @@ +import { defaultStore } from "./storage"; +import { SettingsVals, WispServers } from "./values"; +import { Marketplace } from "./marketplace"; +import { setTransport } from "./serviceWorker"; + +const tab = { + ab: (redirect: string) => { + window.location.replace(redirect); + const win = window.open(); + const iframe = win!.document.createElement("iframe") as HTMLIFrameElement; + win!.document.body.setAttribute('style', 'margin: 0; height: 100vh; width: 100%;'); + iframe.setAttribute('style', 'border: none; width: 100%; height: 100%; margin: 0;'); + iframe.src = window.location.href; + win!.document.body.appendChild(iframe); + }, + blob: (redirect: string) => { + const content = ` + + + + + + + + + + `; + window.location.replace(redirect); + const blob = new Blob([content], { type: 'text/html' }); + window.open(URL.createObjectURL(blob), "_blank"); + }, + cloak: (cloak: string) => { + const fElem = document.getElementById("favicon")! as HTMLLinkElement; + const c = (title: string, href: string) => { + document.title = title; + fElem.href = href; + } + switch(cloak) { + case "google": { + c("Google", "/cloaks/google.png"); + break; + } + case "wikipedia": { + c("Wikipedia", "/cloaks/wikipedia.ico"); + break; + } + case "canvas": { + c("Dashboard", "/cloaks/canvas.ico"); + break; + } + case "classroom": { + c("Home", "/cloaks/classroom.ico"); + break; + } + case "powerschool": { + c("PowerSchool", "/cloaks/ps.ico"); + break; + } + case "reset": { + defaultStore.setVal(SettingsVals.tab.cloak, "default"); + window.location.reload(); + } + default: { + return; + } + } + } +} + +const proxy = { + change: (proxy: "uv" | "sj" | "automatic") => { + defaultStore.setVal(SettingsVals.proxy.proxy.key, proxy); + }, + searchEngine: (s: string) => { + defaultStore.setVal(SettingsVals.proxy.searchEngine, s); + }, + wisp: (s: string) => { + defaultStore.setVal(SettingsVals.proxy.wispServer, s); + }, + transport: async (t: "libcurl" | "epoxy") => { + const { bareMuxConn } = await window.sw.getSWInfo(); + await setTransport(bareMuxConn, t as "libcurl" | "epoxy"); + defaultStore.setVal(SettingsVals.proxy.transport.key, t); + } +} + +async function* initDefaults() { + yield proxy.change(defaultStore.getVal(SettingsVals.proxy.proxy.key) ? defaultStore.getVal(SettingsVals.proxy.proxy.key) as "uv" | "sj" | "automatic" : "automatic"); + yield proxy.wisp(defaultStore.getVal(SettingsVals.proxy.wispServer) ? defaultStore.getVal(SettingsVals.proxy.wispServer) : "default"); + yield proxy.transport(defaultStore.getVal(SettingsVals.proxy.transport.key) ? defaultStore.getVal(SettingsVals.proxy.transport.key) as "libcurl" | "epoxy" : "libcurl"); +} + +const Settings = { + tab, + proxy, + initDefaults +} + +window.settings = Settings; + +export { Settings }; diff --git a/src/utils/values.ts b/src/utils/values.ts index d411b71..d22f6b9 100644 --- a/src/utils/values.ts +++ b/src/utils/values.ts @@ -57,6 +57,8 @@ interface SettingsVals { cloak: string }, marketPlace: { + themes: string; + plugins: string; appearance: { video: string; image: string; @@ -76,7 +78,7 @@ const SettingsVals: SettingsVals = { } }, proxy: { - wispServer: "wispServerUrl", + wispServer: "wispServer", proxy: { key: "proxy", available: { @@ -98,6 +100,8 @@ const SettingsVals: SettingsVals = { cloak: "cloak" }, marketPlace: { + themes: "themes", + plugins: "plugins", appearance: { video: "video", image: "image",