diff --git a/apps/meteor/app/lib/server/functions/addUserToRoom.ts b/apps/meteor/app/lib/server/functions/addUserToRoom.ts index 70e0746c18cd5..881afb11812c7 100644 --- a/apps/meteor/app/lib/server/functions/addUserToRoom.ts +++ b/apps/meteor/app/lib/server/functions/addUserToRoom.ts @@ -21,7 +21,7 @@ import { notifyOnRoomChangedById, notifyOnSubscriptionChangedById } from '../lib export const addUserToRoom = async ( rid: string, - user: Pick | string, + user: Pick, inviter?: Pick, { skipSystemMessage, @@ -42,7 +42,7 @@ export const addUserToRoom = async ( }); } - const userToBeAdded = typeof user === 'string' ? await Users.findOneByUsername(user.replace('@', '')) : await Users.findOneById(user._id); + const userToBeAdded = await Users.findOneById(user._id); const roomDirectives = roomCoordinator.getRoomDirectives(room.t); if (!userToBeAdded) { diff --git a/apps/meteor/app/lib/server/methods/addUsersToRoom.ts b/apps/meteor/app/lib/server/methods/addUsersToRoom.ts index a78e70baec1cc..30830385b1dcd 100644 --- a/apps/meteor/app/lib/server/methods/addUsersToRoom.ts +++ b/apps/meteor/app/lib/server/methods/addUsersToRoom.ts @@ -1,5 +1,6 @@ import { api } from '@rocket.chat/core-services'; import type { IUser } from '@rocket.chat/core-typings'; +import { isRoomNativeFederated, isUserNativeFederated } from '@rocket.chat/core-typings'; import type { ServerMethods } from '@rocket.chat/ddp-client'; import { Subscriptions, Users, Rooms } from '@rocket.chat/models'; import { Match } from 'meteor/check'; @@ -17,8 +18,13 @@ declare module '@rocket.chat/ddp-client' { } } -const isAFederatedUsername = (username: string) => { - return username.includes('@') && username.includes(':'); +export const sanitizeUsername = (username: string) => { + const isFederatedUsername = username.includes('@') && username.includes(':'); + if (isFederatedUsername) { + return username; + } + + return username.replace(/(^@)|( @)/, ''); }; export const addUsersToRoomMethod = async (userId: string, data: { rid: string; users: string[] }, user?: IUser): Promise => { @@ -82,15 +88,22 @@ export const addUsersToRoomMethod = async (userId: string, data: { rid: string; await Promise.all( data.users.map(async (username) => { - const newUser = await Users.findOneByUsernameIgnoringCase(username); - if (!newUser && !isAFederatedUsername(username)) { - throw new Meteor.Error('error-invalid-username', 'Invalid username', { + const newUser = await Users.findOneByUsernameIgnoringCase(sanitizeUsername(username)); + if (!newUser) { + throw new Meteor.Error('error-user-not-found', 'User not found', { method: 'addUsersToRoom', }); } - const subscription = newUser && (await Subscriptions.findOneByRoomIdAndUserId(data.rid, newUser._id)); + + if (isUserNativeFederated(newUser) && !isRoomNativeFederated(room)) { + throw new Meteor.Error('error-federated-users-in-non-federated-rooms', 'Cannot add federated users to non-federated rooms', { + method: 'addUsersToRoom', + }); + } + + const subscription = await Subscriptions.findOneByRoomIdAndUserId(data.rid, newUser._id); if (!subscription) { - await addUserToRoom(data.rid, newUser || username, user); + await addUserToRoom(data.rid, newUser, user); } else { if (!newUser.username) { return; diff --git a/apps/meteor/app/slashcommands-invite/server/server.ts b/apps/meteor/app/slashcommands-invite/server/server.ts index 06a85301540c1..24ad0484fddcc 100644 --- a/apps/meteor/app/slashcommands-invite/server/server.ts +++ b/apps/meteor/app/slashcommands-invite/server/server.ts @@ -4,7 +4,7 @@ import { Subscriptions, Users } from '@rocket.chat/models'; import { Meteor } from 'meteor/meteor'; import { i18n } from '../../../server/lib/i18n'; -import { addUsersToRoomMethod } from '../../lib/server/methods/addUsersToRoom'; +import { addUsersToRoomMethod, sanitizeUsername } from '../../lib/server/methods/addUsersToRoom'; import { settings } from '../../settings/server'; import { slashCommands } from '../../utils/server/slashCommand'; @@ -17,16 +17,12 @@ slashCommands.add({ callback: async ({ params, message, userId }: SlashCommandCallbackParams<'invite'>): Promise => { const usernames = params .split(/[\s,]/) - .map((username) => username.replace(/(^@)|( @)/, '')) + .map((username) => sanitizeUsername(username)) .filter((a) => a !== ''); if (usernames.length === 0) { return; } - const users = await Users.find({ - username: { - $in: usernames, - }, - }).toArray(); + const users = await Users.findByUsernames(usernames).toArray(); if (users.length === 0) { void api.broadcast('notify.ephemeralMessage', userId, message.rid, { msg: i18n.t('User_doesnt_exist', { @@ -81,7 +77,12 @@ slashCommands.add({ if (typeof error !== 'string') { return; } - if (error === 'cant-invite-for-direct-room') { + + if (error === 'error-federated-users-in-non-federated-rooms') { + void api.broadcast('notify.ephemeralMessage', userId, message.rid, { + msg: i18n.t('You_cannot_add_external_users_to_non_federated_room', { lng: settings.get('Language') || 'en' }), + }); + } else if (error === 'cant-invite-for-direct-room') { void api.broadcast('notify.ephemeralMessage', userId, message.rid, { msg: i18n.t('Cannot_invite_users_to_direct_rooms', { lng: settings.get('Language') || 'en' }), });