From c8e778a64a78c88be7db121200da6ea3081b03fa Mon Sep 17 00:00:00 2001 From: "dionisio-bot[bot]" <117394943+dionisio-bot[bot]@users.noreply.github.com> Date: Fri, 19 Sep 2025 21:15:09 +0200 Subject: [PATCH] fix: imported fixes 09-18-2025 (#37000) Signed-off-by: Abhinav Kumar Co-authored-by: Julio Araujo Co-authored-by: Abhinav Kumar --- .changeset/grumpy-berries-arrive.md | 5 +++ apps/meteor/app/api/server/ApiClass.ts | 7 ++- apps/meteor/tests/end-to-end/api/channels.ts | 4 +- apps/meteor/tests/end-to-end/api/users.ts | 47 ++++++++++++++++++++ 4 files changed, 59 insertions(+), 4 deletions(-) create mode 100644 .changeset/grumpy-berries-arrive.md diff --git a/.changeset/grumpy-berries-arrive.md b/.changeset/grumpy-berries-arrive.md new file mode 100644 index 00000000000..eacb88108a0 --- /dev/null +++ b/.changeset/grumpy-berries-arrive.md @@ -0,0 +1,5 @@ +--- +'@rocket.chat/meteor': patch +--- + +Security Hotfix (https://docs.rocket.chat/docs/security-fixes-and-updates) diff --git a/apps/meteor/app/api/server/ApiClass.ts b/apps/meteor/app/api/server/ApiClass.ts index e81788e6ec4..83bbfde4046 100644 --- a/apps/meteor/app/api/server/ApiClass.ts +++ b/apps/meteor/app/api/server/ApiClass.ts @@ -811,12 +811,15 @@ export class APIClass< if (options.authRequired || options.authOrAnonRequired) { const user = await api.authenticatedRoute.call(this, this.request); this.user = user!; - this.userId = String(this.request.headers.get('x-user-id')); + this.userId = this.user?._id; const authToken = this.request.headers.get('x-auth-token'); this.token = (authToken && Accounts._hashLoginToken(String(authToken)))!; } - if (!this.user && options.authRequired && !options.authOrAnonRequired && !settings.get('Accounts_AllowAnonymousRead')) { + const shouldPreventAnonymousRead = !this.user && options.authOrAnonRequired && !settings.get('Accounts_AllowAnonymousRead'); + const shouldPreventUserRead = !this.user && options.authRequired; + + if (shouldPreventAnonymousRead || shouldPreventUserRead) { const result = api.unauthorized('You must be logged in to do this.'); // compatibility with the old API // TODO: MAJOR diff --git a/apps/meteor/tests/end-to-end/api/channels.ts b/apps/meteor/tests/end-to-end/api/channels.ts index 66690df7985..02a859a916c 100644 --- a/apps/meteor/tests/end-to-end/api/channels.ts +++ b/apps/meteor/tests/end-to-end/api/channels.ts @@ -3503,10 +3503,10 @@ describe('[Channels]', () => { roomId: testChannel._id, }) .expect('Content-Type', 'application/json') - .expect(400) + .expect(401) .expect((res) => { expect(res.body).to.have.a.property('success', false); - expect(res.body).to.have.a.property('error', 'Enable "Allow Anonymous Read" [error-not-allowed]'); + expect(res.body).to.have.a.property('error', 'You must be logged in to do this.'); }) .end(done); }); diff --git a/apps/meteor/tests/end-to-end/api/users.ts b/apps/meteor/tests/end-to-end/api/users.ts index 45beb3b4997..fa2057137a4 100644 --- a/apps/meteor/tests/end-to-end/api/users.ts +++ b/apps/meteor/tests/end-to-end/api/users.ts @@ -681,6 +681,53 @@ describe('[Users]', () => { ]), ); + it('should fail when request is without authentication credentials', async () => { + await request + .get(api('users.info')) + .query({ + userId: targetUser._id, + }) + .expect('Content-Type', 'application/json') + .expect(401) + .expect((res) => { + expect(res.body).to.have.property('success', false); + expect(res.body).to.have.property('error'); + }); + }); + + describe('authentication', () => { + before(() => updateSetting('Accounts_AllowAnonymousRead', true)); + after(() => updateSetting('Accounts_AllowAnonymousRead', false)); + it('should fail when request is without authentication credentials and Anonymous Read is enabled', async () => { + await request + .get(api('users.info')) + .query({ + userId: targetUser._id, + }) + .expect('Content-Type', 'application/json') + .expect(401) + .expect((res) => { + expect(res.body).to.have.property('success', false); + expect(res.body).to.have.property('error'); + }); + }); + + it('should fail when request is without token and Anonymous Read is enabled', async () => { + await request + .get(api('users.info')) + .query({ + userId: targetUser._id, + }) + .set({ 'X-User-Id': credentials['X-User-Id'] }) + .expect('Content-Type', 'application/json') + .expect(401) + .expect((res) => { + expect(res.body).to.have.property('success', false); + expect(res.body).to.have.property('error'); + }); + }); + }); + it('should return an error when the user does not exist', (done) => { void request .get(api('users.info'))