*/ class Listener implements IEventListener { public function __construct( protected Util $util, protected ParticipantService $participantService, protected IUserManager $userManager, protected TalkSession $talkSession, ) { } #[\Override] public function handle(Event $event): void { match (get_class($event)) { BeforeUserJoinedRoomEvent::class => $this->beforeUserJoinedRoomEvent($event), BeforeGuestJoinedRoomEvent::class => $this->beforeGuestJoinedRoomEvent($event), }; } protected function beforeUserJoinedRoomEvent(BeforeUserJoinedRoomEvent $event): void { try { $this->preventUsersWithoutAccessToTheFileFromJoining($event->getRoom(), $event->getUser()->getUID()); $this->addUserAsPersistentParticipant($event->getRoom(), $event->getUser()->getUID()); } catch (UnauthorizedException) { $event->setCancelJoin(true); } } protected function beforeGuestJoinedRoomEvent(BeforeGuestJoinedRoomEvent $event): void { try { $this->preventGuestsFromJoiningIfNotPubliclyAccessible($event->getRoom()); } catch (UnauthorizedException) { $event->setCancelJoin(true); } } /** * Prevents users from joining if they do not have access to the file. * * A user has access to the file if the file is publicly accessible (through * a link share, for example) or if the user has direct access to it. * * A user has direct access to a file if they received the file (or an * ancestor) through a user, group, circle or room share (but not through a * link share, for example), or if they are the owner of such a file. * * This method should be called before a user joins a room. * * @param Room $room * @param string $userId * @throws UnauthorizedException */ protected function preventUsersWithoutAccessToTheFileFromJoining(Room $room, string $userId): void { if ($room->getObjectType() !== 'file') { return; } // If a guest can access the file then any user can too. $shareToken = $this->talkSession->getFileShareTokenForRoom($room->getToken()); if ($shareToken && $this->util->canGuestAccessFile($shareToken)) { return; } $node = $this->util->getAnyNodeOfFileAccessibleByUser($room->getObjectId(), $userId); if ($node === null) { throw new UnauthorizedException('User does not have access to the file'); } } /** * Add user as a persistent participant of a file room. * * Only users with direct access to the file are added as persistent * participants of the room. * * This method should be called before a user joins a room, but only if the * user should be able to join the room. * * @param Room $room * @param string $userId */ protected function addUserAsPersistentParticipant(Room $room, string $userId): void { if ($room->getObjectType() !== 'file') { return; } if ($this->util->getAnyNodeOfFileAccessibleByUser($room->getObjectId(), $userId) === null) { return; } try { $this->participantService->getParticipant($room, $userId, false); } catch (ParticipantNotFoundException $e) { $user = $this->userManager->get($userId); $this->participantService->addUsers($room, [[ 'actorType' => Attendee::ACTOR_USERS, 'actorId' => $userId, 'displayName' => $user ? $user->getDisplayName() : $userId, ]]); } } /** * Prevents guests from joining the room if it is not publicly accessible. * * This method should be called before a guest joins a room. * * @param Room $room * @throws UnauthorizedException */ protected function preventGuestsFromJoiningIfNotPubliclyAccessible(Room $room): void { if ($room->getObjectType() !== 'file') { return; } $shareToken = $this->talkSession->getFileShareTokenForRoom($room->getToken()); if ($shareToken && $this->util->canGuestAccessFile($shareToken)) { return; } throw new UnauthorizedException('Guests are not allowed in this room'); } }