From a7ab99f272b2adb658c4b5832a5a606f0bcdc734 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BAlia=20Jaeger=20Foresti?= <60678893+juliajforesti@users.noreply.github.com> Date: Tue, 23 Dec 2025 15:25:56 -0300 Subject: [PATCH 01/68] test: remove `home-sidenav` fragment (#37943) --- .../page-objects/fragments/home-sidenav.ts | 62 ------------------- .../tests/e2e/page-objects/fragments/index.ts | 1 - .../tests/e2e/page-objects/home-channel.ts | 11 ++-- .../tests/e2e/page-objects/home-discussion.ts | 5 +- .../e2e/page-objects/omnichannel-room-info.ts | 8 +-- 5 files changed, 11 insertions(+), 76 deletions(-) delete mode 100644 apps/meteor/tests/e2e/page-objects/fragments/home-sidenav.ts diff --git a/apps/meteor/tests/e2e/page-objects/fragments/home-sidenav.ts b/apps/meteor/tests/e2e/page-objects/fragments/home-sidenav.ts deleted file mode 100644 index 34b38c60c6280..0000000000000 --- a/apps/meteor/tests/e2e/page-objects/fragments/home-sidenav.ts +++ /dev/null @@ -1,62 +0,0 @@ -import type { Locator, Page } from '@playwright/test'; - -export class HomeSidenav { - private readonly page: Page; - - constructor(page: Page) { - this.page = page; - } - - get advancedSettingsAccordion(): Locator { - return this.page.getByRole('dialog').getByRole('button', { name: 'Advanced settings', exact: true }); - } - - get checkboxPrivateChannel(): Locator { - return this.page.locator('label', { has: this.page.getByRole('checkbox', { name: 'Private' }) }); - } - - get checkboxEncryption(): Locator { - return this.page.locator('role=dialog[name="Create channel"] >> label >> text="Encrypted"'); - } - - get checkboxReadOnly(): Locator { - return this.page.locator('label', { has: this.page.getByRole('checkbox', { name: 'Read-only' }) }); - } - - get inputChannelName(): Locator { - return this.page.locator('#modal-root [data-qa="create-channel-modal"] [data-qa-type="channel-name-input"]'); - } - - get inputDirectUsername(): Locator { - return this.page.locator('#modal-root [data-qa="create-direct-modal"] [data-qa-type="user-auto-complete-input"]'); - } - - get btnCreate(): Locator { - return this.page.locator('role=button[name="Create"]'); - } - - get inputSearch(): Locator { - return this.page.locator('role=search >> role=searchbox').first(); - } - - get sidebarChannelsList(): Locator { - return this.page.getByRole('list', { name: 'Channels' }); - } - - get sidebarToolbar(): Locator { - return this.page.getByRole('toolbar', { name: 'Sidebar actions' }); - } - - // Note: this is different from openChat because queued chats are not searchable - getQueuedChat(name: string): Locator { - return this.page.locator('[data-qa="sidebar-item-title"]', { hasText: new RegExp(`^${name}$`) }).first(); - } - - getSidebarItemByName(name: string): Locator { - return this.page.getByRole('link').filter({ has: this.page.getByText(name, { exact: true }) }); - } - - get homepageHeader(): Locator { - return this.page.locator('main').getByRole('heading', { name: 'Home' }); - } -} diff --git a/apps/meteor/tests/e2e/page-objects/fragments/index.ts b/apps/meteor/tests/e2e/page-objects/fragments/index.ts index a46cbe188f3bb..3bdd1d3d63b0d 100644 --- a/apps/meteor/tests/e2e/page-objects/fragments/index.ts +++ b/apps/meteor/tests/e2e/page-objects/fragments/index.ts @@ -3,7 +3,6 @@ export * from './user-info-flextab'; export * from './home-content'; export * from './home-omnichannel-content'; export * from './home-flextab'; -export * from './home-sidenav'; export * from './omnichannel-sidenav'; export * from './omnichannel-close-chat-modal'; export * from './navbar'; diff --git a/apps/meteor/tests/e2e/page-objects/home-channel.ts b/apps/meteor/tests/e2e/page-objects/home-channel.ts index 42f2316401f98..478ca3d2f84b6 100644 --- a/apps/meteor/tests/e2e/page-objects/home-channel.ts +++ b/apps/meteor/tests/e2e/page-objects/home-channel.ts @@ -1,6 +1,6 @@ import type { Locator, Page } from '@playwright/test'; -import { HomeContent, HomeSidenav, HomeFlextab, Navbar, Sidepanel, RoomSidebar, ToastMessages } from './fragments'; +import { HomeContent, HomeFlextab, Navbar, Sidepanel, RoomSidebar, ToastMessages } from './fragments'; import { RoomToolbar } from './fragments/toolbar'; import { VoiceCalls } from './fragments/voice-calls'; @@ -9,8 +9,6 @@ export class HomeChannel { readonly content: HomeContent; - readonly sidenav: HomeSidenav; - readonly sidebar: RoomSidebar; readonly sidepanel: Sidepanel; @@ -28,7 +26,6 @@ export class HomeChannel { constructor(page: Page) { this.page = page; this.content = new HomeContent(page); - this.sidenav = new HomeSidenav(page); this.sidebar = new RoomSidebar(page); this.sidepanel = new Sidepanel(page); this.navbar = new Navbar(page); @@ -122,8 +119,12 @@ export class HomeChannel { return this.page.getByRole('main').getByRole('status'); } + get homepageHeader(): Locator { + return this.page.locator('main').getByRole('heading', { name: 'Home' }); + } + async waitForHome(): Promise { - await this.sidenav.homepageHeader.waitFor({ state: 'visible' }); + await this.homepageHeader.waitFor({ state: 'visible' }); } async waitForRoomLoad(): Promise { diff --git a/apps/meteor/tests/e2e/page-objects/home-discussion.ts b/apps/meteor/tests/e2e/page-objects/home-discussion.ts index 040b4436e8c95..1088007bd9152 100644 --- a/apps/meteor/tests/e2e/page-objects/home-discussion.ts +++ b/apps/meteor/tests/e2e/page-objects/home-discussion.ts @@ -1,14 +1,12 @@ import type { Locator, Page } from '@playwright/test'; -import { HomeContent, HomeSidenav, HomeFlextab, Navbar } from './fragments'; +import { HomeContent, HomeFlextab, Navbar } from './fragments'; export class HomeDiscussion { private readonly page: Page; readonly content: HomeContent; - readonly sidenav: HomeSidenav; - readonly navbar: Navbar; readonly tabs: HomeFlextab; @@ -16,7 +14,6 @@ export class HomeDiscussion { constructor(page: Page) { this.page = page; this.content = new HomeContent(page); - this.sidenav = new HomeSidenav(page); this.navbar = new Navbar(page); this.tabs = new HomeFlextab(page); } diff --git a/apps/meteor/tests/e2e/page-objects/omnichannel-room-info.ts b/apps/meteor/tests/e2e/page-objects/omnichannel-room-info.ts index 7c415faccdb70..e7f6430fc38e0 100644 --- a/apps/meteor/tests/e2e/page-objects/omnichannel-room-info.ts +++ b/apps/meteor/tests/e2e/page-objects/omnichannel-room-info.ts @@ -1,15 +1,15 @@ import type { Locator, Page } from '@playwright/test'; -import { HomeSidenav } from './fragments/home-sidenav'; +import { RoomSidebar } from './fragments'; export class OmnichannelRoomInfo { private readonly page: Page; - private readonly homeSidenav: HomeSidenav; + private readonly sidebar: RoomSidebar; constructor(page: Page) { this.page = page; - this.homeSidenav = new HomeSidenav(page); + this.sidebar = new RoomSidebar(page); } get dialogRoomInfo(): Locator { @@ -70,6 +70,6 @@ export class OmnichannelRoomInfo { } getBadgeIndicator(name: string, title: string): Locator { - return this.homeSidenav.getSidebarItemByName(name).getByTitle(title); + return this.sidebar.getSidebarItemByName(name).getByTitle(title); } } From d7043fd880460bc504b955d360c5b807e3688242 Mon Sep 17 00:00:00 2001 From: Kevin Aleman Date: Tue, 23 Dec 2025 15:03:57 -0600 Subject: [PATCH 02/68] regression: Remove Mobex & Voxtelesys settings (#37949) --- apps/meteor/server/settings/omnichannel.ts | 94 ------------------- .../meteor/server/startup/migrations/index.ts | 1 + apps/meteor/server/startup/migrations/v333.ts | 35 +++++++ 3 files changed, 36 insertions(+), 94 deletions(-) create mode 100644 apps/meteor/server/startup/migrations/v333.ts diff --git a/apps/meteor/server/settings/omnichannel.ts b/apps/meteor/server/settings/omnichannel.ts index 78b9463a883af..1fba2b6801883 100644 --- a/apps/meteor/server/settings/omnichannel.ts +++ b/apps/meteor/server/settings/omnichannel.ts @@ -736,100 +736,6 @@ await settingsRegistry.addGroup('SMS', async function () { }); }); - await this.section('Voxtelesys', async function () { - await this.add('SMS_Voxtelesys_authToken', '', { - type: 'string', - enableQuery: { - _id: 'SMS_Service', - value: 'voxtelesys', - }, - i18nLabel: 'Auth_Token', - secret: true, - }); - await this.add('SMS_Voxtelesys_URL', 'https://smsapi.voxtelesys.net/api/v1/sms', { - type: 'string', - enableQuery: { - _id: 'SMS_Service', - value: 'voxtelesys', - }, - i18nLabel: 'URL', - secret: true, - }); - await this.add('SMS_Voxtelesys_FileUpload_Enabled', true, { - type: 'boolean', - enableQuery: { - _id: 'SMS_Service', - value: 'voxtelesys', - }, - i18nLabel: 'FileUpload_Enabled', - secret: true, - }); - await this.add('SMS_Voxtelesys_FileUpload_MediaTypeWhiteList', 'image/*,audio/*,video/*,text/*,application/pdf', { - type: 'string', - enableQuery: { - _id: 'SMS_Service', - value: 'voxtelesys', - }, - i18nLabel: 'FileUpload_MediaTypeWhiteList', - i18nDescription: 'FileUpload_MediaTypeWhiteListDescription', - secret: true, - }); - }); - - await this.section('Mobex', async function () { - await this.add('SMS_Mobex_gateway_address', '', { - type: 'string', - enableQuery: { - _id: 'SMS_Service', - value: 'mobex', - }, - i18nLabel: 'Mobex_sms_gateway_address', - i18nDescription: 'Mobex_sms_gateway_address_desc', - }); - await this.add('SMS_Mobex_restful_address', '', { - type: 'string', - enableQuery: { - _id: 'SMS_Service', - value: 'mobex', - }, - i18nLabel: 'Mobex_sms_gateway_restful_address', - i18nDescription: 'Mobex_sms_gateway_restful_address_desc', - }); - await this.add('SMS_Mobex_username', '', { - type: 'string', - enableQuery: { - _id: 'SMS_Service', - value: 'mobex', - }, - i18nLabel: 'Mobex_sms_gateway_username', - }); - await this.add('SMS_Mobex_password', '', { - type: 'password', - enableQuery: { - _id: 'SMS_Service', - value: 'mobex', - }, - i18nLabel: 'Mobex_sms_gateway_password', - }); - await this.add('SMS_Mobex_from_number', '', { - type: 'string', - enableQuery: { - _id: 'SMS_Service', - value: 'mobex', - }, - i18nLabel: 'Mobex_sms_gateway_from_number', - i18nDescription: 'Mobex_sms_gateway_from_number_desc', - }); - await this.add('SMS_Mobex_from_numbers_list', '', { - type: 'string', - enableQuery: { - _id: 'SMS_Service', - value: 'mobex', - }, - i18nLabel: 'Mobex_sms_gateway_from_numbers_list', - i18nDescription: 'Mobex_sms_gateway_from_numbers_list_desc', - }); - }); await this.section('External Frame', async function () { await this.add('Omnichannel_External_Frame_Enabled', false, { type: 'boolean', diff --git a/apps/meteor/server/startup/migrations/index.ts b/apps/meteor/server/startup/migrations/index.ts index 969a4b1a668be..ef0431addac8c 100644 --- a/apps/meteor/server/startup/migrations/index.ts +++ b/apps/meteor/server/startup/migrations/index.ts @@ -38,5 +38,6 @@ import './v329'; import './v330'; import './v331'; import './v332'; +import './v333'; export * from './xrun'; diff --git a/apps/meteor/server/startup/migrations/v333.ts b/apps/meteor/server/startup/migrations/v333.ts new file mode 100644 index 0000000000000..216340d465582 --- /dev/null +++ b/apps/meteor/server/startup/migrations/v333.ts @@ -0,0 +1,35 @@ +import { Settings } from '@rocket.chat/models'; + +import { addMigration } from '../../lib/migrations'; + +addMigration({ + version: 333, + name: 'Remove Voxtelesys & Mobex SMS settings by ID', + async up() { + const ids = [ + // Voxtelesys settings + 'SMS_Voxtelesys_authToken', + 'SMS_Voxtelesys_URL', + 'SMS_Voxtelesys_FileUpload_Enabled', + 'SMS_Voxtelesys_FileUpload_MediaTypeWhiteList', + + // Mobex settings + 'SMS_Mobex_gateway_address', + 'SMS_Mobex_gateway_address_desc', + 'SMS_Mobex_from_number', + 'SMS_Mobex_from_number_desc', + 'SMS_Mobex_from_numbers_list', + 'SMS_Mobex_from_numbers_list_desc', + 'SMS_Mobex_password', + 'SMS_Mobex_restful_address', + 'SMS_Mobex_restful_address_desc', + 'SMS_Mobex_username', + ]; + + await Settings.deleteMany({ + _id: { $in: ids }, + }); + + await Settings.findOneAndUpdate({ _id: 'SMS_Service', value: { $ne: 'twilio' } }, { $set: { value: 'twilio' } }); + }, +}); From ebc1281a7da2d506bb084e58b62ad0ddb9670cf7 Mon Sep 17 00:00:00 2001 From: juliajforesti Date: Tue, 23 Dec 2025 18:57:30 -0300 Subject: [PATCH 03/68] chore!: add `webrtc` migration --- .../meteor/server/startup/migrations/index.ts | 1 + apps/meteor/server/startup/migrations/v334.ts | 22 +++++++++++++++++++ 2 files changed, 23 insertions(+) create mode 100644 apps/meteor/server/startup/migrations/v334.ts diff --git a/apps/meteor/server/startup/migrations/index.ts b/apps/meteor/server/startup/migrations/index.ts index ef0431addac8c..b9095037a3d9b 100644 --- a/apps/meteor/server/startup/migrations/index.ts +++ b/apps/meteor/server/startup/migrations/index.ts @@ -39,5 +39,6 @@ import './v330'; import './v331'; import './v332'; import './v333'; +import './v334'; export * from './xrun'; diff --git a/apps/meteor/server/startup/migrations/v334.ts b/apps/meteor/server/startup/migrations/v334.ts new file mode 100644 index 0000000000000..318496c481a6e --- /dev/null +++ b/apps/meteor/server/startup/migrations/v334.ts @@ -0,0 +1,22 @@ +import { Settings } from '@rocket.chat/models'; + +import { addMigration } from '../../lib/migrations'; + +addMigration({ + version: 334, + name: 'Remove webRTC settings', + async up() { + await Settings.deleteMany({ + _id: { + $in: [ + 'WebRTC_Enabled', + 'WebRTC_Enable_Channel', + 'WebRTC_Enable_Private', + 'WebRTC_Enable_Direct', + 'WebRTC_Calls_Count', + 'WebRTC_Servers', + ], + }, + }); + }, +}); From c3c97fa047627e81027a9e6744b4561a30670cec Mon Sep 17 00:00:00 2001 From: juliajforesti Date: Tue, 23 Dec 2025 18:43:06 -0300 Subject: [PATCH 04/68] chore!: add `otr` migration --- apps/meteor/server/startup/migrations/index.ts | 1 + apps/meteor/server/startup/migrations/v335.ts | 11 +++++++++++ 2 files changed, 12 insertions(+) create mode 100644 apps/meteor/server/startup/migrations/v335.ts diff --git a/apps/meteor/server/startup/migrations/index.ts b/apps/meteor/server/startup/migrations/index.ts index b9095037a3d9b..d10693f181110 100644 --- a/apps/meteor/server/startup/migrations/index.ts +++ b/apps/meteor/server/startup/migrations/index.ts @@ -40,5 +40,6 @@ import './v331'; import './v332'; import './v333'; import './v334'; +import './v335'; export * from './xrun'; diff --git a/apps/meteor/server/startup/migrations/v335.ts b/apps/meteor/server/startup/migrations/v335.ts new file mode 100644 index 0000000000000..49b56b21dbf57 --- /dev/null +++ b/apps/meteor/server/startup/migrations/v335.ts @@ -0,0 +1,11 @@ +import { Settings } from '@rocket.chat/models'; + +import { addMigration } from '../../lib/migrations'; + +addMigration({ + version: 335, + name: 'Remove OTR_Enable and OTR_Count settings', + async up() { + await Settings.deleteMany({ _id: { $in: ['OTR_Enable', 'OTR_Count'] } }); + }, +}); From a868db6b5117cdc360b389c814fa6150172a8568 Mon Sep 17 00:00:00 2001 From: Aleksander Nicacio da Silva Date: Tue, 23 Dec 2025 23:39:31 -0300 Subject: [PATCH 05/68] regression: Prevent room infinite loop when invitation is revoked during invite view (#37955) --- apps/meteor/client/views/room/Room.tsx | 5 +++-- apps/meteor/client/views/room/RoomInvite.tsx | 9 +++++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/apps/meteor/client/views/room/Room.tsx b/apps/meteor/client/views/room/Room.tsx index 69438ed251d8d..fed2a9da31e58 100644 --- a/apps/meteor/client/views/room/Room.tsx +++ b/apps/meteor/client/views/room/Room.tsx @@ -1,6 +1,6 @@ import { isInviteSubscription } from '@rocket.chat/core-typings'; import { ContextualbarSkeleton } from '@rocket.chat/ui-client'; -import { useSetting, useRoomToolbox } from '@rocket.chat/ui-contexts'; +import { useSetting, useRoomToolbox, useUserId } from '@rocket.chat/ui-contexts'; import type { ReactElement } from 'react'; import { createElement, lazy, memo, Suspense } from 'react'; import { FocusScope } from 'react-aria'; @@ -23,6 +23,7 @@ const UiKitContextualBar = lazy(() => import('./contextualBar/uikit/UiKitContext const Room = (): ReactElement => { const { t } = useTranslation(); + const userId = useUserId(); const room = useRoom(); const subscription = useRoomSubscription(); const toolbox = useRoomToolbox(); @@ -36,7 +37,7 @@ const Room = (): ReactElement => { if (subscription && isInviteSubscription(subscription)) { return ( - + ); } diff --git a/apps/meteor/client/views/room/RoomInvite.tsx b/apps/meteor/client/views/room/RoomInvite.tsx index 36d8ab8f16420..476609770a5c0 100644 --- a/apps/meteor/client/views/room/RoomInvite.tsx +++ b/apps/meteor/client/views/room/RoomInvite.tsx @@ -1,25 +1,30 @@ -import { isRoomFederated, type IInviteSubscription } from '@rocket.chat/core-typings'; +import { isRoomFederated } from '@rocket.chat/core-typings'; +import type { IUser, IInviteSubscription } from '@rocket.chat/core-typings'; import type { ComponentProps } from 'react'; import { useTranslation } from 'react-i18next'; import Header from './Header'; import RoomInviteBody from './body/RoomInviteBody'; +import { useGoToHomeOnRemoved } from './body/hooks/useGoToHomeOnRemoved'; import type { IRoomWithFederationOriginalName } from './contexts/RoomContext'; import { useRoomInvitation } from './hooks/useRoomInvitation'; import RoomLayout from './layout/RoomLayout'; import { links } from '../../lib/links'; type RoomInviteProps = Omit, 'header' | 'body' | 'aside'> & { + userId?: IUser['_id']; room: IRoomWithFederationOriginalName; subscription: IInviteSubscription; }; -const RoomInvite = ({ room, subscription, ...props }: RoomInviteProps) => { +const RoomInvite = ({ room, subscription, userId, ...props }: RoomInviteProps) => { const { t } = useTranslation(); const { acceptInvite, rejectInvite, isPending } = useRoomInvitation(room); const infoLink = isRoomFederated(room) ? { label: t('Learn_more_about_Federation'), href: links.go.matrixFederation } : undefined; + useGoToHomeOnRemoved(room, userId); + return ( Date: Wed, 24 Dec 2025 00:18:43 -0300 Subject: [PATCH 06/68] regression(federation): fix group DM name (#37957) --- apps/meteor/package.json | 2 +- ee/packages/federation-matrix/package.json | 2 +- .../federation-matrix/src/FederationMatrix.ts | 48 ++------ .../tests/end-to-end/dms.spec.ts | 106 +++++++++++------- yarn.lock | 16 +-- 5 files changed, 86 insertions(+), 88 deletions(-) diff --git a/apps/meteor/package.json b/apps/meteor/package.json index 5215ad149a265..becbf6c9534d1 100644 --- a/apps/meteor/package.json +++ b/apps/meteor/package.json @@ -99,7 +99,7 @@ "@rocket.chat/emitter": "~0.31.25", "@rocket.chat/favicon": "workspace:^", "@rocket.chat/federation-matrix": "workspace:^", - "@rocket.chat/federation-sdk": "0.3.5", + "@rocket.chat/federation-sdk": "0.3.7", "@rocket.chat/fuselage": "^0.70.0", "@rocket.chat/fuselage-forms": "~0.1.1", "@rocket.chat/fuselage-hooks": "~0.38.1", diff --git a/ee/packages/federation-matrix/package.json b/ee/packages/federation-matrix/package.json index 72c841daf0654..acc9e6ea10e8f 100644 --- a/ee/packages/federation-matrix/package.json +++ b/ee/packages/federation-matrix/package.json @@ -22,7 +22,7 @@ "@rocket.chat/core-services": "workspace:^", "@rocket.chat/core-typings": "workspace:^", "@rocket.chat/emitter": "^0.31.25", - "@rocket.chat/federation-sdk": "0.3.5", + "@rocket.chat/federation-sdk": "0.3.7", "@rocket.chat/http-router": "workspace:^", "@rocket.chat/license": "workspace:^", "@rocket.chat/models": "workspace:^", diff --git a/ee/packages/federation-matrix/src/FederationMatrix.ts b/ee/packages/federation-matrix/src/FederationMatrix.ts index bb47f5b2d9fab..4ad48d94bbe69 100644 --- a/ee/packages/federation-matrix/src/FederationMatrix.ts +++ b/ee/packages/federation-matrix/src/FederationMatrix.ts @@ -260,53 +260,23 @@ export class FederationMatrix extends ServiceClass implements IFederationMatrixS try { this.logger.debug('Creating direct message room in Matrix', { roomId: room._id, memberCount: members.length }); - const creator = await Users.findOneById(creatorId); + const creator = await Users.findOneById>(creatorId, { projection: { username: 1 } }); if (!creator) { throw new Error('Creator not found in members list'); } - const actualMatrixUserId = `@${creator.username}:${this.serverName}`; - - let matrixRoomResult: { room_id: string; event_id?: string }; - if (members.length === 2) { - const otherMember = members.find((member) => member._id !== creatorId); - if (!otherMember) { - throw new Error('Other member not found for 1-on-1 DM'); - } - if (!isUserNativeFederated(otherMember)) { - throw new Error('Other member is not federated'); - } - const roomId = await federationSDK.createDirectMessageRoom( - userIdSchema.parse(actualMatrixUserId), - userIdSchema.parse(otherMember.username), - ); - matrixRoomResult = { room_id: roomId }; - } else { - // For group DMs (more than 2 members), create a private room - const roomName = room.name || room.fname || `Group chat with ${members.length} members`; - matrixRoomResult = await federationSDK.createRoom(userIdSchema.parse(actualMatrixUserId), roomName, 'invite'); - - for await (const member of members) { - if (member._id === creatorId) { - continue; - } - - try { - await federationSDK.inviteUserToRoom( - isUserNativeFederated(member) ? userIdSchema.parse(member.username) : `@${member.username}:${this.serverName}`, - roomIdSchema.parse(matrixRoomResult.room_id), - userIdSchema.parse(actualMatrixUserId), - ); - } catch (error) { - this.logger.error(error, 'Error creating or updating bridged user for DM'); - } - } - } + const roomId = await federationSDK.createDirectMessage({ + creatorUserId: userIdSchema.parse(`@${creator.username}:${this.serverName}`), + members: members + .filter((member) => member._id !== creatorId) + .map((member) => userIdSchema.parse(isUserNativeFederated(member) ? member.username : `@${member.username}:${this.serverName}`)), + }); await Rooms.setAsFederated(room._id, { - mrid: matrixRoomResult.room_id, + mrid: roomId, origin: this.serverName, }); + this.logger.debug({ roomId: room._id, msg: 'Direct message room creation completed successfully' }); } catch (error) { this.logger.error(error, 'Failed to create direct message room'); diff --git a/ee/packages/federation-matrix/tests/end-to-end/dms.spec.ts b/ee/packages/federation-matrix/tests/end-to-end/dms.spec.ts index 083d695f4b989..6c45ce193b28c 100644 --- a/ee/packages/federation-matrix/tests/end-to-end/dms.spec.ts +++ b/ee/packages/federation-matrix/tests/end-to-end/dms.spec.ts @@ -937,6 +937,10 @@ const waitForRoomEvent = async ( }); }); + it('should show the room name as the inviter name on Synapse before join', async () => { + expect(hs1Room1.name).toBe(rcUser1.username); + }); + it('should display the fname containing the two invited users for the inviter', async () => { // Check the subscription for the inviter const sub = await getSubscriptionByRoomId(rcRoom._id, rcUserConfig1.credentials, rcUserConfig1.request); @@ -954,16 +958,23 @@ const waitForRoomEvent = async ( expect(sub).toHaveProperty('fname', rcUser1.username); }); - it.failing('should keep the fname to the RC invited user when the Synapse invited user accepts the DM', async () => { - const waitForRoomEventPromise1 = waitForRoomEvent(hs1Room1, RoomStateEvent.Members, ({ event }) => { - expect(event).toHaveProperty('content.membership', 'join'); - expect(event).toHaveProperty('state_key', federationConfig.hs1.adminMatrixUserId); - }); - + it('should accept the invitation on Synapse', async () => { await hs1AdminApp.matrixClient.joinRoom(rcRoom.federation.mrid); - await waitForRoomEventPromise1; + await retry( + 'wait for the join to be processed', + async () => { + expect(hs1Room1.getMyMembership()).toBe('join'); + }, + { delayMs: 100 }, + ); + }); + it('should show the room name with all members on Synapse after join', async () => { + expect(hs1Room1.name).toBe(`${rcUser1.username} and ${rcUser2.username}`); + }); + + it.failing('should keep the fname to the RC invited user when the Synapse invited user accepts the DM', async () => { await retry( 'this is an async operation, so we need to wait for the event to be processed', async () => { @@ -991,11 +1002,6 @@ const waitForRoomEvent = async ( { delayMs: 100 }, ); }); - - it('should validate the room name for group DMs on Synapse', async () => { - // TODO this should probably change - expect(hs1Room1.name).toBe('Group chat with 3 members'); - }); }); describe('Permission validations', () => { @@ -1103,12 +1109,11 @@ const waitForRoomEvent = async ( }); // TODO maybe we should allow it - // is this working now? - it.failing('should fail if a user from rc try to add another user to the group DM', async () => { + it('should fail if a user from rc try to add another user to the group DM', async () => { const response = await addUserToRoom({ usernames: [rcUser3.username], rid: rcRoom._id, - config: rcUserConfig1, + config: rcUserConfig2, }); expect(response.body).toHaveProperty('success', true); @@ -1120,23 +1125,32 @@ const waitForRoomEvent = async ( expect(messageData).toHaveProperty('error.error', 'error-not-allowed'); }); - // TODO we're creating DMs with powerlevel 50 for invites, so this is not working - it.failing('should add another user by another user than the initial inviter', async () => { + it('should add another user by another user than the initial inviter', async () => { await hs1AdminApp.matrixClient.joinRoom(rcRoom.federation.mrid); - await retry('waiting for join', async () => { - const members = await hs1Room1.getMembers(); - expect(members.length).toBe(3); - }); + await retry( + 'waiting for join', + async () => { + expect(hs1Room1.getMyMembership()).toBe('join'); + + const members = await hs1Room1.getMembers(); + expect(members.length).toBe(3); + }, + { delayMs: 100 }, + ); await hs1AdminApp.inviteUserToRoom(hs1Room1.roomId, userDmId3); - await retry('waiting for user4 to receive invitation', async () => { - const members = await hs1Room1.getMembers(); - const user4Member = members.find((m) => m.userId === userDmId3); - expect(user4Member).toBeDefined(); - expect(user4Member?.membership).toBe('invite'); - }); + await retry( + 'waiting for user4 to receive invitation', + async () => { + const members = await hs1Room1.getMembers(); + const user4Member = members.find((m) => m.userId === userDmId3); + expect(user4Member).toBeDefined(); + expect(user4Member?.membership).toBe('invite'); + }, + { delayMs: 100 }, + ); }); }); @@ -1662,7 +1676,7 @@ const waitForRoomEvent = async ( expect(messageData).toHaveProperty('error.error', 'error-cant-invite-for-direct-room'); }); - it('should create a 1:1 a federated DM between', async () => { + it('should create a 1:1 federated DM', async () => { // Create 1:1 DM from RC user to another RC user const response = await rcUser1.config.request .post(api('dm.create')) @@ -1696,7 +1710,7 @@ const waitForRoomEvent = async ( expect(sub).toHaveProperty('fname', federationConfig.hs1.adminMatrixUserId); }); - it('should show the invite to the third user', async () => { + it('should send an invite to another Synapse user', async () => { // invite from rocket.chat const response = await addUserToRoom({ usernames: [federationConfig.hs1.additionalUser1.matrixUserId], @@ -1744,19 +1758,33 @@ const waitForRoomEvent = async ( expect(roomInfo.room).toHaveProperty('usersCount', 3); }); - // TODO we're creating DMs with powerlevel 50 for invites, so this is not working - it.failing('should invite a fourth user from Rocket.Chat by a Synapse user', async () => { + it('should invite a fourth Rocket.Chat user by the invited Synapse user', async () => { await hs1User1.inviteUserToRoom(hs1Room1.roomId, rcUser2.matrixId); - await retry('waiting for fourth user to receive invitation', async () => { - const subscriptionInvite = await getSubscriptionByRoomId(rcRoom._id, rcUser2.config.credentials, rcUser2.config.request); + await retry( + 'waiting for user4 to receive invitation', + async () => { + const members = await hs1Room1.getMembers(); - expect(subscriptionInvite).toHaveProperty('status', 'INVITED'); - expect(subscriptionInvite).toHaveProperty( - 'fname', - `${federationConfig.hs1.adminMatrixUserId}, ${federationConfig.hs1.additionalUser1.matrixUserId}, ${rcUser1.matrixId}`, - ); - }); + const user4Member = members.find((m) => m.userId === rcUser2.matrixId); + + expect(user4Member).toBeDefined(); + expect(user4Member?.membership).toBe('invite'); + }, + { delayMs: 100 }, + ); + + await retry( + 'waiting for fourth user to receive invitation', + async () => { + const sub = await getSubscriptionByRoomId(rcRoom._id, rcUser2.config.credentials, rcUser2.config.request); + + expect(sub).toHaveProperty('status', 'INVITED'); + expect(sub).toHaveProperty('name', federationConfig.hs1.additionalUser1.matrixUserId); + expect(sub).toHaveProperty('fname', federationConfig.hs1.additionalUser1.matrixUserId); + }, + { delayMs: 100 }, + ); }); }); }); diff --git a/yarn.lock b/yarn.lock index 999452db5d501..900f9ced99bfe 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8467,7 +8467,7 @@ __metadata: "@rocket.chat/apps-engine": "workspace:^" "@rocket.chat/core-typings": "workspace:^" "@rocket.chat/eslint-config": "workspace:^" - "@rocket.chat/federation-sdk": "npm:0.3.5" + "@rocket.chat/federation-sdk": "npm:0.3.7" "@rocket.chat/http-router": "workspace:^" "@rocket.chat/icons": "npm:~0.46.0" "@rocket.chat/jest-presets": "workspace:~" @@ -8674,7 +8674,7 @@ __metadata: "@rocket.chat/ddp-client": "workspace:^" "@rocket.chat/emitter": "npm:^0.31.25" "@rocket.chat/eslint-config": "workspace:^" - "@rocket.chat/federation-sdk": "npm:0.3.5" + "@rocket.chat/federation-sdk": "npm:0.3.7" "@rocket.chat/http-router": "workspace:^" "@rocket.chat/license": "workspace:^" "@rocket.chat/models": "workspace:^" @@ -8700,9 +8700,9 @@ __metadata: languageName: unknown linkType: soft -"@rocket.chat/federation-sdk@npm:0.3.5": - version: 0.3.5 - resolution: "@rocket.chat/federation-sdk@npm:0.3.5" +"@rocket.chat/federation-sdk@npm:0.3.7": + version: 0.3.7 + resolution: "@rocket.chat/federation-sdk@npm:0.3.7" dependencies: "@datastructures-js/priority-queue": "npm:^6.3.5" "@noble/ed25519": "npm:^3.0.0" @@ -8715,7 +8715,7 @@ __metadata: zod: "npm:^3.24.1" peerDependencies: typescript: ~5.9.2 - checksum: 10/47de2265555649b375620c7a90cf84134b14f3e38d171d84276dee9196b7b303a2d8c6f693223d63ba1c464ce12c128c5f6a795c0bb42c0e5339587b2429d034 + checksum: 10/fd3bce12146ad906970ebe88ddc54f118362a52fe600d90d39a99a684aa7c637922b39791b671f1b9de8fb160076468de5034286673da443dfad6a68924fed91 languageName: node linkType: hard @@ -9342,7 +9342,7 @@ __metadata: "@rocket.chat/eslint-config": "workspace:^" "@rocket.chat/favicon": "workspace:^" "@rocket.chat/federation-matrix": "workspace:^" - "@rocket.chat/federation-sdk": "npm:0.3.5" + "@rocket.chat/federation-sdk": "npm:0.3.7" "@rocket.chat/fuselage": "npm:^0.70.0" "@rocket.chat/fuselage-forms": "npm:~0.1.1" "@rocket.chat/fuselage-hooks": "npm:~0.38.1" @@ -10797,7 +10797,7 @@ __metadata: peerDependencies: "@rocket.chat/layout": "*" "@rocket.chat/tools": 0.2.4-rc.0 - "@rocket.chat/ui-contexts": 26.0.0-rc.0 + "@rocket.chat/ui-contexts": 26.0.0-rc.1 "@tanstack/react-query": "*" react: "*" react-hook-form: "*" From d2b0e30f85c16e3f9ce02352ad12c2190b972ddd Mon Sep 17 00:00:00 2001 From: gabriellsh <40830821+gabriellsh@users.noreply.github.com> Date: Wed, 24 Dec 2025 11:04:26 -0300 Subject: [PATCH 07/68] regression: Call History button not working on smaller screens (mobile layout) (#37946) --- .../navbar/NavBarControls/NavBarControlsWithData.tsx | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/apps/meteor/client/navbar/NavBarControls/NavBarControlsWithData.tsx b/apps/meteor/client/navbar/NavBarControls/NavBarControlsWithData.tsx index 04a28da309b3c..1a54983ac5e93 100644 --- a/apps/meteor/client/navbar/NavBarControls/NavBarControlsWithData.tsx +++ b/apps/meteor/client/navbar/NavBarControls/NavBarControlsWithData.tsx @@ -1,6 +1,7 @@ import type { GenericMenuItemProps } from '@rocket.chat/ui-client'; +import { useRouter } from '@rocket.chat/ui-contexts'; import { useMediaCallAction } from '@rocket.chat/ui-voip'; -import type { HTMLAttributes } from 'react'; +import { useCallback, type HTMLAttributes } from 'react'; import { useTranslation } from 'react-i18next'; import NavBarControlsMenu from './NavBarControlsMenu'; @@ -14,6 +15,11 @@ const NavBarControlsWithData = (props: NavBarControlsMenuProps) => { const { t } = useTranslation(); const callAction = useMediaCallAction(); + const router = useRouter(); + const openCallHistory = useCallback(() => { + router.navigate('/call-history'); + }, [router]); + const { isEnabled: queueEnabled, icon: queueIcon, @@ -49,6 +55,7 @@ const NavBarControlsWithData = (props: NavBarControlsMenuProps) => { id: 'rcx-media-call-history', icon: 'clock' as const, content: t('Call_history'), + onClick: openCallHistory, } : undefined; From 6986bbbecbb5856ccb1d1d3586d9872cd029eaff Mon Sep 17 00:00:00 2001 From: Matheus Cardoso Date: Wed, 24 Dec 2025 11:36:16 -0300 Subject: [PATCH 08/68] regression: fix crash on insecure context (#37964) --- apps/meteor/client/lib/e2ee/crypto/shared.ts | 4 ++-- apps/meteor/client/lib/e2ee/rocketchat.e2e.ts | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/apps/meteor/client/lib/e2ee/crypto/shared.ts b/apps/meteor/client/lib/e2ee/crypto/shared.ts index ea95b651c6f57..1605a106e53b3 100644 --- a/apps/meteor/client/lib/e2ee/crypto/shared.ts +++ b/apps/meteor/client/lib/e2ee/crypto/shared.ts @@ -1,5 +1,5 @@ const { subtle } = crypto; -export const randomUUID = crypto.randomUUID.bind(crypto); +export const randomUUID = () => crypto.randomUUID(); export const getRandomValues = crypto.getRandomValues.bind(crypto); interface IAesGcmParams extends AesGcmParams { @@ -40,7 +40,7 @@ export const decryptBuffer = ( params: ParamsOf, data: BufferSource, ): Promise => subtle.decrypt(params, key, data) as Promise; -export const deriveBits = subtle.deriveBits.bind(subtle); +export const deriveBits = (...args: Parameters) => subtle.deriveBits(...args); type AesParams = { name: 'AES-CBC' | 'AES-GCM' | 'AES-CTR'; diff --git a/apps/meteor/client/lib/e2ee/rocketchat.e2e.ts b/apps/meteor/client/lib/e2ee/rocketchat.e2e.ts index 7632ee64e9e39..4268630bb50b2 100644 --- a/apps/meteor/client/lib/e2ee/rocketchat.e2e.ts +++ b/apps/meteor/client/lib/e2ee/rocketchat.e2e.ts @@ -345,6 +345,10 @@ class E2E extends Emitter { } async startClient(userId: string): Promise { + if (!isSecureContext) { + throw new Error('E2E encryption can only be enabled in secure contexts (HTTPS)'); + } + const span = log.span('startClient'); if (this.userId === userId) { return; From 0dddad65f736f2330cd6c0941bb979c484ecc356 Mon Sep 17 00:00:00 2001 From: Martin Schoeler Date: Wed, 24 Dec 2025 12:42:40 -0300 Subject: [PATCH 09/68] regression(ABAC): list not updating when room change (#37952) Co-authored-by: Tasso --- apps/meteor/client/lib/queryKeys.ts | 8 ++++---- .../ABAC/ABACAttributesTab/AttributesContextualBar.tsx | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/meteor/client/lib/queryKeys.ts b/apps/meteor/client/lib/queryKeys.ts index a619b03178100..8dff5a6068991 100644 --- a/apps/meteor/client/lib/queryKeys.ts +++ b/apps/meteor/client/lib/queryKeys.ts @@ -128,17 +128,17 @@ export const ABACQueryKeys = { all: ['abac'] as const, logs: { all: () => [...ABACQueryKeys.all, 'logs'] as const, - list: (query?: PaginatedRequest) => [...ABACQueryKeys.logs.all(), 'list', query] as const, + list: (...args: [query?: PaginatedRequest]) => [...ABACQueryKeys.logs.all(), 'list', ...args] as const, }, roomAttributes: { all: () => [...ABACQueryKeys.all, 'room-attributes'] as const, - list: (query?: PaginatedRequest) => [...ABACQueryKeys.roomAttributes.all(), query] as const, + list: (...args: [query?: PaginatedRequest]) => [...ABACQueryKeys.roomAttributes.all(), ...args] as const, attribute: (attributeId: string) => [...ABACQueryKeys.roomAttributes.all(), attributeId] as const, }, rooms: { all: () => [...ABACQueryKeys.all, 'rooms'] as const, - list: (query?: PaginatedRequest) => [...ABACQueryKeys.rooms.all(), query] as const, - autocomplete: (query?: PaginatedRequest) => [...ABACQueryKeys.rooms.all(), 'autocomplete', query] as const, + list: (...args: [query?: PaginatedRequest]) => [...ABACQueryKeys.rooms.all(), ...args] as const, + autocomplete: (...args: [query?: PaginatedRequest]) => [...ABACQueryKeys.rooms.all(), 'autocomplete', ...args] as const, room: (roomId: string) => [...ABACQueryKeys.rooms.all(), roomId] as const, }, }; diff --git a/apps/meteor/client/views/admin/ABAC/ABACAttributesTab/AttributesContextualBar.tsx b/apps/meteor/client/views/admin/ABAC/ABACAttributesTab/AttributesContextualBar.tsx index a1f22fd11a1dd..a41e7b6b87ca2 100644 --- a/apps/meteor/client/views/admin/ABAC/ABACAttributesTab/AttributesContextualBar.tsx +++ b/apps/meteor/client/views/admin/ABAC/ABACAttributesTab/AttributesContextualBar.tsx @@ -75,7 +75,7 @@ const AttributesContextualBar = ({ attributeData, onClose }: AttributesContextua dispatchToastMessage({ type: 'error', message: error }); }, onSettled: () => { - queryClient.invalidateQueries({ queryKey: ABACQueryKeys.roomAttributes.list({}) }); + queryClient.invalidateQueries({ queryKey: ABACQueryKeys.roomAttributes.list() }); }, }); From 0bb2a332b92b0cd8bff740d2b46a164b3986af7e Mon Sep 17 00:00:00 2001 From: gabriellsh <40830821+gabriellsh@users.noreply.github.com> Date: Fri, 26 Dec 2025 14:49:44 -0300 Subject: [PATCH 10/68] regression: Plus sign being added to external numbers (#37968) --- packages/ui-voip/src/components/CallHistoryExternalUser.tsx | 2 +- .../__snapshots__/CallHistoryContextualbar.spec.tsx.snap | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/ui-voip/src/components/CallHistoryExternalUser.tsx b/packages/ui-voip/src/components/CallHistoryExternalUser.tsx index ca8818bcc16a2..d4307026f515f 100644 --- a/packages/ui-voip/src/components/CallHistoryExternalUser.tsx +++ b/packages/ui-voip/src/components/CallHistoryExternalUser.tsx @@ -16,7 +16,7 @@ const CallHistoryExternalUser = ({ number, showIcon = true }: CallHistoryExterna )} - {number.startsWith('+') ? number : `+${number}`} + {number} ); }; diff --git a/packages/ui-voip/src/views/CallHistoryContextualbar/__snapshots__/CallHistoryContextualbar.spec.tsx.snap b/packages/ui-voip/src/views/CallHistoryContextualbar/__snapshots__/CallHistoryContextualbar.spec.tsx.snap index 56ea65eb25bb9..2237901c55ff3 100644 --- a/packages/ui-voip/src/views/CallHistoryContextualbar/__snapshots__/CallHistoryContextualbar.spec.tsx.snap +++ b/packages/ui-voip/src/views/CallHistoryContextualbar/__snapshots__/CallHistoryContextualbar.spec.tsx.snap @@ -491,7 +491,7 @@ exports[`renders ExternalContact without crashing 1`] = `
- +1234567890 + 1234567890
From 13021c3f774b83ccc155d086a19d146bb0619bb2 Mon Sep 17 00:00:00 2001 From: gabriellsh <40830821+gabriellsh@users.noreply.github.com> Date: Fri, 26 Dec 2025 16:11:17 -0300 Subject: [PATCH 11/68] regression: Media call items showing without having `teams-voip` module (#37960) --- .../client/hooks/useVoipWarningModal.tsx | 30 ----- .../client/providers/MediaCallProvider.tsx | 19 +-- .../contextualBar/TeamsVoipConfigModal.tsx | 114 ------------------ apps/meteor/tests/e2e/voice-calls-ce.spec.ts | 58 --------- 4 files changed, 1 insertion(+), 220 deletions(-) delete mode 100644 apps/meteor/client/hooks/useVoipWarningModal.tsx delete mode 100644 apps/meteor/client/views/room/contextualBar/TeamsVoipConfigModal.tsx delete mode 100644 apps/meteor/tests/e2e/voice-calls-ce.spec.ts diff --git a/apps/meteor/client/hooks/useVoipWarningModal.tsx b/apps/meteor/client/hooks/useVoipWarningModal.tsx deleted file mode 100644 index 568475d3a5efa..0000000000000 --- a/apps/meteor/client/hooks/useVoipWarningModal.tsx +++ /dev/null @@ -1,30 +0,0 @@ -import { useEffectEvent } from '@rocket.chat/fuselage-hooks'; -import { useRole, useRoute, useSetModal } from '@rocket.chat/ui-contexts'; -import { useMemo } from 'react'; - -import { useHasLicenseModule } from './useHasLicenseModule'; -import TeamsVoipConfigModal from '../views/room/contextualBar/TeamsVoipConfigModal'; - -export const useVoipWarningModal = (): (() => void) => { - const setModal = useSetModal(); - const isAdmin = useRole('admin'); - const { data: hasModule = false } = useHasLicenseModule('teams-voip'); - const teamsVoipSettingsRoute = useRoute('admin-settings'); - - const handleClose = useEffectEvent(() => setModal(null)); - - const handleRedirectToConfiguration = useEffectEvent(() => { - handleClose(); - teamsVoipSettingsRoute.push({ - group: 'VoIP_TeamCollab', - }); - }); - - return useMemo( - () => (): void => - setModal( - , - ), - [handleClose, handleRedirectToConfiguration, isAdmin, setModal, hasModule], - ); -}; diff --git a/apps/meteor/client/providers/MediaCallProvider.tsx b/apps/meteor/client/providers/MediaCallProvider.tsx index a1e8f552808a0..68d773d49e776 100644 --- a/apps/meteor/client/providers/MediaCallProvider.tsx +++ b/apps/meteor/client/providers/MediaCallProvider.tsx @@ -4,11 +4,8 @@ import type { ReactNode } from 'react'; import { useMemo } from 'react'; import { useHasLicenseModule } from '../hooks/useHasLicenseModule'; -import { useVoipWarningModal } from '../hooks/useVoipWarningModal'; const MediaCallProvider = ({ children }: { children: ReactNode }) => { - const dispatchWarning = useVoipWarningModal(); - const canMakeInternalCall = usePermission('allow-internal-voice-calls'); const canMakeExternalCall = usePermission('allow-external-voice-calls'); @@ -24,21 +21,7 @@ const MediaCallProvider = ({ children }: { children: ReactNode }) => { [], ); - const unlicensedContextValue = useMemo( - () => ({ - state: 'unlicensed' as const, - onToggleWidget: dispatchWarning, - onEndCall: undefined, - peerInfo: undefined, - }), - [dispatchWarning], - ); - - if (!hasModule) { - return {children}; - } - - if (!canMakeInternalCall && !canMakeExternalCall) { + if (!hasModule || (!canMakeInternalCall && !canMakeExternalCall)) { return {children}; } diff --git a/apps/meteor/client/views/room/contextualBar/TeamsVoipConfigModal.tsx b/apps/meteor/client/views/room/contextualBar/TeamsVoipConfigModal.tsx deleted file mode 100644 index 0fe200a7aaff6..0000000000000 --- a/apps/meteor/client/views/room/contextualBar/TeamsVoipConfigModal.tsx +++ /dev/null @@ -1,114 +0,0 @@ -import { - Modal, - Button, - Box, - Callout, - Margins, - ModalHeader, - ModalHeaderText, - ModalTagline, - ModalTitle, - ModalClose, - ModalContent, - ModalHeroImage, - ModalFooter, - ModalFooterAnnotation, - ModalFooterControllers, -} from '@rocket.chat/fuselage'; -import type { ReactElement } from 'react'; -import { useId } from 'react'; -import { Trans, useTranslation } from 'react-i18next'; - -import { useExternalLink } from '../../../hooks/useExternalLink'; -import { GET_ADDONS_LINK } from '../../admin/subscription/utils/links'; - -type TeamsVoipConfigModalProps = { - onClose: () => void; - onConfirm?: () => void; - isAdmin: boolean; - hasModule: boolean; -}; - -const TeamsVoipConfigModal = ({ onClose, onConfirm, isAdmin, hasModule }: TeamsVoipConfigModalProps): ReactElement => { - const { t } = useTranslation(); - const openExternalLink = useExternalLink(); - const teamsVoipConfigModalId = useId(); - - const getCalloutWarning = () => { - if (isAdmin) { - return t('Contact_sales_start_using_VoIP'); - } - - return t('Contact_your_workspace_admin_to_start_using_VoIP'); - }; - - return ( - - - - {t('VoIP')} - {t('Team_voice_call')} - - - - - - - {t('Fully_integrated_voip_receive_internal_external_calls_without_switching_between_apps_external_systems')} - - {t('Features')} - - - -
  • - - Direct calling: Instantly start or receive calls with team members within your Rocket.Chat workspace. - -
  • -
  • - - Extension management: Admins can assign unique extensions to users, enabling quick, direct dialing both - from inside and outside your organization. - -
  • -
  • - - Call transfers: Seamlessly transfer active calls to ensure users reach the right team member. - -
  • -
  • - - Availability settings: Users can control their availability to receive calls, enhancing flexibility. - -
  • -
    -
    -
    - - {t('Required_action')} - - - {getCalloutWarning()} - -
    - - {!isAdmin && hasModule && {t('Only_admins_can_perform_this_setup')}} - - - {onConfirm && isAdmin && hasModule && ( - - )} - {isAdmin && !hasModule && ( - - )} - - -
    - ); -}; - -export default TeamsVoipConfigModal; diff --git a/apps/meteor/tests/e2e/voice-calls-ce.spec.ts b/apps/meteor/tests/e2e/voice-calls-ce.spec.ts deleted file mode 100644 index 1b5bba7dd9c3f..0000000000000 --- a/apps/meteor/tests/e2e/voice-calls-ce.spec.ts +++ /dev/null @@ -1,58 +0,0 @@ -import { IS_EE } from './config/constants'; -import { Users } from './fixtures/userStates'; -import { HomeChannel } from './page-objects'; -import { VoiceCallsUpsellModal } from './page-objects/fragments/upsell-modal'; -import { expect, test } from './utils/test'; - -test.use({ storageState: Users.user1.state }); - -test.describe('Voice Calls - Community Edition', () => { - test.skip(IS_EE, 'Community Edition Only'); - let poHomeChannel: HomeChannel; - let upsellVoiceCallsModal: VoiceCallsUpsellModal; - - test.beforeEach(async ({ page }) => { - poHomeChannel = new HomeChannel(page); - upsellVoiceCallsModal = new VoiceCallsUpsellModal(page); - await page.goto('/home'); - }); - - test('should see upsell modal when clicked on DM > voice call button', async () => { - await test.step('should open direct message with user2', async () => { - await poHomeChannel.navbar.openChat('user2'); - await expect(poHomeChannel.content.inputMessage).toBeVisible(); - }); - - await test.step('should click voice call from room toolbar and see upsell modal', async () => { - await poHomeChannel.content.btnVoiceCall.click(); - await upsellVoiceCallsModal.waitForDisplay(); - }); - }); - - test('should see upsell modal when clicked on user info > voice call button', async () => { - await test.step('should open direct message with user2', async () => { - await poHomeChannel.navbar.openChat('user2'); - await expect(poHomeChannel.content.inputMessage).toBeVisible(); - }); - - await test.step('should click voice call from contact information and see upsell modal', async () => { - await poHomeChannel.content.btnContactInformation.click(); - await poHomeChannel.content.btnContactInfoVoiceCall.click(); - await upsellVoiceCallsModal.waitForDisplay(); - }); - }); - - test('should see upsell modal when clicked on User menu > New voice call', async () => { - await test.step('should open user menu', async () => { - await poHomeChannel.navbar.btnNewVoiceCall.click(); - }); - - await test.step('should see upsell modal', async () => { - await upsellVoiceCallsModal.waitForDisplay(); - }); - - await test.step('should close upsell modal', async () => { - await upsellVoiceCallsModal.close(); - }); - }); -}); From 65bbb5eac9dceae2ea5a301bd41a0ce16fb1e468 Mon Sep 17 00:00:00 2001 From: Aleksander Nicacio da Silva Date: Fri, 26 Dec 2025 17:33:59 -0300 Subject: [PATCH 12/68] regression: Members list not being updated after invite is revoked (#37981) --- apps/meteor/client/lib/queryKeys.ts | 4 ++++ apps/meteor/client/views/hooks/useMembersList.ts | 5 +++-- .../hooks/useUserInfoActions/actions/useRemoveUserAction.tsx | 4 ++++ 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/apps/meteor/client/lib/queryKeys.ts b/apps/meteor/client/lib/queryKeys.ts index 8dff5a6068991..9d1a86dea8f3a 100644 --- a/apps/meteor/client/lib/queryKeys.ts +++ b/apps/meteor/client/lib/queryKeys.ts @@ -26,6 +26,10 @@ export const roomsQueryKeys = { threads: (rid: IRoom['_id']) => [...roomsQueryKeys.room(rid), 'threads'] as const, roles: (rid: IRoom['_id']) => [...roomsQueryKeys.room(rid), 'roles'] as const, info: (rid: IRoom['_id']) => [...roomsQueryKeys.room(rid), 'info'] as const, + members: (rid: IRoom['_id'], roomType: RoomType, type?: 'all' | 'online', filter?: string) => + !type && !filter + ? ([...roomsQueryKeys.room(rid), 'members', roomType] as const) + : ([...roomsQueryKeys.room(rid), 'members', roomType, type, filter] as const), }; export const subscriptionsQueryKeys = { diff --git a/apps/meteor/client/views/hooks/useMembersList.ts b/apps/meteor/client/views/hooks/useMembersList.ts index 128b227d28def..476b8eef4251c 100644 --- a/apps/meteor/client/views/hooks/useMembersList.ts +++ b/apps/meteor/client/views/hooks/useMembersList.ts @@ -5,6 +5,7 @@ import { useInfiniteQuery, useQueryClient } from '@tanstack/react-query'; import { useEffect } from 'react'; import { calculateRoomRolePriorityFromRoles } from '../../../lib/roles/calculateRoomRolePriorityFromRoles'; +import { roomsQueryKeys } from '../../lib/queryKeys'; type MembersListOptions = { rid: string; @@ -73,7 +74,7 @@ const updateMemberInCache = ( useRealName = false, ) => { queryClient.setQueryData( - [options.roomType, 'members', options.rid, options.type, options.debouncedText], + roomsQueryKeys.members(options.rid, options.roomType, options.type, options.debouncedText), (oldData: InfiniteData) => { if (!oldData) { return oldData; @@ -136,7 +137,7 @@ export const useMembersList = (options: MembersListOptions) => { }, [options, queryClient, subscribeToNotifyLoggedIn, useRealName]); return useInfiniteQuery({ - queryKey: [options.roomType, 'members', options.rid, options.type, options.debouncedText], + queryKey: roomsQueryKeys.members(options.rid, options.roomType, options.type, options.debouncedText), queryFn: async ({ pageParam }) => { const start = pageParam ?? 0; diff --git a/apps/meteor/client/views/room/hooks/useUserInfoActions/actions/useRemoveUserAction.tsx b/apps/meteor/client/views/room/hooks/useUserInfoActions/actions/useRemoveUserAction.tsx index 19b1078f8eece..28c3d6252f4f8 100644 --- a/apps/meteor/client/views/room/hooks/useUserInfoActions/actions/useRemoveUserAction.tsx +++ b/apps/meteor/client/views/room/hooks/useUserInfoActions/actions/useRemoveUserAction.tsx @@ -12,10 +12,12 @@ import { useUserRoom, useUserSubscription, } from '@rocket.chat/ui-contexts'; +import { useQueryClient } from '@tanstack/react-query'; import { useMemo } from 'react'; import { useEndpointMutation } from '../../../../../hooks/useEndpointMutation'; import * as Federation from '../../../../../lib/federation/Federation'; +import { roomsQueryKeys } from '../../../../../lib/queryKeys'; import { roomCoordinator } from '../../../../../lib/rooms/roomCoordinator'; import RemoveUsersModal from '../../../../teams/contextualBar/members/RemoveUsersModal'; import { getRoomDirectives } from '../../../lib/getRoomDirectives'; @@ -34,6 +36,7 @@ export const useRemoveUserAction = ( } const t = useTranslation(); + const queryClient = useQueryClient(); const currentUser = useUser(); const subscription = useUserSubscription(rid); @@ -69,6 +72,7 @@ export const useRemoveUserAction = ( const { mutateAsync: removeFromRoom } = useEndpointMutation('POST', removeFromRoomEndpoint, { onSuccess: () => { dispatchToastMessage({ type: 'success', message: t('User_has_been_removed_from_s', roomName) }); + queryClient.invalidateQueries({ queryKey: roomsQueryKeys.members(room._id, room.t) }); }, onSettled: () => { closeModal(); From 586a88ac49932397ac65ba4c24e9e5ca78f32fda Mon Sep 17 00:00:00 2001 From: Martin Schoeler Date: Sat, 27 Dec 2025 15:43:46 -0300 Subject: [PATCH 13/68] regression: don't show a new field on edit ABAC attribute (#37966) --- .../admin/ABAC/ABACAttributesTab/AttributesContextualBar.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/meteor/client/views/admin/ABAC/ABACAttributesTab/AttributesContextualBar.tsx b/apps/meteor/client/views/admin/ABAC/ABACAttributesTab/AttributesContextualBar.tsx index a41e7b6b87ca2..0285afa82f787 100644 --- a/apps/meteor/client/views/admin/ABAC/ABACAttributesTab/AttributesContextualBar.tsx +++ b/apps/meteor/client/views/admin/ABAC/ABACAttributesTab/AttributesContextualBar.tsx @@ -30,7 +30,7 @@ const AttributesContextualBar = ({ attributeData, onClose }: AttributesContextua defaultValues: attributeData ? { name: attributeData.key, - attributeValues: [{ value: '' }], + attributeValues: [], lockedAttributes: attributeData.values.map((value) => ({ value })), } : { From 1f0c0d02d3079b53ec554ad4b7cab2da78ccd310 Mon Sep 17 00:00:00 2001 From: Martin Schoeler Date: Sat, 27 Dec 2025 15:44:55 -0300 Subject: [PATCH 14/68] regression(ABAC): "All" dates filter defaulting to 1969 (#37983) --- .../views/admin/moderation/helpers/DateRangePicker.tsx | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/apps/meteor/client/views/admin/moderation/helpers/DateRangePicker.tsx b/apps/meteor/client/views/admin/moderation/helpers/DateRangePicker.tsx index 82b3d7419d541..b17d664f1cdad 100644 --- a/apps/meteor/client/views/admin/moderation/helpers/DateRangePicker.tsx +++ b/apps/meteor/client/views/admin/moderation/helpers/DateRangePicker.tsx @@ -12,8 +12,6 @@ type DateRangePickerProps = { const formatToDateInput = (date: Moment) => date.locale('en').format('YYYY-MM-DD'); -const todayDate = formatToDateInput(moment()); - const getMonthRange = (monthsToSubtractFromToday: number) => ({ start: formatToDateInput(moment().subtract(monthsToSubtractFromToday, 'month').date(1)), end: formatToDateInput(monthsToSubtractFromToday === 0 ? moment() : moment().subtract(monthsToSubtractFromToday).date(0)), @@ -61,8 +59,8 @@ const DateRangePicker = ({ onChange, defaultSelectedKey = 'alldates' }: DateRang break; case 'alldates': handleRange({ - start: formatToDateInput(moment(0)), - end: todayDate, + start: '', + end: '', }); break; default: From 30575e76b9ee929fcca58f74e29b50d610191f1b Mon Sep 17 00:00:00 2001 From: Diego Sampaio Date: Mon, 29 Dec 2025 09:24:27 -0300 Subject: [PATCH 15/68] regression(federation): allow invite users with upper case username (#37970) --- .../federation-matrix/src/FederationMatrix.ts | 114 +----------------- .../federation-matrix/src/events/member.ts | 3 +- .../federation-matrix/src/events/room.ts | 2 +- .../helpers/createOrUpdateFederatedUser.ts | 54 +++++++++ .../helpers/extractDomainFromMatrixUserId.ts | 7 ++ .../src/helpers/getUsernameServername.ts | 21 ++++ .../helpers/validateFederatedUsername.spec.ts | 94 +++++++++++++++ .../src/helpers/validateFederatedUsername.ts | 76 ++++++++++++ ee/packages/federation-matrix/src/index.ts | 4 +- packages/core-services/package.json | 2 +- 10 files changed, 263 insertions(+), 114 deletions(-) create mode 100644 ee/packages/federation-matrix/src/helpers/createOrUpdateFederatedUser.ts create mode 100644 ee/packages/federation-matrix/src/helpers/extractDomainFromMatrixUserId.ts create mode 100644 ee/packages/federation-matrix/src/helpers/getUsernameServername.ts create mode 100644 ee/packages/federation-matrix/src/helpers/validateFederatedUsername.spec.ts create mode 100644 ee/packages/federation-matrix/src/helpers/validateFederatedUsername.ts diff --git a/ee/packages/federation-matrix/src/FederationMatrix.ts b/ee/packages/federation-matrix/src/FederationMatrix.ts index 4ad48d94bbe69..76c719d3b2db0 100644 --- a/ee/packages/federation-matrix/src/FederationMatrix.ts +++ b/ee/packages/federation-matrix/src/FederationMatrix.ts @@ -9,12 +9,15 @@ import { } from '@rocket.chat/core-typings'; import type { MessageQuoteAttachment, IMessage, IRoom, IUser, IRoomNativeFederated } from '@rocket.chat/core-typings'; import { eventIdSchema, roomIdSchema, userIdSchema, federationSDK, FederationRequestError } from '@rocket.chat/federation-sdk'; -import type { EventID, UserID, FileMessageType, PresenceState } from '@rocket.chat/federation-sdk'; +import type { EventID, FileMessageType, PresenceState } from '@rocket.chat/federation-sdk'; import { Logger } from '@rocket.chat/logger'; import { Users, Subscriptions, Messages, Rooms, Settings } from '@rocket.chat/models'; import emojione from 'emojione'; +import { createOrUpdateFederatedUser } from './helpers/createOrUpdateFederatedUser'; +import { extractDomainFromMatrixUserId } from './helpers/extractDomainFromMatrixUserId'; import { toExternalMessageFormat, toExternalQuoteMessageFormat } from './helpers/message.parsers'; +import { validateFederatedUsername } from './helpers/validateFederatedUsername'; import { MatrixMediaService } from './services/MatrixMediaService'; export const fileTypes: Record = { @@ -24,115 +27,6 @@ export const fileTypes: Record = { file: 'm.file', }; -/** helper to validate the username format */ -export function validateFederatedUsername(mxid: string): mxid is UserID { - if (!mxid.startsWith('@')) return false; - - const parts = mxid.substring(1).split(':'); - if (parts.length < 2) return false; - - const localpart = parts[0]; - const domainAndPort = parts.slice(1).join(':'); - - const localpartRegex = /^(?:[a-z0-9._\-]|=[0-9a-fA-F]{2}){1,255}$/; - if (!localpartRegex.test(localpart)) return false; - - const [domain, port] = domainAndPort.split(':'); - - const hostnameRegex = /^(?=.{1,253}$)([a-z0-9](?:[a-z0-9\-]{0,61}[a-z0-9])?)(?:\.[a-z0-9](?:[a-z0-9\-]{0,61}[a-z0-9])?)*$/i; - const ipv4Regex = /^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/; - const ipv6Regex = /^\[([0-9a-f:.]+)\]$/i; - - if (!(hostnameRegex.test(domain) || ipv4Regex.test(domain) || ipv6Regex.test(domain))) { - return false; - } - - if (port !== undefined) { - const portNum = Number(port); - if (!/^[0-9]+$/.test(port) || portNum < 1 || portNum > 65535) { - return false; - } - } - - return true; -} -export const extractDomainFromMatrixUserId = (mxid: string): string => { - const separatorIndex = mxid.indexOf(':', 1); - if (separatorIndex === -1) { - throw new Error(`Invalid federated username: ${mxid}`); - } - return mxid.substring(separatorIndex + 1); -}; - -/** - * Extract the username and the servername from a matrix user id - * if the serverName is the same as the serverName in the mxid, return only the username (rocket.chat regular username) - * otherwise, return the full mxid and the servername - */ -export const getUsernameServername = (mxid: string, serverName: string): [mxid: string, serverName: string, isLocal: boolean] => { - const senderServerName = extractDomainFromMatrixUserId(mxid); - // if the serverName is the same as the serverName in the mxid, return only the username (rocket.chat regular username) - if (serverName === senderServerName) { - const separatorIndex = mxid.indexOf(':', 1); - if (separatorIndex === -1) { - throw new Error(`Invalid federated username: ${mxid}`); - } - return [mxid.substring(1, separatorIndex), senderServerName, true]; // removers also the @ - } - - return [mxid, senderServerName, false]; -}; -/** - * Helper function to create a federated user - * - * Because of historical reasons, we can have users only with federated flag but no federation object - * So we need to upsert the user with the federation object - */ -export async function createOrUpdateFederatedUser(options: { username: string; name?: string; origin: string }): Promise { - const { username, name = username, origin } = options; - - // TODO: Have a specific method to handle this upsert - const user = await Users.findOneAndUpdate( - { - username, - }, - { - $set: { - username, - name: name || username, - type: 'user' as const, - status: UserStatus.OFFLINE, - active: true, - roles: ['user'], - requirePasswordChange: false, - federated: true, - federation: { - version: 1, - mui: username, - origin, - }, - _updatedAt: new Date(), - }, - $setOnInsert: { - createdAt: new Date(), - }, - }, - { - upsert: true, - projection: { _id: 1, username: 1 }, - returnDocument: 'after', - }, - ); - - if (!user) { - throw new Error(`Failed to create or update federated user: ${username}`); - } - - return user; -} - -export { generateEd25519RandomSecretKey } from '@rocket.chat/federation-sdk'; - export class FederationMatrix extends ServiceClass implements IFederationMatrixService { protected name = 'federation-matrix'; diff --git a/ee/packages/federation-matrix/src/events/member.ts b/ee/packages/federation-matrix/src/events/member.ts index 8de384253281a..2dd2b532d23f1 100644 --- a/ee/packages/federation-matrix/src/events/member.ts +++ b/ee/packages/federation-matrix/src/events/member.ts @@ -4,7 +4,8 @@ import { federationSDK, type HomeserverEventSignatures, type PduForType } from ' import { Logger } from '@rocket.chat/logger'; import { Rooms, Subscriptions, Users } from '@rocket.chat/models'; -import { createOrUpdateFederatedUser, getUsernameServername } from '../FederationMatrix'; +import { createOrUpdateFederatedUser } from '../helpers/createOrUpdateFederatedUser'; +import { getUsernameServername } from '../helpers/getUsernameServername'; const logger = new Logger('federation-matrix:member'); diff --git a/ee/packages/federation-matrix/src/events/room.ts b/ee/packages/federation-matrix/src/events/room.ts index 80b344ae2e96a..23b3688fd9373 100644 --- a/ee/packages/federation-matrix/src/events/room.ts +++ b/ee/packages/federation-matrix/src/events/room.ts @@ -2,7 +2,7 @@ import { Room } from '@rocket.chat/core-services'; import { federationSDK } from '@rocket.chat/federation-sdk'; import { Rooms, Users } from '@rocket.chat/models'; -import { getUsernameServername } from '../FederationMatrix'; +import { getUsernameServername } from '../helpers/getUsernameServername'; export function room() { federationSDK.eventEmitterService.on('homeserver.matrix.room.name', async ({ event }) => { diff --git a/ee/packages/federation-matrix/src/helpers/createOrUpdateFederatedUser.ts b/ee/packages/federation-matrix/src/helpers/createOrUpdateFederatedUser.ts new file mode 100644 index 0000000000000..27a7d42c0019d --- /dev/null +++ b/ee/packages/federation-matrix/src/helpers/createOrUpdateFederatedUser.ts @@ -0,0 +1,54 @@ +import { type IUser, UserStatus } from '@rocket.chat/core-typings'; +import { Users } from '@rocket.chat/models'; + +/** + * Helper function to create a federated user + * + * Because of historical reasons, we can have users only with federated flag but no federation object + * So we need to upsert the user with the federation object + */ + +export async function createOrUpdateFederatedUser(options: { username: string; name?: string; origin: string }): Promise { + const { username, name = username, origin } = options; + + console.log('createOrUpdateFederatedUser ->', options); + + // TODO: Have a specific method to handle this upsert + const user = await Users.findOneAndUpdate( + { + username, + }, + { + $set: { + username, + name: name || username, + type: 'user' as const, + status: UserStatus.OFFLINE, + active: true, + roles: ['user'], + requirePasswordChange: false, + federated: true, + federation: { + version: 1, + mui: username, + origin, + }, + _updatedAt: new Date(), + }, + $setOnInsert: { + createdAt: new Date(), + }, + }, + { + upsert: true, + projection: { _id: 1, username: 1 }, + returnDocument: 'after', + }, + ); + + if (!user) { + throw new Error(`Failed to create or update federated user: ${username}`); + } + + return user; +} diff --git a/ee/packages/federation-matrix/src/helpers/extractDomainFromMatrixUserId.ts b/ee/packages/federation-matrix/src/helpers/extractDomainFromMatrixUserId.ts new file mode 100644 index 0000000000000..779120ba4f781 --- /dev/null +++ b/ee/packages/federation-matrix/src/helpers/extractDomainFromMatrixUserId.ts @@ -0,0 +1,7 @@ +export const extractDomainFromMatrixUserId = (mxid: string): string => { + const separatorIndex = mxid.indexOf(':', 1); + if (separatorIndex === -1) { + throw new Error(`Invalid federated username: ${mxid}`); + } + return mxid.substring(separatorIndex + 1); +}; diff --git a/ee/packages/federation-matrix/src/helpers/getUsernameServername.ts b/ee/packages/federation-matrix/src/helpers/getUsernameServername.ts new file mode 100644 index 0000000000000..270d09416d889 --- /dev/null +++ b/ee/packages/federation-matrix/src/helpers/getUsernameServername.ts @@ -0,0 +1,21 @@ +import { extractDomainFromMatrixUserId } from './extractDomainFromMatrixUserId'; + +/** + * Extract the username and the servername from a matrix user id + * if the serverName is the same as the serverName in the mxid, return only the username (rocket.chat regular username) + * otherwise, return the full mxid and the servername + */ + +export const getUsernameServername = (mxid: string, serverName: string): [mxid: string, serverName: string, isLocal: boolean] => { + const senderServerName = extractDomainFromMatrixUserId(mxid); + // if the serverName is the same as the serverName in the mxid, return only the username (rocket.chat regular username) + if (serverName === senderServerName) { + const separatorIndex = mxid.indexOf(':', 1); + if (separatorIndex === -1) { + throw new Error(`Invalid federated username: ${mxid}`); + } + return [mxid.substring(1, separatorIndex), senderServerName, true]; // removers also the @ + } + + return [mxid, senderServerName, false]; +}; diff --git a/ee/packages/federation-matrix/src/helpers/validateFederatedUsername.spec.ts b/ee/packages/federation-matrix/src/helpers/validateFederatedUsername.spec.ts new file mode 100644 index 0000000000000..5b1990bf6ac5d --- /dev/null +++ b/ee/packages/federation-matrix/src/helpers/validateFederatedUsername.spec.ts @@ -0,0 +1,94 @@ +import { validateFederatedUsername } from './validateFederatedUsername'; + +describe('validateFederatedUsername', () => { + describe('invalid formats', () => { + it('should return false when mxid does not start with @', () => { + expect(validateFederatedUsername('user:example.com')).toBe(false); + }); + + it('should return false when mxid has no colon separator', () => { + expect(validateFederatedUsername('@user')).toBe(false); + }); + + it('should return false when mxid has empty localpart', () => { + expect(validateFederatedUsername('@:example.com')).toBe(false); + }); + + it('should return false when localpart contains invalid characters', () => { + expect(validateFederatedUsername('@user@name:example.com')).toBe(false); + expect(validateFederatedUsername('@user#name:example.com')).toBe(false); + }); + + it('should return false when localpart exceeds 255 characters', () => { + const longLocalpart = 'a'.repeat(256); + expect(validateFederatedUsername(`@${longLocalpart}:example.com`)).toBe(false); + }); + + it('should return false when domain is invalid', () => { + expect(validateFederatedUsername('@user:invalid_domain')).toBe(false); + expect(validateFederatedUsername('@user:-example.com')).toBe(false); + }); + + it('should return false when port is invalid', () => { + expect(validateFederatedUsername('@user:example.com:0')).toBe(false); + expect(validateFederatedUsername('@user:example.com:65536')).toBe(false); + expect(validateFederatedUsername('@user:example.com:abc')).toBe(false); + expect(validateFederatedUsername('@user:example.com:-1')).toBe(false); + }); + }); + + describe('valid formats', () => { + it('should return true for basic valid mxid', () => { + expect(validateFederatedUsername('@user:example.com')).toBe(true); + }); + + it('should return true when localpart contains uppercase letters', () => { + expect(validateFederatedUsername('@User:example.com')).toBe(true); + }); + + it('should return true for mxid with dots and hyphens in localpart', () => { + expect(validateFederatedUsername('@user.name:example.com')).toBe(true); + expect(validateFederatedUsername('@user-name:example.com')).toBe(true); + expect(validateFederatedUsername('@user_name:example.com')).toBe(true); + }); + + it('should return true for mxid with encoded characters in localpart', () => { + expect(validateFederatedUsername('@user=2dname:example.com')).toBe(true); + expect(validateFederatedUsername('@user=2Dname:example.com')).toBe(true); + }); + + it('should return true for mxid with subdomain', () => { + expect(validateFederatedUsername('@user:subdomain.example.com')).toBe(true); + }); + + it('should return true for mxid with valid port', () => { + expect(validateFederatedUsername('@user:example.com:8008')).toBe(true); + expect(validateFederatedUsername('@user:example.com:1')).toBe(true); + expect(validateFederatedUsername('@user:example.com:65535')).toBe(true); + }); + + it('should return true for mxid with IPv4 address', () => { + expect(validateFederatedUsername('@user:192.168.1.1')).toBe(true); + expect(validateFederatedUsername('@user:192.168.1.1:8008')).toBe(true); + }); + + it('should return true for mxid with IPv6 address', () => { + expect(validateFederatedUsername('@user:[::1]')).toBe(true); + expect(validateFederatedUsername('@user:[2001:db8::1]')).toBe(true); + }); + + it('should return true for mxid with numbers in localpart', () => { + expect(validateFederatedUsername('@user123:example.com')).toBe(true); + expect(validateFederatedUsername('@123user:example.com')).toBe(true); + }); + + it('should return true for mxid with single character localpart', () => { + expect(validateFederatedUsername('@a:example.com')).toBe(true); + }); + + it('should return true for mxid with 255 character localpart', () => { + const maxLocalpart = 'a'.repeat(255); + expect(validateFederatedUsername(`@${maxLocalpart}:example.com`)).toBe(true); + }); + }); +}); diff --git a/ee/packages/federation-matrix/src/helpers/validateFederatedUsername.ts b/ee/packages/federation-matrix/src/helpers/validateFederatedUsername.ts new file mode 100644 index 0000000000000..f3d4943365dc8 --- /dev/null +++ b/ee/packages/federation-matrix/src/helpers/validateFederatedUsername.ts @@ -0,0 +1,76 @@ +import { isIPv4, isIPv6 } from 'net'; + +import type { UserID } from '@rocket.chat/federation-sdk'; + +/** helper to validate the username format */ +export function validateFederatedUsername(mxid: string): mxid is UserID { + if (!mxid.startsWith('@')) return false; + + const withoutAt = mxid.substring(1); + const firstColonIndex = withoutAt.indexOf(':'); + + if (firstColonIndex === -1) return false; + + const localpart = withoutAt.substring(0, firstColonIndex); + const domainAndPort = withoutAt.substring(firstColonIndex + 1); + + const localpartRegex = /^(?:[a-zA-Z0-9._\-]|=[0-9a-fA-F]{2}){1,255}$/; + if (!localpartRegex.test(localpart)) return false; + + // Handle IPv6 addresses specially - they're wrapped in brackets and contain colons + let domain: string; + let port: string | undefined; + + if (domainAndPort.startsWith('[')) { + // IPv6 address + const closeBracketIndex = domainAndPort.indexOf(']'); + if (closeBracketIndex === -1) return false; + + domain = domainAndPort.substring(0, closeBracketIndex + 1); + + // Check if there's a port after the IPv6 address + const afterBracket = domainAndPort.substring(closeBracketIndex + 1); + if (afterBracket.startsWith(':')) { + port = afterBracket.substring(1); + } else if (afterBracket.length > 0) { + return false; // Invalid format after IPv6 bracket + } + } else { + // Regular domain or IPv4 + const lastColonIndex = domainAndPort.lastIndexOf(':'); + const possiblePort = domainAndPort.substring(lastColonIndex + 1); + + // Check if the part after the last colon is a valid port number + if (lastColonIndex !== -1 && /^[0-9]+$/.test(possiblePort)) { + domain = domainAndPort.substring(0, lastColonIndex); + port = possiblePort; + } else { + domain = domainAndPort; + } + } + + // Validate domain: hostname, IPv4, or IPv6 + const hostnameRegex = /^(?=.{1,253}$)([a-z0-9](?:[a-z0-9\-]{0,61}[a-z0-9])?)(?:\.[a-z0-9](?:[a-z0-9\-]{0,61}[a-z0-9])?)*$/i; + + // Check if it's a valid IPv6 address (in brackets) + if (domain.startsWith('[') && domain.endsWith(']')) { + const ipv6Address = domain.substring(1, domain.length - 1); + if (!isIPv6(ipv6Address)) { + return false; + } + } else if (isIPv4(domain)) { + // Valid IPv4 address + } else if (!hostnameRegex.test(domain)) { + // Not a valid hostname + return false; + } + + if (port !== undefined) { + const portNum = Number(port); + if (!/^[0-9]+$/.test(port) || portNum < 1 || portNum > 65535) { + return false; + } + } + + return true; +} diff --git a/ee/packages/federation-matrix/src/index.ts b/ee/packages/federation-matrix/src/index.ts index b56729b4524ba..88acc4bb5ece5 100644 --- a/ee/packages/federation-matrix/src/index.ts +++ b/ee/packages/federation-matrix/src/index.ts @@ -1,6 +1,8 @@ import 'reflect-metadata'; -export { FederationMatrix, validateFederatedUsername } from './FederationMatrix'; +export { validateFederatedUsername } from './helpers/validateFederatedUsername'; + +export { FederationMatrix } from './FederationMatrix'; export { generateEd25519RandomSecretKey } from '@rocket.chat/federation-sdk'; diff --git a/packages/core-services/package.json b/packages/core-services/package.json index d77db21db0fa1..14ffb332a09c7 100644 --- a/packages/core-services/package.json +++ b/packages/core-services/package.json @@ -17,7 +17,7 @@ }, "dependencies": { "@rocket.chat/core-typings": "workspace:^", - "@rocket.chat/federation-sdk": "0.3.5", + "@rocket.chat/federation-sdk": "0.3.7", "@rocket.chat/http-router": "workspace:^", "@rocket.chat/icons": "~0.46.0", "@rocket.chat/media-signaling": "workspace:^", From 466137a3d5c446a7934ac0405c82924b1148163e Mon Sep 17 00:00:00 2001 From: Diego Sampaio Date: Mon, 29 Dec 2025 09:25:47 -0300 Subject: [PATCH 16/68] test(federation): fix test to assert better subscription names when invite comes from Rocket.Chat (#37969) --- .../tests/end-to-end/dms.spec.ts | 82 ++++++++++--------- 1 file changed, 45 insertions(+), 37 deletions(-) diff --git a/ee/packages/federation-matrix/tests/end-to-end/dms.spec.ts b/ee/packages/federation-matrix/tests/end-to-end/dms.spec.ts index 6c45ce193b28c..771fe4870a7f1 100644 --- a/ee/packages/federation-matrix/tests/end-to-end/dms.spec.ts +++ b/ee/packages/federation-matrix/tests/end-to-end/dms.spec.ts @@ -861,55 +861,63 @@ const waitForRoomEvent = async ( let rcRoom: IRoomNativeFederated; let hs1Room1: Room; - let rcUser1: TestUser; - let rcUserConfig1: IRequestConfig; - - let rcUser2: TestUser; - let rcUserConfig2: IRequestConfig; - - const rcUserName1 = `dm-rc-multi-user1-${Date.now()}`; - const rcUserFullName1 = `DM RC Multi User1 ${Date.now()}`; + const rcUser1 = { + username: `dm-rc-multi-user1-${Date.now()}`, + fullName: `DM RC Multi User1 ${Date.now()}`, + get matrixId() { + return `@${this.username}:${federationConfig.rc1.domain}`; + }, + config: {} as IRequestConfig, + user: {} as TestUser, + }; - const rcUserName2 = `dm-rc-multi-user2-${Date.now()}`; - const rcUserFullName2 = `DM RC Multi User2 ${Date.now()}`; + const rcUser2 = { + username: `dm-rc-multi-user2-${Date.now()}`, + fullName: `DM RC Multi User2 ${Date.now()}`, + get matrixId() { + return `@${this.username}:${federationConfig.rc1.domain}`; + }, + config: {} as IRequestConfig, + user: {} as TestUser, + }; beforeAll(async () => { // Create RC user - rcUser1 = await createUser( + rcUser1.user = await createUser( { - username: rcUserName1, + username: rcUser1.username, password: 'random', - email: `${rcUserName1}@rocket.chat`, - name: rcUserFullName1, + email: `${rcUser1.username}@rocket.chat`, + name: rcUser1.fullName, }, rc1AdminRequestConfig, ); - rcUserConfig1 = await getRequestConfig(federationConfig.rc1.url, rcUser1.username, 'random'); + rcUser1.config = await getRequestConfig(federationConfig.rc1.url, rcUser1.username, 'random'); - rcUser2 = await createUser( + rcUser2.user = await createUser( { - username: rcUserName2, + username: rcUser2.username, password: 'random', - email: `${rcUserName2}@rocket.chat`, - name: rcUserFullName2, + email: `${rcUser2.username}@rocket.chat`, + name: rcUser2.fullName, }, rc1AdminRequestConfig, ); - rcUserConfig2 = await getRequestConfig(federationConfig.rc1.url, rcUser2.username, 'random'); + rcUser2.config = await getRequestConfig(federationConfig.rc1.url, rcUser2.username, 'random'); }); afterAll(async () => { - await deleteUser(rcUser1, {}, rc1AdminRequestConfig); - await deleteUser(rcUser2, {}, rc1AdminRequestConfig); + await deleteUser(rcUser1.user, {}, rc1AdminRequestConfig); + await deleteUser(rcUser2.user, {}, rc1AdminRequestConfig); }); it('should create a group DM with a Synapse and Rocket.Chat user', async () => { // Create group DM from RC user to two Synapse users - const response = await rcUserConfig1.request + const response = await rcUser1.config.request .post(api('dm.create')) - .set(rcUserConfig1.credentials) + .set(rcUser1.config.credentials) .send({ usernames: [federationConfig.hs1.adminMatrixUserId, rcUser2.username].join(','), }) @@ -918,7 +926,7 @@ const waitForRoomEvent = async ( expect(response.body).toHaveProperty('success', true); expect(response.body).toHaveProperty('room'); - const roomInfo = await getRoomInfo(response.body.room._id, rcUserConfig1); + const roomInfo = await getRoomInfo(response.body.room._id, rcUser1.config); expect(roomInfo).toHaveProperty('room'); @@ -943,19 +951,19 @@ const waitForRoomEvent = async ( it('should display the fname containing the two invited users for the inviter', async () => { // Check the subscription for the inviter - const sub = await getSubscriptionByRoomId(rcRoom._id, rcUserConfig1.credentials, rcUserConfig1.request); + const sub = await getSubscriptionByRoomId(rcRoom._id, rcUser1.config.credentials, rcUser1.config.request); // Should contain both invited users in the name expect(sub).toHaveProperty('name', `${federationConfig.hs1.adminMatrixUserId}, ${rcUser2.username}`); - expect(sub).toHaveProperty('fname', `${federationConfig.hs1.adminMatrixUserId}, ${rcUser2.name}`); + expect(sub).toHaveProperty('fname', `${federationConfig.hs1.adminMatrixUserId}, ${rcUser2.fullName}`); }); - it.failing("should display only the inviter's username for the invited user on Rocket.Chat", async () => { - const sub = await getSubscriptionByRoomId(rcRoom._id, rcUserConfig2.credentials, rcUserConfig2.request); + it("should display only the inviter's username for the invited user on Rocket.Chat", async () => { + const sub = await getSubscriptionByRoomId(rcRoom._id, rcUser2.config.credentials, rcUser2.config.request); expect(sub).toHaveProperty('status', 'INVITED'); - expect(sub).toHaveProperty('name', rcUser1.name); - expect(sub).toHaveProperty('fname', rcUser1.username); + expect(sub).toHaveProperty('name', `${federationConfig.hs1.adminMatrixUserId}, ${rcUser1.username}`); + expect(sub).toHaveProperty('fname', `${federationConfig.hs1.adminMatrixUserId}, ${rcUser1.fullName}`); }); it('should accept the invitation on Synapse', async () => { @@ -974,15 +982,15 @@ const waitForRoomEvent = async ( expect(hs1Room1.name).toBe(`${rcUser1.username} and ${rcUser2.username}`); }); - it.failing('should keep the fname to the RC invited user when the Synapse invited user accepts the DM', async () => { + it('should keep the fname to the RC invited user when the Synapse invited user accepts the DM', async () => { await retry( 'this is an async operation, so we need to wait for the event to be processed', async () => { - const sub = await getSubscriptionByRoomId(rcRoom._id, rcUserConfig2.credentials, rcUserConfig2.request); + const sub = await getSubscriptionByRoomId(rcRoom._id, rcUser2.config.credentials, rcUser2.config.request); expect(sub).toHaveProperty('status', 'INVITED'); - expect(sub).toHaveProperty('name', rcUser1.name); - expect(sub).toHaveProperty('fname', rcUser1.username); + expect(sub).toHaveProperty('name', `${federationConfig.hs1.adminMatrixUserId}, ${rcUser1.username}`); + expect(sub).toHaveProperty('fname', `${federationConfig.hs1.adminMatrixUserId}, ${rcUser1.fullName}`); }, { delayMs: 100 }, ); @@ -994,10 +1002,10 @@ const waitForRoomEvent = async ( await retry( 'this is an async operation, so we need to wait for the event to be processed', async () => { - const sub = await getSubscriptionByRoomId(rcRoom._id, rcUserConfig1.credentials, rcUserConfig1.request); + const sub = await getSubscriptionByRoomId(rcRoom._id, rcUser1.config.credentials, rcUser1.config.request); expect(sub).toHaveProperty('name', rcUser2.username); - expect(sub).toHaveProperty('fname', rcUser2.name); + expect(sub).toHaveProperty('fname', rcUser2.fullName); }, { delayMs: 100 }, ); From cf748a6faf6276608bf0cce5a1d315ce0df9dae1 Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Mon, 29 Dec 2025 10:16:01 -0300 Subject: [PATCH 17/68] regression(federation): enhance user authorization checks for federation access (#37965) Co-authored-by: Diego Sampaio --- .../app/lib/server/functions/createRoom.ts | 9 +- .../getRoomByNameOrIdWithOptionToJoin.ts | 2 +- .../meteor/app/lib/server/methods/joinRoom.ts | 6 +- .../app/slashcommands-join/server/server.ts | 10 +- .../ee/server/hooks/federation/index.ts | 3 +- apps/meteor/server/services/room/service.ts | 9 +- .../tests/end-to-end/dms.spec.ts | 13 +- .../tests/end-to-end/permissions.spec.ts | 281 ++++++++++++++++++ .../tests/helper/withTimeout.ts | 11 + .../core-services/src/types/IRoomService.ts | 2 +- 10 files changed, 321 insertions(+), 25 deletions(-) create mode 100644 ee/packages/federation-matrix/tests/end-to-end/permissions.spec.ts create mode 100644 ee/packages/federation-matrix/tests/helper/withTimeout.ts diff --git a/apps/meteor/app/lib/server/functions/createRoom.ts b/apps/meteor/app/lib/server/functions/createRoom.ts index bb99ae7237f19..7b64ec9e68b09 100644 --- a/apps/meteor/app/lib/server/functions/createRoom.ts +++ b/apps/meteor/app/lib/server/functions/createRoom.ts @@ -2,7 +2,7 @@ import { AppEvents, Apps } from '@rocket.chat/apps'; import { AppsEngineException } from '@rocket.chat/apps-engine/definition/exceptions'; import { FederationMatrix, Message, Room, Team } from '@rocket.chat/core-services'; import type { ICreateRoomParams, ISubscriptionExtraData } from '@rocket.chat/core-services'; -import type { ICreatedRoom, IUser, IRoom, RoomType } from '@rocket.chat/core-typings'; +import { type ICreatedRoom, type IUser, type IRoom, type RoomType, isUserNativeFederated } from '@rocket.chat/core-typings'; import { Rooms, Subscriptions, Users } from '@rocket.chat/models'; import { Meteor } from 'meteor/meteor'; @@ -184,7 +184,12 @@ export const createRoom = async ( const shouldBeHandledByFederation = extraData.federated === true; - if (shouldBeHandledByFederation && owner && !(await hasPermissionAsync(owner._id, 'access-federation'))) { + if ( + shouldBeHandledByFederation && + owner && + !isUserNativeFederated(owner) && + !(await hasPermissionAsync(owner._id, 'access-federation')) + ) { throw new Meteor.Error('error-not-authorized-federation', 'Not authorized to access federation', { method: 'createRoom', }); diff --git a/apps/meteor/app/lib/server/functions/getRoomByNameOrIdWithOptionToJoin.ts b/apps/meteor/app/lib/server/functions/getRoomByNameOrIdWithOptionToJoin.ts index e1aeabe1b46a5..6217342d0c534 100644 --- a/apps/meteor/app/lib/server/functions/getRoomByNameOrIdWithOptionToJoin.ts +++ b/apps/meteor/app/lib/server/functions/getRoomByNameOrIdWithOptionToJoin.ts @@ -14,7 +14,7 @@ export const getRoomByNameOrIdWithOptionToJoin = async ({ joinChannel = true, errorOnEmpty = true, }: { - user: Pick; + user: Pick; nameOrId: string; type?: RoomType; tryDirectByUserIdOnly?: boolean; diff --git a/apps/meteor/app/lib/server/methods/joinRoom.ts b/apps/meteor/app/lib/server/methods/joinRoom.ts index 8960936d7c33d..d11050bbb2201 100644 --- a/apps/meteor/app/lib/server/methods/joinRoom.ts +++ b/apps/meteor/app/lib/server/methods/joinRoom.ts @@ -16,8 +16,8 @@ Meteor.methods({ async joinRoom(rid, code) { check(rid, String); - const userId = await Meteor.userId(); - if (!userId) { + const user = await Meteor.userAsync(); + if (!user) { throw new Meteor.Error('error-invalid-user', 'Invalid user', { method: 'joinRoom' }); } @@ -26,6 +26,6 @@ Meteor.methods({ throw new Meteor.Error('error-invalid-room', 'Invalid room', { method: 'joinRoom' }); } - return Room.join({ room, user: { _id: userId }, ...(code ? { joinCode: code } : {}) }); + return Room.join({ room, user, ...(code ? { joinCode: code } : {}) }); }, }); diff --git a/apps/meteor/app/slashcommands-join/server/server.ts b/apps/meteor/app/slashcommands-join/server/server.ts index 6497324ae9e0e..2a70552ef839f 100644 --- a/apps/meteor/app/slashcommands-join/server/server.ts +++ b/apps/meteor/app/slashcommands-join/server/server.ts @@ -1,6 +1,6 @@ import { api, Room } from '@rocket.chat/core-services'; import type { SlashCommandCallbackParams } from '@rocket.chat/core-typings'; -import { Rooms, Subscriptions } from '@rocket.chat/models'; +import { Rooms, Subscriptions, Users } from '@rocket.chat/models'; import { Meteor } from 'meteor/meteor'; import { i18n } from '../../../server/lib/i18n'; @@ -43,7 +43,13 @@ slashCommands.add({ }); } - await Room.join({ room, user: { _id: userId } }); + const user = await Users.findOneById(userId, { projection: { federated: 1, federation: 1 } }); + if (!user) { + throw new Meteor.Error('error-invalid-user', 'Invalid user', { + method: 'slashCommands', + }); + } + await Room.join({ room, user }); }, options: { description: 'Join_the_given_channel', diff --git a/apps/meteor/ee/server/hooks/federation/index.ts b/apps/meteor/ee/server/hooks/federation/index.ts index fa2433a9aa424..f717c7e0847b3 100644 --- a/apps/meteor/ee/server/hooks/federation/index.ts +++ b/apps/meteor/ee/server/hooks/federation/index.ts @@ -112,8 +112,7 @@ beforeAddUserToRoom.add( return; } - // TODO should we really check for "user" here? it is potentially an external user - if (!(await Authorization.hasPermission(user._id, 'access-federation'))) { + if (!isUserNativeFederated(user) && !(await Authorization.hasPermission(user._id, 'access-federation'))) { throw new MeteorError('error-not-authorized-federation', 'Not authorized to access federation'); } diff --git a/apps/meteor/server/services/room/service.ts b/apps/meteor/server/services/room/service.ts index aa3985a8920af..15ab4dbb85e21 100644 --- a/apps/meteor/server/services/room/service.ts +++ b/apps/meteor/server/services/room/service.ts @@ -9,6 +9,7 @@ import { isOmnichannelRoom, isRoomWithJoinCode, } from '@rocket.chat/core-typings'; +import { isUserNativeFederated } from '@rocket.chat/core-typings'; import { Rooms, Subscriptions, Users } from '@rocket.chat/models'; import { getNameForDMs } from './getNameForDMs'; @@ -148,7 +149,7 @@ export class RoomService extends ServiceClassInternal implements IRoomService { /** * Method called by users to join a room. */ - async join({ room, user, joinCode }: { room: IRoom; user: Pick; joinCode?: string }) { + async join({ room, user, joinCode }: { room: IRoom; user: Pick; joinCode?: string }) { if (!(await roomCoordinator.getRoomDirectives(room.t)?.allowMemberAction(room, RoomMemberActions.JOIN, user._id))) { throw new MeteorError('error-not-allowed', 'Not allowed', { method: 'joinRoom' }); } @@ -161,7 +162,11 @@ export class RoomService extends ServiceClassInternal implements IRoomService { throw new MeteorError('error-not-allowed', 'Not allowed', { method: 'joinRoom' }); } - if (FederationActions.shouldPerformFederationAction(room) && !(await Authorization.hasPermission(user._id, 'access-federation'))) { + if ( + FederationActions.shouldPerformFederationAction(room) && + !isUserNativeFederated(user) && + !(await Authorization.hasPermission(user._id, 'access-federation')) + ) { throw new MeteorError('error-not-authorized-federation', 'Not authorized to access federation', { method: 'joinRoom' }); } diff --git a/ee/packages/federation-matrix/tests/end-to-end/dms.spec.ts b/ee/packages/federation-matrix/tests/end-to-end/dms.spec.ts index 771fe4870a7f1..ec8f04f88f62c 100644 --- a/ee/packages/federation-matrix/tests/end-to-end/dms.spec.ts +++ b/ee/packages/federation-matrix/tests/end-to-end/dms.spec.ts @@ -10,18 +10,7 @@ import { IS_EE } from '../../../../../apps/meteor/tests/e2e/config/constants'; import { retry } from '../../../../../apps/meteor/tests/end-to-end/api/helpers/retry'; import { federationConfig } from '../helper/config'; import { SynapseClient } from '../helper/synapse-client'; - -function withTimeout(fn: (signal: AbortSignal) => Promise, ms: number): Promise { - const controller = new AbortController(); - - const timeoutId = setTimeout(() => { - controller.abort(); - }, ms); - - return fn(controller.signal).finally(() => { - clearTimeout(timeoutId); - }); -} +import { withTimeout } from '../helper/withTimeout'; const waitForRoomEvent = async ( room: Room, diff --git a/ee/packages/federation-matrix/tests/end-to-end/permissions.spec.ts b/ee/packages/federation-matrix/tests/end-to-end/permissions.spec.ts new file mode 100644 index 0000000000000..fdb07ca0d08f6 --- /dev/null +++ b/ee/packages/federation-matrix/tests/end-to-end/permissions.spec.ts @@ -0,0 +1,281 @@ +import type { IUser } from '@rocket.chat/core-typings'; + +import type {} from '../../../../../apps/meteor/app/api/server/v1/permissions.ts'; +import { api } from '../../../../../apps/meteor/tests/data/api-data'; +import { addUserToRoom, createRoom, getSubscriptions } from '../../../../../apps/meteor/tests/data/rooms.helper'; +import { createUser, deleteUser, getRequestConfig } from '../../../../../apps/meteor/tests/data/users.helper'; +import type { IRequestConfig, TestUser } from '../../../../../apps/meteor/tests/data/users.helper'; +import { IS_EE } from '../../../../../apps/meteor/tests/e2e/config/constants'; +import { retry } from '../../../../../apps/meteor/tests/end-to-end/api/helpers/retry.ts'; +import { federationConfig } from '../helper/config'; +import { SynapseClient } from '../helper/synapse-client'; + +(IS_EE ? describe : describe.skip)('Federation Permissions', () => { + let rc1AdminRequestConfig: IRequestConfig; + let rc1User1RequestConfig: IRequestConfig; + let hs1AdminApp: SynapseClient; + + beforeAll(async () => { + // Create admin request config for RC1 + rc1AdminRequestConfig = await getRequestConfig( + federationConfig.rc1.url, + federationConfig.rc1.adminUser, + federationConfig.rc1.adminPassword, + ); + + // Create user1 request config for RC1 + rc1User1RequestConfig = await getRequestConfig( + federationConfig.rc1.url, + federationConfig.rc1.additionalUser1.username, + federationConfig.rc1.additionalUser1.password, + ); + + // Create admin Synapse client for HS1 + hs1AdminApp = new SynapseClient(federationConfig.hs1.url, federationConfig.hs1.adminUser, federationConfig.hs1.adminPassword); + await hs1AdminApp.initialize(); + await rc1AdminRequestConfig.request + .post(api('permissions.update')) + .set(rc1AdminRequestConfig.credentials) + .send({ permissions: [{ _id: 'access-federation', roles: ['admin'] }] }) + .expect('Content-Type', 'application/json') + .expect(200); + }); + + afterAll(async () => + // Add permissions for access-federation to any user but admin + rc1AdminRequestConfig.request + .post(api('permissions.update')) + .set(rc1AdminRequestConfig.credentials) + .send({ permissions: [{ _id: 'access-federation', roles: ['admin', 'user'] }] }) + .expect('Content-Type', 'application/json') + .expect(200), + ); + + afterAll(async () => hs1AdminApp.close()); + + describe('Access Federation Permission', () => { + describe('Users without access-federation permission', () => { + beforeAll(async () => { + await rc1AdminRequestConfig.request + .post(api('permissions.update')) + .set(rc1AdminRequestConfig.credentials) + .send({ permissions: [{ _id: 'access-federation', roles: ['admin'] }] }) + .expect('Content-Type', 'application/json') + .expect(200); + }); + + afterAll(async () => { + // Add permissions for access-federation to any user but admin + await rc1AdminRequestConfig.request + .post(api('permissions.update')) + .set(rc1AdminRequestConfig.credentials) + .send({ permissions: [{ _id: 'access-federation', roles: ['admin', 'user'] }] }) + .expect('Content-Type', 'application/json') + .expect(200); + }); + + describe('Inviting from a remote server', () => { + let user: TestUser; + + let matrixRoomId: string; + + beforeAll(async () => { + user = await createUser( + { + username: `g3-${Date.now()}`, + password: '1', + roles: ['user'], + }, + rc1AdminRequestConfig, + ); + }); + + afterAll(async () => { + await deleteUser(user, {}, rc1AdminRequestConfig); + }); + + let channelName: string; + + beforeAll(async () => { + channelName = `federated-room-${Date.now()}`; + matrixRoomId = await hs1AdminApp.createRoom(channelName); + }); + + it('should throw an error if a remote user tries to invite a user without access-federation permission to a room', async () => { + await expect(hs1AdminApp.matrixClient.invite(matrixRoomId, `@${user.username}:${federationConfig.rc1.url}`)).rejects.toThrow(); + const subscriptions = await getSubscriptions(rc1AdminRequestConfig); + const invitedSub = subscriptions.update.find((sub) => sub.fname?.includes(channelName)); + expect(invitedSub).toBeUndefined(); + }); + + it('should be able to invite a user to a room if the user has access-federation permission', async () => { + await expect(hs1AdminApp.matrixClient.invite(matrixRoomId, federationConfig.rc1.adminMatrixUserId)).resolves.not.toThrow(); + + await retry('waiting for invitation to be processed', async () => { + const subscriptions = await getSubscriptions(rc1AdminRequestConfig); + + const pendingInvitation = subscriptions.update.find( + (subscription) => subscription.status === 'INVITED' && subscription.fname?.includes(channelName), + ); + expect(pendingInvitation).not.toBeUndefined(); + }); + }); + }); + + it('should throw an error if a user without access-federation permission tries to create a federated room', async () => { + const channelName = `federated-room-${Date.now()}`; + const createResponse = await createRoom({ + type: 'p', + name: channelName, + members: [], + extraData: { + federated: true, + }, + config: rc1User1RequestConfig, + }); + + expect(createResponse.status).toBe(400); + expect(createResponse.body).toHaveProperty('success', false); + expect(createResponse.body).toHaveProperty('errorType', 'error-not-authorized-federation'); + }); + + describe('Inviting from a local server', () => { + let channelName: string; + + let createResponse; + let addUserResponse; + + beforeAll(async () => { + channelName = `federated-room-${Date.now()}`; + createResponse = await createRoom({ + type: 'p', + name: channelName, + members: [], + extraData: { + federated: true, + }, + config: rc1AdminRequestConfig, + }); + expect(createResponse.status).toBe(200); + expect(createResponse.body).toHaveProperty('success', true); + expect(createResponse.body).toHaveProperty('group'); + expect(createResponse.body.group).toHaveProperty('_id'); + expect(createResponse.body.group).toHaveProperty('t', 'p'); + expect(createResponse.body.group).toHaveProperty('federated', true); + }); + let user: TestUser; + + beforeAll(async () => { + user = await createUser( + { + username: `g3-${Date.now()}`, + password: '1', + roles: ['user'], + }, + rc1AdminRequestConfig, + ); + }); + + afterAll(async () => { + await deleteUser(user, {}, rc1AdminRequestConfig); + }); + it('should not be able to add a user without access-federation permission to a room', async () => { + const addUserResponse = await addUserToRoom({ + usernames: [user.username], + rid: createResponse.body.group._id, + config: rc1AdminRequestConfig, + }); + + expect(addUserResponse.status).toBe(200); + expect(addUserResponse.body).toHaveProperty('success', true); + expect(addUserResponse.body.message).toMatch(/error-not-authorized-federation/); + }); + + it("should be able to add a remote user to a room regardless of the user's access-federation permission defined locally", async () => { + addUserResponse = await addUserToRoom({ + usernames: [federationConfig.hs1.adminMatrixUserId], + rid: createResponse.body.group._id, + config: rc1AdminRequestConfig, + }); + + expect(addUserResponse.status).toBe(200); + expect(addUserResponse.body).toHaveProperty('success', true); + expect(addUserResponse.body).toHaveProperty('message'); + expect(addUserResponse.body.message).toMatch('{"msg":"result","id":"id","result":true}'); + }); + }); + }); + + describe('Users with access-federation permission', () => { + let user: TestUser; + + beforeAll(async () => { + user = await createUser( + { + username: `g3-${Date.now()}`, + password: '1', + roles: ['user', 'admin'], + }, + rc1AdminRequestConfig, + ); + }); + + afterAll(async () => { + await deleteUser(user, {}, rc1AdminRequestConfig); + }); + + it('should be able to create a federated room if the user has access-federation permission', async () => { + const channelName = `federated-room-${Date.now()}`; + const createResponse = await createRoom({ + type: 'p', + name: channelName, + members: [], + extraData: { + federated: true, + }, + config: rc1AdminRequestConfig, + }); + + expect(createResponse.status).toBe(200); + expect(createResponse.body).toHaveProperty('success', true); + expect(createResponse.body).toHaveProperty('group'); + expect(createResponse.body.group).toHaveProperty('_id'); + expect(createResponse.body.group).toHaveProperty('t', 'p'); + expect(createResponse.body.group).toHaveProperty('federated', true); + }); + + describe('Add a user with access-federation permission to a room', () => { + beforeAll(async () => + rc1AdminRequestConfig.request + .post(api('permissions.update')) + .set(rc1AdminRequestConfig.credentials) + .send({ permissions: [{ _id: 'access-federation', roles: ['admin', 'user'] }] }) + .expect('Content-Type', 'application/json') + .expect(200), + ); + + it('should be able to add a user with access-federation permission to a room', async () => { + const createResponse = await createRoom({ + type: 'p', + name: `federated-room-${Date.now()}`, + members: [], + extraData: { + federated: true, + }, + config: rc1AdminRequestConfig, + }).expect(200); + + const addUserResponse = await addUserToRoom({ + usernames: [user.username], + rid: createResponse.body.group._id, + config: rc1AdminRequestConfig, + }).expect(200); + + expect(addUserResponse.body).toHaveProperty('success', true); + expect(addUserResponse.body).toHaveProperty('message'); + expect(addUserResponse.body.message).toMatch('{"msg":"result","id":"id","result":true}'); + }); + }); + }); + }); +}); diff --git a/ee/packages/federation-matrix/tests/helper/withTimeout.ts b/ee/packages/federation-matrix/tests/helper/withTimeout.ts new file mode 100644 index 0000000000000..12cd128fde316 --- /dev/null +++ b/ee/packages/federation-matrix/tests/helper/withTimeout.ts @@ -0,0 +1,11 @@ +export function withTimeout(fn: (signal: AbortSignal) => Promise, ms: number): Promise { + const controller = new AbortController(); + + const timeoutId = setTimeout(() => { + controller.abort(); + }, ms); + + return fn(controller.signal).finally(() => { + clearTimeout(timeoutId); + }); +} diff --git a/packages/core-services/src/types/IRoomService.ts b/packages/core-services/src/types/IRoomService.ts index 62ccf27bcde6f..a5850fe21bea9 100644 --- a/packages/core-services/src/types/IRoomService.ts +++ b/packages/core-services/src/types/IRoomService.ts @@ -51,7 +51,7 @@ export interface IRoomService { sendMessage?: boolean, ): Promise; getRouteLink(room: AtLeast): Promise; - join(param: { room: IRoom; user: Pick; joinCode?: string }): Promise; + join(param: { room: IRoom; user: Pick; joinCode?: string }): Promise; beforeLeave(room: IRoom): Promise; beforeUserRemoved(room: IRoom): Promise; beforeNameChange(room: IRoom): Promise; From d7830822998cad888fa739a9a562134672aaf684 Mon Sep 17 00:00:00 2001 From: Tasso Evangelista Date: Mon, 29 Dec 2025 10:46:28 -0300 Subject: [PATCH 18/68] regression(abac): Exclude unit test modules from package build (#37986) --- ee/packages/abac/package.json | 2 +- ee/packages/abac/tsconfig.build.json | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) create mode 100644 ee/packages/abac/tsconfig.build.json diff --git a/ee/packages/abac/package.json b/ee/packages/abac/package.json index 65c0892a35afa..fa9ecf8ab89e1 100644 --- a/ee/packages/abac/package.json +++ b/ee/packages/abac/package.json @@ -9,7 +9,7 @@ "/dist" ], "scripts": { - "build": "tsc", + "build": "tsc -p tsconfig.build.json", "dev": "tsc --watch --preserveWatchOutput", "lint": "eslint --ext .js,.jsx,.ts,.tsx src", "lint:fix": "eslint --ext .js,.jsx,.ts,.tsx src --fix", diff --git a/ee/packages/abac/tsconfig.build.json b/ee/packages/abac/tsconfig.build.json new file mode 100644 index 0000000000000..a119587d4b618 --- /dev/null +++ b/ee/packages/abac/tsconfig.build.json @@ -0,0 +1,4 @@ +{ + "extends": "./tsconfig.json", + "exclude": ["./dist", "./src/**/*.spec.ts"] +} From 356ad51e064cff9e9b50bf724cb6e59822fd8505 Mon Sep 17 00:00:00 2001 From: gabriellsh <40830821+gabriellsh@users.noreply.github.com> Date: Mon, 29 Dec 2025 13:25:33 -0300 Subject: [PATCH 19/68] regression: Call History page layout tweaks (#37927) --- .../mediaCallHistory/CallHistoryPage.tsx | 116 +++++++++--------- .../CallHistoryPageFilters.tsx | 28 +++-- .../CallHistoryPageLayout.tsx | 30 +++++ .../MediaCallHistoryInternal.tsx | 4 +- .../CallHistoryContextualbar.tsx | 2 +- .../CallHistoryContextualbar.spec.tsx.snap | 4 +- 6 files changed, 109 insertions(+), 75 deletions(-) create mode 100644 apps/meteor/client/views/mediaCallHistory/CallHistoryPageLayout.tsx diff --git a/apps/meteor/client/views/mediaCallHistory/CallHistoryPage.tsx b/apps/meteor/client/views/mediaCallHistory/CallHistoryPage.tsx index efa52920baed8..31dce65c22924 100644 --- a/apps/meteor/client/views/mediaCallHistory/CallHistoryPage.tsx +++ b/apps/meteor/client/views/mediaCallHistory/CallHistoryPage.tsx @@ -1,6 +1,6 @@ import { Pagination } from '@rocket.chat/fuselage'; import { useDebouncedValue } from '@rocket.chat/fuselage-hooks'; -import { useSort, Page, PageHeader, PageContent, usePagination, GenericTableLoadingRow } from '@rocket.chat/ui-client'; +import { useSort, usePagination, GenericTableLoadingRow } from '@rocket.chat/ui-client'; import { useEndpoint, useRouteParameter, useRouter } from '@rocket.chat/ui-contexts'; import { MediaCallHistoryTable, isCallHistoryUnknownContact, isCallHistoryTableInternalContact } from '@rocket.chat/ui-voip'; import type { CallHistoryTableInternalContact, CallHistoryUnknownContact, CallHistoryTableExternalContact } from '@rocket.chat/ui-voip'; @@ -8,7 +8,8 @@ import { useQuery } from '@tanstack/react-query'; import { useCallback, useMemo, useState } from 'react'; import { useTranslation } from 'react-i18next'; -import CallHistoryPageFilters, { useCallHistoryPageFilters } from './CallHistoryPageFilters'; +import { useCallHistoryPageFilters } from './CallHistoryPageFilters'; +import CallHistoryPageLayout from './CallHistoryPageLayout'; import CallHistoryRowExternalUser from './CallHistoryRowExternalUser'; import CallHistoryRowInternalUser from './CallHistoryRowInternalUser'; import CallHistoryRowUnknownUser from './CallHistoryRowUnknownUser'; @@ -164,77 +165,76 @@ const CallHistoryPage = () => { }); }, [data]); + const contextualBar = (() => { + if (tab?.openTab === 'user-info') { + return ; + } + if (tab?.openTab === 'details' && historyId) { + return ; + } + return null; + })(); + + const pagination = ( + + ); + if (isPending) { return ( - + + + + - + {pagination} + ); } if (error) { return ( - - - - refetch()} - /> - - + + refetch()} + /> + ); } return ( - - - - - - {!tableData || (tableData.length === 0 && )} - {tableData && tableData.length > 0 && ( - - {tableData.map((item) => { - if (isCallHistoryUnknownContact(item.contact)) { - return ( - onClickRow('', item._id)} /> - ); - } - if (isCallHistoryTableInternalContact(item.contact)) { - return ( - onClickRow(item.rid ?? '', item._id)} - rid={item.rid ?? ''} - onClickUserInfo={item.rid ? openUserInfo : undefined} - /> - ); - } - - return ( - onClickRow('', item._id)} /> - ); - })} - - )} - - - - {tab?.openTab === 'user-info' && ( - - )} - {tab?.openTab === 'details' && historyId && ( - + + {!tableData || (tableData.length === 0 && )} + {tableData && tableData.length > 0 && ( + + {tableData.map((item) => { + if (isCallHistoryUnknownContact(item.contact)) { + return onClickRow('', item._id)} />; + } + if (isCallHistoryTableInternalContact(item.contact)) { + return ( + onClickRow(item.rid ?? '', item._id)} + rid={item.rid ?? ''} + onClickUserInfo={item.rid ? openUserInfo : undefined} + /> + ); + } + + return onClickRow('', item._id)} />; + })} + )} - + {pagination} + ); }; diff --git a/apps/meteor/client/views/mediaCallHistory/CallHistoryPageFilters.tsx b/apps/meteor/client/views/mediaCallHistory/CallHistoryPageFilters.tsx index cf1a199613d9a..69719a03e4000 100644 --- a/apps/meteor/client/views/mediaCallHistory/CallHistoryPageFilters.tsx +++ b/apps/meteor/client/views/mediaCallHistory/CallHistoryPageFilters.tsx @@ -8,7 +8,7 @@ import { useTranslation } from 'react-i18next'; type StatesFilter = Array<'ended' | 'transferred' | 'not-answered' | 'failed'>; type TypeFilter = 'inbound' | 'outbound' | 'all'; -type CallHistoryPageFiltersProps = { +export type CallHistoryPageFiltersProps = { onChangeText: (nameOrUsernameOrExtension: string) => void; onChangeType: (type: TypeFilter) => void; onChangeStates: (states: StatesFilter) => void; @@ -86,7 +86,7 @@ const CallHistoryPageFilters = ({ onChangeText, onChangeType, onChangeStates, se alignItems='center' justifyContent='center' > - + - - onChangeType(key as TypeFilter)} /> + + + + ); diff --git a/apps/meteor/client/views/mediaCallHistory/CallHistoryPageLayout.tsx b/apps/meteor/client/views/mediaCallHistory/CallHistoryPageLayout.tsx new file mode 100644 index 0000000000000..f5dcdb108be0d --- /dev/null +++ b/apps/meteor/client/views/mediaCallHistory/CallHistoryPageLayout.tsx @@ -0,0 +1,30 @@ +import { Page, PageHeader, PageContent } from '@rocket.chat/ui-client'; +import type { ReactNode } from 'react'; +import { useTranslation } from 'react-i18next'; + +import CallHistoryPageFilters, { type CallHistoryPageFiltersProps } from './CallHistoryPageFilters'; + +type CallHistoryPageLayoutProps = { + children: ReactNode; + contextualBar?: ReactNode; + filterProps: CallHistoryPageFiltersProps; +}; + +const CallHistoryPageLayout = ({ children, contextualBar, filterProps }: CallHistoryPageLayoutProps) => { + const { t } = useTranslation(); + + return ( + + + + + + {children} + + + {contextualBar} + + ); +}; + +export default CallHistoryPageLayout; diff --git a/apps/meteor/client/views/mediaCallHistory/MediaCallHistoryInternal.tsx b/apps/meteor/client/views/mediaCallHistory/MediaCallHistoryInternal.tsx index 795fe4263f64d..bf0dacc652c24 100644 --- a/apps/meteor/client/views/mediaCallHistory/MediaCallHistoryInternal.tsx +++ b/apps/meteor/client/views/mediaCallHistory/MediaCallHistoryInternal.tsx @@ -24,11 +24,13 @@ export const isInternalCallHistoryItem = (data: { item: Serialized { const { caller, callee } = call ?? {}; const contact = caller?.id === item.contactId ? caller : callee; - const { id, sipExtension, username, ...rest } = contact; + const { id, sipExtension, username, displayName, ...rest } = contact; return { ...rest, _id: id, username: username ?? '', + name: displayName, + displayName, voiceCallExtension: sipExtension, }; }; diff --git a/packages/ui-voip/src/views/CallHistoryContextualbar/CallHistoryContextualbar.tsx b/packages/ui-voip/src/views/CallHistoryContextualbar/CallHistoryContextualbar.tsx index cc93312bbadfb..62a16f3035d3c 100644 --- a/packages/ui-voip/src/views/CallHistoryContextualbar/CallHistoryContextualbar.tsx +++ b/packages/ui-voip/src/views/CallHistoryContextualbar/CallHistoryContextualbar.tsx @@ -75,7 +75,7 @@ const CallHistoryContextualBar = ({ onClose, actions, contact, data }: CallHisto - + {isInternalCallHistoryContact(contact) ? ( ) : ( diff --git a/packages/ui-voip/src/views/CallHistoryContextualbar/__snapshots__/CallHistoryContextualbar.spec.tsx.snap b/packages/ui-voip/src/views/CallHistoryContextualbar/__snapshots__/CallHistoryContextualbar.spec.tsx.snap index 2237901c55ff3..5e972d70323b8 100644 --- a/packages/ui-voip/src/views/CallHistoryContextualbar/__snapshots__/CallHistoryContextualbar.spec.tsx.snap +++ b/packages/ui-voip/src/views/CallHistoryContextualbar/__snapshots__/CallHistoryContextualbar.spec.tsx.snap @@ -97,7 +97,7 @@ exports[`renders Default without crashing 1`] = ` class="rcx-box rcx-box--full rcx-css-15qq8ie" >
    Date: Mon, 29 Dec 2025 16:25:12 -0300 Subject: [PATCH 20/68] regression: "Voice call" action enabled when a call is in progress (#37967) --- .../CallHistoryRowExternalUser.tsx | 10 ++++--- .../CallHistoryRowInternalUser.tsx | 26 ++++++++++++------- .../useMediaCallInternalHistoryActions.ts | 4 +-- packages/i18n/src/locales/en.i18n.json | 1 + .../ui-voip/src/context/MediaCallContext.ts | 6 +++++ packages/ui-voip/src/context/index.ts | 4 +-- packages/ui-voip/src/index.ts | 4 +-- .../CallHistoryActions.stories.tsx | 23 +++++++++++++++- .../CallHistoryActions.tsx | 25 ++++++++++++------ .../CallHistoryContextualbar.tsx | 10 ++++++- 10 files changed, 83 insertions(+), 30 deletions(-) diff --git a/apps/meteor/client/views/mediaCallHistory/CallHistoryRowExternalUser.tsx b/apps/meteor/client/views/mediaCallHistory/CallHistoryRowExternalUser.tsx index 8ae8b562ee217..b26b3621b632b 100644 --- a/apps/meteor/client/views/mediaCallHistory/CallHistoryRowExternalUser.tsx +++ b/apps/meteor/client/views/mediaCallHistory/CallHistoryRowExternalUser.tsx @@ -1,6 +1,6 @@ import { GenericMenu } from '@rocket.chat/ui-client'; -import { CallHistoryTableRow, useMediaCallContext } from '@rocket.chat/ui-voip'; import type { CallHistoryTableExternalContact, CallHistoryTableRowProps } from '@rocket.chat/ui-voip'; +import { CallHistoryTableRow, useMediaCallContext, isCallingBlocked } from '@rocket.chat/ui-voip'; import { useCallback, useMemo } from 'react'; import { useTranslation } from 'react-i18next'; @@ -11,14 +11,14 @@ type CallHistoryRowExternalUserProps = Omit { const { t } = useTranslation(); - const { onToggleWidget } = useMediaCallContext(); + const { onToggleWidget, state } = useMediaCallContext(); const handleClick = useCallback(() => { onClick(_id); }, [onClick, _id]); const actions = useMemo(() => { - if (!onToggleWidget) { + if (state === 'unauthorized' || state === 'unlicensed' || !onToggleWidget) { return []; } return [ @@ -26,10 +26,12 @@ const CallHistoryRowExternalUser = ({ _id, contact, type, status, duration, time id: 'voiceCall', icon: 'phone', content: t('Voice_call'), + disabled: isCallingBlocked(state), + tooltip: isCallingBlocked(state) ? t('Call_in_progress') : undefined, onClick: () => onToggleWidget({ number: contact.number }), } as const, ]; - }, [contact, onToggleWidget, t]); + }, [contact, onToggleWidget, t, state]); return ( = { userInfo: 'User_info', } as const; -const getItems = (actions: HistoryActionCallbacks, t: TFunction) => { +const getItems = (actions: HistoryActionCallbacks, t: TFunction, state: MediaCallState) => { return (Object.entries(actions) as [HistoryActions, () => void][]) .filter(([_, callback]) => callback) - .map(([action, callback]) => ({ - id: action, - icon: iconDictionary[action], - content: t(i18nDictionary[action]), - onClick: callback, - })); + .map(([action, callback]) => { + const disabled = action === 'voiceCall' && isCallingBlocked(state); + return { + id: action, + icon: iconDictionary[action], + content: t(i18nDictionary[action]), + disabled, + tooltip: disabled ? t('Call_in_progress') : undefined, + onClick: callback, + }; + }); }; const CallHistoryRowInternalUser = ({ @@ -61,6 +66,7 @@ const CallHistoryRowInternalUser = ({ onClick, }: CallHistoryRowInternalUserProps) => { const { t } = useTranslation(); + const { state } = useMediaCallContext(); const actions = useMediaCallInternalHistoryActions({ contact: { _id: contact._id, @@ -73,7 +79,7 @@ const CallHistoryRowInternalUser = ({ openUserInfo: onClickUserInfo ? (userId) => onClickUserInfo(userId, rid) : undefined, }); - const items = getItems(actions, t); + const items = getItems(actions, t, state); const handleClick = useCallback(() => { onClick(_id); diff --git a/apps/meteor/client/views/mediaCallHistory/useMediaCallInternalHistoryActions.ts b/apps/meteor/client/views/mediaCallHistory/useMediaCallInternalHistoryActions.ts index ef6d4c7af2fd3..d1a47d83119c7 100644 --- a/apps/meteor/client/views/mediaCallHistory/useMediaCallInternalHistoryActions.ts +++ b/apps/meteor/client/views/mediaCallHistory/useMediaCallInternalHistoryActions.ts @@ -29,13 +29,13 @@ export const useMediaCallInternalHistoryActions = ({ messageRoomId, openUserInfo, }: UseMediaCallInternalHistoryActionsBaseOptions) => { - const { onToggleWidget } = useMediaCallContext(); + const { onToggleWidget, state } = useMediaCallContext(); const router = useRouter(); const getAvatarUrl = useUserAvatarPath(); const voiceCall = useEffectEvent(() => { - if (!onToggleWidget) { + if (state === 'unauthorized' || state === 'unlicensed' || !onToggleWidget) { return; } diff --git a/packages/i18n/src/locales/en.i18n.json b/packages/i18n/src/locales/en.i18n.json index 887eb27955fad..d8be192dacc1d 100644 --- a/packages/i18n/src/locales/en.i18n.json +++ b/packages/i18n/src/locales/en.i18n.json @@ -976,6 +976,7 @@ "Call": "Call", "Call_Already_Ended": "Call Already Ended", "Call_ID": "Call ID", + "Call_in_progress": "Call in progress", "Call_info": "Call info", "Call_info_could_not_be_loaded": "Call info could not be loaded", "Call_Information": "Call Information", diff --git a/packages/ui-voip/src/context/MediaCallContext.ts b/packages/ui-voip/src/context/MediaCallContext.ts index c063138807981..463bd335df102 100644 --- a/packages/ui-voip/src/context/MediaCallContext.ts +++ b/packages/ui-voip/src/context/MediaCallContext.ts @@ -119,6 +119,12 @@ const MediaCallContext = createContext { + return state !== 'new' && state !== 'closed'; +}; + // This hook is for internal use only. It will only be available if the user has the necessary permissions and the workspace has the necessary modules. export const useMediaCallContext = (): MediaCallContextType => { const context = useContext(MediaCallContext); diff --git a/packages/ui-voip/src/context/index.ts b/packages/ui-voip/src/context/index.ts index b0e94b134c883..8b1ca3d329105 100644 --- a/packages/ui-voip/src/context/index.ts +++ b/packages/ui-voip/src/context/index.ts @@ -1,4 +1,4 @@ export { useMediaCallContext, useMediaCallExternalContext, default as MediaCallContext, usePeerAutocomplete } from './MediaCallContext'; -export type { PeerInfo, ConnectionState } from './MediaCallContext'; -export { isFirstPeerAutocompleteOption } from './MediaCallContext'; +export type { PeerInfo, ConnectionState, MediaCallExternalState as MediaCallState } from './MediaCallContext'; +export { isFirstPeerAutocompleteOption, isCallingBlocked } from './MediaCallContext'; export { default as MockedMediaCallProvider } from './MockedMediaCallProvider'; diff --git a/packages/ui-voip/src/index.ts b/packages/ui-voip/src/index.ts index 14b61f4c3ec7c..a659830740e53 100644 --- a/packages/ui-voip/src/index.ts +++ b/packages/ui-voip/src/index.ts @@ -1,7 +1,7 @@ export { default as MediaCallProvider } from './context/MediaCallProvider'; -export { MediaCallContext, useMediaCallExternalContext as useMediaCallContext, type PeerInfo } from './context'; - +export { MediaCallContext, useMediaCallExternalContext as useMediaCallContext, isCallingBlocked } from './context'; +export type { PeerInfo, MediaCallState } from './context'; export { useMediaCallAction } from './hooks'; export { CallHistoryContextualBar } from './views'; diff --git a/packages/ui-voip/src/views/CallHistoryContextualbar/CallHistoryActions.stories.tsx b/packages/ui-voip/src/views/CallHistoryContextualbar/CallHistoryActions.stories.tsx index be86fed7e4e6e..c31caa3060d54 100644 --- a/packages/ui-voip/src/views/CallHistoryContextualbar/CallHistoryActions.stories.tsx +++ b/packages/ui-voip/src/views/CallHistoryContextualbar/CallHistoryActions.stories.tsx @@ -1,9 +1,11 @@ import { mockAppRoot } from '@rocket.chat/mock-providers'; -import type { Meta, StoryObj } from '@storybook/react'; +import type { Meta, StoryFn, StoryObj } from '@storybook/react'; import type { ReactElement } from 'react'; import type { HistoryActionCallbacks } from './CallHistoryActions'; import CallHistoryActions from './CallHistoryActions'; +import { MockedMediaCallProvider } from '../../context'; +import type { State } from '../../context/MediaCallContext'; const noop = () => undefined; @@ -36,11 +38,20 @@ const getArgs = (index: number) => { return Object.fromEntries(actionList.slice(0, index).map((action) => [action, noop])) as HistoryActionCallbacks; }; +const getDecorator = (state: State) => { + return (Story: StoryFn): ReactElement => ( + + + + ); +}; + export const Default: Story = { args: { onClose: noop, actions: getArgs(5), }, + decorators: [getDecorator('closed')], }; export const WithLessActions: Story = { @@ -48,6 +59,7 @@ export const WithLessActions: Story = { onClose: noop, actions: getArgs(3), }, + decorators: [getDecorator('closed')], }; export const WithSingleAction: Story = { @@ -55,4 +67,13 @@ export const WithSingleAction: Story = { onClose: noop, actions: getArgs(1), }, + decorators: [getDecorator('closed')], +}; + +export const WithDisabledVoiceCall: Story = { + args: { + onClose: noop, + actions: getArgs(1), + }, + decorators: [getDecorator('ongoing')], }; diff --git a/packages/ui-voip/src/views/CallHistoryContextualbar/CallHistoryActions.tsx b/packages/ui-voip/src/views/CallHistoryContextualbar/CallHistoryActions.tsx index fce4d09644634..24af64a5ceb5e 100644 --- a/packages/ui-voip/src/views/CallHistoryContextualbar/CallHistoryActions.tsx +++ b/packages/ui-voip/src/views/CallHistoryContextualbar/CallHistoryActions.tsx @@ -3,6 +3,9 @@ import { ContextualbarActions, ContextualbarClose, GenericMenu } from '@rocket.c import type { TFunction } from 'i18next'; import { useTranslation } from 'react-i18next'; +import type { MediaCallState } from '../../context'; +import { isCallingBlocked, useMediaCallExternalContext } from '../../context/MediaCallContext'; + type HistoryActions = 'voiceCall' | 'videoCall' | 'jumpToMessage' | 'directMessage' | 'userInfo'; export type HistoryActionCallbacks = { @@ -30,21 +33,27 @@ const i18nDictionary: Record = { userInfo: 'User_info', } as const; -const getItems = (actions: HistoryActionCallbacks, t: TFunction) => { +const getItems = (actions: HistoryActionCallbacks, t: TFunction, state: MediaCallState) => { return (Object.entries(actions) as [HistoryActions, () => void][]) .filter(([_, callback]) => callback) - .map(([action, callback]) => ({ - id: action, - icon: iconDictionary[action], - content: t(i18nDictionary[action]), - onClick: callback, - })); + .map(([action, callback]) => { + const disabled = action === 'voiceCall' && isCallingBlocked(state); + return { + id: action, + icon: iconDictionary[action], + content: t(i18nDictionary[action]), + disabled, + onClick: callback, + tooltip: disabled ? t('Call_in_progress') : undefined, + }; + }); }; const CallHistoryActions = ({ onClose, actions }: CallHistoryActionsProps) => { const { t } = useTranslation(); - const items = getItems(actions, t); + const { state } = useMediaCallExternalContext(); + const items = getItems(actions, t, state); return ( {items.length > 0 && } diff --git a/packages/ui-voip/src/views/CallHistoryContextualbar/CallHistoryContextualbar.tsx b/packages/ui-voip/src/views/CallHistoryContextualbar/CallHistoryContextualbar.tsx index 62a16f3035d3c..2e6f6e8af952d 100644 --- a/packages/ui-voip/src/views/CallHistoryContextualbar/CallHistoryContextualbar.tsx +++ b/packages/ui-voip/src/views/CallHistoryContextualbar/CallHistoryContextualbar.tsx @@ -18,6 +18,8 @@ import type { HistoryActionCallbacks } from './CallHistoryActions'; import CallHistoryActions from './CallHistoryActions'; import { useFullStartDate } from './useFullStartDate'; import { CallHistoryExternalUser, CallHistoryInternalUser } from '../../components'; +import { useMediaCallExternalContext } from '../../context'; +import { isCallingBlocked } from '../../context/MediaCallContext'; import { getHistoryMessagePayload } from '../../ui-kit/getHistoryMessagePayload'; export type InternalCallHistoryContact = { @@ -64,6 +66,7 @@ const CallHistoryContextualBar = ({ onClose, actions, contact, data }: CallHisto const { voiceCall, directMessage } = actions; const { duration, callId, direction, startedAt } = data; + const { state } = useMediaCallExternalContext(); const date = useFullStartDate(startedAt); return ( @@ -117,7 +120,12 @@ const CallHistoryContextualBar = ({ onClose, actions, contact, data }: CallHisto )} {voiceCall && ( - From 5b23623535f9df4d50142cd0151336ba68f5d3fb Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Mon, 29 Dec 2025 16:33:05 -0300 Subject: [PATCH 21/68] regression: federated messages out of order (#37999) --- apps/meteor/app/api/server/v1/chat.ts | 2 +- .../app/lib/server/methods/sendMessage.ts | 32 ++++++++++++----- .../server/services/messages/service.ts | 36 +++++++++++-------- .../federation-matrix/src/events/message.ts | 6 +++- .../src/types/IMessageService.ts | 2 ++ 5 files changed, 53 insertions(+), 25 deletions(-) diff --git a/apps/meteor/app/api/server/v1/chat.ts b/apps/meteor/app/api/server/v1/chat.ts index 5a6707beb6a10..a2b5f93d1b0e3 100644 --- a/apps/meteor/app/api/server/v1/chat.ts +++ b/apps/meteor/app/api/server/v1/chat.ts @@ -434,7 +434,7 @@ API.v1.addRoute( } const sent = await applyAirGappedRestrictionsValidation(() => - executeSendMessage(this.userId, this.bodyParams.message as Pick, this.bodyParams.previewUrls), + executeSendMessage(this.userId, this.bodyParams.message as Pick, { previewUrls: this.bodyParams.previewUrls }), ); const [message] = await normalizeMessagesForUser([sent], this.userId); diff --git a/apps/meteor/app/lib/server/methods/sendMessage.ts b/apps/meteor/app/lib/server/methods/sendMessage.ts index 66758bc7faa1c..db7a017ee7a01 100644 --- a/apps/meteor/app/lib/server/methods/sendMessage.ts +++ b/apps/meteor/app/lib/server/methods/sendMessage.ts @@ -19,7 +19,21 @@ import { settings } from '../../../settings/server'; import { sendMessage } from '../functions/sendMessage'; import { RateLimiter } from '../lib'; -export async function executeSendMessage(uid: IUser['_id'], message: AtLeast, previewUrls?: string[]) { +/** + * + * @param uid + * @param message + * @param extraInfo + * - ts: The timestamp of the message. the message object already has a ts, but this value is validated and only a window of 10 seconds is allowed to be used. this value overrides the message.ts value without validation. + * + * + * @returns + */ +export async function executeSendMessage( + uid: IUser['_id'], + message: AtLeast, + extraInfo?: { ts?: Date; previewUrls?: string[] }, +) { if (message.tshow && !message.tmid) { throw new Meteor.Error('invalid-params', 'tshow provided but missing tmid', { method: 'sendMessage', @@ -32,7 +46,10 @@ export async function executeSendMessage(uid: IUser['_id'], message: AtLeast 60000) { throw new Meteor.Error('error-message-ts-out-of-sync', 'Message timestamp is out of sync', { @@ -40,11 +57,10 @@ export async function executeSendMessage(uid: IUser['_id'], message: AtLeast 10000) { - message.ts = new Date(); } - } else { - message.ts = new Date(); + if (tsDiff > 10000) { + message.ts = now; + } } if (message.msg) { @@ -90,7 +106,7 @@ export async function executeSendMessage(uid: IUser['_id'], message: AtLeast({ } try { - return await applyAirGappedRestrictionsValidation(() => executeSendMessage(uid, message, previewUrls)); + return await applyAirGappedRestrictionsValidation(() => executeSendMessage(uid, message, { previewUrls })); } catch (error: any) { if (['error-not-allowed', 'restricted-workspace'].includes(error.error || error.message)) { throw new Meteor.Error(error.error || error.message, error.reason, { diff --git a/apps/meteor/server/services/messages/service.ts b/apps/meteor/server/services/messages/service.ts index 9b7e59fb800d5..669441a63c186 100644 --- a/apps/meteor/server/services/messages/service.ts +++ b/apps/meteor/server/services/messages/service.ts @@ -95,6 +95,7 @@ export class MessageService extends ServiceClassInternal implements IMessageServ files, attachments, thread, + ts, }: { fromId: string; rid: string; @@ -108,23 +109,28 @@ export class MessageService extends ServiceClassInternal implements IMessageServ files?: IMessage['files']; attachments?: IMessage['attachments']; thread?: { tmid: string; tshow: boolean }; + ts: Date; }): Promise { - return executeSendMessage(fromId, { - rid, - msg, - ...thread, - federation: { - eventId: federation_event_id, - version: 1, + return executeSendMessage( + fromId, + { + rid, + msg, + ...thread, + federation: { + eventId: federation_event_id, + version: 1, + }, + ...(file && { file }), + ...(files && { files }), + ...(attachments && { attachments }), + ...(e2e_content && { + t: 'e2e', + content: e2e_content, + }), }, - ...(file && { file }), - ...(files && { files }), - ...(attachments && { attachments }), - ...(e2e_content && { - t: 'e2e', - content: e2e_content, - }), - }); + { ts }, + ); } async sendMessageWithValidation(user: IUser, message: Partial, room: Partial, upsert = false): Promise { diff --git a/ee/packages/federation-matrix/src/events/message.ts b/ee/packages/federation-matrix/src/events/message.ts index 609d33459f530..67ef247332625 100644 --- a/ee/packages/federation-matrix/src/events/message.ts +++ b/ee/packages/federation-matrix/src/events/message.ts @@ -225,6 +225,7 @@ export function message() { msg: formatted, federation_event_id: eventId, thread, + ts: new Date(event.origin_server_ts), }); return; } @@ -242,7 +243,7 @@ export function message() { eventId, thread, ); - await Message.saveMessageFromFederation(result); + await Message.saveMessageFromFederation({ ...result, ts: new Date(event.origin_server_ts) }); } else { const formatted = toInternalMessageFormat({ rawMessage: messageBody, @@ -257,6 +258,7 @@ export function message() { msg: formatted, federation_event_id: eventId, thread, + ts: new Date(event.origin_server_ts), }); } } catch (error) { @@ -359,6 +361,7 @@ export function message() { }, federation_event_id: eventId, thread, + ts: new Date(event.origin_server_ts), }); return; } @@ -372,6 +375,7 @@ export function message() { }, federation_event_id: eventId, thread, + ts: new Date(event.origin_server_ts), }); } catch (error) { logger.error(error, 'Error processing Matrix message:'); diff --git a/packages/core-services/src/types/IMessageService.ts b/packages/core-services/src/types/IMessageService.ts index 5532a553f6d6f..c9490e81bb01e 100644 --- a/packages/core-services/src/types/IMessageService.ts +++ b/packages/core-services/src/types/IMessageService.ts @@ -19,6 +19,7 @@ export interface IMessageService { files, attachments, thread, + ts, }: { fromId: string; rid: string; @@ -32,6 +33,7 @@ export interface IMessageService { files?: IMessage['files']; attachments?: IMessage['attachments']; thread?: { tmid: string; tshow: boolean }; + ts: Date; }): Promise; saveSystemMessageAndNotifyUser( type: MessageTypesValues, From 8928e4a8c1ec7fd24cbfb7eb0dda0e7546ffbeef Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Tue, 30 Dec 2025 17:29:18 -0300 Subject: [PATCH 22/68] chore!: change http code results for ddp over rest (#38007) --- .changeset/long-swans-sin.md | 5 ++ apps/meteor/app/api/server/ApiClass.ts | 3 +- apps/meteor/app/api/server/definition.ts | 8 ++ apps/meteor/app/api/server/v1/chat.ts | 4 +- apps/meteor/app/api/server/v1/misc.ts | 5 +- .../lib/server/methods/getChannelHistory.ts | 4 - .../app/message-star/server/starMessage.ts | 22 +++--- .../client/meteor/overrides/ddpOverREST.ts | 5 +- apps/meteor/tests/end-to-end/api/abac.ts | 2 +- .../tests/end-to-end/api/guest-permissions.ts | 4 +- apps/meteor/tests/end-to-end/api/methods.ts | 74 ++++++++++--------- .../end-to-end/api/methods/2fa-enable.ts | 4 +- .../tests/end-to-end/dms.spec.ts | 6 +- .../tests/end-to-end/permissions.spec.ts | 4 +- .../tests/end-to-end/room.spec.ts | 2 +- 15 files changed, 85 insertions(+), 67 deletions(-) create mode 100644 .changeset/long-swans-sin.md diff --git a/.changeset/long-swans-sin.md b/.changeset/long-swans-sin.md new file mode 100644 index 0000000000000..b5dd7a9c16b4c --- /dev/null +++ b/.changeset/long-swans-sin.md @@ -0,0 +1,5 @@ +--- +'@rocket.chat/meteor': patch +--- + +Changes the HTTP code of `/api/v1/method.call` and `/api/v1/method.callAnon` in case of internal errors diff --git a/apps/meteor/app/api/server/ApiClass.ts b/apps/meteor/app/api/server/ApiClass.ts index 895bd659af326..413a7de4bf1e9 100644 --- a/apps/meteor/app/api/server/ApiClass.ts +++ b/apps/meteor/app/api/server/ApiClass.ts @@ -37,6 +37,7 @@ import type { RedirectResult, UnavailableResult, GenericRouteExecutionContext, + TooManyRequestsResult, } from './definition'; import { getUserInfo } from './helpers/getUserInfo'; import { parseJsonQuery } from './helpers/parseJsonQuery'; @@ -383,7 +384,7 @@ export class APIClass & { success?: boolean } } { + public tooManyRequests(msg?: T): TooManyRequestsResult { return { statusCode: 429, body: { diff --git a/apps/meteor/app/api/server/definition.ts b/apps/meteor/app/api/server/definition.ts index 478acc01d0252..9684b99c798c8 100644 --- a/apps/meteor/app/api/server/definition.ts +++ b/apps/meteor/app/api/server/definition.ts @@ -56,6 +56,14 @@ export type ForbiddenResult = { }; }; +export type TooManyRequestsResult = { + statusCode: 429; + body: { + success: false; + error: T | 'Too many requests'; + }; +}; + export type InternalError = { statusCode: StatusCode; body: { diff --git a/apps/meteor/app/api/server/v1/chat.ts b/apps/meteor/app/api/server/v1/chat.ts index a2b5f93d1b0e3..25978aefce3e8 100644 --- a/apps/meteor/app/api/server/v1/chat.ts +++ b/apps/meteor/app/api/server/v1/chat.ts @@ -456,7 +456,7 @@ API.v1.addRoute( throw new Meteor.Error('error-message-not-found', 'The provided "messageId" does not match any existing message.'); } - await starMessage(this.userId, { + await starMessage(this.user, { _id: msg._id, rid: msg.rid, starred: true, @@ -478,7 +478,7 @@ API.v1.addRoute( throw new Meteor.Error('error-message-not-found', 'The provided "messageId" does not match any existing message.'); } - await starMessage(this.userId, { + await starMessage(this.user, { _id: msg._id, rid: msg.rid, starred: false, diff --git a/apps/meteor/app/api/server/v1/misc.ts b/apps/meteor/app/api/server/v1/misc.ts index 75803bbed759d..403ffcc29b4ce 100644 --- a/apps/meteor/app/api/server/v1/misc.ts +++ b/apps/meteor/app/api/server/v1/misc.ts @@ -525,7 +525,8 @@ API.v1.addRoute( if (settings.get('Log_Level') === '2') { Meteor._debug(`Exception while invoking method ${method}`, err); } - return API.v1.success(mountResult({ id, error: err })); + + return API.v1.failure(mountResult({ id, error: err })); } }, }, @@ -580,7 +581,7 @@ API.v1.addRoute( if (settings.get('Log_Level') === '2') { Meteor._debug(`Exception while invoking method ${method}`, err); } - return API.v1.success(mountResult({ id, error: err })); + return API.v1.failure(mountResult({ id, error: err })); } }, }, diff --git a/apps/meteor/app/lib/server/methods/getChannelHistory.ts b/apps/meteor/app/lib/server/methods/getChannelHistory.ts index e0a2a844a75eb..cd2096a82a1a9 100644 --- a/apps/meteor/app/lib/server/methods/getChannelHistory.ts +++ b/apps/meteor/app/lib/server/methods/getChannelHistory.ts @@ -48,10 +48,6 @@ export const getChannelHistory = async ({ }): Promise => { check(rid, String); - if (!Meteor.userId()) { - throw new Meteor.Error('error-invalid-user', 'Invalid user', { method: 'getChannelHistory' }); - } - if (!fromUserId) { return false; } diff --git a/apps/meteor/app/message-star/server/starMessage.ts b/apps/meteor/app/message-star/server/starMessage.ts index 96b342f8bfa69..38cfc648af04d 100644 --- a/apps/meteor/app/message-star/server/starMessage.ts +++ b/apps/meteor/app/message-star/server/starMessage.ts @@ -1,11 +1,12 @@ import { Apps, AppEvents } from '@rocket.chat/apps'; -import type { IMessage } from '@rocket.chat/core-typings'; +import type { IMessage, IUser } from '@rocket.chat/core-typings'; import type { ServerMethods } from '@rocket.chat/ddp-client'; import { Messages, Subscriptions, Rooms } from '@rocket.chat/models'; import { Meteor } from 'meteor/meteor'; import { canAccessRoomAsync, roomAccessAttributes } from '../../authorization/server'; import { isTheLastMessage } from '../../lib/server/functions/isTheLastMessage'; +import { methodDeprecationLogger } from '../../lib/server/lib/deprecationWarningLogger'; import { notifyOnRoomChangedById, notifyOnMessageChange } from '../../lib/server/lib/notifyListener'; import { settings } from '../../settings/server'; @@ -16,7 +17,7 @@ declare module '@rocket.chat/ddp-client' { } } -export const starMessage = async (userId: string, message: Pick & { starred: boolean }): Promise => { +export const starMessage = async (user: IUser, message: Pick & { starred: boolean }): Promise => { if (!settings.get('Message_AllowStarring')) { throw new Meteor.Error('error-action-not-allowed', 'Message starring not allowed', { method: 'starMessage', @@ -24,7 +25,7 @@ export const starMessage = async (userId: string, message: Pick({ async starMessage(message) { - const uid = Meteor.userId(); + methodDeprecationLogger.method('starMessage', '9.0.0', '/v1/chat.starMessage'); + const user = (await Meteor.userAsync()) as IUser; - if (!uid) { + if (!user) { throw new Meteor.Error('error-invalid-user', 'Invalid user', { method: 'starMessage', }); } - return starMessage(uid, message); + return starMessage(user, message); }, }); diff --git a/apps/meteor/client/meteor/overrides/ddpOverREST.ts b/apps/meteor/client/meteor/overrides/ddpOverREST.ts index 205f0d5a4c6ac..e7fb05275e3ab 100644 --- a/apps/meteor/client/meteor/overrides/ddpOverREST.ts +++ b/apps/meteor/client/meteor/overrides/ddpOverREST.ts @@ -88,7 +88,10 @@ const withDDPOverREST = (_send: (this: Meteor.IMeteorConnection, message: Meteor processResult(_message); }) - .catch((error) => { + .catch(async (error) => { + if ('message' in error && error.message) { + processResult(error.message); + } console.error(error); }); }; diff --git a/apps/meteor/tests/end-to-end/api/abac.ts b/apps/meteor/tests/end-to-end/api/abac.ts index 18f522d396652..bb4d9ee8d4799 100644 --- a/apps/meteor/tests/end-to-end/api/abac.ts +++ b/apps/meteor/tests/end-to-end/api/abac.ts @@ -408,7 +408,7 @@ const addAbacAttributesToUserDirectly = async (userId: string, abacAttributes: I msg: 'method', }), }) - .expect(200) + .expect(400) .expect((res) => { const result = JSON.parse(res.body.message); expect(result).to.have.property('error'); diff --git a/apps/meteor/tests/end-to-end/api/guest-permissions.ts b/apps/meteor/tests/end-to-end/api/guest-permissions.ts index 3afda0ea15710..4aa4a581aaf0a 100644 --- a/apps/meteor/tests/end-to-end/api/guest-permissions.ts +++ b/apps/meteor/tests/end-to-end/api/guest-permissions.ts @@ -106,9 +106,9 @@ import { IS_EE } from '../../e2e/config/constants'; }), }) .expect('Content-Type', 'application/json') - .expect(200); + .expect(400); - expect(res.body).to.have.property('success', true); + expect(res.body).to.have.property('success', false); expect(res.body).to.have.property('message'); const message = JSON.parse(res.body.message); expect(message).to.have.property('error'); diff --git a/apps/meteor/tests/end-to-end/api/methods.ts b/apps/meteor/tests/end-to-end/api/methods.ts index 088aef3aeff4d..020840d05f736 100644 --- a/apps/meteor/tests/end-to-end/api/methods.ts +++ b/apps/meteor/tests/end-to-end/api/methods.ts @@ -166,9 +166,10 @@ describe('Meteor.methods', () => { }), }) .expect('Content-Type', 'application/json') - .expect(200) + .expect(400) .expect((res) => { - expect(res.body).to.have.property('success', true); + expect(res.body).to.have.property('success', false); + const data = JSON.parse(res.body.message); expect(data).to.have.property('error').that.is.an('object'); expect(data.error).to.have.property('error', 'error-action-not-allowed'); @@ -576,9 +577,9 @@ describe('Meteor.methods', () => { }), }) .expect('Content-Type', 'application/json') - .expect(200) + .expect(400) .expect((res) => { - expect(res.body).to.have.a.property('success', true); + expect(res.body).to.have.a.property('success', false); expect(res.body).to.have.a.property('message').that.is.a('string'); const data = JSON.parse(res.body.message); @@ -734,9 +735,9 @@ describe('Meteor.methods', () => { msg: 'method', }), }) - .expect(200) + .expect(400) .expect((res) => { - expect(res.body).to.have.a.property('success', true); + expect(res.body).to.have.a.property('success', false); const data = JSON.parse(res.body.message); expect(data).to.have.a.property('error').that.is.an('object'); expect(data.error).to.have.a.property('error', 'error-not-allowed'); @@ -903,9 +904,9 @@ describe('Meteor.methods', () => { }), }) .expect('Content-Type', 'application/json') - .expect(200) + .expect(400) .expect((res) => { - expect(res.body).to.have.a.property('success', true); + expect(res.body).to.have.a.property('success', false); expect(res.body).to.have.a.property('message').that.is.a('string'); const data = JSON.parse(res.body.message); @@ -1121,9 +1122,9 @@ describe('Meteor.methods', () => { }), }) .expect('Content-Type', 'application/json') - .expect(200) + .expect(400) .expect((res) => { - expect(res.body).to.have.a.property('success', true); + expect(res.body).to.have.a.property('success', false); expect(res.body).to.have.a.property('message').that.is.a('string'); const data = JSON.parse(res.body.message); @@ -1301,9 +1302,9 @@ describe('Meteor.methods', () => { }), }) .expect('Content-Type', 'application/json') - .expect(200) + .expect(400) .expect((res) => { - expect(res.body).to.have.a.property('success', true); + expect(res.body).to.have.a.property('success', false); expect(res.body).to.have.a.property('message').that.is.a('string'); const data = JSON.parse(res.body.message); @@ -1562,9 +1563,9 @@ describe('Meteor.methods', () => { }), }) .expect('Content-Type', 'application/json') - .expect(200) + .expect(400) .expect((res) => { - expect(res.body).to.have.a.property('success', true); + expect(res.body).to.have.a.property('success', false); expect(res.body).to.have.a.property('message').that.include('error-invalid-room'); }) .end(done); @@ -1583,9 +1584,9 @@ describe('Meteor.methods', () => { }), }) .expect('Content-Type', 'application/json') - .expect(200) + .expect(400) .expect((res) => { - expect(res.body).to.have.a.property('success', true); + expect(res.body).to.have.a.property('success', false); expect(res.body).to.have.a.property('message').that.include('Match error'); }) .end(done); @@ -2022,9 +2023,9 @@ describe('Meteor.methods', () => { }), }) .expect('Content-Type', 'application/json') - .expect(200) + .expect(400) .expect((res) => { - expect(res.body).to.have.property('success', true); + expect(res.body).to.have.property('success', false); const data = JSON.parse(res.body.message); expect(data).to.not.have.a.property('result').that.is.an('object'); expect(data).to.have.a.property('error').that.is.an('object'); @@ -2053,9 +2054,9 @@ describe('Meteor.methods', () => { }), }) .expect('Content-Type', 'application/json') - .expect(200) + .expect(400) .expect((res) => { - expect(res.body).to.have.property('success', true); + expect(res.body).to.have.property('success', false); const data = JSON.parse(res.body.message); expect(data).to.have.a.property('error').that.is.an('object'); expect(data.error.sanitizedError).to.have.a.property('reason', 'Match failed'); @@ -2241,9 +2242,9 @@ describe('Meteor.methods', () => { }), }) .expect('Content-Type', 'application/json') - .expect(200) + .expect(400) .expect((res) => { - expect(res.body).to.have.a.property('success', true); + expect(res.body).to.have.a.property('success', false); expect(res.body).to.have.a.property('message').that.is.a('string'); const data = JSON.parse(res.body.message); expect(data).to.have.a.property('msg').that.is.an('string'); @@ -2264,9 +2265,9 @@ describe('Meteor.methods', () => { }), }) .expect('Content-Type', 'application/json') - .expect(200) + .expect(400) .expect((res) => { - expect(res.body).to.have.a.property('success', true); + expect(res.body).to.have.a.property('success', false); expect(res.body).to.have.a.property('message').that.is.a('string'); const data = JSON.parse(res.body.message); expect(data).to.have.a.property('msg').that.is.an('string'); @@ -2274,7 +2275,7 @@ describe('Meteor.methods', () => { }); }); - it('should add a quote attachment to a message', async () => { + it.skip('should add a quote attachment to a message', async () => { const quotedMsgLink = `${siteUrl}/group/${roomName}?msg=${messageWithMarkdownId}`; await request .post(methodCall('updateMessage')) @@ -2291,6 +2292,7 @@ describe('Meteor.methods', () => { .expect(200) .expect((res) => { expect(res.body).to.have.a.property('success', true); + // TODO: this test is not testing anything useful expect(res.body).to.have.a.property('message').that.is.a('string'); }); @@ -2378,7 +2380,7 @@ describe('Meteor.methods', () => { }); }); - it('should remove a quote attachment from a message', async () => { + it.skip('should remove a quote attachment from a message', async () => { await request .post(methodCall('updateMessage')) .set(credentials) @@ -2534,9 +2536,9 @@ describe('Meteor.methods', () => { }), }) .expect('Content-Type', 'application/json') - .expect(200) + .expect(400) .expect((res) => { - expect(res.body).to.have.a.property('success', true); + expect(res.body).to.have.a.property('success', false); expect(res.body).to.have.a.property('message').that.is.a('string'); const data = JSON.parse(res.body.message); @@ -3098,7 +3100,7 @@ describe('Meteor.methods', () => { }), }) .expect('Content-Type', 'application/json') - .expect(200) + .expect(400) .expect((res) => { expect(res.body).to.have.property('message').that.is.an('string'); expect(res.body.message).to.include('error-cant-invite-for-direct-room'); @@ -3201,9 +3203,9 @@ describe('Meteor.methods', () => { }), }) .expect('Content-Type', 'application/json') - .expect(200) + .expect(400) .expect((res) => { - expect(res.body).to.have.property('success', true); + expect(res.body).to.have.property('success', false); const parsedBody = JSON.parse(res.body.message); expect(parsedBody).to.have.property('error'); expect(parsedBody.error).to.have.property('error', 'error-max-rooms-per-guest-reached'); @@ -3225,9 +3227,9 @@ describe('Meteor.methods', () => { params: [[{ _id: 'Message_AllowEditing_BlockEditInMinutes', value: { $InfNaN: 0 } }]], }), }) - .expect(200) + .expect(400) .expect((res) => { - expect(res.body).to.have.property('success', true); + expect(res.body).to.have.property('success', false); const parsedBody = JSON.parse(res.body.message); expect(parsedBody).to.have.property('error'); expect(parsedBody.error).to.have.property('error', 'Invalid setting value NaN'); @@ -3333,7 +3335,7 @@ describe('Meteor.methods', () => { }), }) .expect('Content-Type', 'application/json') - .expect(200) + .expect(400) .expect((res) => { expect(res.body).to.have.a.property('message'); const data = JSON.parse(res.body.message); @@ -3411,9 +3413,9 @@ describe('Meteor.methods', () => { }), }) .expect('Content-Type', 'application/json') - .expect(200) + .expect(400) .expect((res) => { - expect(res.body).to.have.a.property('success', true); + expect(res.body).to.have.a.property('success', false); expect(res.body).to.have.a.property('message').that.is.a('string'); const data = JSON.parse(res.body.message); diff --git a/apps/meteor/tests/end-to-end/api/methods/2fa-enable.ts b/apps/meteor/tests/end-to-end/api/methods/2fa-enable.ts index 9c2a6962fc614..68a1dfc8e4404 100644 --- a/apps/meteor/tests/end-to-end/api/methods/2fa-enable.ts +++ b/apps/meteor/tests/end-to-end/api/methods/2fa-enable.ts @@ -151,9 +151,9 @@ describe('2fa:enable', function () { params: [], }), }) - .expect(200) + .expect(400) .expect((res) => { - expect(res.body).to.have.property('success', true); + expect(res.body).to.have.property('success', false); const parsedBody = JSON.parse(res.body.message); expect(parsedBody).to.have.property('error'); expect(parsedBody).to.not.have.property('result'); diff --git a/ee/packages/federation-matrix/tests/end-to-end/dms.spec.ts b/ee/packages/federation-matrix/tests/end-to-end/dms.spec.ts index ec8f04f88f62c..7a9873d8b0da2 100644 --- a/ee/packages/federation-matrix/tests/end-to-end/dms.spec.ts +++ b/ee/packages/federation-matrix/tests/end-to-end/dms.spec.ts @@ -646,7 +646,7 @@ const waitForRoomEvent = async ( config: rcUserConfig1, }); - expect(response.body).toHaveProperty('success', true); + expect(response.body).toHaveProperty('success', false); expect(response.body).toHaveProperty('message'); // Parse the error message from the DDP response @@ -1113,7 +1113,7 @@ const waitForRoomEvent = async ( config: rcUserConfig2, }); - expect(response.body).toHaveProperty('success', true); + expect(response.body).toHaveProperty('success', false); expect(response.body).toHaveProperty('message'); // Parse the error message from the DDP response @@ -1664,7 +1664,7 @@ const waitForRoomEvent = async ( config: rcUser1.config, }); - expect(response.body).toHaveProperty('success', true); + expect(response.body).toHaveProperty('success', false); expect(response.body).toHaveProperty('message'); // Parse the error message from the DDP response diff --git a/ee/packages/federation-matrix/tests/end-to-end/permissions.spec.ts b/ee/packages/federation-matrix/tests/end-to-end/permissions.spec.ts index fdb07ca0d08f6..f1084816346b8 100644 --- a/ee/packages/federation-matrix/tests/end-to-end/permissions.spec.ts +++ b/ee/packages/federation-matrix/tests/end-to-end/permissions.spec.ts @@ -186,8 +186,8 @@ import { SynapseClient } from '../helper/synapse-client'; config: rc1AdminRequestConfig, }); - expect(addUserResponse.status).toBe(200); - expect(addUserResponse.body).toHaveProperty('success', true); + expect(addUserResponse.status).toBe(400); + expect(addUserResponse.body).toHaveProperty('success', false); expect(addUserResponse.body.message).toMatch(/error-not-authorized-federation/); }); diff --git a/ee/packages/federation-matrix/tests/end-to-end/room.spec.ts b/ee/packages/federation-matrix/tests/end-to-end/room.spec.ts index f0b2f169f752d..ff120a10f5764 100644 --- a/ee/packages/federation-matrix/tests/end-to-end/room.spec.ts +++ b/ee/packages/federation-matrix/tests/end-to-end/room.spec.ts @@ -231,7 +231,7 @@ import { SynapseClient } from '../helper/synapse-client'; config: rc1AdminRequestConfig, }); - expect(response.body).toHaveProperty('success', true); + expect(response.body).toHaveProperty('success', false); expect(response.body).toHaveProperty('message'); // Parse the error message from the DDP response From bc83d3f41a41699961b1d839d4311cbcfece073c Mon Sep 17 00:00:00 2001 From: Martin Schoeler Date: Wed, 31 Dec 2025 09:36:06 -0300 Subject: [PATCH 23/68] regression(ABAC): Improve errors on attribute form (#37982) --- .../ABAC/ABACAttributesTab/AttributesContextualBar.tsx | 8 ++++++-- packages/i18n/src/locales/en.i18n.json | 1 + 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/apps/meteor/client/views/admin/ABAC/ABACAttributesTab/AttributesContextualBar.tsx b/apps/meteor/client/views/admin/ABAC/ABACAttributesTab/AttributesContextualBar.tsx index 0285afa82f787..7e0971a421097 100644 --- a/apps/meteor/client/views/admin/ABAC/ABACAttributesTab/AttributesContextualBar.tsx +++ b/apps/meteor/client/views/admin/ABAC/ABACAttributesTab/AttributesContextualBar.tsx @@ -71,8 +71,12 @@ const AttributesContextualBar = ({ attributeData, onClose }: AttributesContextua } onClose(); }, - onError: (error) => { - dispatchToastMessage({ type: 'error', message: error }); + onError: (error: { errorType: string; error: string }) => { + if (error.errorType === 'invalid-params') { + dispatchToastMessage({ type: 'error', message: t('ABAC_Invalid_attribute') }); + } else { + dispatchToastMessage({ type: 'error', message: error }); + } }, onSettled: () => { queryClient.invalidateQueries({ queryKey: ABACQueryKeys.roomAttributes.list() }); diff --git a/packages/i18n/src/locales/en.i18n.json b/packages/i18n/src/locales/en.i18n.json index d8be192dacc1d..6345d19291c97 100644 --- a/packages/i18n/src/locales/en.i18n.json +++ b/packages/i18n/src/locales/en.i18n.json @@ -83,6 +83,7 @@ "ABAC_Managed_description": "Only compliant users have access to attribute-based access controlled rooms. Attributes determine room access.", "ABAC_Room_Attributes": "Room Attributes", "ABAC_Logs": "Logs", + "ABAC_Invalid_attribute": "Invalid characters in attribute name or values", "AI_Actions": "AI actions", "API": "API", "API_Add_Personal_Access_Token": "Add new Personal Access Token", From b6e3a8726a58413fe9425f9f39314b1249e1859e Mon Sep 17 00:00:00 2001 From: Aleksander Nicacio da Silva Date: Wed, 31 Dec 2025 11:27:44 -0300 Subject: [PATCH 24/68] regression: Room invited state not being displayed in embedded layout (#38009) Co-authored-by: Guilherme Gazzo --- .../client/views/room/RoomOpenerEmbedded.tsx | 6 ++---- apps/meteor/client/views/room/hooks/useOpenRoom.ts | 14 +++++--------- .../client/views/room/hooks/useRoomInvitation.tsx | 3 ++- apps/meteor/server/publications/room/index.ts | 11 ++++++++++- .../server/services/authorization/canAccessRoom.ts | 5 +++-- .../src/models/ISubscriptionsModel.ts | 2 +- packages/models/src/models/Subscriptions.ts | 4 ++-- 7 files changed, 25 insertions(+), 20 deletions(-) diff --git a/apps/meteor/client/views/room/RoomOpenerEmbedded.tsx b/apps/meteor/client/views/room/RoomOpenerEmbedded.tsx index 542bf68413d83..919990af1a985 100644 --- a/apps/meteor/client/views/room/RoomOpenerEmbedded.tsx +++ b/apps/meteor/client/views/room/RoomOpenerEmbedded.tsx @@ -68,13 +68,11 @@ const RoomOpenerEmbedded = ({ type, reference }: RoomOpenerProps): ReactElement return; } return subscribeToNotifyUser(`${uid}/subscriptions-changed`, (event, sub) => { - if (event !== 'inserted') { + if (sub.rid !== rid || event === 'removed') { return; } - if (sub.rid === rid) { - refetch(); - } + refetch(); }); }, [refetch, rid, subscribeToNotifyUser, uid]); diff --git a/apps/meteor/client/views/room/hooks/useOpenRoom.ts b/apps/meteor/client/views/room/hooks/useOpenRoom.ts index 45983eae62c3f..ee4b28fc19c47 100644 --- a/apps/meteor/client/views/room/hooks/useOpenRoom.ts +++ b/apps/meteor/client/views/room/hooks/useOpenRoom.ts @@ -1,4 +1,4 @@ -import { isPublicRoom, isInviteSubscription, type IRoom, type RoomType } from '@rocket.chat/core-typings'; +import { isPublicRoom, type IRoom, type RoomType } from '@rocket.chat/core-typings'; import { getObjectKeys } from '@rocket.chat/tools'; import { useMethod, usePermission, useRoute, useSetting, useUser } from '@rocket.chat/ui-contexts'; import { useQuery, useQueryClient } from '@tanstack/react-query'; @@ -35,14 +35,6 @@ export function useOpenRoom({ type, reference }: { type: RoomType; reference: st throw new RoomNotFoundError(undefined, { type, reference }); } - const { Rooms, Subscriptions } = await import('../../../stores'); - - const sub = Subscriptions.state.find((record) => record.rid === reference || record.name === reference); - - if (sub && isInviteSubscription(sub)) { - return { rid: sub.rid }; - } - let roomData: IRoom; try { roomData = await getRoomByTypeAndName(type, reference); @@ -66,6 +58,8 @@ export function useOpenRoom({ type, reference }: { type: RoomType; reference: st throw new RoomNotFoundError(undefined, { type, reference }); } + const { Rooms, Subscriptions } = await import('../../../stores'); + const unsetKeys = getObjectKeys(roomData).filter((key) => !(key in roomFields)); unsetKeys.forEach((key) => { delete roomData[key]; @@ -80,6 +74,8 @@ export function useOpenRoom({ type, reference }: { type: RoomType; reference: st const { LegacyRoomManager } = await import('../../../../app/ui-utils/client'); + const sub = Subscriptions.state.find((record) => record.rid === reference || record.name === reference); + if (reference !== undefined && room._id !== reference && type === 'd') { // Redirect old url using username to rid LegacyRoomManager.close(type + reference); diff --git a/apps/meteor/client/views/room/hooks/useRoomInvitation.tsx b/apps/meteor/client/views/room/hooks/useRoomInvitation.tsx index 7989fdf3291ed..0920a7416d327 100644 --- a/apps/meteor/client/views/room/hooks/useRoomInvitation.tsx +++ b/apps/meteor/client/views/room/hooks/useRoomInvitation.tsx @@ -3,7 +3,7 @@ import { useQueryClient } from '@tanstack/react-query'; import { useRoomRejectInvitationModal } from './useRoomRejectInvitationModal'; import { useEndpointMutation } from '../../../hooks/useEndpointMutation'; -import { roomsQueryKeys } from '../../../lib/queryKeys'; +import { roomsQueryKeys, subscriptionsQueryKeys } from '../../../lib/queryKeys'; import type { IRoomWithFederationOriginalName } from '../contexts/RoomContext'; export const useRoomInvitation = (room: IRoomWithFederationOriginalName) => { @@ -24,6 +24,7 @@ export const useRoomInvitation = (room: IRoomWithFederationOriginalName) => { } await queryClient.invalidateQueries({ queryKey: roomsQueryKeys.room(room._id) }); + await queryClient.invalidateQueries({ queryKey: subscriptionsQueryKeys.subscription(room._id) }); if (action === 'reject') { router.navigate('/home'); diff --git a/apps/meteor/server/publications/room/index.ts b/apps/meteor/server/publications/room/index.ts index 5a457daa937e3..e3cbfdcc9a8ca 100644 --- a/apps/meteor/server/publications/room/index.ts +++ b/apps/meteor/server/publications/room/index.ts @@ -79,7 +79,16 @@ Meteor.methods({ }); } - if (userId && !(await canAccessRoomAsync(room, { _id: userId }))) { + if ( + userId && + !(await canAccessRoomAsync( + room, + { _id: userId }, + { + includeInvitations: true, + }, + )) + ) { throw new Meteor.Error('error-no-permission', 'No permission', { method: 'getRoomByTypeAndName', }); diff --git a/apps/meteor/server/services/authorization/canAccessRoom.ts b/apps/meteor/server/services/authorization/canAccessRoom.ts index 1aed9cc907309..3f348e953a98c 100644 --- a/apps/meteor/server/services/authorization/canAccessRoom.ts +++ b/apps/meteor/server/services/authorization/canAccessRoom.ts @@ -51,7 +51,7 @@ const roomAccessValidators: RoomAccessValidator[] = [ return canAccessPublicRoom(user); }, - async function _validateIfAlreadyJoined(room, user): Promise { + async function _validateIfAlreadyJoined(room, user, extraData): Promise { if (!room?._id || !user?._id) { return false; } @@ -67,7 +67,8 @@ const roomAccessValidators: RoomAccessValidator[] = [ !(await License.hasModule('abac')) || (!(await Settings.getValueById('ABAC_Enabled')) as boolean) ) { - if (!(await Subscriptions.countByRoomIdAndUserId(room._id, user._id))) { + const includeInvitations = extraData?.includeInvitations ?? false; + if (!(await Subscriptions.countByRoomIdAndUserId(room._id, user._id, includeInvitations))) { return false; } diff --git a/packages/model-typings/src/models/ISubscriptionsModel.ts b/packages/model-typings/src/models/ISubscriptionsModel.ts index 7958feae702e6..217050a39b2a7 100644 --- a/packages/model-typings/src/models/ISubscriptionsModel.ts +++ b/packages/model-typings/src/models/ISubscriptionsModel.ts @@ -34,7 +34,7 @@ export interface ISubscriptionsModel extends IBaseModel { findByLivechatRoomIdAndNotUserId(roomId: string, userId: string, options?: FindOptions): FindCursor; - countByRoomIdAndUserId(rid: string, uid: string | undefined): Promise; + countByRoomIdAndUserId(rid: string, uid: string | undefined, includeInvitations?: boolean): Promise; countUnarchivedByRoomId(rid: string): Promise; diff --git a/packages/models/src/models/Subscriptions.ts b/packages/models/src/models/Subscriptions.ts index e73a4c1913421..3eb100156cc36 100644 --- a/packages/models/src/models/Subscriptions.ts +++ b/packages/models/src/models/Subscriptions.ts @@ -157,11 +157,11 @@ export class SubscriptionsRaw extends BaseRaw implements ISubscri return this.find(query, options); } - countByRoomIdAndUserId(rid: string, uid: string | undefined): Promise { + countByRoomIdAndUserId(rid: string, uid: string | undefined, includeInvitations = false): Promise { const query = { rid, 'u._id': uid, - 'status': { $exists: false }, + ...(includeInvitations ? { $or: [{ status: { $exists: false } }, { status: 'INVITED' as const }] } : { status: { $exists: false } }), }; return this.countDocuments(query); From 3c20c42e7fe0d3ca4ad3468a5c86890a53a4f4b6 Mon Sep 17 00:00:00 2001 From: rocketchat-github-ci Date: Wed, 31 Dec 2025 14:38:09 +0000 Subject: [PATCH 25/68] Release 8.0.0-rc.2 [no ci] --- .changeset/bump-patch-1767191875055.md | 5 +++ .changeset/pre.json | 2 + apps/meteor/CHANGELOG.md | 43 +++++++++++++++++++ apps/meteor/app/utils/rocketchat.info | 2 +- apps/meteor/ee/server/services/CHANGELOG.md | 14 ++++++ apps/meteor/ee/server/services/package.json | 2 +- apps/meteor/package.json | 2 +- apps/uikit-playground/CHANGELOG.md | 12 ++++++ apps/uikit-playground/package.json | 2 +- ee/apps/account-service/CHANGELOG.md | 14 ++++++ ee/apps/account-service/package.json | 2 +- ee/apps/authorization-service/CHANGELOG.md | 15 +++++++ ee/apps/authorization-service/package.json | 2 +- ee/apps/ddp-streamer/CHANGELOG.md | 15 +++++++ ee/apps/ddp-streamer/package.json | 2 +- ee/apps/omnichannel-transcript/CHANGELOG.md | 15 +++++++ ee/apps/omnichannel-transcript/package.json | 2 +- ee/apps/presence-service/CHANGELOG.md | 14 ++++++ ee/apps/presence-service/package.json | 2 +- ee/apps/queue-worker/CHANGELOG.md | 14 ++++++ ee/apps/queue-worker/package.json | 2 +- ee/packages/abac/CHANGELOG.md | 11 +++++ ee/packages/abac/package.json | 2 +- ee/packages/federation-matrix/CHANGELOG.md | 15 +++++++ ee/packages/federation-matrix/package.json | 2 +- ee/packages/license/CHANGELOG.md | 9 ++++ ee/packages/license/package.json | 2 +- ee/packages/media-calls/CHANGELOG.md | 10 +++++ ee/packages/media-calls/package.json | 2 +- ee/packages/network-broker/CHANGELOG.md | 9 ++++ ee/packages/network-broker/package.json | 2 +- ee/packages/omni-core-ee/CHANGELOG.md | 11 +++++ ee/packages/omni-core-ee/package.json | 2 +- ee/packages/omnichannel-services/CHANGELOG.md | 15 +++++++ ee/packages/omnichannel-services/package.json | 2 +- ee/packages/pdf-worker/CHANGELOG.md | 9 ++++ ee/packages/pdf-worker/package.json | 2 +- ee/packages/presence/CHANGELOG.md | 11 +++++ ee/packages/presence/package.json | 2 +- package.json | 2 +- packages/api-client/CHANGELOG.md | 10 +++++ packages/api-client/package.json | 2 +- packages/apps/CHANGELOG.md | 10 +++++ packages/apps/package.json | 2 +- packages/core-services/CHANGELOG.md | 12 ++++++ packages/core-services/package.json | 2 +- packages/core-typings/CHANGELOG.md | 2 + packages/core-typings/package.json | 2 +- packages/cron/CHANGELOG.md | 10 +++++ packages/cron/package.json | 2 +- packages/ddp-client/CHANGELOG.md | 11 +++++ packages/ddp-client/package.json | 2 +- packages/fuselage-ui-kit/CHANGELOG.md | 13 ++++++ packages/fuselage-ui-kit/package.json | 2 +- packages/gazzodown/CHANGELOG.md | 11 +++++ packages/gazzodown/package.json | 2 +- packages/http-router/CHANGELOG.md | 10 +++++ packages/http-router/package.json | 2 +- packages/instance-status/CHANGELOG.md | 9 ++++ packages/instance-status/package.json | 2 +- packages/livechat/CHANGELOG.md | 9 ++++ packages/livechat/package.json | 2 +- packages/mock-providers/CHANGELOG.md | 9 ++++ packages/mock-providers/package.json | 2 +- packages/model-typings/CHANGELOG.md | 9 ++++ packages/model-typings/package.json | 2 +- packages/models/CHANGELOG.md | 10 +++++ packages/models/package.json | 2 +- packages/omni-core/CHANGELOG.md | 9 ++++ packages/omni-core/package.json | 2 +- packages/rest-typings/CHANGELOG.md | 9 ++++ packages/rest-typings/package.json | 2 +- packages/ui-avatar/CHANGELOG.md | 9 ++++ packages/ui-avatar/package.json | 2 +- packages/ui-client/CHANGELOG.md | 10 +++++ packages/ui-client/package.json | 2 +- packages/ui-contexts/CHANGELOG.md | 11 +++++ packages/ui-contexts/package.json | 2 +- packages/ui-video-conf/CHANGELOG.md | 10 +++++ packages/ui-video-conf/package.json | 2 +- packages/ui-voip/CHANGELOG.md | 12 ++++++ packages/ui-voip/package.json | 2 +- packages/web-ui-registration/CHANGELOG.md | 9 ++++ packages/web-ui-registration/package.json | 4 +- 84 files changed, 520 insertions(+), 43 deletions(-) create mode 100644 .changeset/bump-patch-1767191875055.md diff --git a/.changeset/bump-patch-1767191875055.md b/.changeset/bump-patch-1767191875055.md new file mode 100644 index 0000000000000..e1eaa7980afb1 --- /dev/null +++ b/.changeset/bump-patch-1767191875055.md @@ -0,0 +1,5 @@ +--- +'@rocket.chat/meteor': patch +--- + +Bump @rocket.chat/meteor version. diff --git a/.changeset/pre.json b/.changeset/pre.json index ff78be3fb84cc..56e36d7dadeff 100644 --- a/.changeset/pre.json +++ b/.changeset/pre.json @@ -85,6 +85,7 @@ "brown-carrots-bathe", "brown-llamas-worry", "bump-patch-1766456337926", + "bump-patch-1767191875055", "chatty-dingos-bathe", "chatty-lizards-reflect", "chatty-roses-help", @@ -124,6 +125,7 @@ "large-planes-destroy", "lazy-pianos-care", "lemon-garlics-check", + "long-swans-sin", "loud-elephants-happen", "many-walls-cheat", "many-walls-impress", diff --git a/apps/meteor/CHANGELOG.md b/apps/meteor/CHANGELOG.md index 25c87769347a2..2aeeb16944e00 100644 --- a/apps/meteor/CHANGELOG.md +++ b/apps/meteor/CHANGELOG.md @@ -1,5 +1,48 @@ # @rocket.chat/meteor +## 8.0.0-rc.2 + +### Patch Changes + +- Bump @rocket.chat/meteor version. + +- ([#38007](https://github.com/RocketChat/Rocket.Chat/pull/38007)) Changes the HTTP code of `/api/v1/method.call` and `/api/v1/method.callAnon` in case of internal errors + +-
    Updated dependencies []: + + - @rocket.chat/core-typings@8.0.0-rc.2 + - @rocket.chat/rest-typings@8.0.0-rc.2 + - @rocket.chat/abac@0.1.0-rc.2 + - @rocket.chat/federation-matrix@0.0.9-rc.2 + - @rocket.chat/license@1.1.7-rc.2 + - @rocket.chat/media-calls@0.2.0-rc.2 + - @rocket.chat/omnichannel-services@0.3.44-rc.2 + - @rocket.chat/pdf-worker@0.3.26-rc.2 + - @rocket.chat/presence@0.2.47-rc.2 + - @rocket.chat/api-client@0.2.47-rc.2 + - @rocket.chat/apps@0.6.0-rc.2 + - @rocket.chat/core-services@0.12.0-rc.2 + - @rocket.chat/cron@0.1.47-rc.2 + - @rocket.chat/fuselage-ui-kit@26.0.0-rc.2 + - @rocket.chat/gazzodown@26.0.0-rc.2 + - @rocket.chat/http-router@7.9.14-rc.2 + - @rocket.chat/message-types@0.1.0-rc.0 + - @rocket.chat/model-typings@2.0.0-rc.2 + - @rocket.chat/ui-avatar@22.0.0-rc.2 + - @rocket.chat/ui-client@26.0.0-rc.2 + - @rocket.chat/ui-contexts@26.0.0-rc.2 + - @rocket.chat/ui-voip@16.0.0-rc.2 + - @rocket.chat/web-ui-registration@26.0.0-rc.2 + - @rocket.chat/models@2.0.0-rc.2 + - @rocket.chat/server-cloud-communication@0.0.2 + - @rocket.chat/network-broker@0.2.26-rc.2 + - @rocket.chat/omni-core-ee@0.0.12-rc.2 + - @rocket.chat/ui-theming@0.4.4 + - @rocket.chat/ui-video-conf@26.0.0-rc.2 + - @rocket.chat/instance-status@0.1.47-rc.2 + - @rocket.chat/omni-core@0.0.12-rc.2 +
    + ## 8.0.0-rc.1 ### Patch Changes diff --git a/apps/meteor/app/utils/rocketchat.info b/apps/meteor/app/utils/rocketchat.info index 50842259a0b86..0e9b47493f9f4 100644 --- a/apps/meteor/app/utils/rocketchat.info +++ b/apps/meteor/app/utils/rocketchat.info @@ -1,3 +1,3 @@ { - "version": "8.0.0-rc.1" + "version": "8.0.0-rc.2" } diff --git a/apps/meteor/ee/server/services/CHANGELOG.md b/apps/meteor/ee/server/services/CHANGELOG.md index 45d2e642aa946..356c6d20aecbf 100644 --- a/apps/meteor/ee/server/services/CHANGELOG.md +++ b/apps/meteor/ee/server/services/CHANGELOG.md @@ -1,5 +1,19 @@ # rocketchat-services +## 2.0.38-rc.2 + +### Patch Changes + +-
    Updated dependencies []: + + - @rocket.chat/core-typings@8.0.0-rc.2 + - @rocket.chat/rest-typings@8.0.0-rc.2 + - @rocket.chat/core-services@0.12.0-rc.2 + - @rocket.chat/model-typings@2.0.0-rc.2 + - @rocket.chat/models@2.0.0-rc.2 + - @rocket.chat/network-broker@0.2.26-rc.2 +
    + ## 2.0.38-rc.1 ### Patch Changes diff --git a/apps/meteor/ee/server/services/package.json b/apps/meteor/ee/server/services/package.json index 77079b4f740e9..bb21627489921 100644 --- a/apps/meteor/ee/server/services/package.json +++ b/apps/meteor/ee/server/services/package.json @@ -1,7 +1,7 @@ { "name": "rocketchat-services", "private": true, - "version": "2.0.38-rc.1", + "version": "2.0.38-rc.2", "description": "Rocket.Chat Authorization service", "main": "index.js", "scripts": { diff --git a/apps/meteor/package.json b/apps/meteor/package.json index becbf6c9534d1..1ad5b2ff1f9ae 100644 --- a/apps/meteor/package.json +++ b/apps/meteor/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/meteor", - "version": "8.0.0-rc.1", + "version": "8.0.0-rc.2", "private": true, "description": "The Ultimate Open Source WebChat Platform", "keywords": [ diff --git a/apps/uikit-playground/CHANGELOG.md b/apps/uikit-playground/CHANGELOG.md index 208e9c7a376ce..690e4d856681b 100644 --- a/apps/uikit-playground/CHANGELOG.md +++ b/apps/uikit-playground/CHANGELOG.md @@ -1,5 +1,17 @@ # @rocket.chat/uikit-playground +## 0.7.3-rc.2 + +### Patch Changes + +-
    Updated dependencies []: + + - @rocket.chat/core-typings@8.0.0-rc.2 + - @rocket.chat/fuselage-ui-kit@26.0.0-rc.2 + - @rocket.chat/ui-avatar@22.0.0-rc.2 + - @rocket.chat/ui-contexts@26.0.0-rc.2 +
    + ## 0.7.3-rc.1 ### Patch Changes diff --git a/apps/uikit-playground/package.json b/apps/uikit-playground/package.json index cbb2ad3d98259..6afaa44eca7cc 100644 --- a/apps/uikit-playground/package.json +++ b/apps/uikit-playground/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/uikit-playground", - "version": "0.7.3-rc.1", + "version": "0.7.3-rc.2", "private": true, "type": "module", "scripts": { diff --git a/ee/apps/account-service/CHANGELOG.md b/ee/apps/account-service/CHANGELOG.md index a30fb872de6eb..b78ec4e41daa6 100644 --- a/ee/apps/account-service/CHANGELOG.md +++ b/ee/apps/account-service/CHANGELOG.md @@ -1,5 +1,19 @@ # @rocket.chat/account-service +## 0.4.47-rc.2 + +### Patch Changes + +-
    Updated dependencies []: + + - @rocket.chat/core-typings@8.0.0-rc.2 + - @rocket.chat/rest-typings@8.0.0-rc.2 + - @rocket.chat/core-services@0.12.0-rc.2 + - @rocket.chat/model-typings@2.0.0-rc.2 + - @rocket.chat/models@2.0.0-rc.2 + - @rocket.chat/network-broker@0.2.26-rc.2 +
    + ## 0.4.47-rc.1 ### Patch Changes diff --git a/ee/apps/account-service/package.json b/ee/apps/account-service/package.json index d93c8c56b0aa3..f681cb129adb0 100644 --- a/ee/apps/account-service/package.json +++ b/ee/apps/account-service/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/account-service", - "version": "0.4.47-rc.1", + "version": "0.4.47-rc.2", "private": true, "description": "Rocket.Chat Account service", "keywords": [ diff --git a/ee/apps/authorization-service/CHANGELOG.md b/ee/apps/authorization-service/CHANGELOG.md index c5cf4a0666f20..419bd983fc401 100644 --- a/ee/apps/authorization-service/CHANGELOG.md +++ b/ee/apps/authorization-service/CHANGELOG.md @@ -1,5 +1,20 @@ # @rocket.chat/authorization-service +## 0.5.0-rc.2 + +### Patch Changes + +-
    Updated dependencies []: + + - @rocket.chat/core-typings@8.0.0-rc.2 + - @rocket.chat/rest-typings@8.0.0-rc.2 + - @rocket.chat/abac@0.1.0-rc.2 + - @rocket.chat/core-services@0.12.0-rc.2 + - @rocket.chat/model-typings@2.0.0-rc.2 + - @rocket.chat/models@2.0.0-rc.2 + - @rocket.chat/network-broker@0.2.26-rc.2 +
    + ## 0.5.0-rc.1 ### Patch Changes diff --git a/ee/apps/authorization-service/package.json b/ee/apps/authorization-service/package.json index bd620d39f91a4..72c5c6aee4798 100644 --- a/ee/apps/authorization-service/package.json +++ b/ee/apps/authorization-service/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/authorization-service", - "version": "0.5.0-rc.1", + "version": "0.5.0-rc.2", "private": true, "description": "Rocket.Chat Authorization service", "keywords": [ diff --git a/ee/apps/ddp-streamer/CHANGELOG.md b/ee/apps/ddp-streamer/CHANGELOG.md index e2a286269ea3a..227a65b1dcc84 100644 --- a/ee/apps/ddp-streamer/CHANGELOG.md +++ b/ee/apps/ddp-streamer/CHANGELOG.md @@ -1,5 +1,20 @@ # @rocket.chat/ddp-streamer +## 0.3.47-rc.2 + +### Patch Changes + +-
    Updated dependencies []: + + - @rocket.chat/core-typings@8.0.0-rc.2 + - @rocket.chat/rest-typings@8.0.0-rc.2 + - @rocket.chat/core-services@0.12.0-rc.2 + - @rocket.chat/model-typings@2.0.0-rc.2 + - @rocket.chat/models@2.0.0-rc.2 + - @rocket.chat/network-broker@0.2.26-rc.2 + - @rocket.chat/instance-status@0.1.47-rc.2 +
    + ## 0.3.47-rc.1 ### Patch Changes diff --git a/ee/apps/ddp-streamer/package.json b/ee/apps/ddp-streamer/package.json index 30772ac0cf1ce..90bbc95012c66 100644 --- a/ee/apps/ddp-streamer/package.json +++ b/ee/apps/ddp-streamer/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/ddp-streamer", - "version": "0.3.47-rc.1", + "version": "0.3.47-rc.2", "private": true, "description": "Rocket.Chat DDP-Streamer service", "keywords": [ diff --git a/ee/apps/omnichannel-transcript/CHANGELOG.md b/ee/apps/omnichannel-transcript/CHANGELOG.md index 84bfcfdd22fb7..0ffd25e478df4 100644 --- a/ee/apps/omnichannel-transcript/CHANGELOG.md +++ b/ee/apps/omnichannel-transcript/CHANGELOG.md @@ -1,5 +1,20 @@ # @rocket.chat/omnichannel-transcript +## 0.4.47-rc.2 + +### Patch Changes + +-
    Updated dependencies []: + + - @rocket.chat/core-typings@8.0.0-rc.2 + - @rocket.chat/omnichannel-services@0.3.44-rc.2 + - @rocket.chat/pdf-worker@0.3.26-rc.2 + - @rocket.chat/core-services@0.12.0-rc.2 + - @rocket.chat/model-typings@2.0.0-rc.2 + - @rocket.chat/models@2.0.0-rc.2 + - @rocket.chat/network-broker@0.2.26-rc.2 +
    + ## 0.4.47-rc.1 ### Patch Changes diff --git a/ee/apps/omnichannel-transcript/package.json b/ee/apps/omnichannel-transcript/package.json index 702a294f40228..1491211aef0de 100644 --- a/ee/apps/omnichannel-transcript/package.json +++ b/ee/apps/omnichannel-transcript/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/omnichannel-transcript", - "version": "0.4.47-rc.1", + "version": "0.4.47-rc.2", "private": true, "description": "Rocket.Chat service", "keywords": [ diff --git a/ee/apps/presence-service/CHANGELOG.md b/ee/apps/presence-service/CHANGELOG.md index b72470a2626db..b30b11fee1ed1 100644 --- a/ee/apps/presence-service/CHANGELOG.md +++ b/ee/apps/presence-service/CHANGELOG.md @@ -1,5 +1,19 @@ # @rocket.chat/presence-service +## 0.4.47-rc.2 + +### Patch Changes + +-
    Updated dependencies []: + + - @rocket.chat/core-typings@8.0.0-rc.2 + - @rocket.chat/presence@0.2.47-rc.2 + - @rocket.chat/core-services@0.12.0-rc.2 + - @rocket.chat/model-typings@2.0.0-rc.2 + - @rocket.chat/models@2.0.0-rc.2 + - @rocket.chat/network-broker@0.2.26-rc.2 +
    + ## 0.4.47-rc.1 ### Patch Changes diff --git a/ee/apps/presence-service/package.json b/ee/apps/presence-service/package.json index 7ea3b8add7a5d..3c45a08368d0f 100644 --- a/ee/apps/presence-service/package.json +++ b/ee/apps/presence-service/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/presence-service", - "version": "0.4.47-rc.1", + "version": "0.4.47-rc.2", "private": true, "description": "Rocket.Chat Presence service", "keywords": [ diff --git a/ee/apps/queue-worker/CHANGELOG.md b/ee/apps/queue-worker/CHANGELOG.md index 9e7af4c9603e9..4794655719d25 100644 --- a/ee/apps/queue-worker/CHANGELOG.md +++ b/ee/apps/queue-worker/CHANGELOG.md @@ -1,5 +1,19 @@ # @rocket.chat/queue-worker +## 0.4.47-rc.2 + +### Patch Changes + +-
    Updated dependencies []: + + - @rocket.chat/core-typings@8.0.0-rc.2 + - @rocket.chat/omnichannel-services@0.3.44-rc.2 + - @rocket.chat/core-services@0.12.0-rc.2 + - @rocket.chat/model-typings@2.0.0-rc.2 + - @rocket.chat/models@2.0.0-rc.2 + - @rocket.chat/network-broker@0.2.26-rc.2 +
    + ## 0.4.47-rc.1 ### Patch Changes diff --git a/ee/apps/queue-worker/package.json b/ee/apps/queue-worker/package.json index 772e55e97b952..86bf52be1b9a3 100644 --- a/ee/apps/queue-worker/package.json +++ b/ee/apps/queue-worker/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/queue-worker", - "version": "0.4.47-rc.1", + "version": "0.4.47-rc.2", "private": true, "description": "Rocket.Chat service", "keywords": [ diff --git a/ee/packages/abac/CHANGELOG.md b/ee/packages/abac/CHANGELOG.md index bb6271b59268d..2ae084f88645c 100644 --- a/ee/packages/abac/CHANGELOG.md +++ b/ee/packages/abac/CHANGELOG.md @@ -1,5 +1,16 @@ # @rocket.chat/abac +## 0.1.0-rc.2 + +### Patch Changes + +-
    Updated dependencies []: + + - @rocket.chat/core-typings@8.0.0-rc.2 + - @rocket.chat/core-services@0.12.0-rc.2 + - @rocket.chat/models@2.0.0-rc.2 +
    + ## 0.1.0-rc.1 ### Patch Changes diff --git a/ee/packages/abac/package.json b/ee/packages/abac/package.json index fa9ecf8ab89e1..266410f81432b 100644 --- a/ee/packages/abac/package.json +++ b/ee/packages/abac/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/abac", - "version": "0.1.0-rc.1", + "version": "0.1.0-rc.2", "private": true, "description": "Rocket.Chat - Attribute Based Access Control (ABAC) support utilities", "main": "./dist/index.js", diff --git a/ee/packages/federation-matrix/CHANGELOG.md b/ee/packages/federation-matrix/CHANGELOG.md index b275ab755fae2..7eda68455f3ac 100644 --- a/ee/packages/federation-matrix/CHANGELOG.md +++ b/ee/packages/federation-matrix/CHANGELOG.md @@ -1,5 +1,20 @@ # @rocket.chat/federation-matrix +## 0.0.9-rc.2 + +### Patch Changes + +-
    Updated dependencies []: + + - @rocket.chat/core-typings@8.0.0-rc.2 + - @rocket.chat/rest-typings@8.0.0-rc.2 + - @rocket.chat/license@1.1.7-rc.2 + - @rocket.chat/core-services@0.12.0-rc.2 + - @rocket.chat/http-router@7.9.14-rc.2 + - @rocket.chat/models@2.0.0-rc.2 + - @rocket.chat/network-broker@0.2.26-rc.2 +
    + ## 0.0.9-rc.1 ### Patch Changes diff --git a/ee/packages/federation-matrix/package.json b/ee/packages/federation-matrix/package.json index acc9e6ea10e8f..c136f73b4dab1 100644 --- a/ee/packages/federation-matrix/package.json +++ b/ee/packages/federation-matrix/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/federation-matrix", - "version": "0.0.9-rc.1", + "version": "0.0.9-rc.2", "private": true, "main": "./dist/index.js", "typings": "./dist/index.d.ts", diff --git a/ee/packages/license/CHANGELOG.md b/ee/packages/license/CHANGELOG.md index 184c3fc11fda4..f684e9a7180f2 100644 --- a/ee/packages/license/CHANGELOG.md +++ b/ee/packages/license/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/license +## 1.1.7-rc.2 + +### Patch Changes + +-
    Updated dependencies []: + + - @rocket.chat/core-typings@8.0.0-rc.2 +
    + ## 1.1.7-rc.1 ### Patch Changes diff --git a/ee/packages/license/package.json b/ee/packages/license/package.json index a57713c1d9f4d..cdafc7b5a85ab 100644 --- a/ee/packages/license/package.json +++ b/ee/packages/license/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/license", - "version": "1.1.7-rc.1", + "version": "1.1.7-rc.2", "private": true, "main": "./dist/index.js", "typings": "./dist/index.d.ts", diff --git a/ee/packages/media-calls/CHANGELOG.md b/ee/packages/media-calls/CHANGELOG.md index 1315118d6a491..963f4e7c644b8 100644 --- a/ee/packages/media-calls/CHANGELOG.md +++ b/ee/packages/media-calls/CHANGELOG.md @@ -1,5 +1,15 @@ # @rocket.chat/media-calls +## 0.2.0-rc.2 + +### Patch Changes + +-
    Updated dependencies []: + + - @rocket.chat/core-typings@8.0.0-rc.2 + - @rocket.chat/models@2.0.0-rc.2 +
    + ## 0.2.0-rc.1 ### Patch Changes diff --git a/ee/packages/media-calls/package.json b/ee/packages/media-calls/package.json index c932e3f4724a6..ee42736a37686 100644 --- a/ee/packages/media-calls/package.json +++ b/ee/packages/media-calls/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/media-calls", - "version": "0.2.0-rc.1", + "version": "0.2.0-rc.2", "private": true, "main": "./dist/index.js", "typings": "./dist/index.d.ts", diff --git a/ee/packages/network-broker/CHANGELOG.md b/ee/packages/network-broker/CHANGELOG.md index 36697a7c63888..fd97d8f1acc1e 100644 --- a/ee/packages/network-broker/CHANGELOG.md +++ b/ee/packages/network-broker/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/network-broker +## 0.2.26-rc.2 + +### Patch Changes + +-
    Updated dependencies []: + + - @rocket.chat/core-services@0.12.0-rc.2 +
    + ## 0.2.26-rc.1 ### Patch Changes diff --git a/ee/packages/network-broker/package.json b/ee/packages/network-broker/package.json index fa4e529accda4..15f7f38a5cb02 100644 --- a/ee/packages/network-broker/package.json +++ b/ee/packages/network-broker/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/network-broker", - "version": "0.2.26-rc.1", + "version": "0.2.26-rc.2", "private": true, "main": "./dist/index.js", "typings": "./dist/index.d.ts", diff --git a/ee/packages/omni-core-ee/CHANGELOG.md b/ee/packages/omni-core-ee/CHANGELOG.md index 660b0b6a021e5..d295b7e7f1454 100644 --- a/ee/packages/omni-core-ee/CHANGELOG.md +++ b/ee/packages/omni-core-ee/CHANGELOG.md @@ -1,5 +1,16 @@ # @rocket.chat/omni-core-ee +## 0.0.12-rc.2 + +### Patch Changes + +-
    Updated dependencies []: + + - @rocket.chat/core-services@0.12.0-rc.2 + - @rocket.chat/models@2.0.0-rc.2 + - @rocket.chat/omni-core@0.0.12-rc.2 +
    + ## 0.0.12-rc.1 ### Patch Changes diff --git a/ee/packages/omni-core-ee/package.json b/ee/packages/omni-core-ee/package.json index 7ceb92c54d816..f6e9302dc0769 100644 --- a/ee/packages/omni-core-ee/package.json +++ b/ee/packages/omni-core-ee/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/omni-core-ee", - "version": "0.0.12-rc.1", + "version": "0.0.12-rc.2", "private": true, "main": "./dist/index.js", "typings": "./dist/index.d.ts", diff --git a/ee/packages/omnichannel-services/CHANGELOG.md b/ee/packages/omnichannel-services/CHANGELOG.md index 556eda9bc5de6..b8d74a1542dc7 100644 --- a/ee/packages/omnichannel-services/CHANGELOG.md +++ b/ee/packages/omnichannel-services/CHANGELOG.md @@ -1,5 +1,20 @@ # @rocket.chat/omnichannel-services +## 0.3.44-rc.2 + +### Patch Changes + +-
    Updated dependencies []: + + - @rocket.chat/core-typings@8.0.0-rc.2 + - @rocket.chat/rest-typings@8.0.0-rc.2 + - @rocket.chat/pdf-worker@0.3.26-rc.2 + - @rocket.chat/core-services@0.12.0-rc.2 + - @rocket.chat/message-types@0.1.0-rc.0 + - @rocket.chat/model-typings@2.0.0-rc.2 + - @rocket.chat/models@2.0.0-rc.2 +
    + ## 0.3.44-rc.1 ### Patch Changes diff --git a/ee/packages/omnichannel-services/package.json b/ee/packages/omnichannel-services/package.json index a3948a319c52e..9a40258aa1e88 100644 --- a/ee/packages/omnichannel-services/package.json +++ b/ee/packages/omnichannel-services/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/omnichannel-services", - "version": "0.3.44-rc.1", + "version": "0.3.44-rc.2", "private": true, "main": "./dist/index.js", "typings": "./dist/index.d.ts", diff --git a/ee/packages/pdf-worker/CHANGELOG.md b/ee/packages/pdf-worker/CHANGELOG.md index b1b6d3ddf69e5..1f96158684ddd 100644 --- a/ee/packages/pdf-worker/CHANGELOG.md +++ b/ee/packages/pdf-worker/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/pdf-worker +## 0.3.26-rc.2 + +### Patch Changes + +-
    Updated dependencies []: + + - @rocket.chat/core-typings@8.0.0-rc.2 +
    + ## 0.3.26-rc.1 ### Patch Changes diff --git a/ee/packages/pdf-worker/package.json b/ee/packages/pdf-worker/package.json index 37386e607b7e3..7fae762a1e8a1 100644 --- a/ee/packages/pdf-worker/package.json +++ b/ee/packages/pdf-worker/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/pdf-worker", - "version": "0.3.26-rc.1", + "version": "0.3.26-rc.2", "private": true, "main": "./dist/index.js", "typings": "./dist/index.d.ts", diff --git a/ee/packages/presence/CHANGELOG.md b/ee/packages/presence/CHANGELOG.md index d0ae7e9b049d9..6f402ecf4c443 100644 --- a/ee/packages/presence/CHANGELOG.md +++ b/ee/packages/presence/CHANGELOG.md @@ -1,5 +1,16 @@ # @rocket.chat/presence +## 0.2.47-rc.2 + +### Patch Changes + +-
    Updated dependencies []: + + - @rocket.chat/core-typings@8.0.0-rc.2 + - @rocket.chat/core-services@0.12.0-rc.2 + - @rocket.chat/models@2.0.0-rc.2 +
    + ## 0.2.47-rc.1 ### Patch Changes diff --git a/ee/packages/presence/package.json b/ee/packages/presence/package.json index a736aa031f4e3..472d955658e8d 100644 --- a/ee/packages/presence/package.json +++ b/ee/packages/presence/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/presence", - "version": "0.2.47-rc.1", + "version": "0.2.47-rc.2", "private": true, "main": "./dist/Presence.js", "typings": "./dist/Presence.d.ts", diff --git a/package.json b/package.json index e5797ee34931e..d8d1e5ff40686 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "rocket.chat", - "version": "8.0.0-rc.1", + "version": "8.0.0-rc.2", "private": true, "description": "Rocket.Chat Monorepo", "homepage": "https://github.com/RocketChat/Rocket.Chat#readme", diff --git a/packages/api-client/CHANGELOG.md b/packages/api-client/CHANGELOG.md index 6fa3b648c549c..fb8b00882e688 100644 --- a/packages/api-client/CHANGELOG.md +++ b/packages/api-client/CHANGELOG.md @@ -1,5 +1,15 @@ # @rocket.chat/api-client +## 0.2.47-rc.2 + +### Patch Changes + +-
    Updated dependencies []: + + - @rocket.chat/core-typings@8.0.0-rc.2 + - @rocket.chat/rest-typings@8.0.0-rc.2 +
    + ## 0.2.47-rc.1 ### Patch Changes diff --git a/packages/api-client/package.json b/packages/api-client/package.json index d091bd58e7937..a5b734e6471d9 100644 --- a/packages/api-client/package.json +++ b/packages/api-client/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/api-client", - "version": "0.2.47-rc.1", + "version": "0.2.47-rc.2", "main": "./dist/index.js", "typings": "./dist/index.d.ts", "files": [ diff --git a/packages/apps/CHANGELOG.md b/packages/apps/CHANGELOG.md index 646f38ea4f01e..d8d2f6a48805e 100644 --- a/packages/apps/CHANGELOG.md +++ b/packages/apps/CHANGELOG.md @@ -1,5 +1,15 @@ # @rocket.chat/apps +## 0.6.0-rc.2 + +### Patch Changes + +-
    Updated dependencies []: + + - @rocket.chat/core-typings@8.0.0-rc.2 + - @rocket.chat/model-typings@2.0.0-rc.2 +
    + ## 0.6.0-rc.1 ### Patch Changes diff --git a/packages/apps/package.json b/packages/apps/package.json index 9d5899e8e923b..4a5c0b54466ab 100644 --- a/packages/apps/package.json +++ b/packages/apps/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/apps", - "version": "0.6.0-rc.1", + "version": "0.6.0-rc.2", "private": true, "main": "./dist/index.js", "typings": "./dist/index.d.ts", diff --git a/packages/core-services/CHANGELOG.md b/packages/core-services/CHANGELOG.md index 6e95032802ab0..36715815f00e1 100644 --- a/packages/core-services/CHANGELOG.md +++ b/packages/core-services/CHANGELOG.md @@ -1,5 +1,17 @@ # @rocket.chat/core-services +## 0.12.0-rc.2 + +### Patch Changes + +-
    Updated dependencies []: + + - @rocket.chat/core-typings@8.0.0-rc.2 + - @rocket.chat/rest-typings@8.0.0-rc.2 + - @rocket.chat/http-router@7.9.14-rc.2 + - @rocket.chat/models@2.0.0-rc.2 +
    + ## 0.12.0-rc.1 ### Patch Changes diff --git a/packages/core-services/package.json b/packages/core-services/package.json index 14ffb332a09c7..f312783063eea 100644 --- a/packages/core-services/package.json +++ b/packages/core-services/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/core-services", - "version": "0.12.0-rc.1", + "version": "0.12.0-rc.2", "private": true, "main": "./dist/index.js", "typings": "./dist/index.d.ts", diff --git a/packages/core-typings/CHANGELOG.md b/packages/core-typings/CHANGELOG.md index 9e1f0343b503a..cb1577ccfaa6b 100644 --- a/packages/core-typings/CHANGELOG.md +++ b/packages/core-typings/CHANGELOG.md @@ -1,5 +1,7 @@ # @rocket.chat/core-typings +## 8.0.0-rc.2 + ## 8.0.0-rc.1 ## 8.0.0-rc.0 diff --git a/packages/core-typings/package.json b/packages/core-typings/package.json index e6077970a3916..a29e926e9c64f 100644 --- a/packages/core-typings/package.json +++ b/packages/core-typings/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package", "name": "@rocket.chat/core-typings", - "version": "8.0.0-rc.1", + "version": "8.0.0-rc.2", "private": true, "main": "./dist/index.js", "typings": "./dist/index.d.ts", diff --git a/packages/cron/CHANGELOG.md b/packages/cron/CHANGELOG.md index a4f198ebbdf74..b316f9e0233db 100644 --- a/packages/cron/CHANGELOG.md +++ b/packages/cron/CHANGELOG.md @@ -1,5 +1,15 @@ # @rocket.chat/cron +## 0.1.47-rc.2 + +### Patch Changes + +-
    Updated dependencies []: + + - @rocket.chat/core-typings@8.0.0-rc.2 + - @rocket.chat/models@2.0.0-rc.2 +
    + ## 0.1.47-rc.1 ### Patch Changes diff --git a/packages/cron/package.json b/packages/cron/package.json index e0894e546cac9..1d186f4362aa0 100644 --- a/packages/cron/package.json +++ b/packages/cron/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/cron", - "version": "0.1.47-rc.1", + "version": "0.1.47-rc.2", "private": true, "main": "./dist/index.js", "typings": "./dist/index.d.ts", diff --git a/packages/ddp-client/CHANGELOG.md b/packages/ddp-client/CHANGELOG.md index 7894e5b269294..bd3b502c7712b 100644 --- a/packages/ddp-client/CHANGELOG.md +++ b/packages/ddp-client/CHANGELOG.md @@ -1,5 +1,16 @@ # @rocket.chat/ddp-client +## 1.0.0-rc.2 + +### Patch Changes + +-
    Updated dependencies []: + + - @rocket.chat/core-typings@8.0.0-rc.2 + - @rocket.chat/rest-typings@8.0.0-rc.2 + - @rocket.chat/api-client@0.2.47-rc.2 +
    + ## 1.0.0-rc.1 ### Patch Changes diff --git a/packages/ddp-client/package.json b/packages/ddp-client/package.json index 6a03d9261892d..a4b1c325bb835 100644 --- a/packages/ddp-client/package.json +++ b/packages/ddp-client/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/ddp-client", - "version": "1.0.0-rc.1", + "version": "1.0.0-rc.2", "main": "./dist/index.js", "typings": "./dist/index.d.ts", "files": [ diff --git a/packages/fuselage-ui-kit/CHANGELOG.md b/packages/fuselage-ui-kit/CHANGELOG.md index 46c1ce8bf6764..fa94540bfcac4 100644 --- a/packages/fuselage-ui-kit/CHANGELOG.md +++ b/packages/fuselage-ui-kit/CHANGELOG.md @@ -1,5 +1,18 @@ # Change Log +## 26.0.0-rc.2 + +### Patch Changes + +-
    Updated dependencies []: + + - @rocket.chat/core-typings@8.0.0-rc.2 + - @rocket.chat/gazzodown@26.0.0-rc.2 + - @rocket.chat/ui-avatar@22.0.0-rc.2 + - @rocket.chat/ui-contexts@26.0.0-rc.2 + - @rocket.chat/ui-video-conf@26.0.0-rc.2 +
    + ## 26.0.0-rc.1 ### Patch Changes diff --git a/packages/fuselage-ui-kit/package.json b/packages/fuselage-ui-kit/package.json index f8e10688129c2..61bfe28aed3c8 100644 --- a/packages/fuselage-ui-kit/package.json +++ b/packages/fuselage-ui-kit/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/fuselage-ui-kit", - "version": "26.0.0-rc.1", + "version": "26.0.0-rc.2", "private": true, "description": "UiKit elements for Rocket.Chat Apps built under Fuselage design system", "homepage": "https://rocketchat.github.io/Rocket.Chat.Fuselage/", diff --git a/packages/gazzodown/CHANGELOG.md b/packages/gazzodown/CHANGELOG.md index e9cf7e51842af..b59ef7456594f 100644 --- a/packages/gazzodown/CHANGELOG.md +++ b/packages/gazzodown/CHANGELOG.md @@ -1,5 +1,16 @@ # @rocket.chat/gazzodown +## 26.0.0-rc.2 + +### Patch Changes + +-
    Updated dependencies []: + + - @rocket.chat/core-typings@8.0.0-rc.2 + - @rocket.chat/ui-client@26.0.0-rc.2 + - @rocket.chat/ui-contexts@26.0.0-rc.2 +
    + ## 26.0.0-rc.1 ### Patch Changes diff --git a/packages/gazzodown/package.json b/packages/gazzodown/package.json index 74cff242e1a88..ad9c5d8cc9149 100644 --- a/packages/gazzodown/package.json +++ b/packages/gazzodown/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/gazzodown", - "version": "26.0.0-rc.1", + "version": "26.0.0-rc.2", "private": true, "main": "./dist/index.js", "typings": "./dist/index.d.ts", diff --git a/packages/http-router/CHANGELOG.md b/packages/http-router/CHANGELOG.md index 9da4d379f2059..519677784e08b 100644 --- a/packages/http-router/CHANGELOG.md +++ b/packages/http-router/CHANGELOG.md @@ -1,5 +1,15 @@ # @rocket.chat/http-router +## 7.9.14-rc.2 + +### Patch Changes + +-
    Updated dependencies []: + + - @rocket.chat/core-typings@8.0.0-rc.2 + - @rocket.chat/rest-typings@8.0.0-rc.2 +
    + ## 7.9.14-rc.1 ### Patch Changes diff --git a/packages/http-router/package.json b/packages/http-router/package.json index 0eed19cfd94e8..d66dc830a947e 100644 --- a/packages/http-router/package.json +++ b/packages/http-router/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/http-router", - "version": "7.9.14-rc.1", + "version": "7.9.14-rc.2", "private": true, "main": "./dist/index.js", "typings": "./dist/index.d.ts", diff --git a/packages/instance-status/CHANGELOG.md b/packages/instance-status/CHANGELOG.md index 84253f1f2988c..7c2dfdd254d67 100644 --- a/packages/instance-status/CHANGELOG.md +++ b/packages/instance-status/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/instance-status +## 0.1.47-rc.2 + +### Patch Changes + +-
    Updated dependencies []: + + - @rocket.chat/models@2.0.0-rc.2 +
    + ## 0.1.47-rc.1 ### Patch Changes diff --git a/packages/instance-status/package.json b/packages/instance-status/package.json index 0a2ff93aca87e..0464e4d65d7ce 100644 --- a/packages/instance-status/package.json +++ b/packages/instance-status/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/instance-status", - "version": "0.1.47-rc.1", + "version": "0.1.47-rc.2", "private": true, "main": "./dist/index.js", "typings": "./dist/index.d.ts", diff --git a/packages/livechat/CHANGELOG.md b/packages/livechat/CHANGELOG.md index f255c2d2ff39a..4b94a710304d5 100644 --- a/packages/livechat/CHANGELOG.md +++ b/packages/livechat/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/livechat Change Log +## 2.0.0-rc.2 + +### Patch Changes + +-
    Updated dependencies []: + + - @rocket.chat/gazzodown@26.0.0-rc.2 +
    + ## 2.0.0-rc.1 ### Patch Changes diff --git a/packages/livechat/package.json b/packages/livechat/package.json index dbc2410cd0ccc..47e85aa6c1a8d 100644 --- a/packages/livechat/package.json +++ b/packages/livechat/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/livechat", - "version": "2.0.0-rc.1", + "version": "2.0.0-rc.2", "homepage": "https://rocket.chat", "repository": { "type": "git", diff --git a/packages/mock-providers/CHANGELOG.md b/packages/mock-providers/CHANGELOG.md index 4e63197308139..64cdc4566a664 100644 --- a/packages/mock-providers/CHANGELOG.md +++ b/packages/mock-providers/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/mock-providers +## 0.4.7-rc.2 + +### Patch Changes + +-
    Updated dependencies []: + + - @rocket.chat/ui-contexts@26.0.0-rc.2 +
    + ## 0.4.7-rc.1 ### Patch Changes diff --git a/packages/mock-providers/package.json b/packages/mock-providers/package.json index 23f357fe59084..1ff6ab725745c 100644 --- a/packages/mock-providers/package.json +++ b/packages/mock-providers/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/mock-providers", - "version": "0.4.7-rc.1", + "version": "0.4.7-rc.2", "private": true, "main": "./dist/index.js", "typings": "./dist/index.d.ts", diff --git a/packages/model-typings/CHANGELOG.md b/packages/model-typings/CHANGELOG.md index cf9b027c7e320..214deaacb9927 100644 --- a/packages/model-typings/CHANGELOG.md +++ b/packages/model-typings/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/model-typings +## 2.0.0-rc.2 + +### Patch Changes + +-
    Updated dependencies []: + + - @rocket.chat/core-typings@8.0.0-rc.2 +
    + ## 2.0.0-rc.1 ### Patch Changes diff --git a/packages/model-typings/package.json b/packages/model-typings/package.json index 0a5f5c6aa050a..e11ac59d09dec 100644 --- a/packages/model-typings/package.json +++ b/packages/model-typings/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/model-typings", - "version": "2.0.0-rc.1", + "version": "2.0.0-rc.2", "private": true, "main": "./dist/index.js", "typings": "./dist/index.d.ts", diff --git a/packages/models/CHANGELOG.md b/packages/models/CHANGELOG.md index 10727c7604ed2..03182d888b21a 100644 --- a/packages/models/CHANGELOG.md +++ b/packages/models/CHANGELOG.md @@ -1,5 +1,15 @@ # @rocket.chat/models +## 2.0.0-rc.2 + +### Patch Changes + +-
    Updated dependencies []: + + - @rocket.chat/rest-typings@8.0.0-rc.2 + - @rocket.chat/model-typings@2.0.0-rc.2 +
    + ## 2.0.0-rc.1 ### Patch Changes diff --git a/packages/models/package.json b/packages/models/package.json index 954f69ad3ec4d..4a379cbe91864 100644 --- a/packages/models/package.json +++ b/packages/models/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/models", - "version": "2.0.0-rc.1", + "version": "2.0.0-rc.2", "private": true, "main": "./dist/index.js", "typings": "./dist/index.d.ts", diff --git a/packages/omni-core/CHANGELOG.md b/packages/omni-core/CHANGELOG.md index 10ca77921f6e8..e7e99b01d164d 100644 --- a/packages/omni-core/CHANGELOG.md +++ b/packages/omni-core/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/omni-core +## 0.0.12-rc.2 + +### Patch Changes + +-
    Updated dependencies []: + + - @rocket.chat/models@2.0.0-rc.2 +
    + ## 0.0.12-rc.1 ### Patch Changes diff --git a/packages/omni-core/package.json b/packages/omni-core/package.json index cf98a9bcbf684..be70d1d965cb7 100644 --- a/packages/omni-core/package.json +++ b/packages/omni-core/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/omni-core", - "version": "0.0.12-rc.1", + "version": "0.0.12-rc.2", "private": true, "main": "./dist/index.js", "typings": "./dist/index.d.ts", diff --git a/packages/rest-typings/CHANGELOG.md b/packages/rest-typings/CHANGELOG.md index 06401886dcf6d..68bd0f36afc33 100644 --- a/packages/rest-typings/CHANGELOG.md +++ b/packages/rest-typings/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/rest-typings +## 8.0.0-rc.2 + +### Patch Changes + +-
    Updated dependencies []: + + - @rocket.chat/core-typings@8.0.0-rc.2 +
    + ## 8.0.0-rc.1 ### Patch Changes diff --git a/packages/rest-typings/package.json b/packages/rest-typings/package.json index 3f60c85e7f28c..9f164476dae5a 100644 --- a/packages/rest-typings/package.json +++ b/packages/rest-typings/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/rest-typings", - "version": "8.0.0-rc.1", + "version": "8.0.0-rc.2", "main": "./dist/index.js", "typings": "./dist/index.d.ts", "files": [ diff --git a/packages/ui-avatar/CHANGELOG.md b/packages/ui-avatar/CHANGELOG.md index e50d6d170d44a..405d419425ad1 100644 --- a/packages/ui-avatar/CHANGELOG.md +++ b/packages/ui-avatar/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/ui-avatar +## 22.0.0-rc.2 + +### Patch Changes + +-
    Updated dependencies []: + + - @rocket.chat/ui-contexts@26.0.0-rc.2 +
    + ## 22.0.0-rc.1 ### Patch Changes diff --git a/packages/ui-avatar/package.json b/packages/ui-avatar/package.json index 2478601c09019..49dd25cede66f 100644 --- a/packages/ui-avatar/package.json +++ b/packages/ui-avatar/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/ui-avatar", - "version": "22.0.0-rc.1", + "version": "22.0.0-rc.2", "private": true, "main": "./dist/index.js", "typings": "./dist/index.d.ts", diff --git a/packages/ui-client/CHANGELOG.md b/packages/ui-client/CHANGELOG.md index e3790346f7cee..5dbc67a3fc8db 100644 --- a/packages/ui-client/CHANGELOG.md +++ b/packages/ui-client/CHANGELOG.md @@ -1,5 +1,15 @@ # @rocket.chat/ui-client +## 26.0.0-rc.2 + +### Patch Changes + +-
    Updated dependencies []: + + - @rocket.chat/ui-avatar@22.0.0-rc.2 + - @rocket.chat/ui-contexts@26.0.0-rc.2 +
    + ## 26.0.0-rc.1 ### Patch Changes diff --git a/packages/ui-client/package.json b/packages/ui-client/package.json index 7ff2649a866c3..de7ab8b5562e7 100644 --- a/packages/ui-client/package.json +++ b/packages/ui-client/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/ui-client", - "version": "26.0.0-rc.1", + "version": "26.0.0-rc.2", "private": true, "main": "./dist/index.js", "typings": "./dist/index.d.ts", diff --git a/packages/ui-contexts/CHANGELOG.md b/packages/ui-contexts/CHANGELOG.md index ca477ebbc84bc..ccccdf57ec6a2 100644 --- a/packages/ui-contexts/CHANGELOG.md +++ b/packages/ui-contexts/CHANGELOG.md @@ -1,5 +1,16 @@ # @rocket.chat/ui-contexts +## 26.0.0-rc.2 + +### Patch Changes + +-
    Updated dependencies []: + + - @rocket.chat/core-typings@8.0.0-rc.2 + - @rocket.chat/rest-typings@8.0.0-rc.2 + - @rocket.chat/ddp-client@1.0.0-rc.2 +
    + ## 26.0.0-rc.1 ### Patch Changes diff --git a/packages/ui-contexts/package.json b/packages/ui-contexts/package.json index 44236db910ec5..100f95753b124 100644 --- a/packages/ui-contexts/package.json +++ b/packages/ui-contexts/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/ui-contexts", - "version": "26.0.0-rc.1", + "version": "26.0.0-rc.2", "private": true, "main": "./dist/index.js", "typings": "./dist/index.d.ts", diff --git a/packages/ui-video-conf/CHANGELOG.md b/packages/ui-video-conf/CHANGELOG.md index 5811457284be1..fac6c4daed106 100644 --- a/packages/ui-video-conf/CHANGELOG.md +++ b/packages/ui-video-conf/CHANGELOG.md @@ -1,5 +1,15 @@ # @rocket.chat/ui-video-conf +## 26.0.0-rc.2 + +### Patch Changes + +-
    Updated dependencies []: + + - @rocket.chat/ui-avatar@22.0.0-rc.2 + - @rocket.chat/ui-contexts@26.0.0-rc.2 +
    + ## 26.0.0-rc.1 ### Patch Changes diff --git a/packages/ui-video-conf/package.json b/packages/ui-video-conf/package.json index 9d79c57e70812..1f5a1e3108c6e 100644 --- a/packages/ui-video-conf/package.json +++ b/packages/ui-video-conf/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/ui-video-conf", - "version": "26.0.0-rc.1", + "version": "26.0.0-rc.2", "private": true, "main": "./dist/index.js", "typings": "./dist/index.d.ts", diff --git a/packages/ui-voip/CHANGELOG.md b/packages/ui-voip/CHANGELOG.md index b4b58f1789d9a..0c98f95122420 100644 --- a/packages/ui-voip/CHANGELOG.md +++ b/packages/ui-voip/CHANGELOG.md @@ -1,5 +1,17 @@ # @rocket.chat/ui-voip +## 16.0.0-rc.2 + +### Patch Changes + +-
    Updated dependencies []: + + - @rocket.chat/fuselage-ui-kit@26.0.0-rc.2 + - @rocket.chat/ui-avatar@22.0.0-rc.2 + - @rocket.chat/ui-client@26.0.0-rc.2 + - @rocket.chat/ui-contexts@26.0.0-rc.2 +
    + ## 16.0.0-rc.1 ### Patch Changes diff --git a/packages/ui-voip/package.json b/packages/ui-voip/package.json index 0a9678dc320f7..0242a52c67510 100644 --- a/packages/ui-voip/package.json +++ b/packages/ui-voip/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/ui-voip", - "version": "16.0.0-rc.1", + "version": "16.0.0-rc.2", "private": true, "main": "./dist/index.js", "typings": "./dist/index.d.ts", diff --git a/packages/web-ui-registration/CHANGELOG.md b/packages/web-ui-registration/CHANGELOG.md index 2bffabfb0664d..ff6793e758164 100644 --- a/packages/web-ui-registration/CHANGELOG.md +++ b/packages/web-ui-registration/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/web-ui-registration +## 26.0.0-rc.2 + +### Patch Changes + +-
    Updated dependencies []: + + - @rocket.chat/ui-contexts@26.0.0-rc.2 +
    + ## 26.0.0-rc.1 ### Patch Changes diff --git a/packages/web-ui-registration/package.json b/packages/web-ui-registration/package.json index 799f7e798ac7a..eaf599e257810 100644 --- a/packages/web-ui-registration/package.json +++ b/packages/web-ui-registration/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/web-ui-registration", - "version": "26.0.0-rc.1", + "version": "26.0.0-rc.2", "private": true, "homepage": "https://rocket.chat", "main": "./dist/index.js", @@ -62,7 +62,7 @@ "peerDependencies": { "@rocket.chat/layout": "*", "@rocket.chat/tools": "0.2.4-rc.0", - "@rocket.chat/ui-contexts": "26.0.0-rc.1", + "@rocket.chat/ui-contexts": "26.0.0-rc.2", "@tanstack/react-query": "*", "react": "*", "react-hook-form": "*", From a1f7b9ecb604755f52b526803ac356f21b371ec8 Mon Sep 17 00:00:00 2001 From: Martin Schoeler Date: Fri, 2 Jan 2026 13:04:41 -0300 Subject: [PATCH 26/68] regression(Contact Center): Empty contextual bar when creating a new contact from the omnichannel admin (#38033) --- apps/meteor/client/views/omnichannel/hooks/useContactRoute.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/meteor/client/views/omnichannel/hooks/useContactRoute.ts b/apps/meteor/client/views/omnichannel/hooks/useContactRoute.ts index 867119f7eaa9c..50f25d79a723d 100644 --- a/apps/meteor/client/views/omnichannel/hooks/useContactRoute.ts +++ b/apps/meteor/client/views/omnichannel/hooks/useContactRoute.ts @@ -13,7 +13,8 @@ export const useContactRoute = () => { return; } - if (currentRouteName === 'omnichannel-directory') { + // TODO: Map out all the routes that use this hook and properly handle them + if (currentRouteName === 'omnichannel-directory' || currentRouteName === 'omnichannel-current-chats') { return navigate({ name: currentRouteName, params: { From ae1e2faaeb6f7a086f8affde4c8a81e55e2a0e04 Mon Sep 17 00:00:00 2001 From: Pierre Lehnen <55164754+pierre-lehnen-rc@users.noreply.github.com> Date: Mon, 5 Jan 2026 15:58:00 -0300 Subject: [PATCH 27/68] fix: no ringing timeout on transferred calls (#38025) --- .changeset/violet-cats-lick.md | 5 +++++ packages/media-signaling/src/lib/Call.ts | 5 ++--- 2 files changed, 7 insertions(+), 3 deletions(-) create mode 100644 .changeset/violet-cats-lick.md diff --git a/.changeset/violet-cats-lick.md b/.changeset/violet-cats-lick.md new file mode 100644 index 0000000000000..5e3a68ccaa36a --- /dev/null +++ b/.changeset/violet-cats-lick.md @@ -0,0 +1,5 @@ +--- +'@rocket.chat/media-signaling': patch +--- + +Adds a timeout to ensure transferred calls stop ringing if there's no response from the final user diff --git a/packages/media-signaling/src/lib/Call.ts b/packages/media-signaling/src/lib/Call.ts index d825fadb4e3d5..c6d610422c82c 100644 --- a/packages/media-signaling/src/lib/Call.ts +++ b/packages/media-signaling/src/lib/Call.ts @@ -349,9 +349,8 @@ export class ClientMediaCall implements IClientMediaCall { // Send an ACK so the server knows that this session exists and is reachable this.acknowledge(); - if (this._role === 'callee' || !this.acceptedLocally) { - this.addStateTimeout('pending', TIMEOUT_TO_ACCEPT); - } + // Adds a secondary timeout for all sessions of the call; Won't matter if the original caller session is still active, but is needed for transferred calls. + this.addStateTimeout('pending', TIMEOUT_TO_ACCEPT); // If the call was requested by this specific session, assume we're signed already. if ( From c6ace77b6a182aeb82646e0c88be1a753e0a04bc Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento Date: Tue, 6 Jan 2026 19:55:08 -0300 Subject: [PATCH 28/68] fix(CI): expired enterprise license for rc1 domain (#38051) --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3c36030e2b19b..7d589614476d6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -659,7 +659,7 @@ jobs: working-directory: ./ee/packages/federation-matrix env: ROCKETCHAT_IMAGE: ghcr.io/${{ needs.release-versions.outputs.lowercase-repo }}/rocket.chat:${{ needs.release-versions.outputs.gh-docker-tag }}-amd64 - ENTERPRISE_LICENSE_RC1: ZEuDWcAxkdBZ0iOzn+JIi7Ri0GKPR43hTueeqEEeTjJhzhp1jM7+fA9LiT3aCzU/oJwudwWLFAwqjrtR13axza+Us6lHuAMdfut/1Z6upRWdSgose1LfDP9Nzce6xOVbO3InQonwTQVQJotlYEGRjiry7jn68TSIKhmjMgC6SVYt6v+syEKRgj+r2oT0xNkurQYGGG1AIYHDqGWa1cX0FVd1ddOKU/DNuCJQxH8Rz5aJC2grIKMIzmRVHfBDJAipeTDl6VI28VM5ExEl3w8zDlUk8wCxXawXGCht0A7jZGCd4IQLDNZs/3Zv+nHC4lcDVzjDu+o17vUIEad4m+nhZgGTNlHqkrH3cqEEEPa3bSh8GKBzLmKHB+i0H3dweT9iqGwz56Nue7twyt5yuGq6qYdtrEx0pEKjystU15DUiQxDPqkBL8yRkp5WScsvJIlhiY+4tU6yKI/GAYtU0g+fCYzjzwxXc7tLg5NeY9kiRMdQ+jRytl3ztHGiv5ERhjQKT9ZpUWiCSCmdr8L3njfLLW1e5/AKmXpg00D6HfJvI30xDcoJwmWnCzFvd7KlSbVwNVBlD6KE9+0j6GV1h0JEml1YrpXUxbpEBz5ALdLn2iVPQ3MT5RODRI5yffSX9ikFkwcH360ewU6Zp63WKRkHyfnzE+tsYe96XdaMZowe7Lw= + ENTERPRISE_LICENSE_RC1: ZAikY+LLaal7mT6RNYxpyWEmMQyucrl50/7pYBXqHczc90j+RLwF+T0xuCT2pIpKMC5DxcZ1TtkV6MYJk5whrwmap+mQ0FV+VpILJlL0i4T21K4vMfzZXTWm/pzcAy2fMTUNH+mUA9HTBD6lYYh40KnbGXPAd80VbZk0MO/WbWBm2dOT0YCwfvlRyurRqkDAQrftLaffzCNUsMKk0fh+MKs73UDHZQDp1yvs7WoGpPu5ZVi5mTBOt3ZKVz5KjGfClLwJptFPmW1w6nKelAiJBDPpjcX1ylfjxpnBoixko7uN52zlyaeoAYwfRcdDLnZ8k0Ou6tui/vTQUXjGIjHw2AhMaKwonn4E9LYpuA1KEXt08qJL5J3ZtjSCV1T+A9Z3zFhhLgp5dxP/PPUbxDn/P8XKp7nXM9duIfcCMlnea7V8ixEyCHwwvKQaXVVidcsUGtB8CwS0GlsAEBLOzqMehuQUK2rdQ4WgEz3AYveikeVvSzgBHvyXsxssWAThc0Mht0eEJqdDhUB2QeZ2WmPsaSSD639Z4WgjSUoR0zh8bfqepH+2XRcUryXe2yN+iU+3POzi9wfg0k65MxXT8pBg3PD5RHnR8oflEP0tpZts33JiBhYRxX3MKplAFm4dMuphTsDJTh+e534pT7IPuZF79QSVaLEWZfVVVb7nGFtmMwA= QASE_TESTOPS_JEST_API_TOKEN: ${{ secrets.QASE_TESTOPS_JEST_API_TOKEN }} PR_NUMBER: ${{ github.event.number }} run: yarn test:integration --image "${ROCKETCHAT_IMAGE}" From 9c225b7d696d3f7b573e6442e68354f151ee502f Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento Date: Tue, 6 Jan 2026 19:55:08 -0300 Subject: [PATCH 29/68] fix(CI): expired enterprise license for rc1 domain (#38051) --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 25fe374e8c8e1..5f0d8829ff24f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -625,7 +625,7 @@ jobs: working-directory: ./ee/packages/federation-matrix env: ROCKETCHAT_IMAGE: ghcr.io/${{ needs.release-versions.outputs.lowercase-repo }}/rocket.chat:${{ needs.release-versions.outputs.gh-docker-tag }} - ENTERPRISE_LICENSE_RC1: ${{ secrets.ENTERPRISE_LICENSE_RC1 }} + ENTERPRISE_LICENSE_RC1: ZAikY+LLaal7mT6RNYxpyWEmMQyucrl50/7pYBXqHczc90j+RLwF+T0xuCT2pIpKMC5DxcZ1TtkV6MYJk5whrwmap+mQ0FV+VpILJlL0i4T21K4vMfzZXTWm/pzcAy2fMTUNH+mUA9HTBD6lYYh40KnbGXPAd80VbZk0MO/WbWBm2dOT0YCwfvlRyurRqkDAQrftLaffzCNUsMKk0fh+MKs73UDHZQDp1yvs7WoGpPu5ZVi5mTBOt3ZKVz5KjGfClLwJptFPmW1w6nKelAiJBDPpjcX1ylfjxpnBoixko7uN52zlyaeoAYwfRcdDLnZ8k0Ou6tui/vTQUXjGIjHw2AhMaKwonn4E9LYpuA1KEXt08qJL5J3ZtjSCV1T+A9Z3zFhhLgp5dxP/PPUbxDn/P8XKp7nXM9duIfcCMlnea7V8ixEyCHwwvKQaXVVidcsUGtB8CwS0GlsAEBLOzqMehuQUK2rdQ4WgEz3AYveikeVvSzgBHvyXsxssWAThc0Mht0eEJqdDhUB2QeZ2WmPsaSSD639Z4WgjSUoR0zh8bfqepH+2XRcUryXe2yN+iU+3POzi9wfg0k65MxXT8pBg3PD5RHnR8oflEP0tpZts33JiBhYRxX3MKplAFm4dMuphTsDJTh+e534pT7IPuZF79QSVaLEWZfVVVb7nGFtmMwA= QASE_TESTOPS_JEST_API_TOKEN: ${{ secrets.QASE_TESTOPS_JEST_API_TOKEN }} PR_NUMBER: ${{ github.event.number }} run: yarn test:integration --image "${ROCKETCHAT_IMAGE}" From 5ff2596e28689d16c28186608ec9526d33ea7f26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BAlia=20Jaeger=20Foresti?= <60678893+juliajforesti@users.noreply.github.com> Date: Tue, 6 Jan 2026 22:56:11 -0300 Subject: [PATCH 30/68] test: remove `data-qa-setting-id` locators (#38002) --- .../__snapshots__/SettingToggle.spec.tsx.snap | 3 --- .../settings/Setting/inputs/ActionSettingInput.tsx | 4 ++-- .../settings/Setting/inputs/BooleanSettingInput.tsx | 10 ++-------- .../admin/settings/Setting/inputs/CodeSettingInput.tsx | 3 +-- .../settings/Setting/inputs/ColorSettingInput.tsx | 5 +---- .../admin/settings/Setting/inputs/FontSettingInput.tsx | 3 +-- .../settings/Setting/inputs/GenericSettingInput.tsx | 3 +-- .../admin/settings/Setting/inputs/IntSettingInput.tsx | 3 +-- .../settings/Setting/inputs/LanguageSettingInput.tsx | 3 +-- .../settings/Setting/inputs/LookupSettingInput.tsx | 3 +-- .../Setting/inputs/MultiSelectSettingInput.tsx | 4 ++-- .../settings/Setting/inputs/PasswordSettingInput.tsx | 3 +-- .../settings/Setting/inputs/RangeSettingInput.tsx | 3 +-- .../Setting/inputs/RelativeUrlSettingInput.tsx | 3 +-- .../settings/Setting/inputs/RoomPickSettingInput.tsx | 2 +- .../settings/Setting/inputs/SelectSettingInput.tsx | 3 +-- .../Setting/inputs/SelectTimezoneSettingInput.tsx | 3 +-- .../settings/Setting/inputs/StringSettingInput.tsx | 4 +--- .../settings/Setting/inputs/TimespanSettingInput.tsx | 3 +-- .../__snapshots__/RangeSettingInput.spec.tsx.snap | 1 - apps/meteor/tests/e2e/page-objects/admin-settings.ts | 2 +- .../tests/e2e/page-objects/omnichannel-settings.ts | 2 +- .../e2e/settings-persistence-on-ui-navigation.spec.ts | 9 +++++---- 23 files changed, 28 insertions(+), 54 deletions(-) diff --git a/apps/meteor/client/views/admin/ABAC/ABACSettingTab/__snapshots__/SettingToggle.spec.tsx.snap b/apps/meteor/client/views/admin/ABAC/ABACSettingTab/__snapshots__/SettingToggle.spec.tsx.snap index 7c48a94fb6800..78b091fbbf32f 100644 --- a/apps/meteor/client/views/admin/ABAC/ABACSettingTab/__snapshots__/SettingToggle.spec.tsx.snap +++ b/apps/meteor/client/views/admin/ABAC/ABACSettingTab/__snapshots__/SettingToggle.spec.tsx.snap @@ -31,7 +31,6 @@ exports[`AbacEnabledToggle should be disabled when abac license is not installed diff --git a/apps/meteor/client/views/admin/settings/Setting/inputs/BooleanSettingInput.tsx b/apps/meteor/client/views/admin/settings/Setting/inputs/BooleanSettingInput.tsx index 624150b1709b6..367a8efe5aff7 100644 --- a/apps/meteor/client/views/admin/settings/Setting/inputs/BooleanSettingInput.tsx +++ b/apps/meteor/client/views/admin/settings/Setting/inputs/BooleanSettingInput.tsx @@ -30,14 +30,8 @@ function BooleanSettingInput({ {label} - {hasResetButton && } - + {hasResetButton && } + {hint && {hint}} diff --git a/apps/meteor/client/views/admin/settings/Setting/inputs/CodeSettingInput.tsx b/apps/meteor/client/views/admin/settings/Setting/inputs/CodeSettingInput.tsx index 4302ad165000e..bed4565cf80aa 100644 --- a/apps/meteor/client/views/admin/settings/Setting/inputs/CodeSettingInput.tsx +++ b/apps/meteor/client/views/admin/settings/Setting/inputs/CodeSettingInput.tsx @@ -38,12 +38,11 @@ function CodeSettingInput({ {label} - {hasResetButton && } + {hasResetButton && } {hint && {hint}} {label} - {hasResetButton && } + {hasResetButton && } @@ -61,7 +61,6 @@ function ColorSettingInput({ {editor === 'color' && ( {label} - {hasResetButton && } + {hasResetButton && } {label} - {hasResetButton && } + {hasResetButton && }