chat/server/src/router.js

121 lines
3.6 KiB
JavaScript

import express from "express";
import busboy from "busboy";
import HashThrough from "hash-through";
import { to36 } from "1636";
import { createHash } from "crypto";
import fs from "fs";
import path from "path";
import mime from "mime";
import Message from "./models/Message.js";
import Emoji from "./models/Emoji.js";
import { DATA_DIR } from "./constants.js";
import { shuffleArray } from "./util.js";
export var router = express.Router();
router.get("/messages", (req, res, next) => {
if (req.query.before) var beforeDate = new Date(req.query.before);
if (beforeDate == "Invalid Date") return res.status(400).send("`before` param is invalid date");
if (req.query.after) var afterDate = new Date(req.query.after);
if (afterDate == "Invalid Date") return res.status(400).send("`after` param is invalid date");
if (beforeDate || afterDate) {
var query = {timestamp:{}};
if (beforeDate) query.timestamp.$lt = beforeDate;
if (afterDate) query.timestamp.$gt = afterDate;
}
Message.getMessages({query, secret: req.query.secret}).then(messages => res.send(messages)).catch(next);
});
router.post("/upload", (req, res, next) => {
var boi = busboy({headers: req.headers});
var codes = [];
boi.on("file", (name, file, info) => {
var resolve;
codes.push(new Promise(r => resolve = r));
var hash = HashThrough(() => createHash("sha1"));
var tmpfilepath = path.join(DATA_DIR, "tmp", Math.random().toString());
var write = fs.createWriteStream(tmpfilepath);
file.pipe(hash).pipe(write);
write.on("error", error => next(error));
write.on("close", () => {
var code = to36(hash.digest("hex"));
var j = {name, code, type: info.mimeType};
var targetfilepath = path.join(DATA_DIR, "objects", code);
fs.exists(targetfilepath, exists => {
if (exists) {
resolve(j);
fs.unlink(tmpfilepath, e=>e&&console.error(e.stack));
}
else fs.rename(tmpfilepath, targetfilepath, error => {
if (error) console.error(error.stack);
resolve(j);
});
});
});
});
boi.on("close", () => {
Promise.all(codes).then(codes => res.send(codes));
});
req.pipe(boi);
});
router.get("/objects/:code/:filename?", (req, res) => {
//var type = req.query.type?.trim().toLowerCase().replace(/[^a-z0-9\/; =-]/g,'');
//if (type?.startsWith("text/html")) type = type.replace("text/html", "text/plain");
if (req.params.filename) {
var type = mime.getType(req.params.filename);
}
res.header("Cache-Control", "max-age=31536000");
res.sendFile(req.params.code, {
root: path.join(DATA_DIR, "objects/"),
headers: type ? {"Content-Type": type} : undefined
});
});
router.get("/emoji/:emoji", (req, res, next) => {
Emoji.findOne({name: req.params.emoji}).then(emoji => {
if (!emoji) return res.sendStatus(404);
res.header("Cache-Control", "max-age=31536000");
res.type(emoji.type);
res.send(emoji.data);
}).catch(next);
});
router.get("/emojis", (req, res, next) => {
Emoji.find({}, "name").then(emojis => {
emojis = emojis.map(e => e.name);
res.send(emojis);
}).catch(next);
});
router.put("/emoji/:name", express.raw({limit: "1mb", type: ()=>true}), async (req, res, next) => {
try {
var emoji = new Emoji({
name: req.params.name,
type: req.query.type,
data: req.body
});
await emoji.save();
res.sendStatus(201);
} catch (error) {next(error)}
});
var favicon = fs.readFileSync(path.join(process.cwd(), "logo.svg"), "utf-8");
router.get("/favicon.svg", (req, res) => {
res.header("Cache-Control", "max-age=86400");
res.type("svg").send(favicon.replaceAll("{num}", Number(req.query.num || 0) || ""));
});
router.use(express.static(path.join(process.cwd(), "../app/build/")));