125 lines
		
	
	
		
			3.4 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			125 lines
		
	
	
		
			3.4 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
import express from 'express';
 | 
						|
import bodyParser from 'body-parser';
 | 
						|
import compression from 'compression';
 | 
						|
import contentFilter from 'content-filter';
 | 
						|
import mongoSanitize from 'mongo-sanitize';
 | 
						|
import helmet from 'helmet';
 | 
						|
import cors from 'cors';
 | 
						|
import api from './api';
 | 
						|
import db from './db';
 | 
						|
 | 
						|
// TODO: check header, also in UI
 | 
						|
 | 
						|
// 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();
 | 
						|
 | 
						|
// create Express app
 | 
						|
const app = express();
 | 
						|
app.disable('x-powered-by');
 | 
						|
 | 
						|
// 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: {
 | 
						|
    scriptSrc: [`'self'`],
 | 
						|
    connectSrc: [`'self'`],
 | 
						|
    styleSrc: [`'self'`, `'unsafe-inline'`],
 | 
						|
    imgSrc: [`'self'`, 'data:']
 | 
						|
  }
 | 
						|
}));
 | 
						|
// special CSP header for the bosch-logo.svg
 | 
						|
app.use('/static/img/bosch-logo.svg', helmet.contentSecurityPolicy({
 | 
						|
  ...defaultHeaderConfig,
 | 
						|
  directives: {
 | 
						|
    styleSrc: [`'unsafe-inline'`]
 | 
						|
  }
 | 
						|
}));
 | 
						|
 | 
						|
// middleware
 | 
						|
app.use(contentFilter());  // filter URL query attacks
 | 
						|
app.use(express.json({ limit: '5mb'}));
 | 
						|
app.use(express.urlencoded({ extended: false, limit: '5mb' }));
 | 
						|
app.use(compression());  // compress responses
 | 
						|
app.use(bodyParser.json());
 | 
						|
app.use((req, res, next) => {  // filter body query attacks
 | 
						|
  req.body = mongoSanitize(req.body);
 | 
						|
  next();
 | 
						|
});
 | 
						|
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) => {
 | 
						|
    req.url = '/' + req.params.url;
 | 
						|
    app.handle(req, res);
 | 
						|
  });
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
// require routes
 | 
						|
app.use('/', require('./routes/root'));
 | 
						|
app.use('/', require('./routes/sample'));
 | 
						|
app.use('/', require('./routes/material'));
 | 
						|
app.use('/', require('./routes/template'));
 | 
						|
app.use('/', require('./routes/user'));
 | 
						|
app.use('/', require('./routes/measurement'));
 | 
						|
 | 
						|
// 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; |