Files
fluff/index.js
2026-01-08 15:21:15 +01:00

173 lines
5.5 KiB
JavaScript

const crypto = require("node:crypto");
const fs = require("node:fs");
const os = require("node:os");
const cookieparser = require("cookie-parser");
const sqlite = require("better-sqlite3");
const geoip = require("geoip-country");
const express = require("express");
const bcrypt = require("bcrypt");
const database = sqlite("./database.db");
const app = express();
const panelgenesis = fs.readFileSync("./files/panelgenesis.html", "utf8");
const panelending = fs.readFileSync("./files/panelending.html", "utf8");
const loginp2 = fs.readFileSync("./files/loginp2.html", "utf8");
const invalidp2 = fs.readFileSync("./files/invalidp2.html", "utf8");
const hmacsecret = Buffer.from(fs.readFileSync("./hmacsecret", "utf8"), "base64url");
const queryA = database.prepare("SELECT identifier, quote FROM fluff_authentication_base WHERE identifier = ?;");
const queryB = database.prepare("SELECT id, passhash FROM fluff_authentication_base WHERE identifier = ?;");
const queryC = database.prepare("SELECT * FROM fluff_authentication_base WHERE id = ?;");
const queryD = database.prepare("SELECT serviceId FROM fluff_authorised_services WHERE userId = ?;");
const queryE = database.prepare("SELECT * FROM fluff_services WHERE id = ?;");
function sha384(data) {
return crypto.createHash("sha384").update(data).digest("base64url");
}
function hmacify(data) {
return sha384(`${sha384(data)}${sha384(hmacsecret)}`);
}
function genToken(userId) {
const prepend = `${userId}.${Date.now()+3_600_000}.${crypto.randomBytes(16).toString("base64url")}`;
const signature = hmacify(prepend);
return `${prepend}.${signature}`;
}
function verifyToken(token) {
if (typeof token !== "string") return false;
const split = token.split(".");
const bib = `${split[0]}.${split[1]}.${split[2]}`;
const sig = split[3];
if (hmacify(bib) !== sig)
return false;
const expiration = parseInt(split[1]);
if (Date.now() > expiration) {
return false;
}
return split[0];
}
function sanitiseStringHTML(str) {
return str.replaceAll("&", "&amp;").replaceAll(">", "&gt;").replaceAll("<", "&lt;");
}
app.use(express.urlencoded());
app.use(cookieparser());
app.use((req, res, next) => {
console.log(req.headers);
if (typeof req.headers['referer'] !== "string") return next();
const pars = new URL(req.headers['referer']);
console.log(pars.hostname);
if (pars.hostname !== "desloratadyna.net") {
res.status(403);
res.end();
return;
}
next();
});
app.use((req, res, next) => {
req.userId = verifyToken(req.cookies.token);
if (!req.headers['x-forwarded-for']) return next();
const geo = geoip.lookup(req.headers['x-forwarded-for']);
console.log(geo);
if (geo.country !== "US")
if (geo.country !== "UA")
if (geo.country !== "PL") {
const stream = fs.createReadStream("./files/disallowed.html");
res.status(451);
res.setHeader("Content-Type", "text/html");
stream.pipe(res);
return;
}
next();
});
app.get("/cgi-bin/loginp1.js", async (req, res, next) => {
const stream = fs.createReadStream("./files/login.html");
res.setHeader("Content-Type", "text/html");
stream.pipe(res);
});
app.post("/cgi-bin/loginp2.js", async (req, res, next) => {
const funkyData = queryA.all(req.body.identifier);
if (funkyData.length !== 1) {
const pisstream = fs.createReadStream("./files/invalidp1.html");
res.setHeader("Content-Type", "text/html");
pisstream.pipe(res);
return;
}
if (req.body.invalid === "true") {
res.setHeader("Content-Type", "text/html");
res.write(invalidp2.replaceAll("PYRAPYRAPYRAPYRA").replaceAll("PYRIPYRIPYRIPYRI", funkyData[0].quote));
res.end();
return;
}
res.setHeader("Content-Type", "text/html");
res.write(loginp2.replaceAll("PYRAPYRAPYRAPYRA", req.body.identifier).replaceAll("PYRIPYRIPYRIPYRI", funkyData[0].quote));
res.end();
});
app.post("/cgi-bin/loginp3.js", async (req, res, next) => {
const funnyData = queryB.get(req.body.identifier);
const hashd = sha384(req.body.password);
res.setHeader("Content-type", "text/html");
const valid = await bcrypt.compare(hashd, funnyData.passhash);
if (!valid) {
res.redirect("/cgi-bin/loginp2.js?invalid=true&identifier="+encodeURIComponent(req.body.identifier));
return;
}
console.log(funnyData.id);
res.cookie("token", genToken(funnyData.id), { maxAge: 1 * 1 * 60 * 60 * 1000, sameSite: 'strict' });
res.redirect("/cgi-bin/primarypage");
});
app.get("/cgi-bin/primarypage", async (req, res, next) => {
if (req.userId === false) return res.redirect("/");
const userData = queryC.get(req.userId);
const serviceData = queryD.all(req.userId);
console.log(userData);
res.setHeader("content-type", "text/html");
res.write(panelgenesis);
res.write(`<p id="hello">haihoo, ${userData.identifier}</p>`);
res.write("<table border=1 cellpadding=5 cellspacing=0><tbody><tr><th>name</th><th width=\"400px\">description</th><th>actions</th></tr>");
for (let i = 0; i < serviceData.length; i++) {
const service = queryE.get(serviceData[i].serviceId);
res.write(`<tr><td>${sanitiseStringHTML(service.displayName)}</td><td>${sanitiseStringHTML(service.shortDescription)}</td><td>`);
res.write(`<a href="//desloratadyna.net/cgi-bin/unauthorise/${serviceData[i].serviceId}">unauthorise service</a><br>`);
res.write(`<a href="${encodeURI(service.tosLink)}">terms of service</a><br>`);
res.write(`<a href="${encodeURI(service.ppLink)}">privacy policy</a><br>`);
res.write('</td></tr>');
}
res.write("</tbody></table>");
res.write(`<br><p id="tiny">Generated just for you, by ${os.hostname()}<br>${new Date()}</p>`);
res.write(panelending);
res.end();
});
// haha 420
app.listen(42420);