This repository has been archived on 2023-05-12. You can view files and clone it, but cannot push or open issues or pull requests.
media-host/server.js
2023-02-27 23:56:37 -05:00

1905 lines
63 KiB
JavaScript

const express = require("express");
const app = express();
const cookieParser = require("cookie-parser");
const cors = require("cors");
const config = require("./config.json");
const utils = require("./utils.js");
const zxcvbn = require("zxcvbn");
const bcrypt = require("bcrypt");
const du = require("du");
const ffmpegStatic = require("ffmpeg-static");
const {spawn} = require("child_process");
const formidable = require("formidable");
const {MongoClient} = require("mongodb");
const client = new MongoClient(config["db-url"], {useUnifiedTopology: true});
const fs = require("fs");
const hcaptcha = require("hcaptcha");
const sd = require("showdown");
const mk = new sd.Converter();
const istor = require("is-tor");
if (!config["media-folder"].startsWith("/")) config["media-folder"] = `${__dirname}/${config["media-folder"]}`;
if (config?.["remux"]?.["folder"] && !config?.["remux"]?.["folder"].startsWith("/")) config["remux"]["folder"] = `${__dirname}/${config?.["remux"]?.["folder"]}`;
app.set("view engine", "ejs");
app.use(cookieParser());
app.use(cors());
app.use(express.static("static/"));
if (config?.["remux"]?.["folder"]) app.use("/transcoded/", express.static(config?.["remux"]?.["folder"]));
app.use("/temp", express.static(`temp/`));
app.use(async function(req, res, next) {
let db = client.db("mediahost");
let blocks = db.collection("blockedIPs");
let userIp = (req.headers["X-Real-IP"] || req.headers["x-real-ip"] || req.ip);
let ip = await blocks.findOne({ip: userIp});
if (ip == null) next();
else {
let isBlocked = utils.isBlockedHere(ip.status, req.path);
if (!ip?.status) ip.status = "*";
if (!ip?.reason) ip.reason = "of your continued abuse of our website";
if (isBlocked) {
res.render("pages/blocked", {config: config, account: null, status: utils.toBlockedStatus(ip.status), reason: ip.reason, ip: ip.ip});
return;
} else next();
}
});
app.use("/f/:id/raw", async function(req, res, next) {
try {
let id = req.params.id;
let loc = `${config["media-folder"]}${id}/${fs.readdirSync(`${config["media-folder"]}${id}`)[0]}`;
if (fs.existsSync(loc)) {
let db = client.db("mediahost");
let file = await (await db.collection("uploads")).findOne({id: id});
if (file.mime.startsWith("text/")) res.setHeader("content-type", "text/plain");
if (file.mime.startsWith("image/svg")) res.setHeader("content-disposition", `attachment; filename="${fs.readdirSync(`${config["media-folder"]}${id}`)[0]}"`);
res.sendFile(loc);
} else {
next();
}
} catch(err) {
next();
}
});
app.use("/f/:id/dl", function(req, res, next) {
try {
let id = req.params.id;
let loc = `${config["media-folder"]}${id}/${fs.readdirSync(`${config["media-folder"]}${id}`)[0]}`;
if (fs.existsSync(loc)) {
res.setHeader("content-disposition", `attachment; filename="${fs.readdirSync(`${config["media-folder"]}${id}`)[0]}"`);
res.sendFile(loc);
} else {
next();
}
} catch(err) {
next();
}
});
if (!fs.existsSync(config["media-folder"])) fs.mkdirSync(config["media-folder"])
if (!fs.existsSync(config?.["remux"]?.["folder"])) fs.mkdirSync(config?.["remux"]?.["folder"])
start();
app.get("/", async function (req, res, next) {
let db = client.db("mediahost");
let acc;
if (req.cookies["session"]) {
let accs = await db.collection("accounts");
acc = await accs.findOne({session: req.cookies["session"]});
}
let uploads = await (await (await db.collection("uploads").find({})).toArray()).length;
let size = utils.humanSize((await du(config["media-folder"])));
res.render("pages/home", {config: config, account: acc, message: utils.toMessage(req.query["from"]), fileCount: uploads, fileSize: size});
});
app.get("/register", async function (req, res, next) {
if (config["reject-tor"]) {
if (req.headers["x-real-ip"] || req.headers["X-Real-IP"] || req.ip) {
let ip = (req.headers["X-Real-IP"] || req.headers["x-real-ip"] || req.ip);
try {
let tor = istor(ip);
if (tor == true) {
res.render("pages/not-allowed", {config: config, account: acc});
return;
}
} catch(err) {
if (!err.message.includes("The given IP")) throw err;
}
} else console.log(`ERR! IP not found.`);
}
let acc;
if (req.cookies["session"]) {
let db = client.db("mediahost");
let accs = await db.collection("accounts");
acc = await accs.findOne({session: req.cookies["session"]});
}
if (acc == null && config["allow-signup"] == true) {
res.render("pages/register", {config: config, account: acc});
} else {
res.render("pages/not-allowed", {config: config, account: acc})
}
});
app.post("/register", async function (req, res, next) {
if (config["reject-tor"]) {
if (req.headers["x-real-ip"] || req.headers["X-Real-IP"] || req.ip) {
let ip = (req.headers["X-Real-IP"] || req.headers["x-real-ip"] || req.ip);
try {
let tor = istor(ip);
if (tor == true) {
res.render("pages/not-allowed", {config: config, account: acc});
return;
}
} catch(err) {
if (!err.message.includes("The given IP")) throw err;
}
} else console.log(`ERR! IP not found.`);
}
const form = formidable();
let db = client.db("mediahost");
let collection = await db.collection("accounts");
let acc;
if (req.cookies["session"]) {
let db = client.db("mediahost");
let accs = await db.collection("accounts");
acc = await accs.findOne({session: req.cookies["session"]});
}
if (config["allow-signup"] == false || acc !== null && acc !== undefined) {
res.render("pages/not-allowed", {config: config, account: acc});
return;
}
form.parse(req, async function(err, fields, files) {
if (err) {
res.render("pages/register", {config: config, err: err});
} else {
if (fields.username && fields.password) {
if (config["captcha"]["enabled"] == true && config["captcha"]["show-at-signup"]) {
if (!fields["h-captcha-response"]) {
res.render("pages/register", {config: config, err: "CAPTCHA needs to be solved."});
return;
} else {
let h = await hcaptcha.verify(config["captcha"]["secret"], fields["h-captcha-response"]);
if (!h.success) {
res.render("pages/register", {config: config, err: "CAPTCHA came back invalid."});
return;
}
}
}
let zx = zxcvbn(fields.password);
if (zx.score >= 2.5) {
let p = bcrypt.hashSync(fields.password, 10);
let a = await collection.findOne({username: fields.username});
if (a !== null && fields.username !== "Anonymous") {
res.render("pages/register", {config: config, err: "Account already exists with that username."});
} else {
if (utils.validateUsername(fields.username)) {
let n = await collection.insertOne({username: fields.username, password: p, id: utils.generateString(10)});
if (n.acknowledged == true) {
res.redirect("/login?from=register");
} else {
res.render("pages/register", {config: config, err: "Insertion of account into MongoDB failed."});
}
} else {
res.render("pages/register", {config: config, err: "Invalid username, please try a different one."});
}
}
} else {
res.render("pages/register", {config: config, err: "The password scored below 2.5 on zxcvbn. Give a better password."});
}
} else {
res.render("pages/register", {config: config, err: "A username and password is required to register."});
}
}
});
});
app.get("/signup-with-code", async function (req, res, next) {
if (config["reject-tor"]) {
if (req.headers["x-real-ip"] || req.headers["X-Real-IP"] || req.ip) {
let ip = (req.headers["X-Real-IP"] || req.headers["x-real-ip"] || req.ip);
try {
let tor = istor(ip);
if (tor == true) {
res.render("pages/not-allowed", {config: config, account: acc});
return;
}
} catch(err) {
if (!err.message.includes("The given IP")) throw err;
}
} else console.log(`ERR! IP not found.`);
}
let acc;
if (req.cookies["session"]) {
let db = client.db("mediahost");
let accs = await db.collection("accounts");
acc = await accs.findOne({session: req.cookies["session"]});
}
res.render("pages/signup-code", {config: config, account: acc, code: req.query.code});
});
app.post("/signup-with-code", async function (req, res, next) {
if (config["reject-tor"]) {
if (req.headers["x-real-ip"] || req.headers["X-Real-IP"] || req.ip) {
let ip = (req.headers["X-Real-IP"] || req.headers["x-real-ip"] || req.ip);
try {
let tor = istor(ip);
if (tor == true) {
res.render("pages/not-allowed", {config: config, account: acc});
return;
}
} catch(err) {
if (!err.message.includes("The given IP")) throw err;
}
} else console.log(`ERR! IP not found.`);
}
const form = formidable();
let db = client.db("mediahost");
let acc;
if (req.cookies["session"]) {
let db = client.db("mediahost");
let accs = await db.collection("accounts");
acc = await accs.findOne({session: req.cookies["session"]});
}
let collection = await db.collection("accounts");
let signup = await db.collection("codes");
form.parse(req, async function(err, fields) {
if (err) {
res.render("pages/signup-code", {config: config, err: err, code: req.query.code});
} else {
if (fields.username && fields.password && fields["signup-code"]) {
if (config["captcha"]["enabled"] == true && config["captcha"]["show-at-signup"]) {
if (!fields["h-captcha-response"]) {
res.render("pages/signup-code", {config: config, err: "CAPTCHA needs to be solved.", code: req.query.code, account: acc});
return;
} else {
let h = await hcaptcha.verify(config["captcha"]["secret"], fields["h-captcha-response"]);
if (!h.success) {
res.render("pages/signup-code", {config: config, err: "CAPTCHA came back invalid.", code: req.query.code, account: acc});
return;
}
}
}
let zx = zxcvbn(fields.password);
if (zx.score >= 2.5) {
let p = bcrypt.hashSync(fields.password, 10);
let a = await collection.findOne({username: fields.username});
if (a !== null && fields.username !== "Anonymous") {
res.render("pages/signup-code", {config: config, err: "Account already exists with that username.", code: req.query.code, account: acc});
} else {
let code = await signup.findOne({code: fields["signup-code"]});
if (code == null) {
res.render("pages/signup-code", {config: config, err: "Signup code is invalid.", account: acc});
} else {
if (utils.validateUsername(fields.username)) {
let t1 = await collection.insertOne({username: fields.username, password: p, id: utils.generateString(10)});
if (t1.acknowledged == true) {
await signup.findOneAndDelete({code: fields["signup-code"]});
res.redirect("/login?from=register");
} else {
res.render("pages/signup-code", {config: config, err: "Insertion of the new account into MongoDB database have failed.", account: acc});
}
} else {
res.render("pages/signup-code", {config: config, err: "Invalid username, please try a different one."});
}
}
}
} else {
res.render("pages/signup-code", {config: config, err: "The password scored below 2.5 on zxcvbn. Give a better password.", code: req.query.code, account: acc});
}
} else {
res.render("pages/signup-code", {config: config, err: "A signup code, username, and password is required to register.", code: req.query.code, account: acc});
}
}
});
})
app.get("/login", async function (req, res, next) {
let acc;
if (req.cookies["session"]) {
let db = client.db("mediahost");
let accs = await db.collection("accounts");
acc = await accs.findOne({session: req.cookies["session"]});
}
if (acc == null && req.cookies["session"]) res.clearCookie("session");
if (acc == null) {
res.render("pages/login", {config: config, account: acc, message: utils.toMessage(req.query["from"])});
} else {
res.redirect("/");
}
});
app.get("/logout", async function (req, res, next) {
if (req.cookies["session"]) res.clearCookie("session");
if (req.headers["referer"]) {
res.redirect(req.headers["referer"]);
} else {
res.redirect("/");
}
});
app.post("/login", function(req, res, next) {
if (req.cookies["session"]) {
res.clearCookie("session");
res.redirect("/login");
} else {
const form = formidable();
form.parse(req, async function(err, fields) {
if (err) {
res.render("pages/login", {config: config, err: err});
} else {
if (fields.username && fields.password) {
if (config["captcha"]["enabled"] == true && config["captcha"]["show-at-login"]) {
if (!fields["h-captcha-response"]) {
res.render("pages/login", {config: config, err: "CAPTCHA needs to be solved.", message: null});
return;
} else {
let h = await hcaptcha.verify(config["captcha"]["secret"], fields["h-captcha-response"]);
if (!h.success) {
res.render("pages/login", {config: config, err: "CAPTCHA came back invalid.", message: null});
return;
}
}
}
let db = client.db("mediahost");
let collection = await db.collection("accounts");
let a = await collection.findOne({username: fields.username});
if (a == null) {
res.render("pages/login", {config: config, err: "Username doesn't exist in our database.", message: null});
} else {
let c = bcrypt.compareSync(fields.password, a.password);
if (c == true) {
if (!a.session) {
let s = utils.generateString(50)
let acc = a;
acc.session = s;
res.cookie("session", s);
await collection.findOneAndReplace({_id: a._id}, acc);
res.redirect("/");
} else {
res.cookie("session", a.session);
res.redirect("/");
}
} else {
res.render("pages/login", {config: config, err: "Password is incorrect.", message: null});
}
}
} else {
res.render("pages/login", {config: config, err: "A username and password is required to login.", message: null});
}
}
});
}
});
app.get("/dummy", function(req, res, next) {
res.send({marco: "polo"});
});
app.get("/upload", async function (req, res, next) {
let acc;
if (req.cookies["session"]) {
let db = client.db("mediahost");
let accs = await db.collection("accounts");
acc = await accs.findOne({session: req.cookies["session"]});
}
if (acc == null && req.cookies["session"]) res.clearCookie("session");
if (config["allow-anon-uploads"] == false && acc == null) {
res.render("pages/not-allowed", {config: config, account: acc});
} else {
if (acc == null) {
if (config["reject-tor"]) {
if (req.headers["x-real-ip"] || req.headers["X-Real-IP"] || req.ip) {
let ip = (req.headers["X-Real-IP"] || req.headers["x-real-ip"] || req.ip);
try {
let tor = istor(ip);
if (tor == true) {
res.render("pages/not-allowed", {config: config, account: acc});
return;
}
} catch(err) {
if (!err.message.includes("The given IP")) throw err;
}
} else console.log(`ERR! IP not found.`);
}
}
if (acc == null && config["max-anon-file-size"] !== 0) res.render("pages/upload", {config: config, account: acc, maxsize: utils.humanSize(config["max-anon-file-size"])});
else res.render("pages/upload", {config: config, account: acc, maxsize: utils.humanSize(config["max-file-size"])});
}
});
app.post("/upload", async function (req, res, next) {
let acc;
if (req.cookies["session"]) {
let db = client.db("mediahost");
let accs = await db.collection("accounts");
acc = await accs.findOne({session: req.cookies["session"]});
}
let form;
if (acc == null && config["max-anon-file-size"] !== 0) {
form = formidable({maxFileSize: config["max-anon-file-size"], allowEmptyFiles: false, multiples: true});
} else {
form = formidable({maxFileSize: config["max-file-size"], allowEmptyFiles: false, multiples: true});
}
if (acc == null && req.cookies["session"]) res.clearCookie("session");
if (!config["allow-anon-uploads"] && acc == null) {
if (req.query["json"] !== "1") res.render("pages/not-allowed", {config: config, account: null});
else {
res.send({
success: false,
err: "Anonymous uploads are not allowed on this instance."
})
}
return;
}
form.parse(req, async function(err, fields, files) {
if (err) {
let error;
if (err.httpCode && !err.message) error = `HTTP Error Code ${err.httpCode}`;
else error = (err.message || err);
if (req.query["json"] !== "1") res.render("pages/upload", {config: config, err: error, maxsize: utils.humanSize(config["max-file-size"]), account: acc});
else {
res.send({
success: false,
err: error
});
}
} else {
if (!files.file) {
if (req.query["json"] !== "1") res.render("pages/upload", {config: config, account: acc, err: "File was empty.", maxsize: utils.humanSize(config["max-file-size"])});
else {
res.send({
success: false,
err: "File was empty."
});
}
} else {
try {
let id = utils.generateString(5);
//console.log(`[media-host] Uploaded file to "${id}".`);
fs.mkdirSync(`${config["media-folder"]}${id}/`);
fs.copyFileSync(files.file.filepath, `${config["media-folder"]}${id}/${files.file.originalFilename}`);
let db = client.db("mediahost");
let col = await db.collection("uploads");
let type = utils.getType(files.file.mimetype);
let data = {
id,
direct: `/f/${id}/raw`,
name: files.file.originalFilename,
type,
size: fs.statSync(`${config["media-folder"]}${id}/${files.file.originalFilename}`).size,
humanSize: utils.humanSize(fs.statSync(`${config["media-folder"]}${id}/${files.file.originalFilename}`).size),
date: new Date().toISOString(),
privacy: (parseInt(fields.privacy) || 0),
mime: files.file.mimetype,
};
if (data.mime.startsWith("video/") && data.mime != "video/mp4" && data.mime != "video/webm") data.needsTranscode = true;
if (acc !== null && acc !== undefined) {
data.uploader = acc._id;
data.approved = true;
} else {
data.uploader = "Anonymous";
if (config["captcha"]["show-at-anon-upload"] == true) data.approved = false;
else data.approved = true;
}
if (data.uploader == "Anonymous" && config["captcha"]["enabled"] && config["captcha"]["show-at-anon-upload"] == true) {
col.insertOne(data);
if (data.uploader == "Anonymous" && config["store-anon-ips"] == true) {
data["ip"] = (req.headers["x-real-ip"] || req.headers["X-Real-IP"] || req.ip);
}
res.send({
success: true,
requireCaptcha: true,
data
});
setTimeout(async function() {
let file = await col.findOne({id});
if (file.approved == false) await removeUpload(id);
}, 300000);
if (data.needsTranscode == true) initTranscode(id, data.mime);
return;
}
if (data.uploader == "Anonymous" && config["store-anon-ips"] == true) {
data["ip"] = (req.headers["x-real-ip"] || req.headers["X-Real-IP"] || req.ip);
}
col.insertOne(data);
if (req.query["json"] !== "1") {
res.redirect(`/f/${id}`);
} else {
res.send({
success: true,
requireCaptcha: false,
data
});
}
if (data.needsTranscode == true) initTranscode(id, data.mime);
} catch(e) {
res.send({
success: false,
error: (e.stack || e.message || e.code || e)
})
}
}
}
});
});
app.post("/f/:id/confirm", async function(req, res) {
let form = formidable();
form.parse(req, async function(err, fields) {
if (err) {
let error;
if (err.httpCode && !err.message) error = `HTTP Error Code ${err.httpCode}`;
else error = (err.message || err);
res.send({
success: false,
err: error
});
return;
}
if (fields["h-captcha-response"]) {
let {success} = await hcaptcha.verify(config.captcha.secret, fields["h-captcha-response"]);
if (success) {
let db = client.db("mediahost");
let files = await db.collection("uploads");
let file = await files.findOne({id: req.params.id});
if (file.approved == false) {
file.approved = true;
await files.findOneAndReplace({id: req.params.id}, file);
res.send({
success: true
});
} else {
res.send({
success: false,
err: "File already approved."
});
}
} else {
res.send({
success: false,
err: "Invalid CAPTCHA."
});
}
} else {
res.send({
success: false,
err: "Invalid CAPTCHA."
});
}
})
});
app.get("/f/:id", async function (req, res, next) {
let acc;
let db = client.db("mediahost");
let accs = await db.collection("accounts");
if (req.cookies["session"]) {
acc = await accs.findOne({session: req.cookies["session"]});
}
if (acc == null && req.cookies["session"]) res.clearCookie("session");
let files = await db.collection("uploads");
let file = await files.findOne({id: req.params.id});
if (file == null) next();
else {
let fn = (file.name || file.direct.split("/")[file.direct.split("/").length - 1]);
let accName = (await accs.findOne({_id: file.uploader}));
if (accName == null) {
accName = "Anonymous";
} else {
accName = accName.username;
}
if (file.type !== "video" && file.type !== "audio" && file.type !== "image" && file.type !== "text") {
file.type = "generic";
await files.findOneAndReplace({id: req.params.id}, file);
}
if (file.direct.length !== 12) {
file.direct = `/f/${file.id}/raw`;
await files.findOneAndReplace({id: req.params.id}, file);
}
let ds = {
account: acc,
file: file,
config: config,
isOwned: isOwned(file, acc),
name: fn,
uploaderName: accName
};
if (file.type == "text") {
if (fs.existsSync(`${config["media-folder"]}${file.id}/${file.name}`)) {
ds.raw = (fs.readFileSync(`${config["media-folder"]}${file.id}/${file.name}`)?.toString() || "null");
} else {
ds.raw = "null";
}
}
res.render(`pages/file-types/${file.type}`, ds);
}
});
app.get("/d/:id", async function(req, res, next) {
res.redirect(`/f/${req.params.id}/delete`);
});
app.get("/f/:id/delete", async function (req, res, next) {
let acc;
let db = client.db("mediahost");
let accs = await db.collection("accounts");
if (req.cookies["session"]) {
acc = await accs.findOne({session: req.cookies["session"]});
}
if (acc == null && req.cookies["session"]) res.clearCookie("session");
let files = await db.collection("uploads");
let file = await files.findOne({id: req.params.id});
if (file == null || acc == null) {
res.redirect("/");
} else {
let owned = isOwned(file, acc);
if (owned == false) {
res.redirect("/?from=no-permission");
} else {
res.render("pages/delete-file", {account: acc, config: config});
}
}
});
app.post("/f/:id/delete", async function (req, res, next) {
let acc;
let db = client.db("mediahost");
let accs = await db.collection("accounts");
if (req.cookies["session"]) {
acc = await accs.findOne({session: req.cookies["session"]});
}
if (acc == null && req.cookies["session"]) res.clearCookie("session");
let files = await db.collection("uploads");
let file = await files.findOne({id: req.params.id});
if (file == null || acc == null) res.redirect("/?from=rejected-delete");
else {
if (fs.existsSync(`${config["media-folder"]}${file.id}`)) fs.rmSync(`${config["media-folder"]}${file.id}`, {recursive: true});
await files.findOneAndDelete({id: file.id});
let reports = db.collection("reports");
let reportList = await reports.find({upload: req.params.id}).toArray();
for (let a in reportList) {
let update = reportList[a];
delete update._id;
update.unread = false;
update.systemNotice = "Automatically marked as read, due to the file's deletion.";
await reports.findOneAndReplace({id: reportList[a].id}, update);
}
res.redirect("/?from=deleted-file");
}
});
app.get("/rn/:id", function (req, res, next) {
res.redirect(`/f/${req.params.id}/rename`);
});
app.get("/f/:id/rename", async function(req, res, next) {
let acc;
let db = client.db("mediahost");
let accs = await db.collection("accounts");
if (req.cookies["session"]) {
acc = await accs.findOne({session: req.cookies["session"]});
}
if (acc == null && req.cookies["session"]) res.clearCookie("session");
let files = await db.collection("uploads");
let file = await files.findOne({id: req.params.id});
if (file == null || acc == null) next()
else {
let s = isOwned(file, acc);
if (s == false) {
res.redirect("/");
} else {
res.render("pages/rename-file", {account: acc, config: config, fn: file.name, err: null});
}
}
});
app.post("/f/:id/rename", async function(req, res, next) {
let acc;
let db = client.db("mediahost");
let accs = await db.collection("accounts");
if (req.cookies["session"]) {
acc = await accs.findOne({session: req.cookies["session"]});
}
if (acc == null && req.cookies["session"]) {
res.clearCookie("session");
res.render("pages/not-allowed", {account: acc, config: config});
}
let files = await db.collection("uploads");
let file = await files.findOne({id: req.params.id});
let form = formidable();
form.parse(req, async function(err, fields) {
if (err) {
res.render("pages/rename-file", {account: acc, config: config, fn: file.name, err: err});
return;
}
if (fields.filename == "") {
res.render("pages/rename-file", {account: acc, config: config, fn: file.name, err: "Invalid file name."});
} else {
try {
fs.renameSync(`${config["media-folder"]}/${file.id}/${file.name}`, `${config["media-folder"]}/${file.id}/${fields.filename}`)
file.name = fields.filename;
await files.findOneAndReplace({id: file.id}, file);
res.redirect(`/f/${file.id}`);
} catch(err) {
res.render("pages/rename-file", {account: acc, config: config, fn: file.name, err: "Error renaming file."});
}
}
})
});
app.get("/u/:user", async function (req, res, next) {
let acc;
let db = client.db("mediahost");
let accs = await db.collection("accounts");
if (req.cookies["session"]) {
acc = await accs.findOne({session: req.cookies["session"]});
}
if (acc == null && req.cookies["session"]) res.clearCookie("session");
let a = await accs.findOne({username: req.params.user});
if (a == null) next();
else {
let p = {uploader: a._id};
if (acc == undefined || acc.id !== a.id && acc.admin !== true) {
p.privacy = 1;
}
let files = await db.collection("uploads");
let uploaded = await (await files.find(p).toArray()).reverse();
res.render("pages/user", {uploads: uploaded, account: acc, user: a, config: config});
}
});
app.get("/admin-dashboard", function(req, res, next) {
res.redirect("/admin");
});
app.get("/admin", async function (req, res, next) {
let acc;
let db = client.db("mediahost");
let accs = await db.collection("accounts");
if (req.cookies["session"]) {
acc = await accs.findOne({session: req.cookies["session"]});
}
if (acc == null && req.cookies["session"]) res.clearCookie("session");
if (acc !== null && acc !== undefined) {
if (acc.admin == true) {
let files = await db.collection("uploads");
let reps = await db.collection("reports");
let ups = await (await files.find({}).toArray()).reverse().slice(0, 5);
let reg = await (await accs.find({}).toArray()).reverse().slice(0, 5);
let rep = await (await reps.find({unread: true}).toArray()).reverse();
res.render("pages/admin-panel", {config: config, account: acc, uploads: ups, register: reg, reports: rep, message: utils.toMessage(req.query["from"])});
} else next();
} else next();
});
app.get("/admin/files", async function(req, res, next) {
let acc;
let db = client.db("mediahost");
let accs = await db.collection("accounts");
if (req.cookies["session"]) {
acc = await accs.findOne({session: req.cookies["session"]});
}
if (acc == null && req.cookies["session"]) res.clearCookie("session");
if (acc !== null && acc !== undefined) {
if (acc.admin == true) {
let files = await db.collection("uploads");
let ups = await (await files.find({}).toArray()).reverse();
res.render("pages/admin-actions/all-files", {uploads: ups, account: acc, config: config});
} else next();
} else next();
});
app.get("/admin/kill/:user", async function (req, res, next) {
let acc;
let db = client.db("mediahost");
let accs = await db.collection("accounts");
if (req.cookies["session"]) {
acc = await accs.findOne({session: req.cookies["session"]});
}
if (acc == null && req.cookies["session"]) res.clearCookie("session");
if (acc !== null && acc !== undefined) {
let a = await accs.findOne({username: req.params.user});
if (a == null || acc.admin !== true) next();
else {
res.render("pages/admin-actions/delete-acc", {account: acc, config: config, user: a});
}
} else next();
});
app.post("/admin/kill/:user", async function (req, res, next) {
let acc;
let db = client.db("mediahost");
let accs = await db.collection("accounts");
if (req.cookies["session"]) {
acc = await accs.findOne({session: req.cookies["session"]});
}
if (acc !== null && acc !== undefined) {
if (acc.admin !== true) {
next();
return;
}
let ac = await accs.findOne({username: req.params.user});
let u = await (await db.collection("uploads").find({uploader: ac._id})).toArray();
for (let a in u) {
removeUpload(u[a].id);
}
let a = await accs.findOneAndDelete({username: req.params.user});
if (a.ok == 1) {
if (ac.session == acc.session) {
res.clearCookie("session");
res.redirect("/?from=self-delete");
} else {
res.redirect("/admin-dashboard?from=kill-done");
}
} else {
res.end(a);
}
} else next();
});
app.get("/admin/promote/:user", async function (req, res, next) {
let acc;
let db = client.db("mediahost");
let accs = await db.collection("accounts");
if (req.cookies["session"]) {
acc = await accs.findOne({session: req.cookies["session"]});
}
if (acc == null && req.cookies["session"]) res.clearCookie("session");
if (acc !== null && acc !== undefined) {
let a = await accs.findOne({username: req.params.user});
if (a == null || acc.admin !== true) next();
else {
res.render("pages/admin-actions/promote-user", {account: acc, config: config, user: a});
}
} else next();
});
app.post("/admin/promote/:user", async function (req, res, next) {
let acc;
let db = client.db("mediahost");
let accs = await db.collection("accounts");
if (req.cookies["session"]) {
acc = await accs.findOne({session: req.cookies["session"]});
}
if (acc !== null && acc !== undefined) {
if (acc.admin !== true) {
next();
return;
}
let ac = await accs.findOne({username: req.params.user});
ac.admin = true;
let a = await accs.findOneAndReplace({username: req.params.user}, ac);
if (a.ok == 1) {
if (ac.session == acc.session) res.clearCookie("session");
res.redirect("/admin-dashboard?from=promote-done");
} else {
res.send(a);
}
} else next();
});
app.get("/admin/demote/:user", async function (req, res, next) {
let acc;
let db = client.db("mediahost");
let accs = await db.collection("accounts");
if (req.cookies["session"]) {
acc = await accs.findOne({session: req.cookies["session"]});
}
if (acc == null && req.cookies["session"]) res.clearCookie("session");
if (acc !== null && acc !== undefined) {
let a = await accs.findOne({username: req.params.user});
if (a == null || acc.admin !== true) next();
else {
res.render("pages/admin-actions/demote-user", {account: acc, config: config, user: a});
}
} else next();
});
app.post("/admin/demote/:user", async function (req, res, next) {
let acc;
let db = client.db("mediahost");
let accs = await db.collection("accounts");
if (req.cookies["session"]) {
acc = await accs.findOne({session: req.cookies["session"]});
}
if (acc == null && req.cookies["session"]) res.clearCookie("session");
if (acc !== null && acc !== undefined) {
let a = await accs.findOne({username: req.params.user});
if (a == null || acc.admin !== true) next();
else {
res.render("pages/admin-actions/block-ip", {account: acc, config: config});
}
} else next();
});
app.get("/admin/block/ip", async function(req, res, next) {
let acc;
let db = client.db("mediahost");
let accs = await db.collection("accounts");
if (req.cookies["session"]) {
acc = await accs.findOne({session: req.cookies["session"]});
}
if (acc !== null && acc !== undefined) {
if (acc.admin !== true) {
next();
return;
}
let obj = {config: config, account: acc};
if (req.query.ip) obj.ip = req.query.ip;
if (req.query.reason) obj.reason = req.query.reason;
res.render("pages/admin-actions/block-ip", obj);
} else next();
});
app.post("/admin/block/ip", async function(req, res, next) {
let acc;
let db = client.db("mediahost");
let accs = await db.collection("accounts");
if (req.cookies["session"]) {
acc = await accs.findOne({session: req.cookies["session"]});
}
if (acc !== null && acc !== undefined) {
if (acc.admin !== true) {
next();
return;
}
let form = formidable({maxFileSize: 0});
let ip = (req.headers["X-Real-IP"] || req.headers["x-real-ip"] || req.ip);
form.parse(req, async function(err, fields) {
let obj = {
config: config,
account: acc
};
if (req.query.ip) obj.ip = req.query.ip;
if (req.query.reason) obj.reason = req.query.reason;
if (err) {
obj.err = (err.message || err.code || err);
res.render("pages/admin-actions/block-ip", obj);
return;
}
if (fields.reason == "") {
obj.err = "Invalid reason to block.";
res.render("pages/admin-actions/block-ip", obj);
return;
}
let status = utils.convertToBlockedStatus(fields);
let block = fields.ip;
if (block == ip) {
obj.err = "You cannot block your own IP.";
res.render("pages/admin-actions/block-ip", obj);
return;
}
let db = client.db("mediahost");
let blocks = db.collection("blockedIPs");
let d = await blocks.insertOne({
ip: block,
status: status,
reason: fields.reason,
blockedBy: {
account: acc._id,
ip: ip
},
date: new Date().toUTCString()
});
if (d.acknowledged) {
obj.message = `Successfully blocked ${block}.`;
res.render("pages/admin-actions/block-ip", obj);
} else {
obj.err = `There was an error processing the block. Please try again later.`;
res.render("pages/admin-actions/block-ip", obj);
}
});
} else next();
});
app.get("/admin/blocks/ip", async function(req, res, next) {
let acc;
let db = client.db("mediahost");
let accs = await db.collection("accounts");
if (req.cookies["session"]) {
acc = await accs.findOne({session: req.cookies["session"]});
}
if (acc !== null && acc !== undefined) {
if (acc.admin !== true) {
next();
return;
}
let blocks = await db.collection("blockedIPs");
blocks = await blocks.find({}).toArray();
res.render("pages/admin-actions/all-ip-blocks", {config: config, account: acc, blocks: blocks});
} else next();
});
app.get("/admin/blocks/ip/:ip", async function(req, res, next) {
let acc;
let db = client.db("mediahost");
let accs = await db.collection("accounts");
if (req.cookies["session"]) {
acc = await accs.findOne({session: req.cookies["session"]});
}
if (acc !== null && acc !== undefined) {
if (acc.admin !== true) {
next();
return;
}
let blocks = await db.collection("blockedIPs");
let block = await blocks.findOne({ip: req.params.ip});
if (block == null) {
res.redirect("/admin/blocks");
return;
}
if (block.blockedBy?.account) block.blockedBy.account = (await accs.findOne({_id: block.blockedBy?.account}))?.username;
res.render("pages/admin-actions/view-ip-block", {config: config, account: acc, ip: block});
} else next();
});
app.post("/admin/blocks/ip/:ip", async function (req, res, next) {
let acc;
let db = client.db("mediahost");
let accs = await db.collection("accounts");
if (req.cookies["session"]) {
acc = await accs.findOne({session: req.cookies["session"]});
}
if (acc !== null && acc !== undefined) {
if (acc.admin !== true) {
next();
return;
}
let blocks = await db.collection("blockedIPs");
let block = await blocks.findOne({ip: req.params.ip});
let form = formidable({maxFileSize: 0});
form.parse(req, async function(err, fields) {
if (err) {
err = (err.message || err.code || err);
res.render("pages/admin-actions/view-ip-block", {config: config, account: acc, err: err, ip: block});
return;
}
switch(fields.action) {
case "lift":
block = await blocks.findOneAndDelete({ip: req.params.ip});
if (block.ok == 1) {
res.redirect("/admin?from=lifted-block");
return;
} else {
res.render("pages/admin-actions/view-ip-block", {config: config, account: acc, err: "There was an issue lifting the block.", ip: block});
}
return;
default:
res.render("pages/admin-actions/view-ip-block", {config: config, account: acc, err: "Action is not available or does not exist.", ip: block});
return;
}
});
} else next();
});
app.get("/admin/accounts", async function(req, res, next) {
let acc;
let db = client.db("mediahost");
let accs = await db.collection("accounts");
if (req.cookies["session"]) {
acc = await accs.findOne({session: req.cookies["session"]});
}
if (acc == null && req.cookies["session"]) res.clearCookie("session");
if (acc !== null && acc !== undefined) {
if (acc.admin == true) {
let accounts = await (await accs.find({}).toArray()).reverse();
res.render("pages/admin-actions/all-accounts", {accounts: accounts, account: acc, config: config});
} else next();
} else next();
});
app.get("/admin/reports", async function(req, res, next) {
let acc;
let db = client.db("mediahost");
let accs = await db.collection("accounts");
if (req.cookies["session"]) {
acc = await accs.findOne({session: req.cookies["session"]});
}
if (acc == null && req.cookies["session"]) res.clearCookie("session");
if (acc !== null && acc !== undefined) {
if (acc.admin == true) {
let reports = await db.collection("reports");
reports = await (await reports.find({}).toArray()).reverse();
res.render("pages/admin-actions/all-reports", {reports: reports, account: acc, config: config});
} else next();
} else next();
});
app.get("/admin/signup-code", async function (req, res, next) {
let acc;
let db = client.db("mediahost");
let accs = await db.collection("accounts");
if (req.cookies["session"]) {
acc = await accs.findOne({session: req.cookies["session"]});
}
if (acc == null && req.cookies["session"]) res.clearCookie("session");
if (acc !== null && acc !== undefined) {
if (acc.admin !== true) {
next();
return;
}
res.render("pages/admin-actions/generate-code", {config: config, account: acc, code: null});
} else next();
});
app.post("/admin/signup-code", async function (req, res, next) {
let acc;
let db = client.db("mediahost");
let signup = await db.collection("codes");
let accs = await db.collection("accounts");
if (req.cookies["session"]) {
acc = await accs.findOne({session: req.cookies["session"]});
}
if (acc == null && req.cookies["session"]) res.clearCookie("session");
if (acc !== null && acc !== undefined) {
if (acc.admin !== true) {
next();
return;
}
let c = utils.generateString(12);
let code = await signup.insertOne({code: c});
if (code.acknowledged == true) {
res.render("pages/admin-actions/generate-code", {config: config, account: acc, code: c});
} else {
res.send(code);
}
} else next();
});
app.get("/privacy", async function (req, res, next) {
let acc;
let db = client.db("mediahost");
if (req.cookies["session"]) {
let accs = await db.collection("accounts");
acc = await accs.findOne({session: req.cookies["session"]});
}
if (acc == null && req.cookies["session"]) res.clearCookie("session");
let output = mk.makeHtml(fs.readFileSync("articles/privacy.md").toString());
res.render("pages/article", {config: config, account: acc, output: output, aName: "privacy policy"});
});
app.get("/terms", async function (req, res, next) {
let acc;
let db = client.db("mediahost");
if (req.cookies["session"]) {
let accs = await db.collection("accounts");
acc = await accs.findOne({session: req.cookies["session"]});
}
if (acc == null && req.cookies["session"]) res.clearCookie("session");
let output = mk.makeHtml(fs.readFileSync("articles/terms.md").toString());
res.render("pages/article", {config: config, account: acc, output: output, aName: "terms"});
});
app.get("/sharex", async function (req, res, next) {
let acc;
let db = client.db("mediahost");
if (req.cookies["session"]) {
let accs = await db.collection("accounts");
acc = await accs.findOne({session: req.cookies["session"]});
}
if (acc == null && req.cookies["session"]) res.clearCookie("session");
if (config["sharex-support"] == false) {
res.setHeader("content-type", "text/html");
res.render("pages/not-allowed", {config: config, account: acc});
return;
}
let json = fs.readFileSync(`${__dirname}/sharex.json`).toString();
json = JSON.parse(json);
json["Name"] = config.meta.name;
json["RequestURL"] = `http://${config.meta.domain}/upload?json=1`;
json["URL"] = `http://${config.meta.domain}$json:data.direct$`;
if (config["allow-anon-uploads"] == true && acc == null) {
delete json["Headers"];
} else {
if (!req.headers["cookie"]) {
res.render("pages/not-allowed", {config: config, account: acc});
return;
}
json["Headers"]["Cookie"] = req.headers["cookie"];
}
res.setHeader("content-type", "text/plain");
res.setHeader("content-disposition", 'attachment; filename="sharex.sxcu"');
res.send(JSON.stringify(json, null, 2))
});
app.get("/paste", async function (req, res, next) {
let acc;
if (req.cookies["session"]) {
let db = client.db("mediahost");
let accs = await db.collection("accounts");
acc = await accs.findOne({session: req.cookies["session"]});
}
if (acc == null && req.cookies["session"]) res.clearCookie("session");
if (config["allow-anon-uploads"] == false && acc == null) {
res.render("pages/not-allowed", {config: config, account: acc});
} else {
if (acc == null) {
if (config["reject-tor"]) {
if (req.headers["x-real-ip"] || req.headers["X-Real-IP"] || req.ip) {
let ip = (req.headers["X-Real-IP"] || req.headers["x-real-ip"] || req.ip);
try {
let tor = istor(ip);
if (tor == true) {
res.render("pages/not-allowed", {config: config, account: acc});
return;
}
} catch(err) {
if (!err.message.includes("The given IP")) throw err;
}
} else console.log(`ERR! IP not found.`);
}
}
res.render("pages/paste", {config: config, account: acc, maxsize: utils.humanSize(config["max-file-size"])})
}
})
app.post("/paste", async function (req, res, next) {
const form = formidable({maxFileSize: config["max-file-size"], multiples: true});
let acc;
let db = client.db("mediahost");
if (req.cookies["session"]) {
let accs = await db.collection("accounts");
acc = await accs.findOne({session: req.cookies["session"]});
}
if (acc == null && req.cookies["session"]) res.clearCookie("session");
if (acc == null) {
if (config["reject-tor"]) {
if (req.headers["x-real-ip"] || req.headers["X-Real-IP"] || req.ip) {
let ip = (req.headers["X-Real-IP"] || req.headers["x-real-ip"] || req.ip);
try {
let tor = istor(ip);
if (tor == true) {
res.render("pages/not-allowed", {config: config, account: acc});
return;
}
} catch(err) {
if (!err.message.includes("The given IP")) throw err;
}
} else console.log(`ERR! IP not found.`);
}
}
form.parse(req, async function(err, fields, files) {
if (err) {
if (req.query["json"] !== "1") {
let error;
if (err.httpCode && !err.message) {
error = `HTTP Error Code ${err.httpCode}`;
} else {
error = (err.message || err);
}
res.render("pages/paste", {config: config, err: error, maxsize: utils.humanSize(config["max-file-size"])});
} else {
let error;
if (err.httpCode && !err.message) {
error = `HTTP Error Code ${err.httpCode}`;
} else {
error = (err.message || err);
}
res.send({
success: false,
err: error
});
}
} else {
let u;
if (acc !== null && acc !== undefined) {
u = acc._id;
} else {
u = "Anonymous";
}
let id = utils.generateString(5);
//console.log(`[media-host] Uploaded file to "${id}".`);
fs.mkdirSync(`${config["media-folder"]}${id}/`);
let db = client.db("mediahost");
let col = await db.collection("uploads");
if (fields.text) {
fs.writeFileSync(`${config["media-folder"]}${id}/${fields.name}`, fields.text);
} else if (files.file) {
if (files.file.mimetype.startsWith("text")) {
fs.copyFileSync(files.file.filepath, `${config["media-folder"]}${id}/${files.file.originalFilename}`);
} else {
res.render("pages/paste", {config: config, account: acc, err: "Empty or invalid paste."})
return;
}
}
let data = {
id: id,
uploader: u,
direct: `/f/${id}/raw`,
name: (fields.name || "Paste"),
type: `text`,
size: utils.totalBytes(fields.text),
humanSize: utils.humanSize(utils.totalBytes(fields.text)),
date: new Date().toISOString(),
privacy: (parseInt(fields.privacy) || 0),
mime: `text/plain`
};
if (u == "Anonymous" && config["store-anon-ips"]) {
data["ip"] = (req.headers["x-real-ip"] || req.headers["X-Real-IP"]);
}
col.insertOne(data);
if (req.query["json"] == "1") {
res.send({
success: true,
data: data
});
} else {
res.redirect(`/f/${id}`);
}
}
});
});
app.get("/r/:id", function(req, res, next) {
res.redirect(`/f/${req.params.id}/raw`);
});
app.get("/report", async function (req, res, next) {
let acc;
let db = client.db("mediahost");
if (req.cookies["session"]) {
let accs = await db.collection("accounts");
acc = await accs.findOne({session: req.cookies["session"]});
}
if (acc == null && req.cookies["session"]) res.clearCookie("session");
res.render("pages/report", {config: config, account: acc, upload: req.query["upload"], message: null, err: null});
});
app.post("/report", async function (req, res, next) {
const form = formidable({maxFileSize: 0, multiples: true});
let acc;
let db = client.db("mediahost");
if (req.cookies["session"]) {
let accs = await db.collection("accounts");
acc = await accs.findOne({session: req.cookies["session"]});
}
if (acc == null && req.cookies["session"]) res.clearCookie("session");
form.parse(req, async function(err, fields) {
if (err) {
let error;
if (err.httpCode && !err.message) {
error = `HTTP Error Code ${err.httpCode}`;
} else {
error = (err.message || err);
}
res.render("pages/report", {config: config, err: error, upload: req.query["upload"], message: null});
} else {
if (config["captcha"]["enabled"] == true && config["captcha"]["show-at-report"]) {
if (!fields["h-captcha-response"]) {
res.render("pages/report", {config: config, err: "CAPTCHA needs to be solved.", upload: req.query["upload"], message: null});
return;
} else {
let h = await hcaptcha.verify(config["captcha"]["secret"], fields["h-captcha-response"]);
if (!h.success) {
res.render("pages/report", {config: config, err: "CAPTCHA came back invalid.", upload: req.query["upload"], message: null});
return;
}
}
}
if (!fields.offense) {
res.render("pages/report", {config: config, err: "Offense field came back invalid.", upload: req.query["upload"], message: null});
return;
}
let ups = await db.collection("uploads");
let up = await ups.findOne({id: fields.upload});
if (up == null) {
res.render("pages/report", {config: config, err: "Upload ID is invalid. Make sure you didn't make a typo.", upload: req.query["upload"], message: null});
} else {
let reports = await db.collection("reports");
let ip = (req.headers["X-Real-IP"] || req.headers["x-real-ip"] || req.ip);
let report = {
id: utils.generateString(5),
type: fields.offense,
respond: fields.email,
upload: fields.upload,
comments: fields.comment,
ip: ip,
unread: true,
unsolved: true
};
await reports.insertOne(report);
res.render("pages/report", {config: config, err: null, upload: req.query["upload"], message: "Your report has been submitted and will be reviewed as soon as possible.", account: acc});
}
}
});
});
app.get("/reports/:id", async function(req, res, next) {
let acc;
let db = client.db("mediahost");
if (req.cookies["session"]) {
let accs = await db.collection("accounts");
acc = await accs.findOne({session: req.cookies["session"]});
}
if (acc == null && req.cookies["session"]) res.clearCookie("session");
let reports = await db.collection("reports");
let report = await reports.findOne({id: req.params.id});
if (report == null) next();
else {
if (acc !== null && acc !== undefined) {
if (acc.admin == true) {
report.actualType = utils.toFullReportString(report.type);
res.render("pages/admin-actions/view-report", {config: config, account: acc, report: report, message: null});
} else next();
} else next();
}
});
app.post("/reports/:id/read", async function(req, res, next) {
let acc;
let db = client.db("mediahost");
if (req.cookies["session"]) {
let accs = await db.collection("accounts");
acc = await accs.findOne({session: req.cookies["session"]});
}
if (acc == null && req.cookies["session"]) res.clearCookie("session");
let reports = await db.collection("reports");
let report = await reports.findOne({id: req.params.id});
if (acc !== null && acc !== undefined) {
if (acc.admin == true) {
let ar = report;
ar.unread = false;
await reports.findOneAndReplace({id: report.id}, ar);
res.render("pages/admin-actions/view-report", {config: config, account: acc, report: report, message: "Message marked as read."});
} else next();
} else next();
});
app.post("/reports/:id/unread", async function(req, res, next) {
let acc;
let db = client.db("mediahost");
if (req.cookies["session"]) {
let accs = await db.collection("accounts");
acc = await accs.findOne({session: req.cookies["session"]});
}
if (acc == null && req.cookies["session"]) res.clearCookie("session");
let reports = await db.collection("reports");
let report = await reports.findOne({id: req.params.id});
if (acc !== null && acc !== undefined) {
if (acc.admin == true) {
let ar = report;
ar.unread = true;
report.actualType = utils.toFullReportString(report.type);
await reports.findOneAndReplace({id: report.id}, ar);
res.render("pages/admin-actions/view-report", {config: config, account: acc, report: report, message: "Message marked as unread."});
} else next();
} else next();
});
app.post("/reports/:id/solved", async function(req, res, next) {
let acc;
let db = client.db("mediahost");
if (req.cookies["session"]) {
let accs = await db.collection("accounts");
acc = await accs.findOne({session: req.cookies["session"]});
}
if (acc == null && req.cookies["session"]) res.clearCookie("session");
let reports = await db.collection("reports");
let report = await reports.findOne({id: req.params.id});
if (acc !== null && acc !== undefined) {
if (acc.admin == true) {
let ar = report;
ar.unsolved = false;
await reports.findOneAndReplace({id: report.id}, ar);
if (config["transparent-reports"] == true) res.render("pages/admin-actions/redact-reports", {config: config, account: acc, originalComment: report.comments, id: report.id});
else res.render("pages/admin-actions/view-report", {config: config, account: acc, report: report, message: "Message marked as solved."});
} else next();
} else next();
});
app.post("/admin/reports/redact", async function (req, res) {
let acc;
let db = client.db("mediahost");
if (req.cookies["session"]) {
let accs = await db.collection("accounts");
acc = await accs.findOne({session: req.cookies["session"]});
}
let form = formidable({maxFileSize: 0});
if (acc !== null && acc !== undefined) {
if (acc.admin == true) {
form.parse(req, async function(err, fields) {
if (err) res.render("pages/admin-actions/redact-reports", {config: config, account: acc, err: err});
else {
let publicReports = db.collection("publicReports");
let reports = db.collection("reports");
let report = await reports.findOne({id: fields.reportId});
let publicId = utils.generateString(5);
let publicReport = await publicReports.insertOne({
id: publicId,
originalReport: report.id,
comment: fields.originalComment,
emails: fields.emails,
adminComments: fields.comments,
date: new Date().toDateString()
});
if (publicReport.acknowledged) res.redirect(`/transparency/reports/${publicId}?from=done-redacting`);
else res.render("pages/admin-actions/redact-reports", {config: config, account: acc, err: err});
}
});
} else next();
} else next();
});
app.get("/transparency/reports/:id", async function (req, res) {
let acc;
let db = client.db("mediahost");
if (req.cookies["session"]) {
let accs = await db.collection("accounts");
acc = await accs.findOne({session: req.cookies["session"]});
}
let reports = db.collection("publicReports");
let report = await reports.findOne({id: req.params.id});
res.render("pages/transparent-report", {
comment: report.comment,
report: report.originalReport,
emails: report.emails,
adminComments: report.adminComments,
date: report.date,
account: acc,
config: config
});
});
app.post("/reports/:id/unsolved", async function (req, res) {
let acc;
let db = client.db("mediahost");
if (req.cookies["session"]) {
let accs = await db.collection("accounts");
acc = await accs.findOne({session: req.cookies["session"]});
}
let publicReports = db.collection("publicReports");
let reports = db.collection("reports");
let report = await reports.findOne({id: req.params.id});
report.unsolved = true;
let action = await reports.findOneAndReplace({id: req.params.id}, report);
if (action.ok == 1) {
if (config["transparent-reports"] == true) {
action = await publicReports.findOneAndDelete({originalReport: req.params.id});
}
res.render("pages/admin-actions/view-report", {config: config, account: acc, report: report, message: "Message marked as unsolved."});
} else res.render("pages/admin-actions/view-report", {config: config, account: acc, report: report, err: "Could not update report."});
});
app.get("/account/delete", async function(req, res, next) {
let acc;
let db = client.db("mediahost");
if (req.cookies["session"]) {
let accs = await db.collection("accounts");
acc = await accs.findOne({session: req.cookies["session"]});
}
if (acc == null && req.cookies["session"]) res.clearCookie("session");
if (acc !== null && acc !== undefined) {
res.render("pages/delete-acc", {config: config, account: acc});
} else next();
});
app.post("/account/delete", async function(req, res, next) {
let acc;
let db = client.db("mediahost");
let accs = await db.collection("accounts");
if (req.cookies["session"]) {
acc = await accs.findOne({session: req.cookies["session"]});
}
if (acc == null && req.cookies["session"]) res.clearCookie("session");
if (acc !== null && acc !== undefined) {
let u = await (await db.collection("uploads").find({uploader: acc._id})).toArray();
for (let a in u) {
removeUpload(u[a].id);
}
let a = await accs.findOneAndDelete({_id: acc._id});
if (a.ok == 1) {
res.clearCookie("session");
res.redirect("/?from=self-delete");
} else {
res.end(a);
}
} else next();
});
app.get("/account/rename", async function(req, res, next) {
let acc;
let db = client.db("mediahost");
if (req.cookies["session"]) {
let accs = await db.collection("accounts");
acc = await accs.findOne({session: req.cookies["session"]});
}
if (acc == null && req.cookies["session"]) res.clearCookie("session");
if (acc !== null && acc !== undefined) {
res.render("pages/rename-acc", {config: config, account: acc, username: acc.username, err: null});
} else next();
});
app.post("/account/rename", async function(req, res, next) {
let acc, accs;
let db = client.db("mediahost");
if (req.cookies["session"]) {
accs = await db.collection("accounts");
acc = await accs.findOne({session: req.cookies["session"]});
}
if (acc == null && req.cookies["session"]) res.clearCookie("session");
let form = formidable();
form.parse(req, async function(err, fields) {
if (err) res.render("pages/rename-acc", {config: config, account: acc, username: acc.username, err: (err.message || err.code || err)});
else {
try {
if (fields.username) {
let preexist = accs.findOne({username: fields.username});
if (preexist == null || preexist !== "Anonymous") {
if (utils.validateUsername(fields.username)) {
acc.username = fields.username;
let account = await accs.findOneAndReplace({_id: acc._id}, acc);
if (account.ok == 1) {
res.redirect(`/u/${acc.username}`);
} else throw "Could not insert change into database";
} else throw "Invalid username, please try another one";
} else throw "Username is already taken";
} else throw "Need to specify username";
} catch(err) {
res.render("pages/rename-acc", {config: config, account: acc, username: acc.username, err: (err.message || err.code || err)});
}
}
});
});
app.get("/transparency", async function (req, res, next) {
let acc;
let db = client.db("mediahost");
if (req.cookies["session"]) {
let accs = await db.collection("accounts");
acc = await accs.findOne({session: req.cookies["session"]});
}
if (config["transparent-reports"] == true) {
let reports = db.collection("publicReports");
reports = await reports.find({}).toArray();
res.render("pages/transparency", {config: config, account: acc, reports: reports})
} else next();
});
app.get("/*", async function (req, res, next) {
let acc;
let db = client.db("mediahost");
if (req.cookies["session"]) {
let accs = await db.collection("accounts");
acc = await accs.findOne({session: req.cookies["session"]});
}
if (acc == null && req.cookies["session"]) res.clearCookie("session");
res.render("pages/404", {config: config, account: acc});
});
async function start() {
console.log("[media-host] Connecting to DB.");
await client.connect();
console.log("[media-host] Connected to DB.");
app.listen(config["port"], "127.0.0.1", function() {
console.log(`[media-host] HTTP Server listening at ${config["port"]}`);
});
}
function isOwned(file, acc) {
try {
if (acc._id.toString() == file.uploader || acc.admin == true) {return true;} else {return false;}
} catch(e) {
return false;
}
}
async function removeUpload(id) {
let db = await client.db("mediahost");
let files = await db.collection("uploads");
await files.findOneAndDelete({id: id});
if (fs.existsSync(`${config["media-folder"]}${id}`)) fs.rmSync(`${config["media-folder"]}${id}`, {recursive: true});
if (fs.existsSync(`${config?.["remux"]?.["folder"]}${id}`)) fs.rmSync(`${config["remux"]["folder"]}${id}`, {recursive: true});
}
async function initTranscode(id, mime) {
let db = await client.db("mediahost");
let files = await db.collection("uploads");
let file = await files.findOne({id});
if (mime != "video/mp4" && mime != "video/webm") {
if (config?.["remux"]?.["enabled"] == true) {
let originalFile = `${config["media-folder"]}/${id}/${file.name}`;
let transFile = `${config["remux"]["folder"]}/${id}/${file.name}.${config["remux"]["container"]}`; // based file
fs.mkdirSync(`${config["remux"]["folder"]}/${id}`);
let ffmpegProcess = spawn(ffmpegStatic, [`-i`, originalFile, `-vcodec`, config["remux"]["video-codec"], `-acodec`, config["remux"]["audio-codec"], `-preset`, `ultrafast`, transFile]);
ffmpegProcess.on("close", async function(code) {
if (code == 0) {
file.transcodedFile = `/transcoded/${id}/${file.name}.${config["remux"]["container"]}`;
await files.findOneAndReplace({id}, file);
} else console.log(`ffmpeg failed on ${id}`);
});
}
}
}