Gitter migration: Setup redirects (rollout pt. 3)
[gitter.git] / server / web / express.js
blobe8a58f5b2d38297164999c7918ccda040046c1f0
1 'use strict';
3 var env = require('gitter-web-env');
4 var config = env.config;
5 var logger = env.logger;
7 var passport = require('passport');
8 var expressHbs = require('express-hbs');
9 //var rememberMe = require('./middlewares/rememberme-middleware');
10 var resolveStatic = require('./resolve-static');
11 var bodyParser = require('body-parser');
12 var cookieParser = require('cookie-parser');
13 var methodOverride = require('method-override');
14 var session = require('express-session');
15 const { shouldSendSameSiteNone } = require('should-send-same-site-none');
16 var appTag = require('./app-tag');
18 const IS_DEV = process.env.NODE_ENV === 'dev';
19 /**
20 * Only serve static assets in dev mode,
21 * when we don't have a CDN
23 function shouldServeStaticAssets() {
24 if (process.env.SERVE_STATIC_ASSETS) return true;
25 if (!IS_DEV) return false;
26 if (config.get('cdn:use')) return false;
28 return true;
31 // Naughty naughty naught, install some extra methods on the express prototype
32 require('./http');
34 function getSessionStore() {
35 var RedisStore = require('connect-redis')(session);
37 var redisClient = env.ioredis.createClient(config.get('redis_nopersist'));
39 return new RedisStore({
40 client: redisClient,
41 ttl: config.get('web:sessionTTL'),
42 logErrors: function(err) {
43 logger.error('connect-redis reported a redis error: ' + err, { exception: err });
45 });
48 function configureLocals(app) {
49 var locals = app.locals;
51 locals.googleTrackingId = config.get('stats:ga:key');
52 locals.googleTrackingDomain = config.get('stats:ga:domain');
53 locals.liveReload = config.get('web:liveReload');
54 locals.stagingText = appTag.text;
55 locals.stagingLink = appTag.link;
57 locals.headlineGitterUsers = config.get('headlineNumbers:gitterUsers');
58 locals.headlineGitterRooms = config.get('headlineNumbers:gitterRooms');
59 locals.headlineGitterGroups = config.get('headlineNumbers:gitterGroups');
60 locals.headlineGitterCountries = config.get('headlineNumbers:gitterCountries');
62 locals.dnsPrefetch = (config.get('cdn:hosts') || []).concat([config.get('ws:hostname')]);
65 /**
66 * Configure express app with settings and middlewares needed by both API and WEB (excluding passport and user related logic).
68 function installBase(app) {
69 app.disable('x-powered-by');
70 app.set('trust proxy', true);
72 app.use(env.middlewares.accessLogger);
74 app.use(bodyParser.json());
75 app.use(bodyParser.urlencoded({ extended: false }));
76 app.use(methodOverride());
78 app.use(require('./middlewares/pending-request'));
79 app.use(require('./middlewares/ie6-post-caching'));
80 app.use(require('./middlewares/i18n'));
83 // Middleware wrapped in `skipForApi` is not used on API requests
84 // This is only useful in development environment. In production we initialize API
85 // route differently and the `/api/*` requests don't hit the web handler at all
86 // (https://gitlab.com/gitterHQ/webapp/-/merge_requests/1771#note_288137539)
87 const skipForApi = handler => (req, res, next) => {
88 if (req.originalUrl.indexOf('/api/') === 0) {
89 next();
90 } else {
91 handler(req, res, next);
95 module.exports = {
96 /**
97 * Configure express for the full web application.
99 installFull: function(app) {
100 installBase(app);
102 require('./register-helpers')(expressHbs);
104 configureLocals(app);
106 app.engine(
107 'hbs',
108 expressHbs.express3({
109 partialsDir: resolveStatic('/templates/partials'),
110 onCompile: function(exhbs, source) {
111 return exhbs.handlebars.compile(source, { preventIndent: true });
113 layoutsDir: resolveStatic('/layouts'),
114 contentHelperName: 'content'
117 app.set('view engine', 'hbs');
118 app.set('views', resolveStatic('/templates'));
120 if (config.get('express:viewCache')) {
121 app.enable('view cache');
124 if (shouldServeStaticAssets()) {
125 /* Serve static content */
126 require('./express-static').install(app);
129 // Conditionally remove `SameSite=None; Secure` from cookies
130 // for platforms(user agents) that don't support them.
131 // We need to do this otherwise people won't be able to sign in (session and rememberme cookie)
133 // Incompatible platforms:
134 // - Chrome 51 - 66
135 // - iOS 12
136 // - Safari on MacOS 10.14
137 app.use(shouldSendSameSiteNone);
139 app.use(cookieParser());
141 let sessionSecret = config.get('web:sessionSecret');
142 if (!sessionSecret && IS_DEV) {
143 logger.warn(
144 'Missing "web__sessionSecret" environment variable. Using default value for local development.'
146 sessionSecret = 'test-secret';
149 app.use(
150 session({
151 secret: sessionSecret,
152 key: config.get('web:cookiePrefix') + 'session',
153 store: getSessionStore(),
154 cookie: {
155 path: '/',
156 httpOnly: true,
157 maxAge: 14400000,
158 domain: config.get('web:cookieDomain'),
159 secure: config.get('web:secureCookies'),
160 sameSite: config.get('web:secureCookies') ? 'none' : 'lax'
162 resave: true,
163 saveUninitialized: true // Passport will force a save anyway
167 app.use(passport.initialize());
168 // app.use(passport.session());
170 //anonymous tokens can be still valid for accessing API
171 app.use(skipForApi(require('./middlewares/authenticate-bearer')));
172 //app.use(rememberMe.rememberMeMiddleware);
173 app.use(require('./middlewares/rate-limiter'));
174 app.use(require('./middlewares/record-client-usage-stats'));
176 app.use(skipForApi(require('./middlewares/configure-csrf')));
177 app.use(skipForApi(require('./middlewares/enforce-csrf')));
179 // NOTE: it might be better to just drop this middleware entirely or at
180 // least substantially change the behavior, because not having github
181 // tokens is now fine. Maybe it is also fine not having any tokens at all?
182 app.use(require('./middlewares/tokenless-user'));
185 installApi: function(app) {
186 installBase(app);
188 app.use(passport.initialize());
190 app.use(require('./middlewares/rate-limiter'));
191 app.use(require('./middlewares/record-client-usage-stats'));
194 installSocket: function(app) {
195 app.disable('x-powered-by');
196 app.set('trust proxy', true);
197 app.use(env.middlewares.accessLogger);
198 app.use(require('./middlewares/token-error-handler'));
199 app.use(env.middlewares.errorHandler);