diff --git a/apps/meteor/server/routes/avatar/middlewares/auth.js b/apps/meteor/server/routes/avatar/middlewares/auth.js deleted file mode 100644 index 5a4ead7ed048..000000000000 --- a/apps/meteor/server/routes/avatar/middlewares/auth.js +++ /dev/null @@ -1,22 +0,0 @@ -import { userCanAccessAvatar, renderSVGLetters } from '../utils'; - -// protect all avatar endpoints -export const protectAvatars = async (req, res, next) => { - if (!(await userCanAccessAvatar(req))) { - let roomOrUsername; - - if (req.url.startsWith('/room')) { - roomOrUsername = req.url.split('/')[2] || 'Room'; - } else { - roomOrUsername = req.url.split('/')[1] || 'Anonymous'; - } - - res.writeHead(200, { 'Content-Type': 'image/svg+xml' }); - res.write(renderSVGLetters(roomOrUsername, 200)); - res.end(); - - return; - } - - return next(); -}; diff --git a/apps/meteor/server/routes/avatar/middlewares/auth.ts b/apps/meteor/server/routes/avatar/middlewares/auth.ts new file mode 100644 index 000000000000..f6cfa080e8a9 --- /dev/null +++ b/apps/meteor/server/routes/avatar/middlewares/auth.ts @@ -0,0 +1,47 @@ +import type { ServerResponse } from 'http'; + +import type { IIncomingMessage } from '@rocket.chat/core-typings'; +import type { NextFunction } from 'connect'; + +import { userCanAccessAvatar, renderSVGLetters } from '../utils'; + +const renderFallback = (req: IIncomingMessage, res: ServerResponse) => { + if (!req.url) { + res.writeHead(404); + res.end(); + return; + } + + let roomOrUsername; + + if (req.url.startsWith('/room')) { + roomOrUsername = req.url.split('/')[2] || 'Room'; + } else { + roomOrUsername = req.url.split('/')[1] || 'Anonymous'; + } + + res.writeHead(200, { 'Content-Type': 'image/svg+xml' }); + res.write(renderSVGLetters(roomOrUsername, 200)); + res.end(); +}; + +const getProtectAvatars = (callback?: typeof renderFallback) => async (req: IIncomingMessage, res: ServerResponse, next: NextFunction) => { + if (!(await userCanAccessAvatar(req))) { + if (callback) { + callback(req, res); + return; + } + + res.writeHead(404); + res.end(); + return; + } + + return next(); +}; + +// If unauthorized returns the SVG fallback (letter avatar) +export const protectAvatarsWithFallback = getProtectAvatars(renderFallback); + +// Just returns 404 +export const protectAvatars = getProtectAvatars(); diff --git a/apps/meteor/server/routes/avatar/middlewares/index.js b/apps/meteor/server/routes/avatar/middlewares/index.js index 36f99692f042..6a2c05917132 100644 --- a/apps/meteor/server/routes/avatar/middlewares/index.js +++ b/apps/meteor/server/routes/avatar/middlewares/index.js @@ -1,8 +1,8 @@ import { WebApp } from 'meteor/webapp'; -import { protectAvatars } from './auth'; +import { protectAvatars, protectAvatarsWithFallback } from './auth'; import './browserVersion'; -WebApp.connectHandlers.use('/avatar/', protectAvatars); +WebApp.connectHandlers.use('/avatar/', protectAvatarsWithFallback); WebApp.connectHandlers.use('/avatar/uid/', protectAvatars); diff --git a/apps/meteor/server/routes/avatar/user.ts b/apps/meteor/server/routes/avatar/user.ts index 872f8e8ea0e9..0908204e92ea 100644 --- a/apps/meteor/server/routes/avatar/user.ts +++ b/apps/meteor/server/routes/avatar/user.ts @@ -1,6 +1,5 @@ import type { ServerResponse } from 'http'; -// TODO: what is the type of re.query? import type { IUpload, IIncomingMessage } from '@rocket.chat/core-typings'; import { Avatars, Users } from '@rocket.chat/models'; import { serverFetch as fetch } from '@rocket.chat/server-fetch';