diff --git a/.changeset/clean-ears-fly.md b/.changeset/clean-ears-fly.md new file mode 100644 index 0000000000000..781a8a4da4466 --- /dev/null +++ b/.changeset/clean-ears-fly.md @@ -0,0 +1,5 @@ +--- +'@rocket.chat/meteor': patch +--- + +Fixes a cross-resource access issue that allowed users to retrieve emojis from the Custom Sounds endpoint and sounds from the Custom Emojis endpoint when using the FileSystem storage mode. diff --git a/apps/meteor/app/custom-sounds/server/startup/custom-sounds.js b/apps/meteor/app/custom-sounds/server/startup/custom-sounds.js index 117a7d3c9e759..d9a839e3a3b82 100644 --- a/apps/meteor/app/custom-sounds/server/startup/custom-sounds.js +++ b/apps/meteor/app/custom-sounds/server/startup/custom-sounds.js @@ -48,7 +48,8 @@ Meteor.startup(() => { } const file = await RocketChatFileCustomSoundsInstance.getFileWithReadStream(fileId); - if (!file) { + + if (!file || !file.contentType?.startsWith('audio/')) { res.writeHead(404); res.write('Not found'); res.end(); diff --git a/apps/meteor/app/emoji-custom/server/startup/emoji-custom.js b/apps/meteor/app/emoji-custom/server/startup/emoji-custom.js index fed5123b115f4..b98f4dc542382 100644 --- a/apps/meteor/app/emoji-custom/server/startup/emoji-custom.js +++ b/apps/meteor/app/emoji-custom/server/startup/emoji-custom.js @@ -1,6 +1,5 @@ import { Meteor } from 'meteor/meteor'; import { WebApp } from 'meteor/webapp'; -import _ from 'underscore'; import { SystemLogger } from '../../../../server/lib/logger/system'; import { RocketChatFile } from '../../../file/server'; @@ -41,7 +40,9 @@ Meteor.startup(() => { return WebApp.connectHandlers.use('/emoji-custom/', async (req, res /* , next*/) => { const params = { emoji: decodeURIComponent(req.url.replace(/^\//, '').replace(/\?.*$/, '')) }; - if (_.isEmpty(params.emoji)) { + const extension = params.emoji?.split('.').pop()?.toLowerCase() ?? ''; + + if (!extension) { res.writeHead(403); res.write('Forbidden'); res.end(); @@ -52,7 +53,7 @@ Meteor.startup(() => { res.setHeader('Content-Disposition', 'inline'); - if (!file) { + if (!file || !file.contentType?.startsWith('image/')) { // use code from username initials renderer until file upload is complete res.setHeader('Content-Type', 'image/svg+xml'); res.setHeader('Cache-Control', 'public, max-age=0'); @@ -97,9 +98,9 @@ Meteor.startup(() => { res.setHeader('Last-Modified', fileUploadDate || new Date().toUTCString()); res.setHeader('Content-Length', file.length); - if (/^svg$/i.test(params.emoji.split('.').pop())) { + if (/^svg$/i.test(extension)) { res.setHeader('Content-Type', 'image/svg+xml'); - } else if (/^png$/i.test(params.emoji.split('.').pop())) { + } else if (/^png$/i.test(extension)) { res.setHeader('Content-Type', 'image/png'); } else { res.setHeader('Content-Type', 'image/jpeg');