Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[stable20] Fix user management in password request rooms #4798

2 changes: 1 addition & 1 deletion docs/participant.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ Base endpoint is: `/ocs/v2.php/apps/spreed/api/v1`
- Status code:
+ `200 OK`
+ `400 Bad Request` When the source type is unknown, currently `users`, `groups`, `emails` are supported. `circles` are supported with `circles-support` capability
+ `400 Bad Request` When the conversation is a one-to-one conversation
+ `400 Bad Request` When the conversation is a one-to-one conversation or a conversation to request a password for a share
+ `403 Forbidden` When the current user is not a moderator or owner
+ `404 Not Found` When the conversation could not be found for the participant
+ `404 Not Found` When the user or group to add could not be found
Expand Down
2 changes: 1 addition & 1 deletion lib/Controller/RoomController.php
Original file line number Diff line number Diff line change
Expand Up @@ -944,7 +944,7 @@ public function getParticipants(bool $includeStatus = false): DataResponse {
* @return DataResponse
*/
public function addParticipantToRoom(string $newParticipant, string $source = 'users'): DataResponse {
if ($this->room->getType() === Room::ONE_TO_ONE_CALL) {
if ($this->room->getType() === Room::ONE_TO_ONE_CALL || $this->room->getObjectType() === 'share:password') {
return new DataResponse([], Http::STATUS_BAD_REQUEST);
}

Expand Down
42 changes: 40 additions & 2 deletions lib/PublicShareAuth/Listener.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@

namespace OCA\Talk\PublicShareAuth;

use OCA\Talk\Events\AddParticipantsEvent;
use OCA\Talk\Events\JoinRoomGuestEvent;
use OCA\Talk\Events\JoinRoomUserEvent;
use OCA\Talk\Events\RoomEvent;
Expand Down Expand Up @@ -57,6 +58,11 @@ public static function register(IEventDispatcher $dispatcher): void {
};
$dispatcher->addListener(Room::EVENT_BEFORE_GUEST_CONNECT, $listener);

$listener = static function (AddParticipantsEvent $event) {
self::preventExtraUsersFromBeingAdded($event->getRoom(), $event->getParticipants());
};
$dispatcher->addListener(Room::EVENT_BEFORE_USERS_ADD, $listener);

$listener = static function (RoomEvent $event) {
self::destroyRoomOnParticipantLeave($event->getRoom());
};
Expand Down Expand Up @@ -89,7 +95,7 @@ public static function preventExtraUsersFromJoining(Room $room, string $userId):
} catch (ParticipantNotFoundException $e) {
}

if ($room->getActiveGuests() > 0 || \count($room->getParticipantUserIds()) > 1) {
if ($room->getNumberOfParticipants(false) > 1) {
throw new \OverflowException('Only the owner and another participant are allowed in rooms to request the password for a share');
}
}
Expand All @@ -108,7 +114,39 @@ public static function preventExtraGuestsFromJoining(Room $room): void {
return;
}

if ($room->getActiveGuests() > 0 || \count($room->getParticipantUserIds()) > 1) {
if ($room->getNumberOfParticipants(false) > 1) {
throw new \OverflowException('Only the owner and another participant are allowed in rooms to request the password for a share');
}
}

/**
* Prevents other users from being added to the room (as they will not be
* able to join).
*
* This method should be called before a user is added to a room.
*
* @param Room $room
* @param array[] $participants
* @throws \OverflowException
*/
public static function preventExtraUsersFromBeingAdded(Room $room, array $participants): void {
if ($room->getObjectType() !== 'share:password') {
return;
}

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

// Events with more than one participant can be directly aborted, as
// when the owner is added during room creation or a user self-joins the
// event will always have just one participant.
if (count($participants) > 1) {
throw new \OverflowException('Only the owner and another participant are allowed in rooms to request the password for a share');
}

$participant = $participants[0];
if ($participant['participantType'] !== Participant::OWNER && $participant['participantType'] !== Participant::USER_SELF_JOINED) {
throw new \OverflowException('Only the owner and another participant are allowed in rooms to request the password for a share');
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@ export default {
this.cancelableGetParticipants()
} catch (exception) {
console.debug(exception)
showError(t('spreed', 'An error occurred while adding the participants'))
}
},

Expand Down
2 changes: 1 addition & 1 deletion src/components/RightSidebar/RightSidebar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ export default {
displaySearchBox() {
return this.canFullModerate
&& (this.conversation.type === CONVERSATION.TYPE.GROUP
|| this.conversation.type === CONVERSATION.TYPE.PUBLIC)
|| (this.conversation.type === CONVERSATION.TYPE.PUBLIC && this.conversation.objectType !== 'share:password'))
},
isSearching() {
return this.searchText !== ''
Expand Down
89 changes: 80 additions & 9 deletions tests/integration/features/bootstrap/FeatureContext.php
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,14 @@ public function userIsParticipantOfRooms($user, TableNode $formData = null) {
return;
}

$this->assertRooms($rooms, $formData);
}

/**
* @param array $rooms
* @param TableNode $formData
*/
private function assertRooms($rooms, TableNode $formData) {
Assert::assertCount(count($formData->getHash()), $rooms, 'Room count does not match');
Assert::assertEquals($formData->getHash(), array_map(function ($room, $expectedRoom) {
$participantNames = array_map(function ($participant) {
Expand All @@ -169,12 +177,30 @@ public function userIsParticipantOfRooms($user, TableNode $formData = null) {
$participantNames[$lastParticipantKey] .= ' [exact order]';
}

return [
'id' => self::$tokenToIdentifier[$room['token']],
'type' => (string) $room['type'],
'participantType' => (string) $room['participantType'],
'participants' => implode(', ', $participantNames),
];
$data = [];
if (isset($expectedRoom['id'])) {
$data['id'] = self::$tokenToIdentifier[$room['token']];
}
if (isset($expectedRoom['name'])) {
$data['name'] = $room['name'];
}
if (isset($expectedRoom['type'])) {
$data['type'] = (string) $room['type'];
}
if (isset($expectedRoom['hasPassword'])) {
$data['hasPassword'] = (string) $room['hasPassword'];
}
if (isset($expectedRoom['readOnly'])) {
$data['readOnly'] = (string) $room['readOnly'];
}
if (isset($expectedRoom['participantType'])) {
$data['participantType'] = (string) $room['participantType'];
}
if (isset($expectedRoom['participants'])) {
$data['participants'] = implode(', ', $participantNames);
}

return $data;
}, $rooms, $formData->getHash()));
}

Expand All @@ -184,10 +210,11 @@ public function userIsParticipantOfRooms($user, TableNode $formData = null) {
* @param string $user
* @param string $isOrNotParticipant
* @param string $identifier
* @param TableNode|null $formData
*/
public function userIsParticipantOfRoom($user, $isOrNotParticipant, $identifier) {
public function userIsParticipantOfRoom($user, $isOrNotParticipant, $identifier, TableNode $formData = null) {
if (strpos($user, 'guest') === 0) {
$this->guestIsParticipantOfRoom($user, $isOrNotParticipant, $identifier);
$this->guestIsParticipantOfRoom($user, $isOrNotParticipant, $identifier, $formData);

return;
}
Expand All @@ -211,6 +238,15 @@ public function userIsParticipantOfRoom($user, $isOrNotParticipant, $identifier)
foreach ($rooms as $room) {
if (self::$tokenToIdentifier[$room['token']] === $identifier) {
Assert::assertEquals($isParticipant, true, 'Room ' . $identifier . ' found in user´s room list');

if ($formData) {
$this->sendRequest('GET', '/apps/spreed/api/v1/room/' . self::$identifierToToken[$identifier]);

$rooms = [$this->getDataFromResponse($this->response)];

$this->assertRooms($rooms, $formData);
}

return;
}
}
Expand All @@ -222,15 +258,22 @@ public function userIsParticipantOfRoom($user, $isOrNotParticipant, $identifier)
* @param string $guest
* @param string $isOrNotParticipant
* @param string $identifier
* @param TableNode|null $formData
*/
private function guestIsParticipantOfRoom($guest, $isOrNotParticipant, $identifier) {
private function guestIsParticipantOfRoom($guest, $isOrNotParticipant, $identifier, TableNode $formData = null) {
$this->setCurrentUser($guest);
$this->sendRequest('GET', '/apps/spreed/api/v1/room/' . self::$identifierToToken[$identifier]);

$response = $this->getDataFromResponse($this->response);

$isParticipant = $isOrNotParticipant === 'is';

if ($formData) {
$rooms = [$response];

$this->assertRooms($rooms, $formData);
}

if ($isParticipant) {
$this->assertStatusCode($this->response, 200);
Assert::assertEquals(self::$userToSessionId[$guest], $response['sessionId']);
Expand Down Expand Up @@ -404,6 +447,30 @@ public function userGetsTheRoomForLastShare($user, $statusCode) {
self::$tokenToIdentifier[$response['token']] = $identifier;
}

/**
* @Then /^user "([^"]*)" creates the password request room for last share with (\d+)$/
*
* @param string $user
* @param int $statusCode
*/
public function userCreatesThePasswordRequestRoomForLastShare($user, $statusCode) {
$shareToken = $this->sharingContext->getLastShareToken();

$this->setCurrentUser($user);
$this->sendRequest('POST', '/apps/spreed/api/v1/publicshareauth', ['shareToken' => $shareToken]);
$this->assertStatusCode($this->response, $statusCode);

if ($statusCode !== '201') {
return;
}

$response = $this->getDataFromResponse($this->response);

$identifier = 'password request for last share room';
self::$identifierToToken[$identifier] = $response['token'];
self::$tokenToIdentifier[$response['token']] = $identifier;
}

/**
* @Then /^user "([^"]*)" joins room "([^"]*)" with (\d+)$/
*
Expand All @@ -420,6 +487,10 @@ public function userJoinsRoom($user, $identifier, $statusCode, TableNode $formDa
);
$this->assertStatusCode($this->response, $statusCode);

if ($statusCode !== '200') {
return;
}

$response = $this->getDataFromResponse($this->response);
if (array_key_exists('sessionId', $response)) {
// In the chat guest users are identified by their sessionId. The
Expand Down
Loading