diff --git a/apps/meteor/app/lib/server/functions/createRoom.ts b/apps/meteor/app/lib/server/functions/createRoom.ts index b936d30145069..233c6cb9548cc 100644 --- a/apps/meteor/app/lib/server/functions/createRoom.ts +++ b/apps/meteor/app/lib/server/functions/createRoom.ts @@ -136,6 +136,7 @@ export const createRoom = async ( > => { const { teamId, ...optionalExtraData } = roomExtraData || ({} as IRoom); + // TODO: use a shared helper to check whether a user is federated const hasFederatedMembers = members.some((member) => { if (typeof member === 'string') { return member.includes(':') && member.includes('@'); diff --git a/apps/meteor/server/methods/createDirectMessage.ts b/apps/meteor/server/methods/createDirectMessage.ts index ac9a9479a9bce..ffe355f85ed94 100644 --- a/apps/meteor/server/methods/createDirectMessage.ts +++ b/apps/meteor/server/methods/createDirectMessage.ts @@ -42,7 +42,11 @@ export async function createDirectMessage( const users = await Promise.all(usernames.filter((username) => username !== me.username)); const options: Exclude = { creator: me._id }; const roomUsers = excludeSelf ? users : [me, ...users]; - const federated = false; + + // TODO: use a shared helper to check whether a user is federated + // since the DM creation API doesn't tell us if the room is federated (unlike normal channels), + // we're currently inferring it: if any participant has a Matrix-style ID (@user:server), we treat the DM as federated + const hasFederatedMembers = roomUsers.some((user) => typeof user === 'string' && user.includes(':') && user.includes('@')); // allow self-DMs if (roomUsers.length === 1 && roomUsers[0] !== undefined && typeof roomUsers[0] !== 'string' && roomUsers[0]._id !== me._id) { @@ -91,7 +95,7 @@ export async function createDirectMessage( false, undefined, { - federated, + ...(hasFederatedMembers && { federated: true }), }, options, ); 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 3987331816fd1..0927e53620c76 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 @@ -1,4 +1,4 @@ -import type { IMessage } from '@rocket.chat/core-typings'; +import type { IMessage, IUser } from '@rocket.chat/core-typings'; import { createRoom, @@ -8,7 +8,7 @@ import { addUserToRoom, addUserToRoomSlashCommand, } from '../../../../../apps/meteor/tests/data/rooms.helper'; -import { getRequestConfig, createUser } from '../../../../../apps/meteor/tests/data/users.helper'; +import { type IRequestConfig, getRequestConfig, createUser, deleteUser } from '../../../../../apps/meteor/tests/data/users.helper'; import { IS_EE } from '../../../../../apps/meteor/tests/e2e/config/constants'; import { federationConfig } from '../helper/config'; import { createDDPListener } from '../helper/ddp-listener'; @@ -18,8 +18,8 @@ import { SynapseClient } from '../helper/synapse-client'; // import { t } from 'i18next'; (IS_EE ? describe : describe.skip)('Federation', () => { - let rc1AdminRequestConfig: any; - let rc1User1RequestConfig: any; + let rc1AdminRequestConfig: IRequestConfig; + let rc1User1RequestConfig: IRequestConfig; let hs1AdminApp: SynapseClient; let hs1User1App: SynapseClient; @@ -72,6 +72,56 @@ import { SynapseClient } from '../helper/synapse-client'; }); describe('Rooms', () => { + describe('Create direct message rooms', () => { + // Creating a fresh user for this test suite to avoid collisions, + // since DMs are unique for each user pair + let userRequestConfig: IRequestConfig; + let createdUser: IUser; + beforeAll(async () => { + const user = { username: `user-${Date.now()}`, password: '123' }; + createdUser = await createUser(user, rc1AdminRequestConfig); + userRequestConfig = await getRequestConfig(federationConfig.rc1.apiUrl, user.username, user.password); + }); + + afterAll(async () => { + await deleteUser(createdUser, {}, rc1AdminRequestConfig); + }); + + it('It should create a federated room when federated members are added', async () => { + const response = await createRoom({ + type: 'd', + username: federationConfig.hs1.adminMatrixUserId, + config: userRequestConfig, + }); + + expect(response.status).toBe(200); + expect(response.body).toHaveProperty('success', true); + expect(response.body).toHaveProperty('room'); + expect(response.body.room).toHaveProperty('_id'); + expect(response.body.room).toHaveProperty('t', 'd'); + + const roomInfo = await getRoomInfo(response.body.room._id, userRequestConfig); + expect(roomInfo.room).toHaveProperty('federated', true); + }); + + it('It should create a non-federated room when only local members are added', async () => { + const response = await createRoom({ + type: 'd', + username: federationConfig.rc1.additionalUser1.username, + config: userRequestConfig, + }); + + expect(response.status).toBe(200); + expect(response.body).toHaveProperty('success', true); + expect(response.body).toHaveProperty('room'); + expect(response.body.room).toHaveProperty('_id'); + expect(response.body.room).toHaveProperty('t', 'd'); + + const roomInfo = await getRoomInfo(response.body.room._id, userRequestConfig); + expect(roomInfo.room).not.toHaveProperty('federated'); + }); + }); + describe('Create a room on RC as private, explicitly not federated, with federated users in creation modal', () => { describe('Add 1 federated user in the creation modal', () => { it('It should not allow the creation of the room', async () => {