app.js 2.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. import bodyParser from "body-parser";
  2. import compression from "compression";
  3. import express from "express";
  4. import fileUpload from "express-fileupload";
  5. import { isDebugMode } from "./lib/config.js";
  6. import cors from "./lib/express/cors.js";
  7. import jwt from "./lib/express/jwt.js";
  8. import { express as logger } from "./logger.js";
  9. import mainRoutes from "./routes/main.js";
  10. /**
  11. * App
  12. */
  13. const app = express();
  14. app.use(fileUpload());
  15. app.use(bodyParser.json());
  16. app.use(bodyParser.urlencoded({ extended: true }));
  17. // Gzip
  18. app.use(compression());
  19. /**
  20. * General Logging, BEFORE routes
  21. */
  22. app.disable("x-powered-by");
  23. app.enable("trust proxy", ["loopback", "linklocal", "uniquelocal"]);
  24. app.enable("strict routing");
  25. // pretty print JSON when not live
  26. if (isDebugMode()) {
  27. app.set("json spaces", 2);
  28. }
  29. // CORS for everything
  30. app.use(cors);
  31. // General security/cache related headers + server header
  32. app.use((_, res, next) => {
  33. let x_frame_options = "DENY";
  34. if (typeof process.env.X_FRAME_OPTIONS !== "undefined" && process.env.X_FRAME_OPTIONS) {
  35. x_frame_options = process.env.X_FRAME_OPTIONS;
  36. }
  37. res.set({
  38. "X-XSS-Protection": "1; mode=block",
  39. "X-Content-Type-Options": "nosniff",
  40. "X-Frame-Options": x_frame_options,
  41. "Cache-Control": "no-cache, no-store, max-age=0, must-revalidate",
  42. Pragma: "no-cache",
  43. Expires: 0,
  44. });
  45. next();
  46. });
  47. app.use(jwt());
  48. app.use("/", mainRoutes);
  49. // production error handler
  50. // no stacktraces leaked to user
  51. app.use((err, req, res, _) => {
  52. const payload = {
  53. error: {
  54. code: err.status,
  55. message: err.public ? err.message : "Internal Error",
  56. },
  57. };
  58. if (typeof err.message_i18n !== "undefined") {
  59. payload.error.message_i18n = err.message_i18n;
  60. }
  61. if (isDebugMode() || (req.baseUrl + req.path).includes("nginx/certificates")) {
  62. payload.debug = {
  63. stack: typeof err.stack !== "undefined" && err.stack ? err.stack.split("\n") : null,
  64. previous: err.previous,
  65. };
  66. }
  67. // Not every error is worth logging - but this is good for now until it gets annoying.
  68. if (typeof err.stack !== "undefined" && err.stack) {
  69. logger.debug(err.stack);
  70. if (typeof err.public === "undefined" || !err.public) {
  71. logger.warn(err.message);
  72. }
  73. }
  74. res.status(err.status || 500).send(payload);
  75. });
  76. export default app;