function addMiddleware(server) { if (process.env.NODE_ENV === 'production') { // server.use(morgan('combined')) server.use(compression()) server.use(express.static(PUBLIC_DIR, { maxAge: 31536000000 })) } // } else { // server.use(morgan('dev')) // } server.use(express.static(path.join(APP_PATH, 'static'))) server.use(bodyParser.json()) server.use(hpp()) server.use(helmet.contentSecurityPolicy({ defaultSrc: [ "'self'" ], scriptSrc: [ "'self'" ], styleSrc: [ "'self'" ], imgSrc: [ "'self'" ], connectSrc: [ "'self'", 'ws:' ], fontSrc: [ "'self'" ], objectSrc: [ "'none'" ], mediaSrc: [ "'none'" ], frameSrc: [ "'none'" ] })) server.use(helmet.xssFilter()) server.use(helmet.frameguard('deny')) server.use(helmet.ieNoOpen()) server.use(helmet.noSniff()) }
export function csp({ _config = config, noScriptStyles, _log = log } = {}) { const cspConfig = _config.get('CSP') !== 'false' ? deepcopy(_config.get('CSP')) : false; if (cspConfig) { if (noScriptStyles) { if (!_config.get('isDevelopment')) { const hash = crypto .createHash('sha256') .update(noScriptStyles) .digest('base64'); const cspValue = `'sha256-${hash}'`; if ( cspConfig.directives && !cspConfig.directives.styleSrc.includes(cspValue) ) { cspConfig.directives.styleSrc.push(cspValue); } } else { _log.debug(oneLine`CSP style-src hash has been omitted to allow "unsafe-inline" in development`); } } return helmet.contentSecurityPolicy(cspConfig); } return (req, res, next) => { _log.warn('CSP has been disabled from the config'); next(); }; }
const setupHelmet = app => { // Protect against some well known web vulnerabilities // by setting HTTP headers appropriately. app.use(helmet()); // Helmet content security policy (CSP) to allow only assets from same domain. app.use(helmet.contentSecurityPolicy({ directives: { fontSrc: ['\'self\' data:'], scriptSrc: ['\'self\'', '\'unsafe-inline\'', 'www.google-analytics.com', 'hmctspiwik.useconnect.co.uk', 'www.googletagmanager.com'], connectSrc: ['\'self\''], mediaSrc: ['\'self\''], frameSrc: ['\'none\''], imgSrc: ['\'self\'', 'www.google-analytics.com', 'hmctspiwik.useconnect.co.uk'] } })); const maxAge = config.ssl.hpkp.maxAge; const sha256s = [ config.ssl.hpkp.sha256s, config.ssl.hpkp.sha256sBackup ]; // Helmet HTTP public key pinning app.use(helmet.hpkp({ maxAge, sha256s })); // Helmet referrer policy app.use(helmet.referrerPolicy({ policy: 'origin' })); };
module.exports = function (config) { const cspMiddleware = helmet.contentSecurityPolicy(config.rules); return htmlOnly((req, res, next) => { if (isCspRequired(req)) { cspMiddleware(req, res, next); } else { next(); } }); };
super.run(force).then(() => { const app = express(); const router = new Router(); const port = config.port; app.set('views', './private'); app.set('view engine', 'html'); app.engine('html', hogan); app.use(helmet()); app.use(compression()); app.use(bodyParser.json()); app.use(bodyParser.urlencoded({ extended: true })); app.use(express.static('./public', { maxAge: 31557600000 })); if(!envs.__PROD__){ app.use(helmet.noCache()); }else{ app.use(helmet.hsts({ force: true , maxAge: 2592000000 , includeSubDomains: true })); app.use(helmet.contentSecurityPolicy({ defaultSrc: [`'self'`] , fontSrc: [`'self'`] , imgSrc: [`'self'`, 'data:'] , scriptSrc: [ `'self'` , `'unsafe-inline'` , `'unsafe-eval'` , 'http://*.facebook.com/' , 'https://*.facebook.com/' , 'https://*.google-analytics.com' , 'http://*.google-analytics.com' ] , styleSrc: [ `self'` , `'unsafe-inline'` , 'http://*.facebook.com/' , 'https://*.facebook.com/' , 'https://*.google-analytics.com' , 'http://*.google-analytics.com' ] })); } app.use('/', router); app.listen(port, (err) => { if(err){ return reject(err); } console.log(`Express is listening at ${port}`); return resolve(); }); }, reject);
module.exports = function() { var app = express(); app.use(bodyParser.urlencoded({ extended: true })); app.use(bodyParser.json()); app.use(helmet()); /*SEGURANÇA*/ app.disable('x-powered-by'); app.use(helmet.contentSecurityPolicy({ // Specify directives as normal. directives: { defaultSrc: ["'self'", 'default.com'], scriptSrc: ["'self'", "'unsafe-inline'"], styleSrc: ['style.com'], imgSrc: ['img.com', 'data:'], sandbox: ['allow-forms', 'allow-scripts'], reportUri: '/report-violation', objectSrc: [] // An empty array allows nothing through }, // Set to true if you only want browsers to report errors, not block them reportOnly: false, // Set to true if you want to blindly set all headers: Content-Security-Policy, // X-WebKit-CSP, and X-Content-Security-Policy. setAllHeaders: false, // Set to true if you want to disable CSP on Android where it can be buggy. disableAndroid: false, // Set to false if you want to completely disable any user-agent sniffing. // This may make the headers less compatible but it will be much faster. // This defaults to `true`. browserSniff: true })); app.use(helmet.xssFilter()) load('routes', {cwd: 'app'}) .then('infra') .into(app); return app; }
function addMiddleware(server) { server.use(express.static(path.join(APP_PATH, 'static'))) server.use(bodyParser.json()) server.use(hpp()) server.use(helmet.contentSecurityPolicy({ defaultSrc: [ "'self'" ], scriptSrc: [ "'self'" ], styleSrc: [ "'self'" ], imgSrc: [ "'self'" ], connectSrc: [ "'self'", 'ws:' ], fontSrc: [ "'self'" ], objectSrc: [ "'none'" ], mediaSrc: [ "'none'" ], frameSrc: [ "'none'" ] })) server.use(helmet.xssFilter()) server.use(helmet.frameguard('deny')) server.use(helmet.ieNoOpen()) server.use(helmet.noSniff()) }
function bootstrap(options) { let config = getConfig(options); const app = express(); const userMiddleware = express.Router(); app.use(helmet()); if (config.csp !== false && !config.csp.disabled) { app.use(helmet.contentSecurityPolicy({ directives: getContentSecurityPolicy(config) })); } // shallow health check app.get('/healthz/ping', require('express-healthcheck')()); if (!config || !config.routes || !config.routes.length) { throw new Error('Must be called with a list of routes'); } config.routes.forEach(route => { if (!route.steps && !route.pages) { throw new Error('Each app must have steps and/or pages'); } }); config.logger = logger(config); app.use(churchill(config.logger)); if (config.middleware) { config.middleware.forEach(middleware => app.use(middleware)); } serveStatic(app, config); settings(app, config); sessionStore(app, config); app.use(translate({ resources: config.theme.translations, path: path.resolve(config.root, config.translations) + '/__lng__/__ns__.json' })); app.use(mixins()); app.use(markdown(config.markdown)); if (config.getCookies === true) { deprecate( '`getCookies` option is deprecated and may be removed in future versions.', 'Use `pages` to define static cookies page.' ); app.get('/cookies', (req, res) => { res.render('cookies', req.translate('cookies')); }); } if (config.getTerms === true) { deprecate( '`getTerms` option is deprecated and may be removed in future versions.', 'Use `pages` to define static terms and conditions page.' ); app.get('/terms-and-conditions', (req, res) => { res.render('terms', req.translate('terms')); }); } app.use(userMiddleware); app.use(hofMiddleware.cookies()); loadRoutes(app, config); applyErrorMiddlewares(app, config); const instance = { use() { userMiddleware.use.apply(userMiddleware, arguments); return instance; }, server: null, start: (startConfig) => { startConfig = getConfig(config, startConfig); const protocol = startConfig.protocol === 'http' ? http : https; instance.server = protocol.createServer(app); return new Promise((resolve, reject) => { instance.server.listen(startConfig.port, startConfig.host, err => { if (err) { reject(new Error('Unable to connect to server')); } resolve(instance); }); }); }, stop() { return new Promise((resolve, reject) => instance.server.close(err => { if (err) { reject(new Error('Unable to stop server')); } resolve(instance); })); } }; if (config.start !== false) { instance.start(config); } return instance; }
app.use(helmet.frameguard()); app.use(helmet.hidePoweredBy()); app.use(helmet.ieNoOpen()); app.use(helmet.noSniff()); app.use(helmet.xssFilter()); app.use(helmet.hsts({ maxAge: 31536000, includeSubdomains: true, force: httpsEnabled, preload: true })); app.use(helmet.contentSecurityPolicy({ defaultSrc: ['\'none\''], connectSrc: ['*'], scriptSrc: ['\'self\'', '\'unsafe-eval\''], styleSrc: ['\'self\'', 'fonts.googleapis.com', '\'unsafe-inline\''], fontSrc: ['\'self\'', 'fonts.gstatic.com'], mediaSrc: ['\'self\''], objectSrc: ['\'self\''], imgSrc: ['*'] })); var bundles = {}; app.use(require('connect-assets')({ paths: [ 'media/js', 'media/less' ], helperContext: bundles, build: settings.env === 'production', fingerprinting: settings.env === 'production', servePath: 'media/dist'
var express = require('express'); var helmet = require('helmet'); var app = express(); app.use(helmet.contentSecurityPolicy()); app.use(express.static("public")); var server = app.listen(3000, function () { var host = server.address().address; var port = server.address().port; console.log('Example app listening at http://%s:%s', host, port); });
const isDeveloping = process.env.NODE_ENV == 'development' const port = process.env.PORT || 5000 const server = global.server = express() // Security server.disable('x-powered-by') server.set('port', port) server.use(bodyParser.urlencoded({ extended: false })) server.use(bodyParser.json()) server.use(hpp()) server.use(helmet.contentSecurityPolicy({ defaultSrc: ["'self'"], scriptSrc: ["'self'"], styleSrc: ["'self'"], imgSrc: ["'self'"], connectSrc: ["'self'", 'ws:'], fontSrc: ["'self'"], objectSrc: ["'none'"], mediaSrc: ["'none'"], frameSrc: ["'none'"] })) server.use(helmet.xssFilter()) server.use(helmet.frameguard('deny')) server.use(helmet.ieNoOpen()) server.use(helmet.noSniff()) server.use(cookieParser()) server.use(compression()) // API server.use('/api/v0/posts', require('./api/posts')) server.use('/api/v0/post', require('./api/post'))
mongoose.connect(settings.database.uri, function(err) { if (err) { throw err; } // // express.oi Setup // if (httpsEnabled) { app = express().https({ key: fs.readFileSync(settings.https.key), cert: fs.readFileSync(settings.https.cert), passphrase: settings.https.passphrase }).io(); } else { app = express().http().io(); } if (settings.env === 'production') { app.set('env', settings.env); app.set('json spaces', undefined); app.enable('view cache'); } // Session var sessionStore = new MongoStore({ mongooseConnection: mongoose.connection }); // Session var session = { key: 'connect.sid', secret: settings.secrets.cookie, store: sessionStore, cookie: { secure: httpsEnabled }, resave: false, saveUninitialized: true }; // Set compression before any routes app.use(compression({ threshold: 512 })); app.use(cookieParser()); app.io.session(session); auth.setup(app, session, core); // Security protections app.use(helmet.frameguard()); app.use(helmet.hidePoweredBy()); app.use(helmet.ieNoOpen()); app.use(helmet.noSniff()); app.use(helmet.xssFilter()); app.use(helmet.hsts({ maxAge: 31536000, includeSubdomains: true, force: httpsEnabled, preload: true })); app.use(helmet.contentSecurityPolicy({ defaultSrc: ['\'none\''], connectSrc: ['*'], scriptSrc: ['\'self\'', '\'unsafe-eval\''], styleSrc: ['\'self\'', 'fonts.googleapis.com', '\'unsafe-inline\''], fontSrc: ['\'self\'', 'fonts.gstatic.com'], mediaSrc: ['\'self\''], objectSrc: ['\'self\''], imgSrc: ['* data:'] })); var bundles = {}; app.use(require('connect-assets')({ paths: [ 'media/js', 'media/less' ], helperContext: bundles, build: settings.env === 'production', fingerprinting: settings.env === 'production', servePath: 'media/dist' })); // Public app.use('/media', express.static(__dirname + '/media', { maxAge: '364d' })); // Templates var nun = nunjucks.configure('templates', { autoescape: true, express: app, tags: { blockStart: '<%', blockEnd: '%>', variableStart: '<$', variableEnd: '$>', commentStart: '<#', commentEnd: '#>' } }); function wrapBundler(func) { // This method ensures all assets paths start with "./" // Making them relative, and not absolute return function() { return func.apply(func, arguments) .replace(/href="\//g, 'href="./') .replace(/src="\//g, 'src="./'); }; } nun.addFilter('js', wrapBundler(bundles.js)); nun.addFilter('css', wrapBundler(bundles.css)); nun.addGlobal('text_search', false); // i18n i18n.configure({ directory: path.resolve(__dirname, './locales'), locales: settings.i18n.locales || settings.i18n.locale, defaultLocale: settings.i18n.locale }); app.use(i18n.init); // HTTP Middlewares app.use(bodyParser.json()); app.use(bodyParser.urlencoded({ extended: true })); // IE header app.use(function(req, res, next) { res.setHeader('X-UA-Compatible', 'IE=Edge,chrome=1'); next(); }); // // Controllers // _.each(controllers, function(controller) { controller.apply({ app: app, core: core, settings: settings, middlewares: middlewares, models: models, controllers: controllers }); }); // // Go Time // if (!mongoose.mongo || !mongoose.mongo.Admin) { // MongoDB API has changed, assume text search is enabled nun.addGlobal('text_search', true); return; } var admin = new mongoose.mongo.Admin(mongoose.connection.db); admin.buildInfo(function (err, info) { if (err || !info) { return; } var version = info.version.split('.'); if (version.length < 2) { return; } if(version[0] < 2) { return; } if(version[0] === '2' && version[1] < 6) { return; } nun.addGlobal('text_search', true); }); var port = httpsEnabled && settings.https.port || httpEnabled && settings.http.port; var host = httpsEnabled && settings.https.host || httpEnabled && settings.http.host || '0.0.0.0'; if (httpsEnabled && httpEnabled) { // Create an HTTP -> HTTPS redirect server var redirectServer = express(); redirectServer.get('*', function(req, res) { var urlPort = port === 80 ? '' : ':' + port; res.redirect('https://' + req.hostname + urlPort + req.path); }); http.createServer(redirectServer) .listen(settings.http.port || 5000, host); } app.listen(port, host); // // XMPP // if (settings.xmpp.enable) { var xmpp = require('./app/xmpp/index'); xmpp(core); } var art = fs.readFileSync('./app/misc/art.txt', 'utf8'); console.log('\n' + art + '\n\n' + 'Release ' + psjon.version.yellow + '\n'); });
// configure app to handle CORS requests app.use(function(req, res, next) { res.setHeader('Access-Control-Allow-Origin', '*'); res.setHeader('Access-Control-Allow-Methods', 'GET, POST'); res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type, Authorization'); next(); }); app.use(helmet()); app.use(helmet.contentSecurityPolicy({ directives: { defaultSrc: ["'self'"], styleSrc: ["'self'", 'https://netdna.bootstrapcdn.com','https://ajax.googleapis.com','https://fonts.googleapis.com',"'unsafe-inline'"], fontSrc: ['https://netdna.bootstrapcdn.com','https://fonts.gstatic.com'], imgSrc: ["'self'", 'data:'], connectSrc: ["'self'", 'https://www.googleapis.com'], scriptSrc: ["'self'"], } })) require('./app/config/passport')(passport); // pass passport for configuration // log all requests to the console app.use(morgan('dev')); // connect to database (hosted on mongolab) mongoose.Promise = global.Promise; mongoose.connect(db); // set static files location
module.exports = helmet.contentSecurityPolicy({ directives: { reportUri: `${BASE_PATH}api/v1/csp`, // report all policy violations to our reporting uri defaultSrc: ["'none'"], // by default, do not allow anything at all scriptSrc: [ "'self'", 'https://ajax.googleapis.com', // for jquery staticSrc, // for any static files loaded from a cdn nonceSrc, ], styleSrc: [ "'self'", 'https://maxcdn.bootstrapcdn.com', // for bootstrap css 'https://fonts.googleapis.com', // for google fonts 'https://code.getmdl.io', // for mdl css staticSrc, // for any static files loaded from a cdn nonceSrc, ], connectSrc: ["'self'", websocketSrc], fontSrc: [ "'self'", 'https://maxcdn.bootstrapcdn.com', // for font-awesome 'https://fonts.gstatic.com', // for google fonts staticSrc, // for any static files loaded from a cdn nonceSrc, ], imgSrc: [ "'self'", staticSrc, // for any static files loaded from a cdn nonceSrc, ], }, browserSniff: false, // Allow the configuration to disable strict enforcement of CSP. reportOnly: !ENABLE_STRICT_CSP, });
module.exports = function(settings, callback) { var https = require('https'); var http = require('http'); var fs = require('fs'); var path = require('path'); var express = require('express'); var helmet = require('helmet') var bodyParser = require('body-parser'); var logger = require('./lib/log/logger'); var HttpStatus = require('http-status-codes'); var validateResult = settings.validate(); if (validateResult.valid === false) { logger.error("Invalid configuration: " + validateResult.message); throw new Error('settings.json is invalid'); } var serviceBrokerUtil = require('./lib/utils/serviceBrokerUtils')(settings.serviceOffering.serviceBroker); var oauth = require('./lib/oauth/oauth')(settings); var models = require('./lib/models')(settings.db, callback); var port = settings.port; var publicPort = settings.publicPort; var options = {}; if(settings.tls){ if(!fs.existsSync(settings.tls.keyFile)){ logger.error("Invalid TLS key path: " + settings.tls.keyFile); throw new Error("Invalid TLS key path: " + settings.tls.keyFile); } if(!fs.existsSync(settings.tls.certFile)){ logger.error("Invalid TLS certificate path: " + settings.tls.certFile); throw new Error("Invalid TLS certificate path: " + settings.tls.certFile); } if(!fs.existsSync(settings.tls.caCertFile)){ logger.error("Invalid TLS ca certificate path: " + settings.tls.caCertFile); throw new Error("Invalid TLS ca certificate path: " + settings.tls.caCertFile); } options = { key: fs.readFileSync(settings.tls.keyFile), cert: fs.readFileSync(settings.tls.certFile), ca: fs.readFileSync(settings.tls.caCertFile) } } var publicOptions = {}; if(settings.publicTls){ if(!fs.existsSync(settings.publicTls.keyFile)){ logger.error("Invalid public TLS key path: " + settings.publicTls.keyFile); throw new Error("Invalid public TLS key path: " + settings.publicTls.keyFile); } if(!fs.existsSync(settings.publicTls.certFile)){ logger.error("Invalid public TLS certificate path: " + settings.publicTls.certFile); throw new Error("Invalid public TLS certificate path: " + settings.publicTls.certFile); } if(!fs.existsSync(settings.publicTls.caCertFile)){ logger.error("Invalid public TLS ca certificate path: " + settings.publicTls.caCertFile); throw new Error("Invalid public TLS ca certificate path: " + settings.publicTls.caCertFile); } publicOptions = { key: fs.readFileSync(settings.publicTls.keyFile), cert: fs.readFileSync(settings.publicTls.certFile), ca: fs.readFileSync(settings.publicTls.caCertFile) } } var checkBinding = function(req, res, next){ if (settings.serviceOffering.enabled) { serviceBrokerUtil.checkBinding(req.params,function(error,result){ if(error){ res.status(HttpStatus.INTERNAL_SERVER_ERROR).send({}); }else{ if(result.statusCode == HttpStatus.OK){ next(); }else if(result.statusCode == HttpStatus.NOT_FOUND){ res.status(HttpStatus.FORBIDDEN).send({"error": "The application is not bound to Auto-Scaling service"}); }else{ res.status(HttpStatus.INTERNAL_SERVER_ERROR).send({}); } } }); } else { next(); } } var app = express(); app.use(helmet()) app.use(helmet.contentSecurityPolicy({ directives: { defaultSrc : ['\'self\'' ], scriptSrc : [ '\'self\''], }, browserSniff: false })) app.use(helmet.noCache()) app.use(bodyParser.json()); app.use(bodyParser.urlencoded({ extended: false })); app.use('/health', require('express-healthcheck')()); var policies = require('./lib/routes/policies')(settings, models); var scalingHistories = require('./lib/routes/scalingHistories')(settings); var metrics = require('./lib/routes/metrics')(settings); var aggregatedMetrics = require('./lib/routes/aggregated_metrics')(settings); app.use('/v1/apps',policies); app.use(function(err, req, res, next) { var errorResponse = {}; if (err) { errorResponse = { 'error': err, }; } res.status(HttpStatus.BAD_REQUEST).json(errorResponse); }); var publicApp = express(); publicApp.use(helmet()) publicApp.use(helmet.contentSecurityPolicy({ directives: { defaultSrc : ['\'self\'' ], scriptSrc : [ '\'self\''], }, browserSniff: false })) publicApp.use(helmet.noCache()) publicApp.use(bodyParser.json()); publicApp.use(bodyParser.urlencoded({ extended: false })); publicApp.use('/v1/apps/:app_id/*',function(req, res, next){ oauth.checkUserAuthorization(req,function(error,isSpaceDeveloper){ if(error){ if(error.statusCode == HttpStatus.UNAUTHORIZED){ res.status(HttpStatus.UNAUTHORIZED).send({}); }else{ res.status(HttpStatus.INTERNAL_SERVER_ERROR).send({}); } }else{ if(isSpaceDeveloper){ next(); }else{ res.status(HttpStatus.UNAUTHORIZED).send({}); } } }); }); publicApp.use('/health', require('express-healthcheck')()); var info = require('./lib/routes/info')(settings); publicApp.use('/v1/apps/:app_id/policy', checkBinding); publicApp.use('/v1', info); publicApp.use('/v1/apps',policies); publicApp.use('/v1/apps',scalingHistories); publicApp.use('/v1/apps',metrics); publicApp.use('/v1/apps',aggregatedMetrics); publicApp.use(function(err, req, res, next) { var errorResponse = {}; if (err) { errorResponse = { 'error': err, }; } res.status(HttpStatus.BAD_REQUEST).json(errorResponse); }); var server; if(settings.tls){ server = https.createServer(options, app).listen(port || 3002, function() { logger.info('Autoscaler API server started in secure mode',{'port':server.address().port} ); }); }else{ server = http.createServer(app).listen(port || 3002, function() { logger.info('Autoscaler API server started',{'port':server.address().port} ); }); } var publicServer; if(settings.publicTls){ publicServer = https.createServer(publicOptions, publicApp).listen(publicPort || 3003, function() { logger.info('Autoscaler public API server started in secure mode',{'port':publicServer.address().port} ); }); }else{ publicServer = http.createServer(publicApp).listen(publicPort || 3003, function() { logger.info('Autoscaler public API server started',{'port':publicServer.address().port} ); }); } var gracefulShutdown = function(signal) { logger.info("Received " + signal + " signal, shutting down gracefully..."); server.close(function() { logger.info('Everything is cleanly shutdown for internal API server'); publicServer.close(function() { logger.info('Everything is cleanly shutdown for public API server'); process.exit(); }); }); } //listen for SIGUSR2 signal e.g. user-defined signal process.on ('SIGUSR2', function(){ gracefulShutdown('SIGUSR2') }); return {"internalServer": server, "publicServer": publicServer}; }
app.use(helmet.contentSecurityPolicy({ directives: { defaultSrc: [ 'www.youtube.com', 'https://public.etherpad-mozilla.org' ], scriptSrc: [ '\'self\'', '\'unsafe-inline\'', '\'unsafe-eval\'', 'data:', 'www.google-analytics.com', 'cdn.optimizely.com', 'https://www.google.com', 'https://s.ytimg.com', 'https://www.mozilla.org' ], fontSrc: [ '\'self\'', 'fonts.googleapis.com', 'fonts.gstatic.com' ], styleSrc: [ '\'self\'', '\'unsafe-inline\'', 'https://www.google.com', 'fonts.googleapis.com', 'https://api.tiles.mapbox.com', 'https://s.ytimg.com' ], imgSrc: [ '\'self\'', '\'unsafe-inline\'', 'twemoji.maxcdn.com', 'https://upload.wikimedia.org', '*.tiles.mapbox.com', 'www.google-analytics.com', '*.log.optimizely.com' ], connectSrc: [ '\'self\'', 'https://www.google.com', '*.tiles.mapbox.com', '*.log.optimizely.com', '*.mywebmaker.org', '*.makes.org', 'bitly.mofoprod.net', process.env.TEACH_API_URL || 'https://teach-api.herokuapp.com', url.parse(process.env.NEWSLETTER_MAILINGLIST_URL || 'https://basket-dev.allizom.org').hostname ] }, reportOnly: false, browserSniff: false }));
// Add referrer policy to improve privacy app.use( helmet.referrerPolicy({ policy: 'same-origin' }) ) // Generate a random nonce per request, for CSP with inline scripts app.use(csp.addNonceToLocals) // use Content-Security-Policy to limit XSS, dangerous plugins, etc. // https://helmetjs.github.io/docs/csp/ if (config.csp.enable) { app.use(helmet.contentSecurityPolicy({ directives: csp.computeDirectives() })) } else { logger.info('Content-Security-Policy is disabled. This may be a security risk.') } i18n.configure({ locales: ['en', 'zh-CN', 'zh-TW', 'fr', 'de', 'ja', 'es', 'ca', 'el', 'pt', 'it', 'tr', 'ru', 'nl', 'hr', 'pl', 'uk', 'hi', 'sv', 'eo', 'da', 'ko'], cookie: 'locale', directory: path.join(__dirname, '/locales'), updateFiles: config.updateI18nFiles }) app.use(cookieParser()) app.use(i18n.init)
Security.prototype = { csp(directiveList) { directiveList = directiveList || {}; Object.keys(defaultCSPDirectives).forEach(function(directive) { let domainsToAdd = directiveList[directive]; let defaultDomains = defaultCSPDirectives[directive]; if(domainsToAdd && defaultDomains.indexOf("*") !== -1) { directiveList[directive] = domainsToAdd; } else { directiveList[directive] = defaultDomains.concat((domainsToAdd || [])); } }); this.server.use(helmet.contentSecurityPolicy({ directives: directiveList })); return this; }, ssl() { this.server.use(helmet.hsts({ maxAge: ONE_YEAR })); this.server.enable("trust proxy"); return this; }, xss() { this.server.use(helmet.xssFilter()); return this; }, mimeSniff() {
app.use(nonceMiddleware, helmet.contentSecurityPolicy({ directives: { defaultSrc: ["'none'"], baseUri: ['https://docs.helpscout.net'], scriptSrc: [ "'self'", "'strict-dynamic'", (req, res) => { return `'nonce-${res.locals.nonce}'`; }, 'https://beacon-v2.helpscout.net', 'https://d12wqas9hcki3z.cloudfront.net', 'https://d33v4339jhl8k0.cloudfront.net', ], styleSrc: [ "'self'", 'blob:', "'unsafe-inline'", 'https://fonts.googleapis.com', 'https://beacon-v2.helpscout.net', 'https://djtflbt20bdde.cloudfront.net', ], imgSrc: [ "'self'", 'data:', 'https://d33v4339jhl8k0.cloudfront.net', 'https://*.gravatar.com', ], fontSrc: ["'self'", 'data:', 'https://fonts.gstatic.com'], reportUri: '/event/csp-report/violation', objectSrc: ['blob:', 'https://beacon-v2.helpscout.net'], workerSrc: ["'self'", 'blob:'], childSrc: ["'self'", 'blob:', 'https://docs.google.com'], frameSrc: ['https://beacon-v2.helpscout.net', 'https://docs.google.com'], connectSrc: [].concat([ process.env.API_HOST, 'https://api.github.com/repos/tidepool-org/chrome-uploader/releases', 'https://beaconapi.helpscout.net', 'https://chatapi.helpscout.net', 'https://d3hb14vkzrxvla.cloudfront.net', 'wss\://*.pusher.com', '*.sumologic.com', 'sentry.io', ]), }, reportOnly: false, }));
var routes = require('./routes/index'); var app = express(); app.disable('x-powered-by'); //Security settings app.use(helmet.xssFilter()); app.use(helmet.contentSecurityPolicy({ directives: { defaultSrc: ["'self'"], scriptSrc: ["'self'","'unsafe-inline'",'https://maxcdn.bootstrapcdn.com'], styleSrc: ["'self'","'unsafe-inline'",'https://maxcdn.bootstrapcdn.com'], imgSrc: ["'self'"], fontSrc: ['https://maxcdn.bootstrapcdn.com'], connectSrc: [], }, reportOnly:false, setAllHeaders: false, disableAndroid: false })); app.set('trust proxy', 1) // trust first proxy app.use( session({ secret : 's3Cur3', name : 'sessionId', }) );
function baseServer(routes, createStore, { appInstanceName = appName } = {}) { const app = new Express(); app.disable('x-powered-by'); app.use(logRequests); // Set HSTS, note: helmet uses ms not seconds. app.use(helmet.hsts({ maxAge: 31536000000, force: true })); // Sets X-Frame-Options app.use(helmet.frameguard(config.get('frameGuard'))); // Sets x-content-type-options:"nosniff" app.use(helmet.noSniff()); // Sets x-xss-protection:"1; mode=block" app.use(helmet.xssFilter()); // CSP configuration. app.use(helmet.contentSecurityPolicy(config.get('CSP'))); if (config.get('enableNodeStatics')) { app.use(Express.static(path.join(config.get('basePath'), 'dist'))); } // Return version information as json app.get('/__version__', (req, res) => { fs.stat(version, (err) => { if (err) { res.sendStatus(415); } else { res.setHeader('Content-Type', 'application/json'); fs.createReadStream(version).pipe(res); } }); }); // Return 200 for csp reports - this will need to be overridden when deployed. app.post('/__cspreport__', (req, res) => res.status(200).end('ok')); // Redirect from / for the search app it's a 302 to prevent caching. if (appInstanceName === 'search') { app.get('/', (req, res) => res.redirect(302, '/search')); } if (appInstanceName === 'disco' && isDevelopment) { app.get('/', (req, res) => res.redirect(302, '/en-US/firefox/discovery/pane/48.0/Darwin/normal')); } // Handle application and lang redirections. if (config.get('enablePrefixMiddleware')) { app.use(prefixMiddleWare); } app.use((req, res) => { if (isDevelopment) { log.info('Clearing require cache for webpack isomorphic tools. [Development Mode]'); // clear require() cache if in development mode webpackIsomorphicTools.refresh(); } match({ routes, location: req.url }, (err, redirectLocation, renderProps) => { cookie.plugToRequest(req, res); if (err) { log.error({ err, req }); return showErrorPage(res, 500); } if (!renderProps) { return showErrorPage(res, 404); } const store = createStore(); const token = cookie.load(config.get('cookieName')); if (token) { store.dispatch(setJWT(token)); } // Get SRI for deployed services only. const sriData = (isDeployed) ? JSON.parse( fs.readFileSync(path.join(config.get('basePath'), 'dist/sri.json')) ) : {}; // Check the lang supplied by res.locals.lang for validity // or fall-back to the default. const lang = isValidLang(res.locals.lang) ? res.locals.lang : config.get('defaultLang'); const dir = getDirection(lang); const locale = langToLocale(lang); store.dispatch(setLang(lang)); function hydrateOnClient(props = {}) { const pageProps = { appName: appInstanceName, assets: webpackIsomorphicTools.assets(), htmlLang: lang, htmlDir: dir, includeSri: isDeployed, sriData, store, trackingEnabled: convertBoolean(config.get('trackingEnabled')), ...props, }; const HTML = ReactDOM.renderToString( <ServerHtml {...pageProps} />); res.send(`<!DOCTYPE html>\n${HTML}`); } // Set disableSSR to true to debug // client-side-only render. if (config.get('disableSSR') === true) { return Promise.resolve(hydrateOnClient()); } return loadOnServer({ ...renderProps, store }) .then(() => { // eslint-disable-next-line global-require let jedData = {}; try { if (locale !== langToLocale(config.get('defaultLang'))) { // eslint-disable-next-line global-require, import/no-dynamic-require jedData = require(`json!../../locale/${locale}/${appInstanceName}.json`); } } catch (e) { log.info(`Locale JSON not found or required for locale: "${locale}"`); log.info(`Falling back to default lang: "${config.get('defaultLang')}".`); } const i18n = new Jed(jedData); const InitialComponent = ( <I18nProvider i18n={i18n}> <Provider store={store} key="provider"> <ReduxAsyncConnect {...renderProps} /> </Provider> </I18nProvider> ); const asyncConnectLoadState = store.getState().reduxAsyncConnect.loadState || {}; // Create a list of any apiErrors detected. const apiErrors = Object.keys(asyncConnectLoadState) .map((item) => asyncConnectLoadState[item].error) .filter((item) => item); if (apiErrors.length === 1) { // If we have a single API error reflect that in the page's response. const apiStatus = apiErrors[0].response.status; return showErrorPage(res, apiStatus); } else if (apiErrors.length > 1) { // Otherwise we have multiple api errors it should be logged // and throw a 500. log.error(apiErrors); return showErrorPage(res, 500); } return hydrateOnClient({ component: InitialComponent }); }) .catch((error) => { log.error({ err: error }); return showErrorPage(res, 500); }); }); }); // eslint-disable-next-line no-unused-vars app.use((err, req, res, next) => { log.error({ err }); return showErrorPage(500); }); return app; }
// app.use(favicon(__dirname + '/public/favicon.ico')); app.use(bodyParser.json()); app.use(bodyParser.urlencoded({ extended: false })); app.use(cookieParser()); app.use(helmet()); app.use(helmet.hidePoweredBy()); app.use(helmet.frameguard("allow-from", process.env["WEB_HOSTNAME"] || ("http://localhost:8080") )); app.use(helmet.contentSecurityPolicy({ defaultSrc: ["'self'"], scriptSrc: ["'self'", "'unsafe-inline'", "'unsafe-eval'", "*.jsdelivr.net", "jsconsole.com"], styleSrc: ["'self'", "'unsafe-inline'", "*.jsdelivr.net"], imgSrc: ["'self'", "*.jsdelivr.net"], connectSrc: ["'self'", "'unsafe-inline'", "'unsafe-eval'", "ws://*"], fontSrc: ["fonts.google.com"], objectSrc: ["'self'"], mediaSrc: ["'self'"], frameSrc: ["'self'"], //sandbox: ["allow-forms", "allow-scripts", "allow-same-origin"], reportUri: '/report-violation', //reportOnly: true, // set to true if you only want to report errors //setAllHeaders: false, // set to true if you want to set all headers //disableAndroid: false, // set to true if you want to disable Android (browsers can vary and be buggy) //safari5: false // set to true if you want to force buggy CSP in Safari 5 })); app.use(function(req, res, next) { res.setHeader("Access-Control-Allow-Origin", "*"); // Request methods you wish to allow res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE'); // Request headers you wish to allow
const express = require("express"); const helmet = require("helmet"); const errorHandler_1 = require("./middlewares/errorHandler"); const notFoundHandler_1 = require("./middlewares/notFoundHandler"); const mongooseConnectionOptions_1 = require("../mongooseConnectionOptions"); const debug = createDebug('sskts-webhook:app'); const app = express(); app.use(middlewares.basicAuth({ name: process.env.BASIC_AUTH_NAME, pass: process.env.BASIC_AUTH_PASS })); app.use(cors()); // enable All CORS Requests app.use(helmet()); app.use(helmet.contentSecurityPolicy({ directives: { defaultSrc: ['\'self\''] // styleSrc: ['\'unsafe-inline\''] } })); app.use(helmet.referrerPolicy({ policy: 'no-referrer' })); const SIXTY_DAYS_IN_SECONDS = 5184000; app.use(helmet.hsts({ maxAge: SIXTY_DAYS_IN_SECONDS, includeSubdomains: false })); // view engine setup // app.set('views', `${__dirname}/views`); // app.set('view engine', 'ejs'); app.use(bodyParser.json()); // The extended option allows to choose between parsing the URL-encoded data // with the querystring library (when false) or the qs library (when true). app.use(bodyParser.urlencoded({ extended: true }));
})); app.use(helmet.contentSecurityPolicy({ directives: { defaultSrc: ["'self'"], baseUri: ["'self'"], childSrc: ["'none'"], connectSrc: ["'self'"], fontSrc: ["'none'"], formAction: ["'self'"], frameAncestors: ["'none'"], imgSrc: ['data:', '*'], mediaSrc: ["'none'"], objectSrc: ["'none'"], scriptSrc: ["'self'", function (req, res) { if (typeof res !== "undefined" && typeof res.locals !== "undefined") { res.locals.nonce = uuid.v4(); return "'nonce-" + res.locals.nonce + "'"; } else { return null; } }], styleSrc: ["'self'"], // sandbox: ['allow-forms', 'allow-scripts'], // reportUri: config.opt.base_url + '/csp_reports' }, reportOnly: false, setAllHeaders: false, disableAndroid: false, browserSniff: true })); app.use(helmet.referrerPolicy({
export default function csp() { return helmet.contentSecurityPolicy({ directives: { defaultSrc: trusted.concat([ '*.optimizely.com', 'https://*.cloudflare.com', '*.cloudflare.com' ]), scriptSrc: [ "'unsafe-eval'", "'unsafe-inline'", '*.google-analytics.com', '*.gstatic.com', 'https://*.cloudflare.com', '*.cloudflare.com', 'https://*.gitter.im', 'https://*.cdnjs.com', '*.cdnjs.com', 'https://*.jsdelivr.com', '*.jsdelivr.com', '*.twimg.com', 'https://*.twimg.com', '*.youtube.com', '*.ytimg.com' ].concat(trusted), styleSrc: [ "'unsafe-inline'", '*.gstatic.com', '*.googleapis.com', '*.bootstrapcdn.com', 'https://*.bootstrapcdn.com', '*.cloudflare.com', 'https://*.cloudflare.com' ].concat(trusted), fontSrc: [ '*.cloudflare.com', 'https://*.cloudflare.com', '*.bootstrapcdn.com', '*.googleapis.com', '*.gstatic.com', 'https://*.bootstrapcdn.com' ].concat(trusted), imgSrc: [ // allow all input since we have user submitted images for // public profile '*', 'data:' ], mediaSrc: [ '*.bitly.com', '*.amazonaws.com', '*.twitter.com' ].concat(trusted), frameSrc: [ '*.gitter.im', '*.gitter.im https:', '*.youtube.com', '*.twitter.com', '*.ghbtns.com', '*.freecatphotoapp.com', 'freecodecamp.github.io' ].concat(trusted) }, // set to true if you only want to report errors reportOnly: false, // set to true if you want to set all headers setAllHeaders: false, // set to true if you want to force buggy CSP in Safari 5 safari5: false }); }
function create(env, ctx) { var app = express(); var appInfo = env.name + ' ' + env.version; app.set('title', appInfo); app.enable('trust proxy'); // Allows req.secure test on heroku https connections. var insecureUseHttp = env.insecureUseHttp; var secureHstsHeader = env.secureHstsHeader; console.info('Security settings: INSECURE_USE_HTTP=',insecureUseHttp,', SECURE_HSTS_HEADER=',secureHstsHeader); if (!insecureUseHttp) { app.use((req, res, next) => { if (req.header('x-forwarded-proto') !== 'https') res.redirect(`https://${req.header('host')}${req.url}`); else next() }) if (secureHstsHeader) { // Add HSTS (HTTP Strict Transport Security) header const helmet = require('helmet'); var includeSubDomainsValue = env.secureHstsHeaderIncludeSubdomains; var preloadValue = env.secureHstsHeaderPreload; app.use(helmet({ hsts: { maxAge: 31536000, includeSubDomains: includeSubDomainsValue, preload: preloadValue } })) if (env.secureCsp) { app.use(helmet.contentSecurityPolicy({ //TODO make NS work without 'unsafe-inline' directives: { defaultSrc: ["'self'"], styleSrc: ["'self'", 'https://fonts.googleapis.com/',"'unsafe-inline'"], scriptSrc: ["'self'", "'unsafe-inline'"], fontSrc: [ "'self'", 'https://fonts.gstatic.com/'] } })); } } } app.set('view engine', 'ejs'); // this allows you to render .html files as templates in addition to .ejs app.engine('html', require('ejs').renderFile); app.engine('appcache', require('ejs').renderFile); app.set("views", path.join(__dirname, "views/")); app.locals.cachebuster = fs.readFileSync(process.cwd() + '/tmp/cacheBusterToken').toString().trim(); if (ctx.bootErrors && ctx.bootErrors.length > 0) { app.get('*', require('./lib/server/booterror')(ctx)); return app; } if (env.settings.isEnabled('cors')) { var allowOrigin = _get(env, 'extendedSettings.cors.allowOrigin') || '*'; console.info('Enabled CORS, allow-origin:', allowOrigin); app.use(function allowCrossDomain(req, res, next) { res.header('Access-Control-Allow-Origin', allowOrigin); res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS'); res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization, Content-Length, X-Requested-With'); // intercept OPTIONS method if ('OPTIONS' === req.method) { res.send(200); } else { next(); } }); } /////////////////////////////////////////////////// // api and json object variables /////////////////////////////////////////////////// var api = require('./lib/api/')(env, ctx); var ddata = require('./lib/data/endpoints')(env, ctx); app.use(compression({ filter: function shouldCompress(req, res) { //TODO: return false here if we find a condition where we don't want to compress // fallback to standard filter function return compression.filter(req, res); } })); app.get("/", (req, res) => { res.render("index.html", { locals: app.locals }); }); var appPages = { "/clock-color.html":"clock-color.html", "/admin":"adminindex.html", "/profile":"profileindex.html", "/food":"foodindex.html", "/bgclock.html":"bgclock.html", "/weatherbg.html":"weatherbg.html", "/report":"reportindex.html", "/translations":"translationsindex.html", "/clock.html":"clock.html" }; Object.keys(appPages).forEach(function(page) { app.get(page, (req, res) => { res.render(appPages[page], { locals: app.locals }); }); }); app.get("/appcache/*", (req, res) => { res.render("nightscout.appcache", { locals: app.locals }); }); app.use('/api/v1', bodyParser({ limit: 1048576 * 50 }), api); app.use('/api/v2/properties', ctx.properties); app.use('/api/v2/authorization', ctx.authorization.endpoints); app.use('/api/v2/ddata', ddata); // pebble data app.get('/pebble', ctx.pebble); // expose swagger.json app.get('/swagger.json', function(req, res) { res.sendFile(__dirname + '/swagger.json'); }); /* if (env.settings.isEnabled('dumps')) { var heapdump = require('heapdump'); app.get('/api/v2/dumps/start', function(req, res) { var path = new Date().toISOString() + '.heapsnapshot'; path = path.replace(/:/g, '-'); console.info('writing dump to', path); heapdump.writeSnapshot(path); res.send('wrote dump to ' + path); }); } */ //app.get('/package.json', software); // Allow static resources to be cached for week var maxAge = 7 * 24 * 60 * 60 * 1000; if (process.env.NODE_ENV === 'development') { maxAge = 10; console.log('Development environment detected, setting static file cache age to 10 seconds'); app.get('/nightscout.appcache', function(req, res) { res.sendStatus(404); }); } //TODO: JC - changed cache to 1 hour from 30d ays to bypass cache hell until we have a real solution var staticFiles = express.static(env.static_files, { maxAge: maxAge }); // serve the static content app.use(staticFiles); const swaggerUiAssetPath = require("swagger-ui-dist").getAbsoluteFSPath(); var swaggerFiles = express.static(swaggerUiAssetPath, { maxAge: maxAge }); // serve the static content app.use('/swagger-ui-dist', swaggerFiles); var tmpFiles = express.static('tmp', { maxAge: maxAge }); // serve the static content app.use(tmpFiles); if (process.env.NODE_ENV !== 'development') { console.log('Production environment detected, enabling Minify'); var minify = require('express-minify'); var myCssmin = require('cssmin'); app.use(minify({ js_match: /\.js/, css_match: /\.css/, sass_match: /scss/, less_match: /less/, stylus_match: /stylus/, coffee_match: /coffeescript/, json_match: /json/, cssmin: myCssmin, cache: __dirname + '/tmp', onerror: undefined, })); } // if this is dev environment, package scripts on the fly // if production, rely on postinstall script to run packaging for us if (process.env.NODE_ENV === 'development') { var webpack = require("webpack"); var webpack_conf = require('./webpack.config'); webpack(webpack_conf, function(err, stats) { var json = stats.toJson() // => webpack --json var options = { noColor: true }; console.log(prettyjson.render(json.errors, options)); console.log(prettyjson.render(json.assets, options)); }); } // Handle errors with express's errorhandler, to display more readable error messages. var errorhandler = require('errorhandler'); //if (process.env.NODE_ENV === 'development') { app.use(errorhandler()); //} return app; }
app.use(session({ // in case of 'deprecation error' - http://goo.gl/vgcFih name: 'aaroncordova.xyz', // Needed if multiple apps running on same host. resave: false, // Forces cookie to be resaved back to the session store even if no changes. saveUninitialized: true, // Forces a session that is "uninitialized" to be saved to the store. secret: process.env.secret, // The secret used to sign the session ID cookie. cookie: { maxAge: 3600000 }, // Default = `null` - closing browser removes cookie & session. store: store })); // app.disable('x-powered-by'); // Already handled by `helmet`. // https://goo.gl/fPQ9DN app.use(helmet.contentSecurityPolicy({ directives: { // Whitelist domains for scripts & styles. defaultSrc: ["'self'", 'www.google-analytics.com'], styleSrc: ["'self'"] } })); /////////////////////// // CUSTOM MIDDLEWARE // /////////////////////// function adminCheck(req, res, next) { if(req.session.admin) { next(); } else { res.status(403).send('Dispatching the FBI surveillance van...'); }
csp(directiveList) { directiveList = directiveList || {}; Object.keys(defaultCSPDirectives).forEach(function(directive) { let domainsToAdd = directiveList[directive]; let defaultDomains = defaultCSPDirectives[directive]; if (domainsToAdd && defaultDomains.indexOf("*") !== -1) { directiveList[directive] = domainsToAdd; } else { directiveList[directive] = defaultDomains.concat(domainsToAdd || []); } }); this.server.use( helmet.contentSecurityPolicy({ directives: directiveList }) ); return this; }, ssl() { this.server.use(helmet.hsts({ maxAge: ONE_YEAR })); this.server.enable("trust proxy"); return this; }, xss() { this.server.use(helmet.xssFilter()); return this; },
app.use(helmet.contentSecurityPolicy({ defaultSrc: trusted, scriptSrc: ['*.optimizely.com'].concat(trusted), 'connect-src': [ 'ws://*.rafflecopter.com', 'wss://*.rafflecopter.com', 'https://*.rafflecopter.com', 'ws://www.freecodecamp.com', 'ws://localhost:3001/', 'http://localhost:3001', 'http://www.freecodecamp.com' ], styleSrc: trusted, imgSrc: [ '*.evernote.com', '*.amazonaws.com', 'data:', '*.licdn.com', '*.gravatar.com', '*.youtube.com' ].concat(trusted), fontSrc: ['*.googleapis.com'].concat(trusted), mediaSrc: [ '*.amazonaws.com', '*.twitter.com' ], frameSrc: [ '*.gitter.im', '*.vimeo.com', '*.twitter.com', '*.rafflecopter.com' ], reportOnly: false, // set to true if you only want to report errors setAllHeaders: false, // set to true if you want to set all headers safari5: false // set to true if you want to force buggy CSP in Safari 5 }));
function baseServer(routes, createStore, { appInstanceName = appName } = {}) { const app = new Express(); app.disable('x-powered-by'); app.use(logRequests); // Set HTTP Strict Transport Security headers app.use(helmet.hsts({ force: true, includeSubDomains: false, maxAge: 31536000, // seconds })); // Sets X-Frame-Options app.use(helmet.frameguard(config.get('frameGuard'))); // Sets x-content-type-options:"nosniff" app.use(helmet.noSniff()); // Sets x-xss-protection:"1; mode=block" app.use(helmet.xssFilter()); // CSP configuration. const csp = config.get('CSP'); const noScriptStyles = getNoScriptStyles({ appName: appInstanceName }); if (csp) { if (noScriptStyles) { const hash = crypto.createHash('sha256').update(noScriptStyles).digest('base64'); const cspValue = `'sha256-${hash}'`; if (!csp.directives.styleSrc.includes(cspValue)) { csp.directives.styleSrc.push(cspValue); } } app.use(helmet.contentSecurityPolicy(csp)); } else { log.warn('CSP has been disabled from the config'); } if (config.get('enableNodeStatics')) { app.use(Express.static(path.join(config.get('basePath'), 'dist'))); } // Return version information as json app.get('/__version__', (req, res) => { fs.stat(version, (err) => { if (err) { res.sendStatus(415); } else { res.setHeader('Content-Type', 'application/json'); fs.createReadStream(version).pipe(res); } }); }); // Return 200 for csp reports - this will need to be overridden when deployed. app.post('/__cspreport__', (req, res) => res.status(200).end('ok')); // Redirect from / for the search app it's a 302 to prevent caching. if (appInstanceName === 'search') { app.get('/', (req, res) => res.redirect(302, '/search')); } if (appInstanceName === 'disco' && isDevelopment) { app.get('/', (req, res) => res.redirect(302, '/en-US/firefox/discovery/pane/48.0/Darwin/normal')); } // Handle application and lang redirections. if (config.get('enablePrefixMiddleware')) { app.use(prefixMiddleWare); } app.use((req, res) => { if (isDevelopment) { log.info(oneLine`Clearing require cache for webpack isomorphic tools. [Development Mode]`); // clear require() cache if in development mode webpackIsomorphicTools.refresh(); } match({ location: req.url, routes }, ( err, redirectLocation, renderProps ) => { cookie.plugToRequest(req, res); if (err) { log.error({ err, req }); return showErrorPage(res, 500); } if (!renderProps) { return showErrorPage(res, 404); } const store = createStore(); const token = cookie.load(config.get('cookieName')); if (token) { store.dispatch(setJwt(token)); } // Get SRI for deployed services only. const sriData = (isDeployed) ? JSON.parse( fs.readFileSync(path.join(config.get('basePath'), 'dist/sri.json')) ) : {}; // Check the lang supplied by res.locals.lang for validity // or fall-back to the default. const lang = isValidLang(res.locals.lang) ? res.locals.lang : config.get('defaultLang'); const dir = getDirection(lang); const locale = langToLocale(lang); store.dispatch(setLang(lang)); if (res.locals.clientApp) { store.dispatch(setClientApp(res.locals.clientApp)); } else { log.warn(`No clientApp for this URL: ${req.url}`); } function hydrateOnClient(props = {}) { const pageProps = { appName: appInstanceName, assets: webpackIsomorphicTools.assets(), htmlLang: lang, htmlDir: dir, includeSri: isDeployed, noScriptStyles, sriData, store, trackingEnabled: convertBoolean(config.get('trackingEnabled')), ...props, }; const HTML = ReactDOM.renderToString( <ServerHtml {...pageProps} />); res.send(`<!DOCTYPE html>\n${HTML}`); } // Set disableSSR to true to debug // client-side-only render. if (config.get('disableSSR') === true) { return Promise.resolve(hydrateOnClient()); } return loadOnServer({ ...renderProps, store }) .then(() => { // eslint-disable-next-line global-require let i18nData = {}; try { if (locale !== langToLocale(config.get('defaultLang'))) { // eslint-disable-next-line global-require, import/no-dynamic-require i18nData = require( `../../locale/${locale}/${appInstanceName}.js`); } } catch (e) { log.info( `Locale JSON not found or required for locale: "${locale}"`); log.info( `Falling back to default lang: "${config.get('defaultLang')}".`); } const i18n = makeI18n(i18nData, lang); const InitialComponent = ( <I18nProvider i18n={i18n}> <Provider store={store} key="provider"> <ReduxAsyncConnect {...renderProps} /> </Provider> </I18nProvider> ); const asyncConnectLoadState = store.getState().reduxAsyncConnect.loadState || {}; const reduxResult = getReduxConnectError(asyncConnectLoadState); if (reduxResult.status) { return showErrorPage(res, reduxResult.status); } return hydrateOnClient({ component: InitialComponent }); }) .catch((error) => { log.error({ err: error }); return showErrorPage(res, 500); }); }); }); // eslint-disable-next-line no-unused-vars app.use((err, req, res, next) => { log.error({ err }); return showErrorPage(res, 500); }); return app; }