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/")));