import config, { WebConfig } from "./config"; import express from "express"; import { Express } from "express"; import Logging from "@hibas123/nodelogging"; import { Format } from "@hibas123/logging"; import bodyparser from "body-parser"; import cookieparser from "cookie-parser"; import session from "express-session"; import MongoStore from "connect-mongo"; import i18n from "i18n"; import compression from "compression"; import ApiRouter from "./api"; import ViewRouter from "./views"; import RequestError, { HttpStatusCode } from "./helper/request_error"; import DB from "./database"; import promiseMiddleware from "./helper/promiseMiddleware"; import User from "./models/user"; import LoginToken, { CheckToken } from "./models/login_token"; export default class Web { server: Express; private port: number; constructor(config: WebConfig) { this.server = express(); this.server.set("trust proxy", 1); this.port = Number(config.port); this.registerMiddleware(); this.registerUserSession(); this.registerEndpoints(); this.registerErrorHandler(); } listen() { this.server.listen(this.port, () => { Logging.log(`Server listening on port ${this.port}`); }); } private registerMiddleware() { this.server.use(session({ secret: config.core.secret, resave: false, saveUninitialized: false, store: MongoStore.create({ client: DB.getClient(), dbName: DB.db.databaseName, collectionName: "sessions", autoRemove: "native", touchAfter: 60 * 60 * 24, }), cookie: { maxAge: 1000 * 60 * 60 * 24 * 30 * 6, secure: !config.core.dev, sameSite: "strict", } })) this.server.use(cookieparser()); this.server.use( bodyparser.json(), bodyparser.urlencoded({ extended: true }) ); this.server.use(i18n.init); //Logging Middleware this.server.use((req, res, next) => { let start = process.hrtime(); let finished = false; let to = false; let listener = () => { if (finished) return; finished = true; let td = process.hrtime(start); let time = !to ? (td[0] * 1e3 + td[1] / 1e6).toFixed(2) : "--.--"; let resFormat: (arg: any) => any = (arg) => arg; if (res.statusCode >= 200 && res.statusCode < 300) resFormat = Format.green; //Green else if (res.statusCode === 304 || res.statusCode === 302) resFormat = Format.yellow; //"\x1b[33m"; else if (res.statusCode >= 400 && res.statusCode < 500) resFormat = Format.red; // "\x1b[36m"; //Cyan else if (res.statusCode >= 500 && res.statusCode < 600) resFormat = Format.cyan //"\x1b[31m"; //Red let m = req.method; while (m.length < 4) m += " "; Logging.getChild("HTTP").log( `${m} ${req.originalUrl} ${(req as any).language || "" }`, resFormat(res.statusCode), `- ${time}ms` ); res.removeListener("finish", listener); }; res.on("finish", listener); setTimeout(() => { to = true; listener(); }, 2000); next(); }); this.server.use( compression({ filter: (req, res) => { if (req.headers["x-no-compression"]) { return false; } return compression.filter(req, res); }, }) ); } private registerEndpoints() { this.server.use("/api", ApiRouter); this.server.use("/", ViewRouter); } private registerErrorHandler() { this.server.use((error, req: express.Request, res, next) => { if (!(error instanceof RequestError)) { error = new RequestError( error.message, error.status || HttpStatusCode.INTERNAL_SERVER_ERROR, error.nolog || false ); } if (error.status === 500 && !(error).nolog) { Logging.error(error); } else { Logging.log("Responded with Error", error.status, error.message); } if (req.accepts(["json"])) { res.json_status = error.status || 500; res.json({ error: error.message, status: error.status || 500, additional: error.additional, }); } else res.status(error.status || 500).send(error.message); }); } private registerUserSession() { this.server.use(promiseMiddleware(async (req, res, next) => { // if (!req.session.user_id) { // if (req.cookies && req.cookies.login) { // let token = await LoginToken.findOne({ token: req.cookies.login, valid: true }); // if (await CheckToken(token, true)) { // req.session.user_id = token.user.toString(); // } // } // if (req.cookies && req.cookies.special) { // let token = await LoginToken.findOne({ token: req.cookies.special, valid: true }); // if (await CheckToken(token, true)) { // req.session.user_id = token.user.toString(); // } // } // } if (req.session.user_id) { req.user = await User.findById(req.session.user_id); req.isAdmin = req.user.admin; } return next(); })); } }