om/server.js

221 lines
6.3 KiB
JavaScript
Raw Normal View History

// Original file created by Prof.Dr. Matthias Hopf
/**
* Express based http & https server
*
* Requires express >= 4
*/
var common = require('./server/common'),
authorize = require('./server/authorization'),
dbs = require('./server/dbs');
/*
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();
authorize .init(common);
dbs .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
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
}));
// TODO Favicon for Desktop
//app.use (serveFavicon (__dirname + '/public/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);
2019-02-01 14:06:44 +01:00
// 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);
// Validate all other API calls
//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);
}
}
addRoutes(dbs);
/*
* 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
*/
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");
}
/*
* Uncaught Exceptions
*/
process.on("uncaughtException", function (err) {
console.error("*** Uncaught Exception:");
console.error(err.stack);
});