Skip to content

Commit

Permalink
feat: add option to force passwords in public conversations
Browse files Browse the repository at this point in the history
Signed-off-by: Anna Larch <anna@nextcloud.com>
  • Loading branch information
miaulalala committed Nov 13, 2024
1 parent dd23533 commit 3db5a0a
Show file tree
Hide file tree
Showing 5 changed files with 39 additions and 8 deletions.
1 change: 1 addition & 0 deletions docs/settings.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,3 +111,4 @@ Legend:
| `conversations_files` | string<br>`1` or `0` | `1` | No | 🖌️ | Whether the files app integration is enabled allowing to start conversations in the right sidebar |
| `conversations_files_public_shares` | string<br>`1` or `0` | `1` | No | 🖌️ | Whether the public share integration is enabled allowing to start conversations in the right sidebar on the public share page (Requires `conversations_files` also to be enabled) |
| `enable_matterbridge` | string<br>`1` or `0` | `0` | No | 🖌️ | Whether the Matterbridge integration is enabled and can be configured |
| `force_public_chat_passwords` | string<br>`1` or `0` | `0` | No | 🖌️ | Whether public chats are forced to use a password |
4 changes: 4 additions & 0 deletions lib/Config.php
Original file line number Diff line number Diff line change
Expand Up @@ -680,4 +680,8 @@ public function getCallsStartWithoutMedia(?string $userId): bool {

return $this->appConfig->getAppValueBool('calls_start_without_media');
}

public function isPasswordEnforced(): bool {
return $this->appConfig->getAppValueBool('force_public_chat_passwords');
}
}
18 changes: 14 additions & 4 deletions lib/Controller/RoomController.php
Original file line number Diff line number Diff line change
Expand Up @@ -499,6 +499,7 @@ protected function formatRoom(Room $room, ?Participant $currentParticipant, ?arr
* @param 'groups'|'circles'|'' $source Source of the invite ID ('circles' to create a room with a circle, etc.)
* @param string $objectType Type of the object
* @param string $objectId ID of the object
* @param string $password The room password
* @return DataResponse<Http::STATUS_OK|Http::STATUS_CREATED, TalkRoom, array{}>|DataResponse<Http::STATUS_BAD_REQUEST, array{error?: string}, array{}>|DataResponse<Http::STATUS_FORBIDDEN|Http::STATUS_NOT_FOUND, array<empty>, array{}>
*
* 200: Room already existed
Expand All @@ -508,7 +509,14 @@ protected function formatRoom(Room $room, ?Participant $currentParticipant, ?arr
* 404: User, group or other target to invite was not found
*/
#[NoAdminRequired]
public function createRoom(int $roomType, string $invite = '', string $roomName = '', string $source = '', string $objectType = '', string $objectId = ''): DataResponse {
public function createRoom(int $roomType,
string $invite = '',
string $roomName = '',
string $source = '',
string $objectType = '',
string $objectId = '',
string $password = '',
): DataResponse {
if ($roomType !== Room::TYPE_ONE_TO_ONE) {
/** @var IUser $user */
$user = $this->userManager->get($this->userId);
Expand All @@ -530,7 +538,7 @@ public function createRoom(int $roomType, string $invite = '', string $roomName
}
return $this->createGroupRoom($invite);
case Room::TYPE_PUBLIC:
return $this->createEmptyRoom($roomName, true, $objectType, $objectId);
return $this->createEmptyRoom($roomName, true, $objectType, $objectId, $password);
}

return new DataResponse([], Http::STATUS_BAD_REQUEST);
Expand Down Expand Up @@ -645,7 +653,7 @@ protected function createCircleRoom(string $targetCircleId): DataResponse {
* @return DataResponse<Http::STATUS_CREATED, TalkRoom, array{}>|DataResponse<Http::STATUS_BAD_REQUEST, array{error?: string}, array{}>|DataResponse<Http::STATUS_NOT_FOUND, array<empty>, array{}>

Check failure on line 653 in lib/Controller/RoomController.php

View workflow job for this annotation

GitHub Actions / static-psalm-analysis

InvalidReturnType

lib/Controller/RoomController.php:653:13: InvalidReturnType: The declared return type 'OCP\AppFramework\Http\DataResponse<201|400|404, array{actorId?: string, actorType?: string, attendeeId?: int, attendeePermissions?: int, attendeePin?: null|string, avatarVersion?: string, breakoutRoomMode?: int, breakoutRoomStatus?: int, callFlag?: int, callPermissions?: int, callRecording?: int, callStartTime?: int, canDeleteConversation?: bool, canEnableSIP?: bool, canLeaveConversation?: bool, canStartCall?: bool, defaultPermissions?: int, description?: string, displayName?: string, error?: string, hasCall?: bool, hasPassword?: bool, id?: int, invitedActorId?: string, isArchived?: bool, isCustomAvatar?: bool, isFavorite?: bool, lastActivity?: int, lastCommonReadMessage?: int, lastMessage?: array{actorDisplayName?: string, actorId?: string, actorType?: string, deleted?: true, expirationTimestamp?: int, id?: int, isReplyable?: bool, lastEditActorDisplayName?: string, lastEditActorId?: string, lastEditActorType?: string, lastEditTimestamp?: int, markdown?: bool, message?: string, messageParameters?: array<string, array{'call-type'?: 'group'|'one2one'|'public', 'icon-url'?: string, 'message-id'?: string, 'preview-available'?: 'no'|'yes', assignable?: '0'|'1', blurhash?: string, boardname?: string, conversation?: string, description?: string, etag?: string, height?: string, id: string, latitude?: string, link?: string, longitude?: string, mimetype?: string, mtime?: string, name: string, path?: string, permissions?: string, server?: string, size?: string, stackname?: string, thumb?: string, type: string, visibility?: '0'|'1', website?: string, width?: string}>, messageType?: string, reactions?: array<string, int>|stdClass, reactionsSelf?: array<array-key, string>, referenceId?: string, silent?: bool, systemMessage?: string, timestamp?: int, token?: string}, lastPing?: int, lastReadMessage?: int, listable?: int, lobbyState?: int, lobbyTimer?: int, mentionPermissions?: int, messageExpiration?: int, name?: string, notificationCalls?: int, notificationLevel?: int, objectId?: string, objectType?: string, participantFlags?: int, participantType?: int, permissions?: int, readOnly?: int, recordingConsent?: int, remoteServer?: string, remoteToken?: string, sessionId?: string, sipEnabled?: int, status?: string, statusClearAt?: int|null, statusIcon?: null|string, statusMessage?: null|string, token?: string, type?: int, unreadMention?: bool, unreadMentionDirect?: bool, unreadMessages?: int}, array<never, never>>' for OCA\Talk\Controller\RoomController::createEmptyRoom is incorrect, got 'OCP\AppFramework\Http\DataResponse<201|400|403|404, array{actorId?: string, actorType?: string, attendeeId?: int, attendeePermissions?: int, attendeePin?: null|string, avatarVersion?: string, breakoutRoomMode?: int, breakoutRoomStatus?: int, callFlag?: int, callPermissions?: int, callRecording?: int, callStartTime?: int, canDeleteConversation?: bool, canEnableSIP?: bool, canLeaveConversation?: bool, canStartCall?: bool, defaultPermissions?: int, description?: string, displayName?: string, error?: 'mode'|'object'|'permissions'|'room', hasCall?: bool, hasPassword?: bool, hint?: string, id?: int, invitedActorId?: string, isArchived?: bool, isCustomAvatar?: bool, isFavorite?: bool, lastActivity?: int, lastCommonReadMessage?: int, lastMessage?: array{actorDisplayName?: string, actorId?: string, actorType?: string, deleted?: true, expirationTimestamp?: int, id?: int, isReplyable?: bool, lastEditActorDisplayName?: string, lastEditActorId?: string, lastEditActorType?: string, lastEditTimestamp?: int, markdown?: bool, message?: string, messageParameters?: array<string, array{'call-type'?: 'group'|'one2one'|'public', 'icon-url'?: string, 'message-id'?: string, 'preview-available'?: 'no'|'yes', assignable?: '0'|'1', blurhash?: string, boardname?: string, conversation?: string, description?: string, etag?: string, height?: string, id: string, latitude?: string, link?: string, longitude?: string, mimetype?: string, mtime?: string, name: string, path?: string, permissions?: string,
*/
#[NoAdminRequired]
protected function createEmptyRoom(string $roomName, bool $public = true, string $objectType = '', string $objectId = ''): DataResponse {
protected function createEmptyRoom(string $roomName, bool $public = true, string $objectType = '', string $objectId = '', string $password = ''): DataResponse {
$currentUser = $this->userManager->get($this->userId);
if (!$currentUser instanceof IUser) {
return new DataResponse([], Http::STATUS_NOT_FOUND);
Expand Down Expand Up @@ -683,7 +691,9 @@ protected function createEmptyRoom(string $roomName, bool $public = true, string

// Create the room
try {
$room = $this->roomService->createConversation($roomType, $roomName, $currentUser, $objectType, $objectId);
$room = $this->roomService->createConversation($roomType, $roomName, $currentUser, $objectType, $objectId, $password);
} catch (PasswordException $e) {
return new DataResponse(['reason' => $e->getReason(), 'hint' => $e->getHint()], Http::STATUS_FORBIDDEN);

Check failure on line 696 in lib/Controller/RoomController.php

View workflow job for this annotation

GitHub Actions / static-psalm-analysis

InvalidReturnStatement

lib/Controller/RoomController.php:696:11: InvalidReturnStatement: The inferred type 'OCP\AppFramework\Http\DataResponse<403, array{hint: string, reason: 'breakout-room'|'type'|'value'}, array<never, never>>' does not match the declared return type 'OCP\AppFramework\Http\DataResponse<201|400|404, array{actorId?: string, actorType?: string, attendeeId?: int, attendeePermissions?: int, attendeePin?: null|string, avatarVersion?: string, breakoutRoomMode?: int, breakoutRoomStatus?: int, callFlag?: int, callPermissions?: int, callRecording?: int, callStartTime?: int, canDeleteConversation?: bool, canEnableSIP?: bool, canLeaveConversation?: bool, canStartCall?: bool, defaultPermissions?: int, description?: string, displayName?: string, error?: string, hasCall?: bool, hasPassword?: bool, id?: int, invitedActorId?: string, isArchived?: bool, isCustomAvatar?: bool, isFavorite?: bool, lastActivity?: int, lastCommonReadMessage?: int, lastMessage?: array{actorDisplayName?: string, actorId?: string, actorType?: string, deleted?: true, expirationTimestamp?: int, id?: int, isReplyable?: bool, lastEditActorDisplayName?: string, lastEditActorId?: string, lastEditActorType?: string, lastEditTimestamp?: int, markdown?: bool, message?: string, messageParameters?: array<string, array{'call-type'?: 'group'|'one2one'|'public', 'icon-url'?: string, 'message-id'?: string, 'preview-available'?: 'no'|'yes', assignable?: '0'|'1', blurhash?: string, boardname?: string, conversation?: string, description?: string, etag?: string, height?: string, id: string, latitude?: string, link?: string, longitude?: string, mimetype?: string, mtime?: string, name: string, path?: string, permissions?: string, server?: string, size?: string, stackname?: string, thumb?: string, type: string, visibility?: '0'|'1', website?: string, width?: string}>, messageType?: string, reactions?: array<string, int>|stdClass, reactionsSelf?: array<array-key, string>, referenceId?: string, silent?: bool, systemMessage?: string, timestamp?: int, token?: string}, lastPing?: int, lastReadMessage?: int, listable?: int, lobbyState?: int, lobbyTimer?: int, mentionPermissions?: int, messageExpiration?: int, name?: string, notificationCalls?: int, notificationLevel?: int, objectId?: string, objectType?: string, participantFlags?: int, participantType?: int, permissions?: int, readOnly?: int, recordingConsent?: int, remoteServer?: string, remoteToken?: string, sessionId?: string, sipEnabled?: int, status?: string, statusClearAt?: int|null, statusIcon?: null|string, statusMessage?: null|string, token?: string, type?: int, unreadMention?: bool, unreadMentionDirect?: bool, unreadMessages?: int}, array<never, never>>' for OCA\Talk\Controller\RoomController::createEmptyRoom (see https://psalm.dev/128)
} catch (\InvalidArgumentException $e) {
return new DataResponse([], Http::STATUS_BAD_REQUEST);
}
Expand Down
3 changes: 2 additions & 1 deletion lib/Manager.php
Original file line number Diff line number Diff line change
Expand Up @@ -1084,7 +1084,7 @@ public function getChangelogRoom(string $userId): Room {
* @param string $objectId
* @return Room
*/
public function createRoom(int $type, string $name = '', string $objectType = '', string $objectId = ''): Room {
public function createRoom(int $type, string $name = '', string $objectType = '', string $objectId = '', string $password = ''): Room {
$token = $this->getNewToken();

$insert = $this->db->getQueryBuilder();
Expand All @@ -1111,6 +1111,7 @@ public function createRoom(int $type, string $name = '', string $objectType = ''
'token' => $token,
'object_type' => $objectType,
'object_id' => $objectId,
'password' => $password
]);

$event = new RoomCreatedEvent($room);
Expand Down
21 changes: 18 additions & 3 deletions lib/Service/RoomService.php
Original file line number Diff line number Diff line change
Expand Up @@ -132,12 +132,14 @@ public function createOneToOneConversation(IUser $actor, IUser $targetUser): Roo
* @param IUser|null $owner
* @param string $objectType
* @param string $objectId
* @param string $password
* @return Room
* @throws InvalidArgumentException on too long or empty names
* @throws InvalidArgumentException unsupported type
* @throws InvalidArgumentException invalid object data
* @throws PasswordException empty or invalid password
*/
public function createConversation(int $type, string $name, ?IUser $owner = null, string $objectType = '', string $objectId = ''): Room {
public function createConversation(int $type, string $name, ?IUser $owner = null, string $objectType = '', string $objectId = '', string $password = ''): Room {
$name = trim($name);
if ($name === '' || mb_strlen($name) > 255) {
throw new InvalidArgumentException('name');
Expand Down Expand Up @@ -167,7 +169,20 @@ public function createConversation(int $type, string $name, ?IUser $owner = null
throw new InvalidArgumentException('object');
}

$room = $this->manager->createRoom($type, $name, $objectType, $objectId);
if ($type !== Room::TYPE_PUBLIC || !$this->config->isPasswordEnforced()) {
$room = $this->manager->createRoom($type, $name, $objectType, $objectId);
} elseif ($password === '') {
throw new PasswordException(PasswordException::REASON_VALUE, 'Password needs to be set');
} else {
$event = new ValidatePasswordPolicyEvent($password);
try {
$this->dispatcher->dispatchTyped($event);
} catch (HintException $e) {
throw new PasswordException(PasswordException::REASON_VALUE, $e->getHint());
}

$room = $this->manager->createRoom($type, $name, $objectType, $objectId, $password);
}

if ($owner instanceof IUser) {
$this->participantService->addUsers($room, [[
Expand All @@ -177,8 +192,8 @@ public function createConversation(int $type, string $name, ?IUser $owner = null
'participantType' => Participant::OWNER,
]], null);
}

return $room;

}

public function prepareConversationName(string $objectName): string {
Expand Down

0 comments on commit 3db5a0a

Please sign in to comment.