Gitter migration: Setup redirects (rollout pt. 3)
[gitter.git] / server / web / middlewares / enforce-csrf.js
blob756471ee4e27321ae9a1859be04c62cd28e71626
1 'use strict';
3 var env = require('gitter-web-env');
4 var stats = env.stats;
5 var logger = env.logger;
6 var debug = require('debug')('gitter:infra:enforce-csrf-middleware');
7 var StatusError = require('statuserror');
9 var escapeRegExp = require('../../utils/escape-regexp');
11 var ALLOWLIST = [
12   '/api/private/fixtures',
13   '/api/private/hook/',
14   '/api/private/transloadit/',
15   '/api/private/statsc',
16   '/api/v1/apn',
17   '/login/oauth/token',
18   '/login/oauth/authorize/decision',
19   '/api/private/subscription/'
22 if (env.config.get('ws:startFayeInPrimaryApp')) {
23   ALLOWLIST.push('/faye');
24   ALLOWLIST.push('/bayeux');
27 var ALLOWLIST_REGEXP = new RegExp('^(' + ALLOWLIST.map(escapeRegExp).join('|') + ')');
29 module.exports = function(req, res, next) {
30   // ignore these methods, they shouldnt alter state
31   if (req.method === 'GET' || req.method === 'HEAD' || req.method === 'OPTIONS') return next();
33   /* OAuth clients have req.authInfo. Aways let them through */
34   if (req.authInfo) return next();
36   if (isInAllowlist(req)) {
37     debug('skipping csrf check for %s', req.path);
38     return next();
39   }
41   var clientToken = getClientToken(req);
42   if (!clientToken) {
43     stats.event('token.rejected.notpresented');
44     logger.warn(
45       'csrf: Rejecting client ' + req.ip + ' request to ' + req.path + ' as they presented no token'
46     );
47     return next(new StatusError(403));
48   }
50   if (req.accessToken !== clientToken) {
51     stats.event('token.rejected.mismatch');
53     if (req.user) {
54       logger.warn(
55         'csrf: Rejecting client ' +
56           req.ip +
57           ' request to ' +
58           req.path +
59           ' as they presented an illegal token',
60         {
61           serverAccessToken: req.accessToken,
62           clientToken: clientToken,
63           username: req.user.username,
64           userId: req.user.id
65         }
66       );
67     } else {
68       logger.warn(
69         'csrf: Rejecting client ' +
70           req.ip +
71           ' request to ' +
72           req.path +
73           ' as they are probably logged out',
74         {
75           serverAccessToken: req.accessToken,
76           clientToken: clientToken
77         }
78       );
79     }
81     return next(new StatusError(403));
82   }
84   return next();
87 function isInAllowlist(req) {
88   return ALLOWLIST_REGEXP.test(req.path);
91 function getClientToken(req) {
92   return (
93     (req.body && req.body.accessToken) ||
94     (req.query && req.query.accessToken) ||
95     req.headers['x-access-token'] ||
96     req.headers['x-csrf-token'] ||
97     req.headers['x-xsrf-token']
98   );