3 var express = require('express');
4 var identifyRoute = require('gitter-web-env').middlewares.identifyRoute;
5 var router = express.Router({ caseSensitive: true, mergeParams: true });
6 var fixMongoIdQueryParam = require('../../../web/fix-mongo-id-query-param');
7 var Promise = require('bluebird');
8 var request = Promise.promisify(require('request'));
9 var cdn = require('gitter-web-cdn');
10 var avatars = require('gitter-web-avatars');
11 var githubUserByUsernameVersioned = require('./github-user-by-username-versioned');
12 var githubUserByUsername = require('./github-user-by-username');
13 var gravatarByEmail = require('./gravatar-by-email');
14 var gravatarByHash = require('./gravatar-by-hash');
15 var twitterByIds = require('./twitter-by-ids');
16 const groupAvatars = require('gitter-web-groups/lib/group-avatars');
17 var userByUsername = require('./user-by-username');
19 var DEFAULT_SIZE = 128;
20 var MISSING_IMAGE_CONTENT_TYPE = 'image/png';
22 function sendMissing(req, res) {
23 // If the nginx image proxy is sitting in front of the app
25 if (req.headers['x-avatar-server']) {
26 res.set('X-Accel-Redirect', '/missing');
27 res.set('Content-Type', MISSING_IMAGE_CONTENT_TYPE);
28 res.status(200).end();
30 res.redirect(avatars.getDefault());
31 res.status(200).end();
35 function sendAvatar(callback) {
36 return function(req, res, next) {
37 return Promise.try(function() {
38 var size = (req.query.s && parseInt(req.query.s, 10)) || DEFAULT_SIZE;
39 return callback(req, size);
41 .then(function(response) {
43 return sendMissing(req, res);
46 var url = response.url;
47 var longTermCachable = response.longTermCachable;
50 return sendMissing(req, res);
53 // If the nginx image proxy is sitting in front of the app
55 if (req.headers['x-avatar-server']) {
56 if (longTermCachable) {
57 res.set('X-Accel-Redirect', '/fetch_lt/' + url);
59 res.set('X-Accel-Redirect', '/fetch/' + url);
65 // No image proxy, in the development environment
66 if (longTermCachable) {
67 res.set('Cache-Control', 'max-age=2592000'); // TODO: add more here
69 res.set('Cache-Control', 'max-age=3600'); // TODO: add more here
80 * Default for development environment
84 identifyRoute('api-private-avatar-default'),
85 sendAvatar(function(/*req, size*/) {
87 url: cdn('images/default-avatar.png'),
88 longTermCachable: true
94 * Group Avatars, by ID
98 identifyRoute('api-private-avatar-group-id'),
99 sendAvatar(async (req, size) => {
100 var groupId = fixMongoIdQueryParam(req.params.groupId);
101 if (!groupId) return null;
103 const avatarUrl = await groupAvatars.getAvatarUrlForGroupId(groupId, size);
104 if (!avatarUrl) return null;
108 longTermCachable: false
114 * Group Avatars, by ID (versioned)
117 '/group/iv/:version/:groupId',
118 identifyRoute('api-private-avatar-group-id-versioned'),
119 sendAvatar(async (req, size) => {
120 // Ignore the version it's only used as a cache-buster
121 var groupId = fixMongoIdQueryParam(req.params.groupId);
122 if (!groupId) return null;
124 const avatarUrl = await groupAvatars.getAvatarUrlForGroupId(groupId, size);
125 if (!avatarUrl) return null;
129 longTermCachable: true
137 identifyRoute('api-private-avatar-gitter-username'),
138 sendAvatar(function(req, size) {
139 var username = req.params.username;
140 if (!username) return null;
142 return userByUsername(username, size);
147 '/gravatar/e/:email',
148 identifyRoute('api-private-avatar-gravatar'),
149 sendAvatar(function(req, size) {
150 var email = req.params.email;
151 if (!email) return null;
153 return gravatarByEmail(email, size);
159 identifyRoute('api-private-avatar-checksum'),
160 sendAvatar(function(req, size) {
161 var md5 = req.params.md5;
162 if (!md5) return null;
164 return gravatarByHash(md5, size);
169 '/tw/i/:id/:filename',
170 identifyRoute('api-private-avatar-twitter'),
171 // NOTE: it doesn't support a size param yet
172 sendAvatar(function(req) {
173 var id = req.params.id;
174 var filename = req.params.filename;
176 if (!id || !filename) return null;
178 return twitterByIds(id, filename);
184 identifyRoute('api-private-gitlab-username'),
185 sendAvatar(function(req) {
186 const { username } = req.params;
187 if (!username) return null;
189 // Gravatar or https://gitlab.com/uploads/-/system/user/avatar/:userid/avatar.png
192 uri: 'https://gitlab.com/api/v4/users?username=' + encodeURIComponent(username),
196 url: res.body.avatar_url,
197 longTermCachable: false
204 * Only used in DEV. Otherwise nginx handles this route
208 identifyRoute('api-private-github-username'),
209 sendAvatar(function(req, size) {
210 var username = req.params.username;
211 if (!username) return null;
213 return githubUserByUsername(username, size);
218 * Only used in DEV. Otherwise nginx handles this route
221 '/gh/uv/:version/:username',
222 identifyRoute('api-private-github-versioned-username'),
223 sendAvatar(function(req, size) {
224 var username = req.params.username;
225 var version = req.params.version;
226 if (!username) return null;
229 return githubUserByUsername(username, size);
232 return githubUserByUsernameVersioned(username, version, size);
236 /* Default route for anything else on the avatar server */
238 identifyRoute('api-private-missing-avatar'),
239 sendAvatar(function() {
244 module.exports = router;