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';
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;
31 // Naughty naughty naught, install some extra methods on the express prototype
34 function getSessionStore() {
35 var RedisStore
= require('connect-redis')(session
);
37 var redisClient
= env
.ioredis
.createClient(config
.get('redis_nopersist'));
39 return new RedisStore({
41 ttl
: config
.get('web:sessionTTL'),
42 logErrors: function(err
) {
43 logger
.error('connect-redis reported a redis error: ' + err
, { exception
: err
});
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')]);
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) {
91 handler(req
, res
, next
);
97 * Configure express for the full web application.
99 installFull: function(app
) {
102 require('./register-helpers')(expressHbs
);
104 configureLocals(app
);
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:
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
) {
144 'Missing "web__sessionSecret" environment variable. Using default value for local development.'
146 sessionSecret
= 'test-secret';
151 secret
: sessionSecret
,
152 key
: config
.get('web:cookiePrefix') + 'session',
153 store
: getSessionStore(),
158 domain
: config
.get('web:cookieDomain'),
159 secure
: config
.get('web:secureCookies'),
160 sameSite
: config
.get('web:secureCookies') ? 'none' : 'lax'
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
) {
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
);