diff --git a/backend.js b/backend.js index 0062b594..1973b5ce 100644 --- a/backend.js +++ b/backend.js @@ -1,3 +1,3 @@ (async () => { - await import("./src/server.mjs"); + await import("./src/fastify.mjs"); })(); diff --git a/package.json b/package.json index 01b17c6e..e8506188 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,8 @@ "author": "Titanium Network", "license": "GNU AFFERO", "dependencies": { + "@fastify/helmet": "^11.1.1", + "@fastify/static": "^7.0.4", "@mercuryworkshop/bare-as-module3": "^2.2.2", "@mercuryworkshop/bare-mux": "^2.0.1", "@mercuryworkshop/epoxy-transport": "^2.1.3", @@ -27,6 +29,7 @@ "@tomphttp/bare-server-node": "^2.0.3", "axios": "^1.7.2", "express": "^4.19.2", + "fastify": "^4.28.1", "helmet": "^7.1.0", "mime-types": "^2.1.35", "puppeteer": "^22.12.1", diff --git a/src/fastify.mjs b/src/fastify.mjs new file mode 100644 index 00000000..9b9fad37 --- /dev/null +++ b/src/fastify.mjs @@ -0,0 +1,114 @@ +import Fastify from 'fastify'; +import { createServer } from 'node:http'; +import wisp from 'wisp-server-node'; +import createRammerhead from "rammerhead/src/server/index.js"; +import { epoxyPath } from "@mercuryworkshop/epoxy-transport"; +import { libcurlPath } from "@mercuryworkshop/libcurl-transport"; +import { bareModulePath } from "@mercuryworkshop/bare-as-module3"; +import { baremuxPath } from "@mercuryworkshop/bare-mux/node"; +import { uvPath } from "@titaniumnetwork-dev/ultraviolet"; +import fastifyHelmet from '@fastify/helmet'; +import fastifyStatic from '@fastify/static'; +import pkg from "./routes.mjs"; +import { readFile } from 'node:fs/promises'; +import path from 'node:path'; +import { paintSource, tryReadFile } from './randomization.mjs'; +import loadTemplates from './templates.mjs'; +import { fileURLToPath } from 'node:url'; +import { existsSync } from 'node:fs'; +const config = JSON.parse(await readFile(new URL("./config.json", import.meta.url))), { pages, text404 } = pkg; +const __dirname = path.resolve(); +const port = process.env.PORT || config.port; + +const rh = createRammerhead(); +const rammerheadScopes = [ + "/rammerhead.js", + "/hammerhead.js", + "/transport-worker.js", + "/task.js", + "/iframe-task.js", + "/worker-hammerhead.js", + "/messaging", + "/sessionexists", + "/deletesession", + "/newsession", + "/editsession", + "/needpassword", + "/syncLocalStorage", + "/api/shuffleDict", + "/mainport", +]; +const rammerheadSession = /^\/[a-z0-9]{32}/; +const shouldRouteRh = req => { + const url = new URL(req.url, "http://0.0.0.0"); + return ( + rammerheadScopes.includes(url.pathname) || + rammerheadSession.test(url.pathname) + ); +} +const routeRhRequest = (req, res) => { + rh.emit("request", req, res); +} +const routeRhUpgrade = (req, socket, head) => { + rh.emit("upgrade", req, socket, head); +} + +//create a server factory for RH, and wisp (and bare if you please) +const serverFactory = (handler) => { + return createServer() + .on('request', (req, res) => { + if (shouldRouteRh(req)) { + routeRhRequest(req, res); + } + else { + handler(req, res); + } + }) + .on('upgrade', (req, socket, head) => { + if (shouldRouteRh(req)) { + routeRhUpgrade(req, socket, head); + } + else if (req.url.endsWith('/wisp/')) { + wisp.routeRequest(req, socket, head); + } + }) +} + +//set logger to true for logs +const app = Fastify({ logger: false, serverFactory: serverFactory }); +app.register(fastifyStatic, { + root: fileURLToPath(new URL('../views', import.meta.url)), +}); +app.register(fastifyStatic, { + root: uvPath, + //due to how Fastify works, we have to have the uvPath live on a different prefix then the one in /views/ + prefix: "/uv-static/", + decorateReply: false +}); +app.register(fastifyStatic, { + root: epoxyPath, + prefix: "/epoxy/", + decorateReply: false +}); +app.register(fastifyStatic, { + root: libcurlPath, + prefix: "/libcurl/", + decorateReply: false +}); +app.register(fastifyStatic, { + root: bareModulePath, + prefix: "/bareasmodule/", + decorateReply: false +}); +app.register(fastifyStatic, { + root: baremuxPath, + prefix: "/baremux/", + decorateReply: false +}); +app.get("/", function(req, reply) { + reply.type('html'); + reply.send(paintSource(loadTemplates(tryReadFile(path.join(__dirname, "views", "/?".indexOf(req.url) ? pages[Object.keys(req.query)[0]] || "error.html" : pages.index))))) +}); + +//host is set as to avoid just being on localhost +app.listen({ port: port, host: '0.0.0.0' }); diff --git a/views/pages/frame.html b/views/pages/frame.html index 2d74b482..0cb7fd5f 100644 --- a/views/pages/frame.html +++ b/views/pages/frame.html @@ -26,7 +26,7 @@ - + diff --git a/views/pages/nav/games5.html b/views/pages/nav/games5.html index 6231b30c..1d15a37f 100644 --- a/views/pages/nav/games5.html +++ b/views/pages/nav/games5.html @@ -26,7 +26,7 @@ - + - + - + diff --git a/views/pages/proxnav/ultraviolet.html b/views/pages/proxnav/ultraviolet.html index 62f679d6..7fe42d89 100644 --- a/views/pages/proxnav/ultraviolet.html +++ b/views/pages/proxnav/ultraviolet.html @@ -26,7 +26,7 @@ - +