// Original file created by Prof.Dr. Matthias Hopf /** * Express based http & https server * * Requires express >= 4 */ var common = require('./server/common'), //admin = require ('./server/admin'), authorize = require('./server/authorization'), dbs = require('./server/dbs'); //files = require ('./server/files'); 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 var app = express(); /* * Init */ common .init(); dbs .init (common); authorize .init(common); //admin .init (common); //files .init (common); mong.Promise = global.Promise; /* * Security * * TODO: Install helmet * https://expressjs.com/de/advanced/best-practice-security.html * * (Disable Header information: Powerd by Express) * -> Information disclosure */ app.disable('x-powered-by'); /* * Route Control */ // 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 saveUninitialized: false, // don't create session until something stored resave: false, //don't save session if unmodified 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 })); // Favicon for Desktop app.use (serveFavicon(__dirname + '/public/img/favicon.ico')); // Minimal Logging //app.use (morgan ('dev')); // Advanced Logging 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'; }); 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'; }); app.use(morgan(':date[iso] :statusColored :method :url :userColored :response-time ms :res[content-length]')); // BodyParser // Returns middleware that only parses json bodies. // (https://www.npmjs.com/package/body-parser#bodyparserjsonoptions) app.use(bodyParser.json()); // Returns middleware that only parses urlencoded bodies // with qs library (https://www.npmjs.com/package/qs#readme) app.use(bodyParser.urlencoded({ extended: true })); // API var api_routes = express.Router(); // express app-object routing app.use('/api', api_routes); // Static Files - Allow access to 'public' folder app.use(express.static(__dirname + '/public')); // Other stuff is NOT authorized unless logged in //app.use (authorize.genCheckAuthorized ('user')); // No error so far? Then it's a 404! app.use(function (req, res, next) { next(common.genError(404, req.url)); }); //app.use (routes.errorHandler (true)); /* true: show stack traces */ /* * API */ // API allowed for all api_routes.post('/login', authorize.login); api_routes.post('/logout', authorize.logout); // Validate all other API calls // TODO - Validate API calls //api_routes.use(authorize.genCheckAuthorized('user')); // 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 isAuth = r.routes[e].auth || r.auth; if (isAuth) { 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); } } addRoutes(dbs); //addRoutes (admin); //addRoutes (files); /* * Servers */ http.createServer(app).listen(common.config.httpPort, function () { console.log("Express http server listening on port " + common.config.httpPort); }); /* * 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 */ // >>>>>>>>>>>>>>>>>>>>>>>>>>> SSL: DISABLED <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< /* if (common.config.httpsPort) { var options; try { try { // In case it's a real certificate: add CA chain cersts (TODO: use array if required) var ca = fs.readFileSync('keys/ca_cert.pem'); } catch (e) { ca = undefined; console.log("Note: Can't read CA bundle: " + e); } if (ca != undefined) { options = { key: fs.readFileSync('keys/omkey.pem'), cert: fs.readFileSync('keys/certificate.pem'), ca: ca }; https.createServer(options, app).listen(common.config.httpsPort, function () { console.log("Express https server listening on port " + common.config.httpsPort); }); } } catch (e) { console.log("Note: Can't read SSL keys/certs: " + e + "\nDisabling https server"); } } else { console.log("Note: https server disabled by config"); } common.mongoose.set('useCreateIndex', true);*/ /* * Uncaught Exceptions */ process.on("uncaughtException", function (err) { console.error("*** Uncaught Exception:"); console.error(err.stack); });