From 23d1fe069a5968a8a04299ccc7b49228548d8853 Mon Sep 17 00:00:00 2001 From: Carlos Rodrigues Date: Wed, 22 Jun 2022 11:40:03 -0300 Subject: [PATCH] [NEW] remove user from matrix room (#25905) * fix: bridge port * feat: leave matrix room when user leaves rocket room * refactor: leave room method * refactor: setup callbacks * fix: add after leave room callback * fix: fix lint and revert hardcoded port * fix: remove dead code * chore: fix lint Co-authored-by: Marcos Defendi --- .../server/application/RoomServiceSender.ts | 22 ++++++++++++++++++- .../server/application/input/RoomSenderDto.ts | 6 +++++ .../server/domain/IFederationBridge.ts | 1 + apps/meteor/app/federation-v2/server/index.ts | 5 +++++ .../server/infrastructure/Factory.ts | 10 +++++++++ .../server/infrastructure/matrix/Bridge.ts | 4 ++++ .../rocket-chat/converters/RoomSender.ts | 13 ++++++++++- .../infrastructure/rocket-chat/hooks/index.ts | 19 ++++++++++++++++ 8 files changed, 78 insertions(+), 2 deletions(-) create mode 100644 apps/meteor/app/federation-v2/server/infrastructure/rocket-chat/hooks/index.ts diff --git a/apps/meteor/app/federation-v2/server/application/RoomServiceSender.ts b/apps/meteor/app/federation-v2/server/application/RoomServiceSender.ts index 8fab7766a6ce..54b9b65ff470 100644 --- a/apps/meteor/app/federation-v2/server/application/RoomServiceSender.ts +++ b/apps/meteor/app/federation-v2/server/application/RoomServiceSender.ts @@ -7,7 +7,11 @@ import { IFederationBridge } from '../domain/IFederationBridge'; import { RocketChatRoomAdapter } from '../infrastructure/rocket-chat/adapters/Room'; import { RocketChatSettingsAdapter } from '../infrastructure/rocket-chat/adapters/Settings'; import { RocketChatUserAdapter } from '../infrastructure/rocket-chat/adapters/User'; -import { FederationCreateDMAndInviteUserDto, FederationRoomSendExternalMessageDto } from './input/RoomSenderDto'; +import { + FederationAfterLeaveRoomDto, + FederationCreateDMAndInviteUserDto, + FederationRoomSendExternalMessageDto, +} from './input/RoomSenderDto'; export class FederationRoomServiceSender { constructor( @@ -80,6 +84,22 @@ export class FederationRoomServiceSender { await this.rocketRoomAdapter.addUserToRoom(federatedRoom, federatedInviteeUser, federatedInviterUser); } + public async leaveRoom(afterLeaveRoomInput: FederationAfterLeaveRoomDto): Promise { + const { internalRoomId, internalUserId } = afterLeaveRoomInput; + + const federatedRoom = await this.rocketRoomAdapter.getFederatedRoomByInternalId(internalRoomId); + if (!federatedRoom) { + return; + } + + const federatedUser = await this.rocketUserAdapter.getFederatedUserByInternalId(internalUserId); + if (!federatedUser) { + return; + } + + await this.bridge.leaveRoom(federatedRoom.externalId, federatedUser.externalId); + } + public async sendMessageFromRocketChat(roomSendExternalMessageInput: FederationRoomSendExternalMessageDto): Promise { const { internalRoomId, internalSenderId, message } = roomSendExternalMessageInput; diff --git a/apps/meteor/app/federation-v2/server/application/input/RoomSenderDto.ts b/apps/meteor/app/federation-v2/server/application/input/RoomSenderDto.ts index 97e4ed5ff89a..ca7193a718bb 100644 --- a/apps/meteor/app/federation-v2/server/application/input/RoomSenderDto.ts +++ b/apps/meteor/app/federation-v2/server/application/input/RoomSenderDto.ts @@ -19,3 +19,9 @@ export class FederationRoomSendExternalMessageDto { message: IMessage; } + +export class FederationAfterLeaveRoomDto { + internalRoomId: string; + + internalUserId: string; +} diff --git a/apps/meteor/app/federation-v2/server/domain/IFederationBridge.ts b/apps/meteor/app/federation-v2/server/domain/IFederationBridge.ts index 019d75039ea3..61ca8cf47aac 100644 --- a/apps/meteor/app/federation-v2/server/domain/IFederationBridge.ts +++ b/apps/meteor/app/federation-v2/server/domain/IFederationBridge.ts @@ -9,6 +9,7 @@ export interface IFederationBridge { sendMessage(externalRoomId: string, externaSenderId: string, text: string): Promise; createUser(username: string, name: string, domain: string): Promise; isUserIdFromTheSameHomeserver(externalUserId: string, domain: string): boolean; + leaveRoom(externalRoomId: string, externalUserId: string): Promise; } export enum EVENT_ORIGIN { diff --git a/apps/meteor/app/federation-v2/server/index.ts b/apps/meteor/app/federation-v2/server/index.ts index 5efd22bc4a30..2852970cde8f 100644 --- a/apps/meteor/app/federation-v2/server/index.ts +++ b/apps/meteor/app/federation-v2/server/index.ts @@ -19,6 +19,7 @@ const federationRoomServiceReceiver = FederationFactory.buildRoomServiceReceiver rocketSettingsAdapter, federation, ); + const federationEventsHandler = FederationFactory.buildEventHandlers(federationRoomServiceReceiver); export const federationRoomServiceSender = FederationFactory.buildRoomServiceSender( @@ -30,8 +31,12 @@ export const federationRoomServiceSender = FederationFactory.buildRoomServiceSen export const runFederation = async (): Promise => { queueInstance.setHandler(federationEventsHandler.handleEvent.bind(federationEventsHandler), FEDERATION_PROCESSING_CONCURRENCY); + await federation.start(); + await rocketSettingsAdapter.onFederationEnabledStatusChanged(federation.onFederationAvailabilityChanged.bind(federation)); + + FederationFactory.setupListeners(federationRoomServiceSender); }; export const stopFederation = async (): Promise => { diff --git a/apps/meteor/app/federation-v2/server/infrastructure/Factory.ts b/apps/meteor/app/federation-v2/server/infrastructure/Factory.ts index e3f00953c8bd..12d238a74d2e 100644 --- a/apps/meteor/app/federation-v2/server/infrastructure/Factory.ts +++ b/apps/meteor/app/federation-v2/server/infrastructure/Factory.ts @@ -1,3 +1,5 @@ +import { IRoom, IUser } from '@rocket.chat/core-typings'; + import { FederationRoomServiceReceiver } from '../application/RoomServiceReceiver'; import { FederationRoomServiceSender } from '../application/RoomServiceSender'; import { MatrixBridge } from './matrix/Bridge'; @@ -9,6 +11,8 @@ import { RocketChatRoomAdapter } from './rocket-chat/adapters/Room'; import { RocketChatSettingsAdapter } from './rocket-chat/adapters/Settings'; import { RocketChatUserAdapter } from './rocket-chat/adapters/User'; import { IFederationBridge } from '../domain/IFederationBridge'; +import { FederationHooks } from './rocket-chat/hooks'; +import { FederationRoomSenderConverter } from './rocket-chat/converters/RoomSender'; export class FederationFactory { public static buildRocketSettingsAdapter(): RocketChatSettingsAdapter { @@ -73,4 +77,10 @@ export class FederationFactory { new MatrixRoomMessageSentHandler(roomServiceReceive), ]; } + + public static setupListeners(roomServiceSender: FederationRoomServiceSender): void { + FederationHooks.afterLeaveRoom(async (user: IUser, room: IRoom) => + roomServiceSender.leaveRoom(FederationRoomSenderConverter.toAfterLeaveRoom(user._id, room._id)), + ); + } } diff --git a/apps/meteor/app/federation-v2/server/infrastructure/matrix/Bridge.ts b/apps/meteor/app/federation-v2/server/infrastructure/matrix/Bridge.ts index fbcbc58d639f..98a3204c7621 100644 --- a/apps/meteor/app/federation-v2/server/infrastructure/matrix/Bridge.ts +++ b/apps/meteor/app/federation-v2/server/infrastructure/matrix/Bridge.ts @@ -132,6 +132,10 @@ export class MatrixBridge implements IFederationBridge { `); } + public async leaveRoom(externalRoomId: string, externalUserId: string): Promise { + await this.bridgeInstance.getIntent(externalUserId).leave(externalRoomId); + } + protected async createInstance(): Promise { bridgeLogger.info('Performing Dynamic Import of matrix-appservice-bridge'); diff --git a/apps/meteor/app/federation-v2/server/infrastructure/rocket-chat/converters/RoomSender.ts b/apps/meteor/app/federation-v2/server/infrastructure/rocket-chat/converters/RoomSender.ts index 7572c0537f02..5e3264e16b2e 100644 --- a/apps/meteor/app/federation-v2/server/infrastructure/rocket-chat/converters/RoomSender.ts +++ b/apps/meteor/app/federation-v2/server/infrastructure/rocket-chat/converters/RoomSender.ts @@ -1,6 +1,10 @@ import { IMessage } from '@rocket.chat/core-typings'; -import { FederationCreateDMAndInviteUserDto, FederationRoomSendExternalMessageDto } from '../../../application/input/RoomSenderDto'; +import { + FederationAfterLeaveRoomDto, + FederationCreateDMAndInviteUserDto, + FederationRoomSendExternalMessageDto, +} from '../../../application/input/RoomSenderDto'; export class FederationRoomSenderConverter { public static toCreateDirectMessageRoomDto( @@ -31,4 +35,11 @@ export class FederationRoomSenderConverter { message, }); } + + public static toAfterLeaveRoom(internalUserId: string, internalRoomId: string): FederationAfterLeaveRoomDto { + return Object.assign(new FederationAfterLeaveRoomDto(), { + internalRoomId, + internalUserId, + }); + } } diff --git a/apps/meteor/app/federation-v2/server/infrastructure/rocket-chat/hooks/index.ts b/apps/meteor/app/federation-v2/server/infrastructure/rocket-chat/hooks/index.ts new file mode 100644 index 000000000000..5c406430c8e7 --- /dev/null +++ b/apps/meteor/app/federation-v2/server/infrastructure/rocket-chat/hooks/index.ts @@ -0,0 +1,19 @@ +import { IRoom, IUser } from '@rocket.chat/core-typings'; + +import { callbacks } from '../../../../../../lib/callbacks'; + +export class FederationHooks { + public static afterLeaveRoom(callback: Function): void { + callbacks.add( + 'afterLeaveRoom', + (user: IUser, room: IRoom | undefined): void => { + if (!room?.federated) { + return; + } + Promise.await(callback(user, room)); + }, + callbacks.priority.HIGH, + 'federation-v2-after-leave-room', + ); + } +}