245 lines
5.9 KiB
TypeScript
245 lines
5.9 KiB
TypeScript
import createError from "http-errors";
|
|
import express from "express";
|
|
|
|
import compression from "compression";
|
|
import path from "path";
|
|
import cookieParser from "cookie-parser";
|
|
import csurf from "csurf";
|
|
import rateLimit from "express-rate-limit";
|
|
|
|
import session from "express-session";
|
|
import FileStore from "session-file-store";
|
|
|
|
import routerLogin from "./routes/login.js";
|
|
import routerDashboard from "./routes/dashboard.js";
|
|
import routerLots from "./routes/lots.js";
|
|
import routerMaps from "./routes/maps.js";
|
|
import routerLotOccupancies from "./routes/lotOccupancies.js";
|
|
import routerWorkOrders from "./routes/workOrders.js";
|
|
import routerReports from "./routes/reports.js";
|
|
import routerAdmin from "./routes/admin.js";
|
|
|
|
import * as configFunctions from "./helpers/functions.config.js";
|
|
import * as dateTimeFns from "@cityssm/expressjs-server-js/dateTimeFns.js";
|
|
import * as stringFns from "@cityssm/expressjs-server-js/stringFns.js";
|
|
import * as htmlFns from "@cityssm/expressjs-server-js/htmlFns.js";
|
|
import { version } from "./version.js";
|
|
|
|
import * as databaseInitializer from "./helpers/databaseInitializer.js";
|
|
|
|
import debug from "debug";
|
|
const debugApp = debug("lot-occupancy-system:app");
|
|
|
|
|
|
/*
|
|
* INITALIZE THE DATABASE
|
|
*/
|
|
|
|
|
|
databaseInitializer.initLotOccupancyDB();
|
|
|
|
|
|
/*
|
|
* INITIALIZE APP
|
|
*/
|
|
|
|
|
|
const __dirname = ".";
|
|
|
|
export const app = express();
|
|
|
|
if (!configFunctions.getProperty("reverseProxy.disableEtag")) {
|
|
app.set("etag", false);
|
|
}
|
|
|
|
// View engine setup
|
|
app.set("views", path.join(__dirname, "views"));
|
|
app.set("view engine", "ejs");
|
|
|
|
if (!configFunctions.getProperty("reverseProxy.disableCompression")) {
|
|
app.use(compression());
|
|
}
|
|
|
|
app.use((request, _response, next) => {
|
|
debugApp(`${request.method} ${request.url}`);
|
|
next();
|
|
});
|
|
|
|
app.use(express.json());
|
|
|
|
app.use(express.urlencoded({
|
|
extended: false
|
|
}));
|
|
|
|
app.use(cookieParser());
|
|
app.use(csurf({ cookie: true }));
|
|
|
|
|
|
/*
|
|
* Rate Limiter
|
|
*/
|
|
|
|
const limiter = rateLimit({
|
|
windowMs: 60 * 1000,
|
|
max: 1000
|
|
});
|
|
|
|
app.use(limiter);
|
|
|
|
|
|
/*
|
|
* STATIC ROUTES
|
|
*/
|
|
|
|
|
|
const urlPrefix = configFunctions.getProperty("reverseProxy.urlPrefix");
|
|
|
|
if (urlPrefix !== "") {
|
|
debugApp("urlPrefix = " + urlPrefix);
|
|
}
|
|
|
|
app.use(urlPrefix, express.static(path.join("public")));
|
|
|
|
app.use(urlPrefix + "/lib/fa",
|
|
express.static(path.join("node_modules", "@fortawesome", "fontawesome-free")));
|
|
|
|
app.use(urlPrefix + "/lib/cityssm-bulma-webapp-js",
|
|
express.static(path.join("node_modules", "@cityssm", "bulma-webapp-js")));
|
|
|
|
app.use(urlPrefix + "/lib/cityssm-bulma-js",
|
|
express.static(path.join("node_modules", "@cityssm", "bulma-js", "dist")));
|
|
|
|
app.use(urlPrefix + "/lib/leaflet",
|
|
express.static(path.join("node_modules", "leaflet", "dist")));
|
|
|
|
|
|
/*
|
|
* SESSION MANAGEMENT
|
|
*/
|
|
|
|
const sessionCookieName: string = configFunctions.getProperty("session.cookieName");
|
|
|
|
const FileStoreSession = FileStore(session);
|
|
|
|
// Initialize session
|
|
app.use(session({
|
|
store: new FileStoreSession({
|
|
path: "./data/sessions",
|
|
logFn: debug("general-licence-manager:session"),
|
|
retries: 10
|
|
}),
|
|
name: sessionCookieName,
|
|
secret: configFunctions.getProperty("session.secret"),
|
|
resave: true,
|
|
saveUninitialized: false,
|
|
rolling: true,
|
|
cookie: {
|
|
maxAge: configFunctions.getProperty("session.maxAgeMillis"),
|
|
sameSite: "strict"
|
|
}
|
|
}));
|
|
|
|
// Clear cookie if no corresponding session
|
|
app.use((request, response, next) => {
|
|
|
|
if (request.cookies[sessionCookieName] && !request.session.user) {
|
|
response.clearCookie(sessionCookieName);
|
|
}
|
|
|
|
next();
|
|
});
|
|
|
|
// Redirect logged in users
|
|
const sessionChecker = (request: express.Request, response: express.Response, next: express.NextFunction) => {
|
|
|
|
if (request.session.user && request.cookies[sessionCookieName]) {
|
|
return next();
|
|
}
|
|
|
|
return response.redirect(`${urlPrefix}/login?redirect=${request.originalUrl}`);
|
|
};
|
|
|
|
|
|
/*
|
|
* ROUTES
|
|
*/
|
|
|
|
|
|
// Make the user and config objects available to the templates
|
|
|
|
app.use((request, response, next) => {
|
|
|
|
response.locals.buildNumber = version;
|
|
|
|
response.locals.user = request.session.user;
|
|
response.locals.csrfToken = request.csrfToken();
|
|
|
|
response.locals.configFunctions = configFunctions;
|
|
response.locals.dateTimeFns = dateTimeFns;
|
|
response.locals.stringFns = stringFns;
|
|
response.locals.htmlFns = htmlFns;
|
|
|
|
response.locals.urlPrefix = configFunctions.getProperty("reverseProxy.urlPrefix");
|
|
|
|
next();
|
|
});
|
|
|
|
|
|
app.get(urlPrefix + "/", sessionChecker, (_request, response) => {
|
|
response.redirect(urlPrefix + "/dashboard");
|
|
});
|
|
|
|
app.use(urlPrefix + "/dashboard", sessionChecker, routerDashboard);
|
|
|
|
app.use(urlPrefix + "/lots", sessionChecker, routerLots);
|
|
app.use(urlPrefix + "/maps", sessionChecker, routerMaps);
|
|
app.use(urlPrefix + "/lotOccupancies", sessionChecker, routerLotOccupancies);
|
|
app.use(urlPrefix + "/workOrders", sessionChecker, routerWorkOrders);
|
|
|
|
app.use(urlPrefix + "/reports", sessionChecker, routerReports);
|
|
app.use(urlPrefix + "/admin", sessionChecker, routerAdmin);
|
|
|
|
app.all(urlPrefix + "/keepAlive", (_request, response) => {
|
|
response.json(true);
|
|
});
|
|
|
|
app.use(urlPrefix + "/login", routerLogin);
|
|
|
|
app.get(urlPrefix + "/logout", (request, response) => {
|
|
|
|
if (request.session.user && request.cookies[sessionCookieName]) {
|
|
|
|
// eslint-disable-next-line unicorn/no-null
|
|
request.session.destroy(null);
|
|
request.session = undefined;
|
|
response.clearCookie(sessionCookieName);
|
|
response.redirect(urlPrefix + "/");
|
|
|
|
} else {
|
|
|
|
response.redirect(urlPrefix + "/login");
|
|
}
|
|
});
|
|
|
|
|
|
// Catch 404 and forward to error handler
|
|
app.use((_request, _response, next) => {
|
|
next(createError(404));
|
|
});
|
|
|
|
// Error handler
|
|
app.use((error: { status: number; message: string },
|
|
request: express.Request, response: express.Response) => {
|
|
|
|
// Set locals, only providing error in development
|
|
response.locals.message = error.message;
|
|
response.locals.error = request.app.get("env") === "development" ? error : {};
|
|
|
|
// Render the error page
|
|
response.status(error.status || 500);
|
|
response.render("error");
|
|
});
|
|
|
|
|
|
export default app;
|