Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion lib/Controller/RoomController.php
Original file line number Diff line number Diff line change
Expand Up @@ -1070,7 +1070,7 @@ protected function formatParticipantList(array $participants, bool $includeStatu
* @return DataResponse<Http::STATUS_OK, array{type: int}|array<empty>, array{}>|DataResponse<Http::STATUS_NOT_FOUND|Http::STATUS_NOT_IMPLEMENTED, array<empty>, array{}>|DataResponse<Http::STATUS_BAD_REQUEST, array{error?: string}, array{}>
*
* 200: Participant successfully added
* 400: Adding participant is not possible
* 400: Adding participant is not possible, e.g. when the user is banned (check error attribute of response for detail key)
* 404: User, group or other target to invite was not found
* 501: SIP dial-out is not configured
*/
Expand Down Expand Up @@ -1117,6 +1117,11 @@ public function addParticipantToRoom(string $newParticipant, string $source = 'u
return new DataResponse([], Http::STATUS_NOT_FOUND);
}

//Check if the user is banned
if ($this->banService->isActorBanned($this->room, Attendee::ACTOR_USERS, $newUser->getUID())) {
return new DataResponse(['error' => 'ban'], Http::STATUS_BAD_REQUEST);
}

$participantsToAdd[] = [
'actorType' => Attendee::ACTOR_USERS,
'actorId' => $newUser->getUID(),
Expand Down
3 changes: 3 additions & 0 deletions lib/Listener/AMembershipListener.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
use OCA\Talk\Model\Attendee;
use OCA\Talk\Participant;
use OCA\Talk\Room;
use OCA\Talk\Service\BanService;
use OCA\Talk\Service\ParticipantService;
use OCP\App\IAppManager;
use OCP\EventDispatcher\Event;
Expand All @@ -35,6 +36,8 @@ public function __construct(
protected IAppManager $appManager,
protected IGroupManager $groupManager,
protected ParticipantService $participantService,
protected BanService $banService,
protected LoggerInterface $logger,
) {
}

Expand Down
18 changes: 17 additions & 1 deletion lib/Listener/CircleMembershipListener.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,15 @@
use OCA\Talk\Manager;
use OCA\Talk\Model\Attendee;
use OCA\Talk\Participant;
use OCA\Talk\Service\BanService;
use OCA\Talk\Service\ParticipantService;
use OCP\App\IAppManager;
use OCP\EventDispatcher\Event;
use OCP\IGroupManager;
use OCP\ISession;
use OCP\IUser;
use OCP\IUserManager;
use Psr\Log\LoggerInterface;

class CircleMembershipListener extends AMembershipListener {

Expand All @@ -30,14 +32,18 @@ public function __construct(
IAppManager $appManager,
IGroupManager $groupManager,
ParticipantService $participantService,
BanService $banService,
LoggerInterface $logger,
private IUserManager $userManager,
private ISession $session,
) {
parent::__construct(
$manager,
$appManager,
$groupManager,
$participantService
$participantService,
$banService,
$logger,
);
}

Expand Down Expand Up @@ -101,6 +107,10 @@ protected function addingCircleMemberEvent(AddingCircleMemberEvent $event): void
}

protected function addNewMemberToRooms(array $rooms, Member $member): void {
if (empty($rooms)) {
return;
}

if ($member->getUserType() !== Member::TYPE_USER || $member->getUserId() === '') {
// Not a user?
return;
Expand All @@ -111,7 +121,13 @@ protected function addNewMemberToRooms(array $rooms, Member $member): void {
return;
}

$bannedRoomIds = $this->banService->getBannedRoomsForUserId($user->getUID());
foreach ($rooms as $room) {
if (isset($bannedRoomIds[$room->getId()])) {
$this->logger->warning('User ' . $user->getUID() . ' is banned from conversation ' . $room->getToken() . ' and was skipped while adding them to circle ' . $member->getCircle()->getDisplayName());
continue;
}

try {
$participant = $room->getParticipant($member->getUserId());
if ($participant->getAttendee()->getParticipantType() === Participant::USER_SELF_JOINED) {
Expand Down
10 changes: 10 additions & 0 deletions lib/Listener/GroupMembershipListener.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,17 @@ public function handle(Event $event): void {
protected function addNewMemberToRooms(IGroup $group, IUser $user): void {
$rooms = $this->manager->getRoomsForActor(Attendee::ACTOR_GROUPS, $group->getGID());

if (empty($rooms)) {
return;
}

$bannedRoomIds = $this->banService->getBannedRoomsForUserId($user->getUID());
foreach ($rooms as $room) {
if (isset($bannedRoomIds[$room->getId()])) {
$this->logger->warning('User ' . $user->getUID() . ' is banned from conversation ' . $room->getToken() . ' and was skipped while adding them to group ' . $group->getDisplayName());
continue;
}

try {
$participant = $this->participantService->getParticipant($room, $user->getUID());
if ($participant->getAttendee()->getParticipantType() === Participant::USER_SELF_JOINED) {
Expand Down
11 changes: 11 additions & 0 deletions lib/Model/BanMapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,17 @@ public function findByRoomId(int $roomId, ?string $bannedActorType = null): arra
return $this->findEntities($query);
}

public function findByUserId(string $userId): array {
$query = $this->db->getQueryBuilder();
$query->select('*')
->from($this->getTableName())
->where($query->expr()->eq('banned_actor_type', $query->createNamedParameter(Attendee::ACTOR_USERS, IQueryBuilder::PARAM_STR)))
->andWhere($query->expr()->eq('banned_actor_id', $query->createNamedParameter($userId, IQueryBuilder::PARAM_STR)))
->orderBy('id', 'ASC');

return $this->findEntities($query);
}

/**
* @throws DoesNotExistException
*/
Expand Down
34 changes: 34 additions & 0 deletions lib/Service/BanService.php
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,20 @@ public function throwIfActorIsBanned(Room $room, ?string $userId): void {
}
}

/**
* Check if the actor is banned without logging
*
* @return bool True if the actor is banned, false otherwise
*/
public function isActorBanned(Room $room, string $actorType, string $actorId): bool {
try {
$this->banMapper->findForBannedActorAndRoom($actorType, $actorId, $room->getId());
return true;
} catch (DoesNotExistException) {
return false;
}
}

/**
* Retrieve all bans for a specific room.
*
Expand All @@ -197,6 +211,26 @@ public function getBansForRoom(int $roomId): array {
return $this->banMapper->findByRoomId($roomId);
}

/**
* Retrieve all banned userIDs for a specific room.
*
* @return array<string, mixed> Key is the user ID
*/
public function getBannedUserIdsForRoom(int $roomId): array {
$bans = $this->banMapper->findByRoomId($roomId, Attendee::ACTOR_USERS);
return array_flip(array_map(static fn (Ban $ban) => $ban->getBannedActorId(), $bans));
}

/**
* Retrieve all room IDs a user is banned from
*
* @return array<int, mixed> Key is the room ID
*/
public function getBannedRoomsForUserId(string $userId): array {
$bans = $this->banMapper->findByUserId($userId);
return array_flip(array_map(static fn (Ban $ban) => $ban->getRoomId(), $bans));
}

/**
* Retrieve a ban by its ID and delete it.
*/
Expand Down
32 changes: 29 additions & 3 deletions lib/Service/ParticipantService.php
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@
use OCP\Server;
use OCP\UserStatus\IManager as IUserStatusManager;
use OCP\UserStatus\IUserStatus;
use Psr\Log\LoggerInterface;

class ParticipantService {

Expand All @@ -98,6 +99,7 @@ public function __construct(
private ITimeFactory $timeFactory,
private ICacheFactory $cacheFactory,
private IUserStatusManager $userStatusManager,
private LoggerInterface $logger,
) {
}

Expand Down Expand Up @@ -456,7 +458,7 @@ public function joinRoomAsNewGuest(RoomService $roomService, Room $room, string
* @throws CannotReachRemoteException thrown when sending the federation request didn't work
* @throws \Exception thrown if $addedBy is not set when adding a federated user
*/
public function addUsers(Room $room, array $participants, ?IUser $addedBy = null): array {
public function addUsers(Room $room, array $participants, ?IUser $addedBy = null, bool $bansAlreadyChecked = false): array {
if (empty($participants)) {
return [];
}
Expand All @@ -466,10 +468,20 @@ public function addUsers(Room $room, array $participants, ?IUser $addedBy = null
$lastMessage = (int) $room->getLastMessage()->getId();
}

$bannedUserIds = [];
if (!$bansAlreadyChecked) {
$banService = Server::get(BanService::class);
$bannedUserIds = $banService->getBannedUserIdsForRoom($room->getId());
}
$attendees = [];
foreach ($participants as $participant) {
$readPrivacy = Participant::PRIVACY_PUBLIC;
if ($participant['actorType'] === Attendee::ACTOR_USERS) {
if (isset($bannedUserIds[$participant['actorId']])) {
$this->logger->warning('User ' . $participant['actorId'] . ' is banned from conversation ' . $room->getToken() . ' and was skipped while adding users');
continue;
}

$readPrivacy = $this->talkConfig->getUserReadPrivacy($participant['actorId']);
} elseif ($participant['actorType'] === Attendee::ACTOR_FEDERATED_USERS) {
if ($addedBy === null) {
Expand Down Expand Up @@ -603,6 +615,8 @@ public function addGroup(Room $room, IGroup $group, array $existingParticipants
$existingParticipants = $this->getParticipantsForRoom($room);
}

$banService = Server::get(BanService::class);
$bannedUserIds = $banService->getBannedUserIdsForRoom($room->getId());
$participantsByUserId = [];
foreach ($existingParticipants as $participant) {
if ($participant->getAttendee()->getActorType() === Attendee::ACTOR_USERS) {
Expand All @@ -622,6 +636,11 @@ public function addGroup(Room $room, IGroup $group, array $existingParticipants
continue;
}

if (isset($bannedUserIds[$user->getUID()])) {
$this->logger->warning('User ' . $user->getUID() . ' is banned from conversation ' . $room->getToken() . ' and was skipped while adding group ' . $group->getDisplayName());
continue;
}

$newParticipants[] = [
'actorType' => Attendee::ACTOR_USERS,
'actorId' => $user->getUID(),
Expand All @@ -646,7 +665,7 @@ public function addGroup(Room $room, IGroup $group, array $existingParticipants
$this->dispatcher->dispatchTyped($attendeeEvent);
}

$this->addUsers($room, $newParticipants);
$this->addUsers($room, $newParticipants, bansAlreadyChecked: true);
}

/**
Expand Down Expand Up @@ -688,6 +707,8 @@ public function addCircle(Room $room, Circle $circle, array $existingParticipant
$existingParticipants = $this->getParticipantsForRoom($room);
}

$banService = Server::get(BanService::class);
$bannedUserIds = $banService->getBannedUserIdsForRoom($room->getId());
$participantsByUserId = [];
foreach ($existingParticipants as $participant) {
if ($participant->getAttendee()->getActorType() === Attendee::ACTOR_USERS) {
Expand Down Expand Up @@ -723,6 +744,11 @@ public function addCircle(Room $room, Circle $circle, array $existingParticipant
continue;
}

if (isset($bannedUserIds[$user->getUID()])) {
$this->logger->warning('User ' . $user->getUID() . ' is banned from conversation ' . $room->getToken() . ' and was skipped while adding circle ' . $circle->getDisplayName());
continue;
}

$newParticipants[] = [
'actorType' => Attendee::ACTOR_USERS,
'actorId' => $user->getUID(),
Expand All @@ -747,7 +773,7 @@ public function addCircle(Room $room, Circle $circle, array $existingParticipant
$this->dispatcher->dispatchTyped($attendeeEvent);
}

$this->addUsers($room, $newParticipants);
$this->addUsers($room, $newParticipants, bansAlreadyChecked: true);
}

/**
Expand Down
2 changes: 1 addition & 1 deletion openapi-full.json
Original file line number Diff line number Diff line change
Expand Up @@ -12557,7 +12557,7 @@
}
},
"400": {
"description": "Adding participant is not possible",
"description": "Adding participant is not possible, e.g. when the user is banned (check error attribute of response for detail key)",
"content": {
"application/json": {
"schema": {
Expand Down
2 changes: 1 addition & 1 deletion openapi.json
Original file line number Diff line number Diff line change
Expand Up @@ -12677,7 +12677,7 @@
}
},
"400": {
"description": "Adding participant is not possible",
"description": "Adding participant is not possible, e.g. when the user is banned (check error attribute of response for detail key)",
"content": {
"application/json": {
"schema": {
Expand Down
2 changes: 1 addition & 1 deletion src/types/openapi/openapi-full.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6759,7 +6759,7 @@ export interface operations {
};
};
};
/** @description Adding participant is not possible */
/** @description Adding participant is not possible, e.g. when the user is banned (check error attribute of response for detail key) */
400: {
headers: {
[name: string]: unknown;
Expand Down
2 changes: 1 addition & 1 deletion src/types/openapi/openapi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6337,7 +6337,7 @@ export interface operations {
};
};
};
/** @description Adding participant is not possible */
/** @description Adding participant is not possible, e.g. when the user is banned (check error attribute of response for detail key) */
400: {
headers: {
[name: string]: unknown;
Expand Down
3 changes: 2 additions & 1 deletion tests/integration/features/bootstrap/FeatureContext.php
Original file line number Diff line number Diff line change
Expand Up @@ -900,6 +900,7 @@ protected function assertAttendeeList(string $identifier, ?TableNode $formData,
}
return $attendee;
}, $formData->getHash(), $result);
$expected = array_filter($expected);

$result = array_map(function ($attendee) {
if (isset($attendee['permissions'])) {
Expand All @@ -918,7 +919,7 @@ protected function assertAttendeeList(string $identifier, ?TableNode $formData,
'expected' => $expected,
'actual' => $attendees,
'result' => $result,
]));
], true));
} else {
Assert::assertNull($formData);
}
Expand Down
Loading