diff --git a/.changeset/olive-queens-protect.md b/.changeset/olive-queens-protect.md new file mode 100644 index 0000000000000..54251bde0b9f7 --- /dev/null +++ b/.changeset/olive-queens-protect.md @@ -0,0 +1,5 @@ +--- +'@rocket.chat/meteor': patch +--- + +fix: Security Hotfix (https://docs.rocket.chat/docs/security-fixes-and-updates) diff --git a/apps/meteor/server/publications/room/index.ts b/apps/meteor/server/publications/room/index.ts index 07dd94be23d00..2ae624d9eedcd 100644 --- a/apps/meteor/server/publications/room/index.ts +++ b/apps/meteor/server/publications/room/index.ts @@ -55,11 +55,15 @@ Meteor.methods({ } const userId = Meteor.userId(); - - if (!userId && settings.get('Accounts_AllowAnonymousRead') === false) { - throw new Meteor.Error('error-invalid-user', 'Invalid user', { - method: 'getRoomByTypeAndName', - }); + const isAnonymous = !userId; + + if (isAnonymous) { + const allowAnon = settings.get('Accounts_AllowAnonymousRead'); + if (!allowAnon || type !== 'c') { + throw new Meteor.Error('error-invalid-user', 'Invalid user', { + method: 'getRoomByTypeAndName', + }); + } } const roomFind = roomCoordinator.getRoomFind(type); diff --git a/apps/meteor/tests/end-to-end/api/methods.ts b/apps/meteor/tests/end-to-end/api/methods.ts index 2671e7f189c0f..401cc9cfefb54 100644 --- a/apps/meteor/tests/end-to-end/api/methods.ts +++ b/apps/meteor/tests/end-to-end/api/methods.ts @@ -2574,6 +2574,7 @@ describe('Meteor.methods', () => { let testUserCredentials: Credentials; let dmId: IRoom['_id']; let room: IRoom; + let privateRoom: IRoom; before(async () => { testUser = await createUser(); @@ -2612,6 +2613,49 @@ describe('Meteor.methods', () => { }); }); + before(async () => { + privateRoom = ( + await createRoom({ + type: 'p', + name: `private.test.${Date.now()}-${Math.random()}`, + }) + ).body.group; + }); + + after(async () => { + await Promise.all([ + deleteRoom({ type: 'd', roomId: dmId }), + deleteRoom({ type: 'c', roomId: room._id }), + deleteRoom({ type: 'p', roomId: privateRoom._id }), + deleteUser(testUser), + deleteUser(testUser2), + updateSetting('Accounts_AllowAnonymousRead', false), + ]); + }); + + it('should throw error when anonymous user tries to read private channel with anonymous read enabled', async () => { + await updateSetting('Accounts_AllowAnonymousRead', true); + + const payload = { + message: JSON.stringify({ + msg: 'method', + id: '2', + method: 'getRoomByTypeAndName', + params: ['p', privateRoom.name], + }), + }; + + const res = await request.post('/api/v1/method.callAnon/getRoomByTypeAndName').set('Content-Type', 'application/json').send(payload); + + expect(res.body).to.have.property('message'); + const parsedMessage = JSON.parse(res.body.message); + + expect(parsedMessage).to.have.property('error'); + expect(parsedMessage.error).to.have.property('error'); + expect(parsedMessage.error.error).to.equal('error-invalid-user'); + + await updateSetting('Accounts_AllowAnonymousRead', false); + }); after(() => Promise.all([ deleteRoom({ type: 'd', roomId: dmId }),