Files
backend/index.js
2025-07-09 02:35:38 -04:00

357 lines
10 KiB
JavaScript
Executable File

import { log } from "./log.js";
import bodyParser from "body-parser";
import express from "express";
import cookieParser from "cookie-parser";
import fs from "node:fs/promises";
import { fileURLToPath } from "url";
import path, { dirname } from "node:path";
import mime from "mime-types";
import compression from "compression";
import { accs, infdb, polytrack } from "./database.js";
import { } from "./accounts/friend.js";
import { search, download } from "./accounts/music.js";
import { banUser, removeAccount, verifyCookie, getUserFromCookie, createAccount, resetPassword, loginAccount, addBadge } from "./accounts/manage.js";
import { } from "./accounts/misc.js";
import { getRawData, generateAccountPage, editProfile, saveData, getUsers, isAdmin, retrieveData } from "./accounts/profile.js";
// import { infiniteCraft, chatBot } from "./ai.js";
import os from "node:os";
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const port = process.env.PORT || 3000;
const app = express();
app.use(compression());
app.use(cookieParser());
app.use(express.json({ limit: "10mb" }));
app.use(express.urlencoded({ extended: false }));
app.use(express.text());
app.use("/", (req, res, next) => {
next();
});
// setInterval(()=>{
// }, 1000)
import WebSocket, { WebSocketServer } from "ws";
const wss = new WebSocketServer({ noServer: true });
let openSockets = 0;
wss.on("connection", function connection(ws, req, res) {
openSockets++;
setInterval(() => {
ws.send("ping");
}, 30000);
ws.on("error", console.error);
ws.on("message", async function message(data, isBinary) {
let message = Buffer.from(data).toString();
if (message.startsWith(process.env.ANNOUNCEMENT_KEY)) {
wss.clients.forEach(function each(client) {
if (client.readyState === WebSocket.OPEN) {
client.send(message.replace(process.env.ANNOUNCEMENT_KEY, "announce."));
}
});
} else if (message.startsWith("token") && (await verifyCookie(message.substring(6)))) {
ws.id = await getUserFromCookie(message.substring(6));
ws.send(ws.id);
const updateAccount = accs.query(`UPDATE accounts SET last_login = $login WHERE username = $user`)
updateAccount.get({ $login: new Date().toUTCString(), $user: ws.id });
} else if (message.startsWith("pong")) {
if (ws.id) {
const updateAccount = accs.query(`UPDATE accounts SET last_login = $login WHERE username = $user`)
updateAccount.get({ $login: new Date().toUTCString(), $user: ws.id });
}
}
});
ws.on("close", () => {openSockets--;});
});
app.post(
"/api/event",
(req, res) => {
fetch("https://analytics.skysthelimit.dev/api/event", {
method: "post",
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: req.body
}).then(async (response) => {
res.send(response.status);
})
}
);
app.post("/register", async (req, res) => {
let status = await createAccount(req.body.username, req.body.password, req.body["h-captcha-response"]);
if (status["success"]) {
res.status(200).send(status);
} else {
res.status(400).send(status);
}
});
app.post("/login", async (req, res) => {
let status = await loginAccount(req.body.username, req.body.password, req.body["h-captcha-response"]);
if (status["success"]) {
res.status(200).send(status);
} else {
res.status(400).send(status);
}
});
app.use(["/register", "/login"], async (req, res, next) => {
if (req.cookies.token && (await verifyCookie(req.cookies.token))) {
res.redirect("/u/");
} else {
res
.type("text/html")
.status(200)
.send(await fs.readFile(`./html${req.baseUrl}.html`));
}
});
app.use("/users", async (req, res, next) => {
res
.type("text/html")
.status(200)
.send(await fs.readFile(`./html/users.html`));
});
app.use("/reset", async (req, res, next) => {
res
.type("text/html")
.status(200)
.send(await fs.readFile(`./html/reset.html`));
});
app.post("/api/account/upload", async (req, res, next) => {
if (req.cookies.token && (await verifyCookie(req.cookies.token))) {
let status = await saveData(req.cookies.token, req.body.data);
if (status["success"]) {
res.status(200).send(status);
} else {
res.status(400).send(status);
}
} else {
return "KILL YOURSELF";
}
});
// ai endpoints
app.post("/api/ai/createChat", async (req, res) => {
// create chat in database and store some metadata about it
// ie: last model, time created, etc etc
})
app.post("/api/ai/sendMessage", async (req, res) => {
// take in chat id and message
// stream back reply
})
app.get("/api/ai/messages", async (req, res) => {
// take in chat id
// use unique uuid to store every chat
// return messages
})
// friends endpoints
app.get("/api/friends/list", async (req, res) => {
// use auth token to get user
// just return array of user infos
})
app.get("/api/friends/requests", async (req, res) => {
// view friend requests
})
app.post("/api/friends/sendRequest", async (req, res) => {
// takes in user
// send friend request
})
app.post("/api/friends/reply", async (req, res) => {
// accepted? true or false
})
// chat endpoints
app.post("/api/chat/create", async (req, res) => {
// create a new chat
// create one for new friends maybe?
// generates metadata
// time created, last message sent, people in the chat, id, owner
})
app.post("/api/chat/send", async (req, res) => {
// send chat message
// id, auth, message
})
app.post("/api/chat/addUser", async (req, res) => {
// add user to chat
})
app.post("/api/chat/removeUser", async (req, res) => {
// remove user from chat
})
app.get("/api/chat/recent", async (req, res) => {
// get last 50 recent messages
// offset by a page param
})
app.use("/api/account/load", async (req, res, next) => {
if (req.cookies.token && (await verifyCookie(req.cookies.token))) {
let status = await retrieveData(req.cookies.token);
if (status["success"]) {
res.status(200).send(status);
} else {
res.status(400).send(status);
}
} else {
res.status(200).send("No token");
}
});
app.use("/api/getUsers", async (req, res, next) => {
console.log(req.query)
let status = await getUsers(req.query.page, req.query.query);
res.status(200).send(status);
});
app.use("/admin", async (req, res, next) => {
if ((await isAdmin(req.cookies.token)) && (await verifyCookie(req.cookies.token))) {
res
.type("text/html")
.status(200)
.send(await fs.readFile(`./html/admin.html`));
} else {
next();
}
});
app.use("/api/stats", async (req, res, next) => {
if ((await isAdmin(req.cookies.token)) && (await verifyCookie(req.cookies.token))) {
res
.type("text/json")
.status(200)
.send({
"users": accs.query(`SELECT COUNT(*) FROM accounts`).get()["COUNT(*)"],
// "cpu": os.cpus(),
"ram": `${(os.totalmem()-os.freemem())/1000000000}GB / ${os.totalmem()/1000000000}GB`,
"cpuUsage": os.loadavg(),
"openWebSockets": openSockets,
"uptime": `${os.uptime()}s`
});
} else {
next();
}
});
app.use("/ai", async (req, res, next) => {
if (await verifyCookie(req.cookies.token) && isAdmin(req.cookies.token)) {
res
.type("text/html")
.status(200)
.send(await fs.readFile(`./html/ai.html`));
} else {
next();
}
});
app.use("/", express.static("./public", { extensions: ["html"] }));
app.use("/data/:id/:file", async (req, res) => {
const id = path.basename(req.params.id);
const file = path.basename(req.params.file);
const filePath = path.join(process.env.DATA_PATH, "data", id, file);
try {
await fs.access(filePath);
const image = await fs.readFile(filePath);
if (mime.lookup(filePath) == "image/webp") {
res.type("image/webp");
res.status(200).send(image);
} else if (mime.lookup(filePath) == "audio/ogg") {
res.type("audio/ogg");
res.status(200).send(image);
} else {
res.status(404).send("File not found");
}
} catch (error) {
console.error(error);
res.status(404).send("File not found");
}
});
app.use("/u/raw", async (req, res) => {
if (req.cookies.token && (await verifyCookie(req.cookies.token))) {
res.send(await getRawData(req.cookies.token));
} else {
res.redirect("/register");
}
});
app.use("/u/:username/edit", async (req, res, next) => {
if (await isAdmin(req.cookies.token)) {
res.send(await generateAccountPage(req.params.username, req.cookies.token, true));
return;
}
next();
});
app.use("/u/:username", async (req, res) => {
if (["skysthelimit.dev", "selenite.cc", "selenite", "owner"].includes(req.params.username)) {
res.redirect("/u/sky");
return;
}
res.send(await generateAccountPage(req.params.username, req.cookies.token));
});
app.use("/u/", async (req, res) => {
if (req.cookies.token && (await verifyCookie(req.cookies.token))) {
res.send(await generateAccountPage(req.params.username, req.cookies.token));
} else {
res.redirect("/register");
}
});
app.post("/api/account/reset", async (req, res) => {
let status = await resetPassword(req.body.username, req.body.key, req.body.password, req.body["h-captcha-response"]);
if (status["success"]) {
res.status(200).send(status);
} else {
res.status(400).send(status);
}
});
app.post("/api/profile/edit", async (req, res) => {
let status = await editProfile(req.body, req.cookies.token, false);
if (status["success"]) {
res.status(200).send(status);
} else {
res.status(400).send(status);
}
});
app.post("/api/admin/badge", async (req, res) => {
let status = await addBadge(req.body.username, req.body.badge, req.cookies.token);
if (status["success"]) {
res.status(200).send(status);
} else {
res.status(400).send(status);
}
});
app.post("/api/admin/removeAcc", async (req, res) => {
let status = await removeAccount(req.body.username, req.cookies.token);
res.status(200).send(status);
});
app.post("/api/admin/removeAcc", async (req, res) => {
let status = await editProfile(req.body, req.cookies.token, true);
res.status(200).send(status);
});
app.post("/api/admin/ban", async (req, res) => {
let status = await banUser(req.body.name, req.body.reason, req.cookies.token);
res.status(200).send(status);
});
app.use("/api/music/search", async (req, res, next) => {
res.status(200).send(await search(req.query.q))
});
const server = app.listen(port, () => {
console.log(log.success("Express is online."));
console.log("- " + log.info("http://localhost:" + port));
});
server.on("upgrade", (request, socket, head) => {
wss.handleUpgrade(request, socket, head, (socket) => {
wss.emit("connection", socket, request);
});
});
app.use(async (req, res) => {
res
.type("text/html")
.send(await fs.readFile(`./public/404.html`))
.status(404);
});