import express from 'express'; import bodyParser from 'body-parser'; import compression from 'compression'; import contentFilter from 'content-filter'; import helmet from 'helmet'; import cors from 'cors'; import api from './api'; import db from './db'; import Mail from './helpers/mail'; // Tell if server is running in debug or production environment console.info(process.env.NODE_ENV === 'production' ? '===== PRODUCTION =====' : process.env.NODE_ENV === 'test' ? '' :'===== DEVELOPMENT ====='); // Mongodb connection db.connect(); // Mail service Mail.init(); // Create Express app const app = express(); // Get port from environment, defaults to 3000 const port = process.env.PORT || 3000; // Security headers const defaultHeaderConfig = { contentSecurityPolicy: { directives: { defaultSrc: [`'none'`], baseUri: [`'self'`], formAction: [`'none'`], frameAncestors: [`'none'`] } }, frameguard: { action: 'deny' }, permittedCrossDomainPolicies: true, refererPolicy: true }; app.use(helmet(defaultHeaderConfig)); // Special CSP header for api-doc app.use('/api-doc', helmet.contentSecurityPolicy({ ...defaultHeaderConfig, directives: { defaultSrc: [`'none'`], scriptSrc: [`'self'`], connectSrc: [`'self'`], styleSrc: [`'self'`, `'unsafe-inline'`], imgSrc: [`'self'`, 'data:'] } })); // Special CSP header for the intro-presentation app.use(/\/static\/intro-presentation\/(index.html)?/, helmet.contentSecurityPolicy({ ...defaultHeaderConfig, directives: { defaultSrc: [`'none'`], scriptSrc: [`'self'`, `'unsafe-inline'`], styleSrc: [`'self'`, `'unsafe-inline'`], imgSrc: [`'self'`] } })); // Special CSP header for the bosch-logo.svg app.use('/static/*.svg', helmet.contentSecurityPolicy({ ...defaultHeaderConfig, directives: { styleSrc: [`'unsafe-inline'`] } })); // Middleware app.use(compression()); // Compress responses app.use(express.json({ limit: '5mb'})); app.use(express.urlencoded({ extended: false, limit: '5mb' })); app.use(bodyParser.json()); app.use(contentFilter({ urlBlackList: ['$', '&&', '||'], bodyBlackList: ['$', '{', '&&', '||'], appendFound: true })); // Filter URL query attacks app.use((err, req, res, ignore) => { // BodyParser error handling res.status(400).send({status: 'Invalid JSON body'}); }); app.use((req, res, next) => { // No database connection error if (db.getState().db) { next(); } else { console.error('No database connection'); res.status(500).send({status: 'Internal server error'}); } }); app.use(cors()); // CORS headers app.use(require('./helpers/authorize')); // Handle authentication // Redirect /api routes for Angular proxy in development if (process.env.NODE_ENV !== 'production') { app.use('/api/:url([^]+)', (req, res) => { if (/help\//.test(req.params.url)) { // Encode URI again for help route req.params.url = 'help/' + encodeURIComponent(req.params.url.replace('help/', '')); } req.url = '/' + req.params.url; app.handle(req, res); }); } // Require routes app.use('/', require('./routes/help')); app.use('/', require('./routes/material')); app.use('/', require('./routes/measurement')); app.use('/', require('./routes/model')); app.use('/', require('./routes/prediction')); app.use('/', require('./routes/root')); app.use('/', require('./routes/sample')); app.use('/', require('./routes/template')); app.use('/', require('./routes/user')); // Static files app.use('/static', express.static('static')); // Swagger UI app.use('/api-doc', api()); app.use((req, res) => { // 404 error handling res.status(404).json({status: 'Not found'}); }); app.use((err, req, res, ignore) => { // Internal server error handling console.error(err); res.status(500).json({status: 'Internal server error'}); }); // Hook up server to port const server = app.listen(port, () => { console.info(process.env.NODE_ENV === 'test' ? '' : `Listening on http://localhost:${port}`); }); module.exports = server;