2019-06-20 17:17:45 +02:00
|
|
|
// Original file created by Prof.Dr. Matthias Hopf
|
|
|
|
|
2018-10-30 17:04:33 +01:00
|
|
|
/**
|
|
|
|
* Express based http & https server
|
|
|
|
*
|
|
|
|
* Requires express >= 4
|
|
|
|
*/
|
2019-06-20 17:17:45 +02:00
|
|
|
var common = require('./server/common'),
|
|
|
|
authorize = require('./server/authorization'),
|
|
|
|
dbs = require('./server/dbs');
|
2018-10-30 17:04:33 +01:00
|
|
|
/*
|
|
|
|
dbs = require ('./server/dbs'),
|
|
|
|
files = require ('./server/files');
|
|
|
|
*/
|
2019-06-20 17:17:45 +02:00
|
|
|
const fs = common.fs, // file sync, read certificates
|
|
|
|
http = common.http, // http handler
|
|
|
|
https = require('https'), // https handler
|
|
|
|
express = require('express'), // node server framework
|
|
|
|
session = require('express-session'), // session management (security)
|
|
|
|
morgan = require('morgan'), // logger
|
|
|
|
mong = common.mongoose, // mongoose
|
|
|
|
// serveFavicon = require('serve-favicon'), // provide favicon
|
|
|
|
bodyParser = require('body-parser'), // post request bodyparser
|
|
|
|
MongoStore = require('connect-mongo')(session); // use mongodb as session storage
|
2018-10-30 17:04:33 +01:00
|
|
|
|
|
|
|
var app = express();
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Init
|
|
|
|
*/
|
2019-06-20 17:17:45 +02:00
|
|
|
common .init();
|
|
|
|
authorize .init(common);
|
|
|
|
dbs .init (common);
|
2019-06-18 15:54:07 +02:00
|
|
|
//files .init (common);
|
2019-06-20 17:17:45 +02:00
|
|
|
mong.Promise = global.Promise;
|
2018-10-30 17:04:33 +01:00
|
|
|
|
|
|
|
/*
|
2019-06-18 15:54:07 +02:00
|
|
|
* Security
|
|
|
|
*
|
|
|
|
* TODO: Install helmet
|
|
|
|
* https://expressjs.com/de/advanced/best-practice-security.html
|
|
|
|
*
|
|
|
|
* (Disable Header information: Powerd by Express)
|
|
|
|
* -> Information disclosure
|
2018-10-30 17:04:33 +01:00
|
|
|
*/
|
2019-06-20 17:17:45 +02:00
|
|
|
app.disable('x-powered-by');
|
2018-10-30 17:04:33 +01:00
|
|
|
|
2019-06-18 15:54:07 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Route Control
|
|
|
|
*/
|
2019-06-20 17:17:45 +02:00
|
|
|
// Session Management
|
|
|
|
app.set('trust proxy', 1) // trust first proxy, neccessary for cookie secure: true flag
|
|
|
|
app.use(session({
|
|
|
|
secret: 'ahhgylhuvh', // caesar(3) 2 letter surname
|
|
|
|
resave: false,
|
|
|
|
saveUninitialized: false,
|
|
|
|
cookie: {
|
|
|
|
maxAge: 30 * 24 * 3600 * 1000, // TODO: ttl for session as well (Store)
|
|
|
|
secure: true, // true for https only (since our app works only with https)
|
|
|
|
},
|
|
|
|
name: 'om.sid',
|
|
|
|
store: new MongoStore({
|
|
|
|
mongooseConnection: mong.connection,
|
|
|
|
ttl: 30 * 24 * 3600
|
|
|
|
}), // mongoose + connect-mongo
|
|
|
|
//store: new MemoryStore ({checkPeriod: 24*3600*1000}), // memorystore
|
|
|
|
}));
|
2019-06-18 15:54:07 +02:00
|
|
|
|
2019-06-20 17:17:45 +02:00
|
|
|
// TODO Favicon for Desktop
|
2019-06-18 15:54:07 +02:00
|
|
|
//app.use (serveFavicon (__dirname + '/public/favicon.ico'));
|
|
|
|
|
|
|
|
// Minimal Logging
|
|
|
|
//app.use (morgan ('dev'));
|
|
|
|
// Advanced Logging
|
2019-06-20 17:17:45 +02:00
|
|
|
morgan.token('user', function (req, res) {
|
|
|
|
return (req.session && req.session.user) || '-';
|
|
|
|
});
|
|
|
|
morgan.token('userColored', function (req, res) {
|
|
|
|
var color = 0;
|
|
|
|
if (req.session && req.session.roles)
|
|
|
|
color = req.session.roles.admin ? 31 // red
|
|
|
|
: req.session.roles.user ? 34 // blue
|
|
|
|
: 0; // no color
|
|
|
|
return '\x1b[' + color + 'm' + ((req.session && req.session.user) || '-') + '\x1b[0m';
|
2019-06-18 15:54:07 +02:00
|
|
|
});
|
2019-06-20 17:17:45 +02:00
|
|
|
morgan.token('statusColored', function (req, res) {
|
|
|
|
var color = res.statusCode >= 500 ? 31 // red
|
|
|
|
: res.statusCode >= 400 ? 33 // yellow
|
|
|
|
: res.statusCode >= 300 ? 36 // cyan
|
|
|
|
: res.statusCode >= 200 ? 32 // green
|
|
|
|
: 0; // no color
|
|
|
|
return '\x1b[' + color + 'm' + (res.headersSent ? res.statusCode : '-') + '\x1b[0m';
|
2019-06-18 15:54:07 +02:00
|
|
|
});
|
2019-06-20 17:17:45 +02:00
|
|
|
app.use(morgan(':date[iso] :statusColored :method :url :userColored :response-time ms :res[content-length]'));
|
2019-06-18 15:54:07 +02:00
|
|
|
|
|
|
|
// BodyParser
|
|
|
|
// Returns middleware that only parses json bodies.
|
|
|
|
// (https://www.npmjs.com/package/body-parser#bodyparserjsonoptions)
|
2019-06-20 17:17:45 +02:00
|
|
|
app.use(bodyParser.json());
|
2019-06-18 15:54:07 +02:00
|
|
|
// Returns middleware that only parses urlencoded bodies
|
|
|
|
// with qs library (https://www.npmjs.com/package/qs#readme)
|
2019-06-20 17:17:45 +02:00
|
|
|
app.use(bodyParser.urlencoded({
|
|
|
|
extended: true
|
|
|
|
}));
|
2018-10-30 17:04:33 +01:00
|
|
|
|
|
|
|
// API
|
2019-06-18 15:54:07 +02:00
|
|
|
var api_routes = express.Router(); // express app-object routing
|
2019-06-20 17:17:45 +02:00
|
|
|
app.use('/api', api_routes);
|
2019-02-01 14:06:44 +01:00
|
|
|
|
2019-06-20 17:17:45 +02:00
|
|
|
// Static Files - Allow access to 'public' folder
|
2019-06-18 15:54:07 +02:00
|
|
|
app.use(express.static(__dirname + '/public'));
|
|
|
|
|
|
|
|
// Other stuff is NOT authorized unless logged in
|
|
|
|
//app.use (authorize.genCheckAuthorized ('user'));
|
2018-10-30 17:04:33 +01:00
|
|
|
|
2019-06-18 15:54:07 +02:00
|
|
|
// No error so far? Then it's a 404!
|
2019-06-20 17:17:45 +02:00
|
|
|
app.use(function (req, res, next) {
|
|
|
|
next(common.genError(404, req.url));
|
|
|
|
});
|
2019-06-18 15:54:07 +02:00
|
|
|
//app.use (routes.errorHandler (true)); /* true: show stack traces */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* API
|
|
|
|
*/
|
|
|
|
// API allowed for all
|
2019-06-20 17:17:45 +02:00
|
|
|
api_routes.post('/login', authorize.login);
|
2019-06-04 15:26:38 +02:00
|
|
|
|
2019-06-18 15:54:07 +02:00
|
|
|
// Validate all other API calls
|
2019-06-20 17:17:45 +02:00
|
|
|
//api_routes.use(authorize.genCheckAuthorized('user'));
|
|
|
|
api_routes.post('/logout', authorize.logout);
|
|
|
|
|
|
|
|
// Add API routes
|
|
|
|
function addRoutes(r) {
|
|
|
|
for (var e in r.routes) {
|
|
|
|
var route = '/' + e + (r.routes[e].params ? "/" + r.routes[e].params : "");
|
|
|
|
var log = "Adding routes for " + route + ":";
|
|
|
|
/*
|
|
|
|
var auth = r.routes[e].auth || r.auth;
|
|
|
|
if (auth) {
|
|
|
|
log += " [auth]";
|
|
|
|
api_routes.use (route, function (req, res, next) {
|
|
|
|
if (! auth(req))
|
|
|
|
return next (common.genError (403, "Unauthorized"));
|
|
|
|
next ();
|
|
|
|
});
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
/*
|
|
|
|
var role = r.routes[e].role || r.role;
|
|
|
|
if (role) {
|
|
|
|
log += " [role:"+role+"]";
|
|
|
|
api_routes.use (route, authorize.genCheckAuthorized (role));
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
const methods = ["get", "post", "put", "delete"];
|
|
|
|
for (var m in methods) {
|
|
|
|
if (r.routes[e][methods[m]]) {
|
|
|
|
log += " " + methods[m];
|
|
|
|
api_routes[methods[m]](route, r.routes[e][methods[m]]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
console.log(log);
|
|
|
|
}
|
2019-06-18 15:54:07 +02:00
|
|
|
}
|
2019-02-07 11:24:45 +01:00
|
|
|
|
2019-06-20 17:17:45 +02:00
|
|
|
addRoutes(dbs);
|
2018-10-30 17:04:33 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Servers
|
|
|
|
*/
|
2019-06-20 17:17:45 +02:00
|
|
|
http.createServer(app).listen(common.config.httpPort, function () {
|
|
|
|
console.log("Express http server listening on port " + common.config.httpPort);
|
2018-10-30 17:04:33 +01:00
|
|
|
});
|
|
|
|
|
|
|
|
/*
|
|
|
|
* SSL certificates
|
|
|
|
*
|
|
|
|
* Keys + Certificate in current dir (not servable!)
|
|
|
|
* to create (self-signed) SSL certs:
|
|
|
|
*
|
|
|
|
* openssl genrsa -out privatekey.pem 1024
|
|
|
|
* openssl req -new -key privatekey.pem -out certrequest.csr
|
|
|
|
* openssl x509 -req -in certrequest.csr -signkey privatekey.pem -out certificate.pem
|
|
|
|
* rm certrequest.csr
|
|
|
|
*/
|
2019-06-18 15:54:07 +02:00
|
|
|
if (common.config.httpsPort) {
|
|
|
|
var options;
|
|
|
|
try {
|
|
|
|
try {
|
|
|
|
// In case it's a real certificate: add CA chain cersts (TODO: use array if required)
|
2019-06-20 17:17:45 +02:00
|
|
|
var ca = fs.readFileSync('keys/ca_cert.pem');
|
2019-06-18 15:54:07 +02:00
|
|
|
} catch (e) {
|
|
|
|
ca = undefined;
|
2019-06-20 17:17:45 +02:00
|
|
|
console.log("Note: Can't read CA bundle: " + e);
|
2019-06-18 15:54:07 +02:00
|
|
|
}
|
|
|
|
if (ca != undefined) {
|
|
|
|
options = {
|
2019-06-20 17:17:45 +02:00
|
|
|
key: fs.readFileSync('keys/omkey.pem'),
|
|
|
|
cert: fs.readFileSync('keys/certificate.pem'),
|
2019-06-18 15:54:07 +02:00
|
|
|
ca: ca
|
2019-06-20 17:17:45 +02:00
|
|
|
};
|
|
|
|
https.createServer(options, app).listen(common.config.httpsPort, function () {
|
|
|
|
console.log("Express https server listening on port " + common.config.httpsPort);
|
2019-06-18 15:54:07 +02:00
|
|
|
});
|
|
|
|
}
|
|
|
|
} catch (e) {
|
2019-06-20 17:17:45 +02:00
|
|
|
console.log("Note: Can't read SSL keys/certs: " + e + "\nDisabling https server");
|
2019-02-09 19:53:40 +01:00
|
|
|
}
|
2019-06-18 15:54:07 +02:00
|
|
|
} else {
|
|
|
|
console.log("Note: https server disabled by config");
|
2018-10-30 17:04:33 +01:00
|
|
|
}
|
2018-11-27 23:33:26 +01:00
|
|
|
|
2018-10-30 17:04:33 +01:00
|
|
|
/*
|
|
|
|
* Uncaught Exceptions
|
|
|
|
*/
|
2019-06-20 17:17:45 +02:00
|
|
|
process.on("uncaughtException", function (err) {
|
|
|
|
console.error("*** Uncaught Exception:");
|
|
|
|
console.error(err.stack);
|
2018-10-30 17:04:33 +01:00
|
|
|
});
|