Commenting and reformatting changes

This commit is contained in:
00Fjongl 2024-08-07 17:47:11 -05:00
parent 192495d44a
commit 4f79f92de9
2 changed files with 136 additions and 110 deletions

View file

@ -22,7 +22,7 @@ const shutdown = fileURLToPath(new URL("./src/.shutdown", import.meta.url));
// Run each command line argument passed after node run-command.mjs. // Run each command line argument passed after node run-command.mjs.
// Commands are defined in the switch case statement below. // Commands are defined in the switch case statement below.
for(let i = 2; i < process.argv.length; i++) for (let i = 2; i < process.argv.length; i++)
switch (process.argv[i]) { switch (process.argv[i]) {
// Commmand to boot up the server. Use PM2 to run if production is true in the // Commmand to boot up the server. Use PM2 to run if production is true in the
// config file. // config file.
@ -54,6 +54,9 @@ for(let i = 2; i < process.argv.length; i++)
case "stop": case "stop":
await writeFile(shutdown, ""); await writeFile(shutdown, "");
try { try {
// Give the server 5 seconds to respond, otherwise cancel this and throw an
// error to the console. The fetch request will also throw an error immediately
// if checking the server on localhost and the port is unused.
let timeoutId = undefined; let timeoutId = undefined;
const response = await Promise.race([ const response = await Promise.race([
fetch(new URL("/test-shutdown", serverUrl)), fetch(new URL("/test-shutdown", serverUrl)),
@ -64,8 +67,11 @@ for(let i = 2; i < process.argv.length; i++)
}) })
]); ]);
clearTimeout(timeoutId); clearTimeout(timeoutId);
if(response === "Error") throw new Error("Server is unresponsive."); if (response === "Error") throw new Error("Server is unresponsive.");
} catch (e) {await unlink(shutdown)} } catch (e) {
console.error(e);
await unlink(shutdown);
}
if (config.production) if (config.production)
exec("npm run pm2-stop", (error, stdout) => { exec("npm run pm2-stop", (error, stdout) => {
if (error) throw error; if (error) throw error;

View file

@ -16,8 +16,14 @@ import { paintSource, tryReadFile } from './randomization.mjs';
import loadTemplates from './templates.mjs'; import loadTemplates from './templates.mjs';
import { fileURLToPath } from 'node:url'; import { fileURLToPath } from 'node:url';
import { existsSync, unlinkSync } from 'node:fs'; import { existsSync, unlinkSync } from 'node:fs';
const config = Object.freeze(JSON.parse(await readFile(new URL("./config.json", import.meta.url)))), { pages, text404 } = pkg;
const __dirname = path.resolve(); const config = Object.freeze(JSON.parse(
await readFile(new URL("./config.json", import.meta.url))
)),
{ pages, text404 } = pkg,
__dirname = path.resolve();
// Record the server's location as a URL object, including its host and port.
const serverUrl = (base => { const serverUrl = (base => {
try { try {
base = new URL(config.host); base = new URL(config.host);
@ -30,6 +36,8 @@ const serverUrl = (base => {
})(); })();
console.log(serverUrl); console.log(serverUrl);
// The server will check for the existence of this file when a shutdown is requested.
// The shutdown script in run-command.js will temporarily produce this file.
const shutdown = fileURLToPath(new URL("./.shutdown", import.meta.url)); const shutdown = fileURLToPath(new URL("./.shutdown", import.meta.url));
const rh = createRammerhead(); const rh = createRammerhead();
@ -50,40 +58,36 @@ const rammerheadScopes = [
"/api/shuffleDict", "/api/shuffleDict",
"/mainport", "/mainport",
]; ];
const rammerheadSession = /^\/[a-z0-9]{32}/;
const shouldRouteRh = req => { const rammerheadSession = /^\/[a-z0-9]{32}/,
const url = new URL(req.url, serverUrl); shouldRouteRh = req => {
return ( const url = new URL(req.url, serverUrl);
rammerheadScopes.includes(url.pathname) || return (
rammerheadSession.test(url.pathname) rammerheadScopes.includes(url.pathname) ||
); rammerheadSession.test(url.pathname)
}; );
const routeRhRequest = (req, res) => { },
rh.emit("request", req, res); routeRhRequest = (req, res) => {
}; rh.emit("request", req, res);
const routeRhUpgrade = (req, socket, head) => { },
rh.emit("upgrade", req, socket, head); routeRhUpgrade = (req, socket, head) => {
}; rh.emit("upgrade", req, socket, head);
};
// Create a server factory for RH, and wisp (and bare if you please). // Create a server factory for RH, and wisp (and bare if you please).
const serverFactory = (handler) => { const serverFactory = (handler) => {
return createServer() return createServer()
.on('request', (req, res) => { .on('request', (req, res) => {
if (shouldRouteRh(req)) { if (shouldRouteRh(req))
routeRhRequest(req, res); routeRhRequest(req, res);
} else handler(req, res);
else { })
handler(req, res); .on('upgrade', (req, socket, head) => {
} if (shouldRouteRh(req))
}) routeRhUpgrade(req, socket, head);
.on('upgrade', (req, socket, head) => { else if (req.url.endsWith('/wisp/'))
if (shouldRouteRh(req)) { wisp.routeRequest(req, socket, head);
routeRhUpgrade(req, socket, head); });
}
else if (req.url.endsWith('/wisp/')) {
wisp.routeRequest(req, socket, head);
}
})
}; };
// Set logger to true for logs // Set logger to true for logs
@ -91,73 +95,86 @@ const app = Fastify({ logger: false, serverFactory: serverFactory });
// Apply Helmet middleware for security // Apply Helmet middleware for security
app.register(fastifyHelmet, { app.register(fastifyHelmet, {
contentSecurityPolicy: false, // Disable CSP contentSecurityPolicy: false, // Disable CSP
xPoweredBy: false xPoweredBy: false
});
// Assign server file paths to different paths, for serving content on the website.
app.register(fastifyStatic, {
root: fileURLToPath(new URL("../views/pages", import.meta.url)),
decorateReply: false
}); });
app.register(fastifyStatic, { app.register(fastifyStatic, {
root: fileURLToPath(new URL("../views/pages", import.meta.url)), root: fileURLToPath(new URL("../views/assets", import.meta.url)),
decorateReply: false prefix: "/assets/",
decorateReply: false
}); });
app.register(fastifyStatic, { app.register(fastifyStatic, {
root: fileURLToPath(new URL("../views/assets", import.meta.url)), root: fileURLToPath(new URL("../views/archive", import.meta.url)),
prefix: "/assets/", prefix: "/arcade/",
decorateReply: false decorateReply: false
}); });
app.register(fastifyStatic, { app.register(fastifyStatic, {
root: fileURLToPath(new URL("../views/archive", import.meta.url)), root: fileURLToPath(new URL(
prefix: "/arcade/", // Use the pre-compiled, minified scripts instead, if enabled in config.
decorateReply: false config.minifyScripts ? "../views/dist/assets/js" : "../views/assets/js",
import.meta.url
)),
prefix: "/assets/js/",
decorateReply: false
}); });
app.register(fastifyStatic, { app.register(fastifyStatic, {
root: fileURLToPath(new URL( root: fileURLToPath(new URL(
config.minifyScripts ? "../views/dist/assets/js" : "../views/assets/js", // Use the pre-compiled, minified stylesheets instead, if enabled in config.
import.meta.url config.minifyScripts ? "../views/dist/assets/css" : "../views/assets/css",
import.meta.url
)),
prefix: "/assets/css/",
decorateReply: false
});
// This combines scripts from the official UV repository with local UV scripts into
// one directory path. Local versions of files override the official versions.
app.register(fastifyStatic, {
root: [
fileURLToPath(new URL(
// Use the pre-compiled, minified scripts instead, if enabled in config.
config.minifyScripts ? "../views/dist/uv" : "../views/uv",
import.meta.url
)), )),
prefix: "/assets/js/", uvPath
decorateReply: false ],
prefix: "/uv/",
decorateReply: false
});
// Register proxy paths to the website.
app.register(fastifyStatic, {
root: epoxyPath,
prefix: "/epoxy/",
decorateReply: false
}); });
app.register(fastifyStatic, { app.register(fastifyStatic, {
root: fileURLToPath(new URL( root: libcurlPath,
config.minifyScripts ? "../views/dist/assets/css" : "../views/assets/css", prefix: "/libcurl/",
import.meta.url decorateReply: false
)),
prefix: "/assets/css/",
decorateReply: false
}); });
app.register(fastifyStatic, { app.register(fastifyStatic, {
root: [fileURLToPath(new URL( root: bareModulePath,
config.minifyScripts ? "../views/dist/uv" : "../views/uv", prefix: "/bareasmodule/",
import.meta.url decorateReply: false
)), uvPath],
prefix: "/uv/",
decorateReply: false
}); });
app.register(fastifyStatic, { app.register(fastifyStatic, {
root: epoxyPath, root: baremuxPath,
prefix: "/epoxy/", prefix: "/baremux/",
decorateReply: false 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
}); });
@ -167,38 +184,41 @@ app.register(fastifyStatic, {
// back here. Which path converts to what is defined in routes.mjs. // back here. Which path converts to what is defined in routes.mjs.
app.get("/:file", (req, reply) => { app.get("/:file", (req, reply) => {
if (req.params.file === "test-shutdown" && existsSync(shutdown)) { // If a GET request is sent to /test-shutdown and a script-generated shutdown file
console.log("Holy Unblocker is shutting down."); // is present, gracefully shut the server down.
app.close(); if (req.params.file === "test-shutdown" && existsSync(shutdown)) {
unlinkSync(shutdown); console.log("Holy Unblocker is shutting down.");
process.exitCode = 0; app.close();
} unlinkSync(shutdown);
process.exitCode = 0;
}
// Testing for future features that need cookies to deliver alternate source files. // Testing for future features that need cookies to deliver alternate source files.
if (req.raw.rawHeaders.includes("Cookie")) if (req.raw.rawHeaders.includes("Cookie"))
console.log(req.raw.rawHeaders[req.raw.rawHeaders.indexOf("Cookie") + 1]); console.log(req.raw.rawHeaders[req.raw.rawHeaders.indexOf("Cookie") + 1]);
reply.type("text/html").send( reply.type("text/html").send(
paintSource( paintSource(
loadTemplates( loadTemplates(
tryReadFile( tryReadFile(
path.join(__dirname, path.join(
"views", __dirname,
// Return the error page if the query is not found in "views",
// routes.mjs. Also set index as the default page. // Return the error page if the query is not found in routes.mjs. Also set
req.params.file // the index the as the default page.
? pages[req.params.file] || "error.html" req.params.file
: pages.index ? pages[req.params.file] || "error.html"
) : pages.index
) )
)
) )
); )
)
);
}); });
// Ignore trailing slashes for the above path handling. // Ignore trailing slashes for the above path handling.
app.get("/:file/", (req, reply) => { app.get("/:file/", (req, reply) => {
reply.redirect("/" + req.params.file); reply.redirect("/" + req.params.file);
}); });
@ -206,15 +226,15 @@ app.get("/:file/", (req, reply) => {
Testing for future restructuring of this config file. Testing for future restructuring of this config file.
app.get("/assets/js/uv/uv.config.js", (req, reply) => { app.get("/assets/js/uv/uv.config.js", (req, reply) => {
console.log(req.url); console.log(req.url);
reply.type("text/javascript"); reply.type("text/javascript");
reply.send(tryReadFile(path.join(__dirname, "views/assets/js/uv/uv.config.js"))); reply.send(tryReadFile(path.join(__dirname, "views/assets/js/uv/uv.config.js")));
}); });
*/ */
// Set an error page for invalid paths outside the query string system. // Set an error page for invalid paths outside the query string system.
app.setNotFoundHandler((req, reply) => { app.setNotFoundHandler((req, reply) => {
reply.code(404).type("text/html").send(paintSource(loadTemplates(tryReadFile(path.join(__dirname, "views/error.html"))))); reply.code(404).type("text/html").send(paintSource(loadTemplates(tryReadFile(path.join(__dirname, "views/error.html")))));
}); });
// Configure host to your liking, but remember to tweak the Rammerhead IP // Configure host to your liking, but remember to tweak the Rammerhead IP