ui stuff, proxy?, and whatever else
This commit is contained in:
90
index.js
90
index.js
@ -17,6 +17,11 @@ import { getRawData, generateAccountPage, editProfile, saveData, getUsers, isAdm
|
||||
import { callAI } from "./ai.js";
|
||||
import { Readable } from 'stream';
|
||||
import os from "node:os";
|
||||
import crypto from "node:crypto";
|
||||
import { server as wisp, logging as wispLogging } from "@mercuryworkshop/wisp-js/server";
|
||||
import { scramjetPath } from "@mercuryworkshop/scramjet/path";
|
||||
import { libcurlPath } from "@mercuryworkshop/libcurl-transport";
|
||||
import { baremuxPath } from "@mercuryworkshop/bare-mux/node";
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = dirname(__filename);
|
||||
|
||||
@ -29,6 +34,19 @@ const port = process.env.PORT || 3000;
|
||||
|
||||
const app = express();
|
||||
|
||||
wispLogging.set_level(wispLogging.WARN);
|
||||
Object.assign(wisp.options, {
|
||||
allow_udp_streams: false,
|
||||
hostname_blacklist: [
|
||||
/^localhost$/, /^127\./, /^0\.0\.0\.0$/,
|
||||
/^10\./, /^192\.168\./, /^172\.(1[6-9]|2\d|3[01])\./,
|
||||
/^169\.254\./, /^::1$/, /^\[::1\]$/,
|
||||
],
|
||||
});
|
||||
app.use("/scram-assets/", express.static(scramjetPath));
|
||||
app.use("/scram-assets/libcurl/", express.static(libcurlPath));
|
||||
app.use("/scram-assets/baremux/", express.static(baremuxPath));
|
||||
|
||||
// why the fuck does this have to exist?
|
||||
app.use("/resources/semag/hotline-miami/", (req, res, next) => {
|
||||
if (req.method == "HEAD") {
|
||||
@ -65,6 +83,42 @@ app.use(cookieParser());
|
||||
app.use(express.json({ limit: "10mb" }));
|
||||
app.use(express.urlencoded({ extended: false }));
|
||||
app.use(express.text());
|
||||
|
||||
function proxyUnlockToken() {
|
||||
if (!process.env.PROXY_PASSWORD) return null;
|
||||
return crypto.createHash("sha256").update(process.env.PROXY_PASSWORD).digest("hex");
|
||||
}
|
||||
function isProxyUnlocked(req) {
|
||||
const expected = proxyUnlockToken();
|
||||
if (!expected) return true;
|
||||
return req.cookies.proxy_unlock === expected;
|
||||
}
|
||||
function isProxyUnlockedRawCookieHeader(cookieHeader) {
|
||||
const expected = proxyUnlockToken();
|
||||
if (!expected) return true;
|
||||
const match = (cookieHeader || "").split(";").map((c) => c.trim()).find((c) => c.startsWith("proxy_unlock="));
|
||||
if (!match) return false;
|
||||
return decodeURIComponent(match.slice("proxy_unlock=".length)) === expected;
|
||||
}
|
||||
app.post("/api/proxy/unlock", (req, res) => {
|
||||
if (!process.env.PROXY_PASSWORD) {
|
||||
res.status(400).send({ success: false, message: "beta access is not configured." });
|
||||
return;
|
||||
}
|
||||
if (req.body.password === process.env.PROXY_PASSWORD) {
|
||||
res.cookie("proxy_unlock", proxyUnlockToken(), {
|
||||
httpOnly: true,
|
||||
maxAge: 1000 * 60 * 60 * 24 * 365,
|
||||
sameSite: "lax",
|
||||
});
|
||||
res.status(200).send({ success: true });
|
||||
} else {
|
||||
res.status(401).send({ success: false, message: "incorrect password." });
|
||||
}
|
||||
});
|
||||
app.get("/api/proxy/status", (req, res) => {
|
||||
res.status(200).send({ unlocked: isProxyUnlocked(req) });
|
||||
});
|
||||
// app.use("/", (req, res, next) => {
|
||||
// next();
|
||||
// });
|
||||
@ -174,7 +228,7 @@ app.post("/api/account/upload", async (req, res, next) => {
|
||||
app.post("/api/analytics/game", async (req, res) => {
|
||||
if (req.body && req.body.path.length < 32) {
|
||||
let game = req.body.path;
|
||||
if(game == "nso_fix") game = "nso";
|
||||
if (game == "nso_fix") game = "nso";
|
||||
const query = top.prepare(`
|
||||
INSERT INTO stats (game, plays)
|
||||
VALUES ($id, 1)
|
||||
@ -193,7 +247,7 @@ let analyticsCache = null;
|
||||
let analyticsCacheTime = 0;
|
||||
const ANALYTICS_TTL = 10 * 1000;
|
||||
|
||||
app.use("/api/analytics/get", async(req, res) => {
|
||||
app.use("/api/analytics/get", async (req, res) => {
|
||||
const now = Date.now();
|
||||
if (analyticsCache && (now - analyticsCacheTime) < ANALYTICS_TTL) {
|
||||
res.send(analyticsCache);
|
||||
@ -217,8 +271,8 @@ app.use("/api/analytics/get", async(req, res) => {
|
||||
res.send(analyticsCache);
|
||||
return;
|
||||
});
|
||||
app.use("/metrics", async(req, res) => {
|
||||
const sql = `
|
||||
app.use("/metrics", async (req, res) => {
|
||||
const sql = `
|
||||
SELECT
|
||||
CASE
|
||||
WHEN game = 'nso_fix' THEN 'nso'
|
||||
@ -232,13 +286,13 @@ const sql = `
|
||||
const query = top.prepare(sql);
|
||||
let data = query.all();
|
||||
let returnData = "#HELP game_plays_total The total number of plays per game.\n";
|
||||
returnData+="#TYPE game_plays_total counter\n"
|
||||
returnData += "#TYPE game_plays_total counter\n"
|
||||
data.forEach(e => {
|
||||
returnData+=`game_plays_total{name="${e.name}"} ${e.plays}\n`
|
||||
returnData += `game_plays_total{name="${e.name}"} ${e.plays}\n`
|
||||
});
|
||||
returnData+="#HELP online_users The total number of people online.\n";
|
||||
returnData+="#TYPE online_users gauge\n"
|
||||
returnData+=`online_users ${onlineUsers}\n`
|
||||
returnData += "#HELP online_users The total number of people online.\n";
|
||||
returnData += "#TYPE online_users gauge\n"
|
||||
returnData += `online_users ${onlineUsers}\n`
|
||||
res.setHeader("Content-Type", "text/plain; version=0.0.4")
|
||||
res.send(returnData);
|
||||
return;
|
||||
@ -361,6 +415,16 @@ app.use("/ai", async (req, res, next) => {
|
||||
next();
|
||||
}
|
||||
});
|
||||
app.use(["/proxy.html", "/proxy"], async (req, res, next) => {
|
||||
if (isProxyUnlocked(req)) {
|
||||
next();
|
||||
return;
|
||||
}
|
||||
res
|
||||
.type("text/html")
|
||||
.status(200)
|
||||
.send(await fs.readFile("./public/proxy-locked.html"));
|
||||
});
|
||||
app.use("/", express.static("./public", { extensions: ["html"] }));
|
||||
app.use("/data/:id/:file", async (req, res) => {
|
||||
const id = path.basename(req.params.id);
|
||||
@ -466,6 +530,14 @@ const server = app.listen(port, () => {
|
||||
console.log("- " + log.info("http://localhost:" + port));
|
||||
});
|
||||
server.on("upgrade", (request, socket, head) => {
|
||||
if (request.url.startsWith("/wisp/")) {
|
||||
if (!isProxyUnlockedRawCookieHeader(request.headers.cookie)) {
|
||||
socket.destroy();
|
||||
return;
|
||||
}
|
||||
wisp.routeRequest(request, socket, head);
|
||||
return;
|
||||
}
|
||||
wss.handleUpgrade(request, socket, head, (socket) => {
|
||||
wss.emit("connection", socket, request);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user