UNPKG

scriptremote

Version:

Message server providing secure remote access to scripted applications from a browser UI

291 lines (249 loc) 9.21 kB
'use strict'; // Derived from meanjs.org boilerplate var express = require('express'), exphbs = require('express-handlebars'), bodyParser = require('body-parser'), session = require('express-session'), compress = require('compression'), cookieParser = require('cookie-parser'), passport = require('passport'), mongoose = require('mongoose'), bruteMongo = require('express-brute-mongo'), streamRotator = require('file-stream-rotator'), path = require('path'), fs = require('fs'), //flash = require('connect-flash'), morgan = require('morgan'), helmet = require('helmet'), //methodOverride = require('method-override'), config = require('./config'); var mongoStore = require('connect-mongo/es5')(session); /** * Initialize express app */ module.exports = function(dbx) { debugger; var app = express(); // Load model files config.getGlobbedFiles('./app/models/**/*.js').forEach(function(modelPath) { require(path.resolve(modelPath)); }); // Setting application local variables app.locals.title = config.app.title; app.locals.description = config.app.description; app.locals.keywords = config.app.keywords; app.locals.appVersion = config.app.version; app.locals.jsFiles = config.getJavaScriptAssets(); app.locals.jsFilesLogin = config.getJavaScriptAssetsLogin(); app.locals.cssFiles = config.getCSSAssets(); app.locals.cssFilesLogin = config.getCSSAssetsLogin(); app.locals.port = config.port; app.locals.projectLimits = config.limits; app.locals.grid = dbx['grid']; app.locals.db = dbx['cnx'].db; app.locals.credentials = config.credentials; app.locals.csurf = {ignoreMethods: ['GET', 'HEAD', 'OPTIONS']}; app.locals.tokenLifetime = config.tokenLifetime; app.locals.regEmailProtocol = 'http://'; app.locals.secureCookies = false; app.locals.mailer = {'from': config.mailer.from, 'options': {'auth': config.mailer.options.auth}}; if (config.mailer.options.service) { app.locals.mailer.options['service'] = config.mailer.options['service']; } else if (config.mailer.options.host && config.mailer.options.port && config.mailer.options.TLS) { app.locals.mailer.options['host'] = config.mailer.options['host']; app.locals.mailer.options['port'] = config.mailer.options['port']; app.locals.mailer.options['TLS'] = config.mailer.options['TLS']; } else { // Should not get here console.log('Invalid mailer options'); return null; } // Settings for limiting login attempts app.locals.bruteStore = new bruteMongo(function(ready) { ready(app.locals.db.collection('bruteforce')); }); if (process.env.NODE_ENV === 'test') { // mocha tests exceed default login retry limits app.locals.bruteOptions = {freeRetries: 1000}; } else { app.locals.bruteOptions = {freeReTries: 2}; } // Should be placed before express.static app.use(compress({ filter: function(req, res) { return (/json|text|javascript|css/).test(res.getHeader('Content-Type')); }, level: 9 })); // Showing stack errors //app.set('showStackError', true); /* * Server-side template engine is express-handlebars. * Layout app/views/layouts/layout.server is for the server-controlled * pages ('/register', '/login'). * Layout app/views/layouts/layout.angular is for the remaining * Angular-controlled single-page part ('/') */ var viewsPath = path.join(__dirname, '../app/views'); var engineName = 'handlebars'; var hbs = exphbs.create({layoutsDir: viewsPath + '/layouts', defaultLayout: 'layout.server.handlebars', extName: engineName}); app.engine(engineName, hbs.engine); // Set views path and view engine app.set('view engine', engineName); app.set('views', viewsPath); // Environment dependent middleware var logDirectory; var accessLogStream; if (process.env.NODE_ENV === 'test') { // Setting the static folder app.use(express.static('public')); // Logger setup logDirectory = path.join(__dirname, '../log'); if (!fs.existsSync(logDirectory)) { fs.mkdirSync(logDirectory); } accessLogStream = streamRotator.getStream({ date_format: 'YYYYMMDD', filename: path.join(logDirectory, 'access-%DATE%.log'), frequency: '168h', verbose: false }) app.use(morgan('combined', {stream: accessLogStream})) } else if (process.env.NODE_ENV === 'development') { // Setting the static folder app.use(express.static('public')); // Disable handlebars template caching app.set('view cache', false); // Logger setup // var accessLogStream = fs.createWriteStream(path.join(__dirname, 'access.log'), {flags: 'a'}) //app.use(morgan('dev')); } else if (process.env.NODE_ENV === 'production') { // Setting the static folder app.use(express.static('public', {maxage: '30 days'})); // Enable handlebars template caching app.set('view cache', true); // setup logger //var accessLogStream = fs.createWriteStream(path.join(__dirname, 'access.log'), {flags: 'a'}) //app.use(morgan('combined', {stream: accessLogStream})) } else if (process.env.NODE_ENV === 'secure') { // Setting the static folder app.use(express.static('public', {maxage: '30 days'})); // Enable handlebars template caching app.set('view cache', true); // Logger setup logDirectory = path.join(__dirname, '../log'); if (!fs.existsSync(logDirectory)) { fs.mkdirSync(logDirectory); } accessLogStream = streamRotator.getStream({ date_format: 'YYYYMMDD', filename: path.join(logDirectory, 'access-%DATE%.log'), frequency: '168h', verbose: false }) app.use(morgan('combined', {stream: accessLogStream})) /* * This setup assumes an exposed node server listening * only for https and no server-side http redirection */ app.locals.regEmailProtocol = 'https://'; app.use(function(req, res, next) { res.set('Strict-Transport-Security', 'max-age=31536000'); if (req.secure) { next(); } else { // Should not get here var err = new Error('Invalid protocol, use https'); next(err); } }) } else if (process.env.NODE_ENV === 'cloudfoundry') { // Setting the static folder app.use(express.static('public', {maxage: '30 days'})); // Enable handlebars template caching app.set('view cache', true); /* * This setup assumes a proxy listening for http * and https with TLS terminating at the proxy * so node sees only http. The original protocol * is passed along in header. */ app.locals.regEmailProtocol = 'https://'; app.use(function(req, res, next) { res.set('Strict-Transport-Security', 'max-age=31536000'); if (req.get('X-Forwarded-Proto') != 'https') { res.redirect('https://' + req.headers.host + req.url); } else { next(); } }) } /* * bodyParser.urlencoded is only invoked on the individual * route that actually need it * app.use(bodyParser.urlencoded({ * extended: true * })); */ app.use(bodyParser.json()); //app.use(methodOverride()); // CookieParser should be placed before session app.use(cookieParser()); // Mongo session storage var db = app.locals.db; var sessionArgs = { saveUninitialized: false, resave: false, unset: 'destroy', cookie: {}, secret: config.sessionSecret, store: new mongoStore({ db: db, ttl: 14*24*3600 }) }; if (process.env.NODE_ENV === 'secure') { /* * Make session cookie secure. * This setup assumes no proxy. */ //app.set('trust proxy', true) // trust first proxy sessionArgs.cookie.secure = true app.locals.secureCookies = true; } else if (process.env.NODE_ENV === 'cloudfoundry') { /* * Make session cookie secure. * This setup assumes a proxy. */ app.set('trust proxy', true) // trust first proxy sessionArgs.cookie.secure = true app.locals.secureCookies = true; } app.use(session(sessionArgs)); // Sessions are handled outside passport for more control app.use(passport.initialize()); //app.use(passport.session()); // connect flash for flash messages // app.use(flash()); // Use helmet to secure Express headers app.use(helmet.xframe()); app.use(helmet.xssFilter()); app.use(helmet.nosniff()); app.use(helmet.ienoopen()); app.disable('x-powered-by'); // Load routing files config.getGlobbedFiles('./app/routes/**/*.js').forEach(function(routePath) { require(path.resolve(routePath))(app); }); // Load default 404 and 500 routes require('../app/routes/default.server.routes.js')(app); // Return Express server instance return app; };