Skip to content
Draft
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
14 changes: 13 additions & 1 deletion apps/user_status/lib/Controller/StatusesController.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@
use OCP\AppFramework\Http\DataResponse;
use OCP\AppFramework\OCS\OCSNotFoundException;
use OCP\AppFramework\OCSController;
use OCP\EventDispatcher\IEventDispatcher;
use OCP\IRequest;
use OCP\User\Events\UserEnumerationFilterEvent;
use OCP\UserStatus\IUserStatus;

/**
Expand All @@ -37,7 +39,8 @@ class StatusesController extends OCSController {
public function __construct(
string $appName,
IRequest $request,
private StatusService $service,
private readonly StatusService $service,
private readonly IEventDispatcher $eventDispatcher,
) {
parent::__construct($appName, $request);
}
Expand All @@ -56,6 +59,15 @@ public function __construct(
public function findAll(?int $limit = null, ?int $offset = null): DataResponse {
$allStatuses = $this->service->findAll($limit, $offset);

$users = array_map(fn (UserStatus $userStatus): string => $userStatus->getUserId(), $allStatuses);
$event = new UserEnumerationFilterEvent($users);
$this->eventDispatcher->dispatchTyped($event);

if ($users !== $event->getUsers()) {
$removedUsers = $event->getFilteredOutUsers();
$allStatuses = array_filter($allStatuses, fn (UserStatus $userStatus): bool => in_array($userStatus->getUserId(), $removedUsers, true));
}

return new DataResponse(array_values(array_map(function ($userStatus) {
return $this->formatStatus($userStatus);
}, $allStatuses)));
Expand Down
6 changes: 3 additions & 3 deletions apps/user_status/lib/Service/StatusService.php
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ public function __construct(
/**
* @param int|null $limit
* @param int|null $offset
* @return UserStatus[]
* @return list<UserStatus>
*/
public function findAll(?int $limit = null, ?int $offset = null): array {
// Return empty array if user enumeration is disabled or limited to groups
Expand All @@ -91,9 +91,9 @@ public function findAll(?int $limit = null, ?int $offset = null): array {
return [];
}

return array_map(function ($status) {
return array_values(array_map(function ($status) {
return $this->processStatus($status);
}, $this->mapper->findAll($limit, $offset));
}, $this->mapper->findAll($limit, $offset)));
}

/**
Expand Down
1 change: 1 addition & 0 deletions lib/composer/composer/autoload_classmap.php
Original file line number Diff line number Diff line change
Expand Up @@ -1039,6 +1039,7 @@
'OCP\\User\\Events\\UserConfigChangedEvent' => $baseDir . '/lib/public/User/Events/UserConfigChangedEvent.php',
'OCP\\User\\Events\\UserCreatedEvent' => $baseDir . '/lib/public/User/Events/UserCreatedEvent.php',
'OCP\\User\\Events\\UserDeletedEvent' => $baseDir . '/lib/public/User/Events/UserDeletedEvent.php',
'OCP\\User\\Events\\UserEnumerationFilterEvent' => $baseDir . '/lib/public/User/Events/UserEnumerationFilterEvent.php',
'OCP\\User\\Events\\UserFirstTimeLoggedInEvent' => $baseDir . '/lib/public/User/Events/UserFirstTimeLoggedInEvent.php',
'OCP\\User\\Events\\UserIdAssignedEvent' => $baseDir . '/lib/public/User/Events/UserIdAssignedEvent.php',
'OCP\\User\\Events\\UserIdUnassignedEvent' => $baseDir . '/lib/public/User/Events/UserIdUnassignedEvent.php',
Expand Down
1 change: 1 addition & 0 deletions lib/composer/composer/autoload_static.php
Original file line number Diff line number Diff line change
Expand Up @@ -1080,6 +1080,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2
'OCP\\User\\Events\\UserConfigChangedEvent' => __DIR__ . '/../../..' . '/lib/public/User/Events/UserConfigChangedEvent.php',
'OCP\\User\\Events\\UserCreatedEvent' => __DIR__ . '/../../..' . '/lib/public/User/Events/UserCreatedEvent.php',
'OCP\\User\\Events\\UserDeletedEvent' => __DIR__ . '/../../..' . '/lib/public/User/Events/UserDeletedEvent.php',
'OCP\\User\\Events\\UserEnumerationFilterEvent' => __DIR__ . '/../../..' . '/lib/public/User/Events/UserEnumerationFilterEvent.php',
'OCP\\User\\Events\\UserFirstTimeLoggedInEvent' => __DIR__ . '/../../..' . '/lib/public/User/Events/UserFirstTimeLoggedInEvent.php',
'OCP\\User\\Events\\UserIdAssignedEvent' => __DIR__ . '/../../..' . '/lib/public/User/Events/UserIdAssignedEvent.php',
'OCP\\User\\Events\\UserIdUnassignedEvent' => __DIR__ . '/../../..' . '/lib/public/User/Events/UserIdUnassignedEvent.php',
Expand Down
66 changes: 66 additions & 0 deletions lib/public/User/Events/UserEnumerationFilterEvent.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
<?php

declare(strict_types=1);

/**
* SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

namespace OCP\User\Events;

use OCP\AppFramework\Attribute\Consumable;
use OCP\AppFramework\Attribute\Listenable;
use OCP\EventDispatcher\Event;

/**
* @brief This event is triggered when a list of users is returned to the user.
*
* Applications that restricts the enumeration of users should listen to this event
* and modify the list of users with the getUsers and setUsers method.
*
* @since 31.0.14
*/
#[Consumable(since: '31.0.14')]
#[Listenable(since: '31.0.14')]
class UserEnumerationFilterEvent extends Event {
/** @var list<string> $initialUsers */
private readonly array $initialUsers;

/**
* @param list<string> $users
* @since 31.0.14
*/
public function __construct(
private array $users,
) {
$this->initialUsers = $users;
parent::__construct();
}

/**
* @return list<string>
* @since 31.0.14
*/
public function getUsers(): array {
return $this->users;
}

/**
* @param list<string> $users
* @since 31.0.14
*/
public function setUsers(array $users): void {
$this->users = $users;
}

/**
* Get the users what were filtered out by one of the listeners of this event.
*
* @return array<int<0, max>, string> $users
* @since 31.0.14
*/
public function getFilteredOutUsers(): array {
return array_diff($this->initialUsers, $this->users);
}
}