| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697 |
- import express, { Express } from 'express';
- import multiparty from 'multiparty-express';
- import { AuthHandler } from './handlers/auth-handler.class';
- import { EchoHandler } from './handlers/echo-handler.class';
- import { SessionHandler } from './handlers/lib/session-handler.class';
- import { PrivateHandler } from './handlers/private-handler.class';
- import { PublicHandler } from './handlers/public-handler.class';
- import { AuthenticationException } from './model/err/authentication.exception';
- import { HttpStatusException } from './model/err/http-status.exception';
- const multipartMiddleware = multiparty();
- export class Webserver {
- private app!: Express;
- private sessionHandler: SessionHandler;
- constructor(port: number) {
- try {
- this.app = express();
- this.app.set('trust proxy', 1); // Must be set for SessionHandler -> cookie.secure = 'auto' to work
- this.app.disable('x-powered-by'); // Prevent Express server to send Header "X-Powered-By: Express" (websecurity issue)
- // Parse Bodies containing application/json
- this.app.use(express.json());
- // Parse Bodies containing application/x-www-form-urlencoded
- this.app.use(express.urlencoded({ extended: true }));
- // Parse Bodies containing multipart/form-data
- this.app.use((req, res, next) => {
- if (req.header('content-type')?.startsWith('multipart/')) {
- multipartMiddleware(req, res, next);
- } else {
- next();
- }
- });
- // General Header Settings
- this.app.use((req, res, next) => {
- res.setHeader('X-Frame-Options', 'SAMEORIGIN');
- res.setHeader('Strict-Transport-Security', 'max-age=63072000; includeSubDomains; preload;');
- res.setHeader('Access-Control-Allow-Credentials', 'true');
- res.setHeader('Access-Control-Allow-Headers', 'X-CSRF-Token');
- res.setHeader('Access-Control-Expose-Headers', 'x-csrf-token');
- res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, PATCH, OPTIONS, HEAD');
- next();
- });
- this.sessionHandler = new SessionHandler();
- /** Authentication endpoint /auth/ */
- const auth = new AuthHandler(this.sessionHandler);
- this.app.use('/auth', auth.router);
- /** Send any request to /echo - receive your request data back */
- const echo = new EchoHandler();
- this.app.use('/echo', echo.router);
- /** Serves files in /private via URL /login/~ */
- const priv = new PrivateHandler(this.sessionHandler);
- this.app.use('/login', priv.router);
- /** Global Error Handler - transforms exceptions into the right HTTP response */
- this.app.use((err, req, res, next) => {
- try {
- if (err instanceof AuthenticationException) {
- res.status(err.statusCode).send(err.statusText);
- } else if (err instanceof HttpStatusException) {
- res.status(err.statusCode).send(err.message);
- } else if (Object.keys(err).includes('code') && err.code === 'EBADCSRFTOKEN') {
- res.status(403).send(err.message);
- } else {
- console.error(err);
- res.status(500).send('INTERNAL SERVER ERROR');
- }
- } catch (error) {
- console.error(error);
- res.status(500).send(error);
- }
- });
- /** Serves files in /public via root URL /~ */
- const pub = new PublicHandler();
- this.app.use('/', pub.router);
- this.app.listen(port, () => {
- console.log(`Example app listening on http://localhost:${port}`);
- });
- } catch (error) {
- console.error(error);
- process.exit(1);
- }
- }
- }
|