Gitter migration: Setup redirects (rollout pt. 3)
[gitter.git] / server / web / middlewares / express-error-handler.js
blob41928234b4330dc9724d694009626bec66c5dcf9
1 'use strict';
3 var Promise = require('bluebird');
4 var env = require('gitter-web-env');
5 var config = env.config;
6 var _ = require('lodash');
7 var urlJoin = require('url-join');
8 var userScopes = require('gitter-web-identity/lib/user-scopes');
9 var logout = Promise.promisify(require('./logout'));
10 var unauthorizedRedirectMap = require('../../utils/unauthorized-redirect-map');
12 function linkStack(stack) {
13   if (!stack) return;
14   return stack
15     .split(/\n/)
16     .map(function(i) {
17       return i.replace(/\(([^:]+):(\d+):(\d+)\)/, function(match, file, line, col) {
18         var ourCode = file.indexOf('node_modules') === -1;
19         var h =
20           "(<a href='atm://open/?url=file://" +
21           file +
22           '&line=' +
23           line +
24           '&column=' +
25           col +
26           "'>" +
27           file +
28           ':' +
29           line +
30           ':' +
31           col +
32           '</a>)';
33         if (ourCode) h = '<b>' + h + '</b>';
34         return h;
35       });
36     })
37     .join('\n');
40 function getTemplateForStatus(status) {
41   switch (status) {
42     case 404:
43       return '' + status;
45     default:
46       return '500';
47   }
50 /* Has to have four args */
51 // eslint-disable-next-line no-unused-vars
52 module.exports = function(err, req, res, next) {
53   // eslint-disable-line no-unused-vars
54   var status = res.statusCode;
56   /* Got a 401, the user isn't logged in and this is a browser? */
57   if (status === 401 && req.accepts(['json', 'html']) === 'html') {
58     var returnUrl = req.originalUrl.replace(/\/~(\w+)$/, '');
60     if (err.clientRevoked) {
61       return logout(req, res).then(() => {
62         return res.redirect(unauthorizedRedirectMap.TOKEN_REVOKED_URL);
63       });
64     } else if (err.revokedUserAgent) {
65       return logout(req, res).then(() => {
66         return res.redirect(unauthorizedRedirectMap.USER_AGENT_REVOKED_URL);
67       });
68     } else if (!req.user && req.session) {
69       req.session.returnTo = returnUrl;
70       return res.redirect(unauthorizedRedirectMap.LOGIN_URL);
71     } else if (!req.user) {
72       // This should not really be happening but
73       // may do if the gitter client isn't doing
74       // oauth properly
75       return res.redirect(
76         urlJoin(unauthorizedRedirectMap.LOGIN_URL, '?returnTo=' + encodeURIComponent(returnUrl))
77       );
78     }
79   }
81   var template = getTemplateForStatus(status);
82   var message = (res.locals && res.locals.errorMessage) || `An unknown error occurred ${err}`;
83   var extraTemplateValues = {
84     title: message
85   };
87   const errorIdentifer = res.locals && res.locals.errorIdentifer;
89   res.format({
90     html: function() {
91       res.render(
92         template,
93         _.extend(
94           {
95             status: status,
96             homeUrl: config.get('web:homeurl'),
97             currentPath: req.path,
98             user: req.user,
99             userMissingPrivateRepoScope: req.user && !userScopes.hasGitHubScope(req.user, 'repo'),
100             message: message,
101             errorIdentifer,
102             // Only generate the stack-frames when we need to
103             stack: config.get('express:showStack') && err && err.stack && linkStack(err.stack)
104           },
105           extraTemplateValues
106         )
107       );
108     },
109     json: function() {
110       res.send({ error: message });
111     },
112     text: function() {
113       res.send('Error: ' + message);
114     }
115   });