2020-01-14 13:25:13 +01:00
|
|
|
import express from 'express';
|
2020-04-22 17:24:15 +02:00
|
|
|
import bodyParser from 'body-parser';
|
2020-06-05 10:51:03 +02:00
|
|
|
import compression from 'compression';
|
2020-04-23 13:59:45 +02:00
|
|
|
import contentFilter from 'content-filter';
|
2020-06-05 10:51:03 +02:00
|
|
|
import helmet from 'helmet';
|
2020-07-09 13:48:27 +02:00
|
|
|
import cors from 'cors';
|
2020-05-12 14:05:47 +02:00
|
|
|
import api from './api';
|
2020-04-22 17:24:15 +02:00
|
|
|
import db from './db';
|
2020-01-14 13:25:13 +01:00
|
|
|
|
2020-07-28 13:59:13 +02:00
|
|
|
// TODO: check header, also in UI
|
2020-01-14 13:25:13 +01:00
|
|
|
|
|
|
|
// tell if server is running in debug or production environment
|
2020-08-04 13:54:14 +02:00
|
|
|
console.info(process.env.NODE_ENV === 'production' ?
|
|
|
|
'===== PRODUCTION =====' : process.env.NODE_ENV === 'test' ? '' :'===== DEVELOPMENT =====');
|
2020-01-14 13:25:13 +01:00
|
|
|
|
|
|
|
|
2020-04-22 17:24:15 +02:00
|
|
|
// mongodb connection
|
|
|
|
db.connect();
|
2020-04-20 16:17:43 +02:00
|
|
|
|
2020-01-14 13:25:13 +01:00
|
|
|
// create Express app
|
|
|
|
const app = express();
|
|
|
|
app.disable('x-powered-by');
|
|
|
|
|
|
|
|
// get port from environment, defaults to 3000
|
|
|
|
const port = process.env.PORT || 3000;
|
|
|
|
|
2020-07-28 10:30:10 +02:00
|
|
|
// security headers
|
2020-07-28 13:59:13 +02:00
|
|
|
const defaultHeaderConfig = {
|
2020-07-28 10:30:10 +02:00
|
|
|
contentSecurityPolicy: {
|
|
|
|
directives: {
|
|
|
|
defaultSrc: [`'none'`],
|
|
|
|
baseUri: [`'self'`],
|
|
|
|
formAction: [`'none'`],
|
|
|
|
frameAncestors: [`'none'`]
|
|
|
|
}
|
2020-07-28 13:59:13 +02:00
|
|
|
},
|
|
|
|
frameguard: {
|
|
|
|
action: 'deny'
|
|
|
|
},
|
|
|
|
permittedCrossDomainPolicies: true,
|
|
|
|
refererPolicy: true
|
|
|
|
};
|
|
|
|
app.use(helmet(defaultHeaderConfig));
|
2020-07-28 10:30:10 +02:00
|
|
|
// special CSP header for api-doc
|
|
|
|
app.use('/api-doc', helmet.contentSecurityPolicy({
|
2020-07-28 13:59:13 +02:00
|
|
|
...defaultHeaderConfig,
|
2020-07-28 10:30:10 +02:00
|
|
|
directives: {
|
2020-07-30 11:36:03 +02:00
|
|
|
defaultSrc: [`'none'`],
|
2020-07-28 10:30:10 +02:00
|
|
|
scriptSrc: [`'self'`],
|
|
|
|
connectSrc: [`'self'`],
|
|
|
|
styleSrc: [`'self'`, `'unsafe-inline'`],
|
2020-07-28 13:59:13 +02:00
|
|
|
imgSrc: [`'self'`, 'data:']
|
2020-07-28 10:30:10 +02:00
|
|
|
}
|
|
|
|
}));
|
|
|
|
// special CSP header for the bosch-logo.svg
|
|
|
|
app.use('/static/img/bosch-logo.svg', helmet.contentSecurityPolicy({
|
2020-07-28 13:59:13 +02:00
|
|
|
...defaultHeaderConfig,
|
2020-07-28 10:30:10 +02:00
|
|
|
directives: {
|
|
|
|
styleSrc: [`'unsafe-inline'`]
|
|
|
|
}
|
|
|
|
}));
|
|
|
|
|
|
|
|
// middleware
|
2020-08-04 13:54:14 +02:00
|
|
|
app.use(compression()); // compress responses
|
2020-04-22 17:24:15 +02:00
|
|
|
app.use(express.json({ limit: '5mb'}));
|
|
|
|
app.use(express.urlencoded({ extended: false, limit: '5mb' }));
|
|
|
|
app.use(bodyParser.json());
|
2020-08-04 13:54:14 +02:00
|
|
|
const injectionBlackList = ['$', '{', '&&', '||'];
|
|
|
|
app.use(contentFilter({
|
|
|
|
urlBlackList: injectionBlackList,
|
|
|
|
bodyBlackList: injectionBlackList
|
|
|
|
})); // filter URL query attacks
|
2020-04-22 17:24:15 +02:00
|
|
|
app.use((err, req, res, ignore) => { // bodyParser error handling
|
|
|
|
res.status(400).send({status: 'Invalid JSON body'});
|
|
|
|
});
|
2020-04-23 13:59:45 +02:00
|
|
|
app.use((req, res, next) => { // no database connection error
|
|
|
|
if (db.getState().db) {
|
|
|
|
next();
|
|
|
|
}
|
|
|
|
else {
|
2020-07-09 13:48:27 +02:00
|
|
|
console.error('No database connection');
|
2020-04-23 13:59:45 +02:00
|
|
|
res.status(500).send({status: 'Internal server error'});
|
|
|
|
}
|
|
|
|
});
|
2020-07-09 13:48:27 +02:00
|
|
|
app.use(cors()); // CORS headers
|
2020-04-23 13:59:45 +02:00
|
|
|
app.use(require('./helpers/authorize')); // handle authentication
|
2020-04-22 17:24:15 +02:00
|
|
|
|
2020-05-27 14:31:17 +02:00
|
|
|
// redirect /api routes for Angular proxy in development
|
2020-05-28 12:18:38 +02:00
|
|
|
if (process.env.NODE_ENV !== 'production') {
|
2020-06-29 15:50:24 +02:00
|
|
|
app.use('/api/:url([^]+)', (req, res) => {
|
2020-05-28 12:18:38 +02:00
|
|
|
req.url = '/' + req.params.url;
|
2020-06-29 15:50:24 +02:00
|
|
|
app.handle(req, res);
|
2020-05-28 12:18:38 +02:00
|
|
|
});
|
|
|
|
}
|
2020-05-27 14:31:17 +02:00
|
|
|
|
|
|
|
|
2020-01-14 13:25:13 +01:00
|
|
|
// require routes
|
2020-05-27 14:31:17 +02:00
|
|
|
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'));
|
2020-01-14 13:25:13 +01:00
|
|
|
|
2020-04-29 15:07:07 +02:00
|
|
|
// static files
|
|
|
|
app.use('/static', express.static('static'));
|
|
|
|
|
2020-01-14 13:25:13 +01:00
|
|
|
// Swagger UI
|
2020-07-28 10:30:10 +02:00
|
|
|
app.use('/api-doc', api());
|
2020-01-14 13:25:13 +01:00
|
|
|
|
2020-04-22 17:24:15 +02:00
|
|
|
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'});
|
|
|
|
});
|
|
|
|
|
|
|
|
|
2020-01-14 13:25:13 +01:00
|
|
|
// hook up server to port
|
2020-04-22 17:24:15 +02:00
|
|
|
const server = app.listen(port, () => {
|
2020-05-07 21:55:29 +02:00
|
|
|
console.info(process.env.NODE_ENV === 'test' ? '' : `Listening on http://localhost:${port}`);
|
2020-01-14 13:25:13 +01:00
|
|
|
});
|
2020-04-22 17:24:15 +02:00
|
|
|
|
|
|
|
module.exports = server;
|