Skip to content

Commit

Permalink
Merge pull request #29559 from nextcloud/feat/28139/profile-respect-u…
Browse files Browse the repository at this point in the history
…ser-enumeration

Respect user enumeration settings on profile
  • Loading branch information
nickvergessen authored Nov 9, 2021
2 parents 52f8f4a + 3b91e4c commit a99efca
Show file tree
Hide file tree
Showing 6 changed files with 203 additions and 32 deletions.
4 changes: 3 additions & 1 deletion apps/files_sharing/tests/CapabilitiesTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
*/
namespace OCA\Files_Sharing\Tests;

use OC\KnownUser\KnownUserService;
use OC\Share20\Manager;
use OCA\Files_Sharing\Capabilities;
use OCP\EventDispatcher\IEventDispatcher;
Expand Down Expand Up @@ -94,7 +95,8 @@ private function getResults(array $map) {
$this->createMock(IURLGenerator::class),
$this->createMock(\OC_Defaults::class),
$this->createMock(IEventDispatcher::class),
$this->createMock(IUserSession::class)
$this->createMock(IUserSession::class),
$this->createMock(KnownUserService::class)
);
$cap = new Capabilities($config, $shareManager);
$result = $this->getFilesSharingPart($cap->getCapabilities());
Expand Down
58 changes: 40 additions & 18 deletions core/Controller/ProfilePageController.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,18 @@

namespace OC\Core\Controller;

use OC\KnownUser\KnownUserService;
use OC\Profile\ProfileManager;
use OCP\Accounts\IAccountManager;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Http\TemplateResponse;
use OCP\AppFramework\Services\IInitialState;
use OCP\IGroupManager;
use OCP\IRequest;
use OCP\IUser;
use OCP\IUserManager;
use OCP\IUserSession;
use OC\Profile\ProfileManager;
use OCP\Share\IManager as IShareManager;
use OCP\UserStatus\IManager as IUserStatusManager;

class ProfilePageController extends Controller {
Expand All @@ -48,6 +52,15 @@ class ProfilePageController extends Controller {
/** @var ProfileManager */
private $profileManager;

/** @var IShareManager */
private $shareManager;

/** @var IGroupManager */
private $groupManager;

/** @var KnownUserService */
private $knownUserService;

/** @var IUserManager */
private $userManager;

Expand All @@ -63,6 +76,9 @@ public function __construct(
IInitialState $initialStateService,
IAccountManager $accountManager,
ProfileManager $profileManager,
IShareManager $shareManager,
IGroupManager $groupManager,
KnownUserService $knownUserService,
IUserManager $userManager,
IUserSession $userSession,
IUserStatusManager $userStatusManager
Expand All @@ -71,6 +87,9 @@ public function __construct(
$this->initialStateService = $initialStateService;
$this->accountManager = $accountManager;
$this->profileManager = $profileManager;
$this->shareManager = $shareManager;
$this->groupManager = $groupManager;
$this->knownUserService = $knownUserService;
$this->userManager = $userManager;
$this->userSession = $userSession;
$this->userStatusManager = $userStatusManager;
Expand All @@ -83,31 +102,34 @@ public function __construct(
* @NoSubAdminRequired
*/
public function index(string $targetUserId): TemplateResponse {
if (!$this->userManager->userExists($targetUserId)) {
return new TemplateResponse(
'core',
'404-profile',
[],
TemplateResponse::RENDER_AS_GUEST,
);
}
$profileNotFoundTemplate = new TemplateResponse(
'core',
'404-profile',
[],
TemplateResponse::RENDER_AS_GUEST,
);

$visitingUser = $this->userSession->getUser();
$targetUser = $this->userManager->get($targetUserId);
if (!$targetUser instanceof IUser) {
return $profileNotFoundTemplate;
}
$visitingUser = $this->userSession->getUser();
$targetAccount = $this->accountManager->getAccount($targetUser);

if (!$this->isProfileEnabled($targetAccount)) {
return new TemplateResponse(
'core',
'404-profile',
[],
TemplateResponse::RENDER_AS_GUEST,
);
return $profileNotFoundTemplate;
}

// Run user enumeration checks only if viewing another user's profile
if ($targetUser !== $visitingUser) {
if (!$this->shareManager->currentUserCanEnumerateTargetUser($visitingUser, $targetUser)) {
return $profileNotFoundTemplate;
}
}

$userStatuses = $this->userStatusManager->getUserStatuses([$targetUserId]);
$status = array_shift($userStatuses);
if (!empty($status)) {
$status = $userStatuses[$targetUserId] ?? null;
if ($status !== null) {
$this->initialStateService->provideInitialState('status', [
'icon' => $status->getIcon(),
'message' => $status->getMessage(),
Expand Down
3 changes: 2 additions & 1 deletion lib/private/Server.php
Original file line number Diff line number Diff line change
Expand Up @@ -1253,7 +1253,8 @@ public function __construct($webRoot, \OC\Config $config) {
$c->get(IURLGenerator::class),
$c->get('ThemingDefaults'),
$c->get(IEventDispatcher::class),
$c->get(IUserSession::class)
$c->get(IUserSession::class),
$c->get(KnownUserService::class)
);

return $manager;
Expand Down
44 changes: 43 additions & 1 deletion lib/private/Share20/Manager.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@

use OC\Cache\CappedMemoryCache;
use OC\Files\Mount\MoveableMount;
use OC\KnownUser\KnownUserService;
use OC\Share20\Exception\ProviderException;
use OCA\Files_Sharing\AppInfo\Application;
use OCA\Files_Sharing\ISharedStorage;
Expand Down Expand Up @@ -118,7 +119,10 @@ class Manager implements IManager {
private $defaults;
/** @var IEventDispatcher */
private $dispatcher;
/** @var IUserSession */
private $userSession;
/** @var KnownUserService */
private $knownUserService;

public function __construct(
ILogger $logger,
Expand All @@ -137,7 +141,8 @@ public function __construct(
IURLGenerator $urlGenerator,
\OC_Defaults $defaults,
IEventDispatcher $dispatcher,
IUserSession $userSession
IUserSession $userSession,
KnownUserService $knownUserService
) {
$this->logger = $logger;
$this->config = $config;
Expand All @@ -160,6 +165,7 @@ public function __construct(
$this->defaults = $defaults;
$this->dispatcher = $dispatcher;
$this->userSession = $userSession;
$this->knownUserService = $knownUserService;
}

/**
Expand Down Expand Up @@ -1909,6 +1915,42 @@ public function allowEnumerationFullMatch(): bool {
return $this->config->getAppValue('core', 'shareapi_restrict_user_enumeration_full_match', 'yes') === 'yes';
}

public function currentUserCanEnumerateTargetUser(?IUser $currentUser, IUser $targetUser): bool {
if ($this->allowEnumerationFullMatch()) {
return true;
}

if (!$this->allowEnumeration()) {
return false;
}

if (!$this->limitEnumerationToPhone() && !$this->limitEnumerationToGroups()) {
// Enumeration is enabled and not restricted: OK
return true;
}

if (!$currentUser instanceof IUser) {
// Enumeration restrictions require an account
return false;
}

// Enumeration is limited to phone match
if ($this->limitEnumerationToPhone() && $this->knownUserService->isKnownToUser($currentUser->getUID(), $targetUser->getUID())) {
return true;
}

// Enumeration is limited to groups
if ($this->limitEnumerationToGroups()) {
$currentUserGroupIds = $this->groupManager->getUserGroupIds($currentUser);
$targetUserGroupIds = $this->groupManager->getUserGroupIds($targetUser);
if (!empty(array_intersect($currentUserGroupIds, $targetUserGroupIds))) {
return true;
}
}

return false;
}

/**
* Copied from \OC_Util::isSharingDisabledForUser
*
Expand Down
11 changes: 11 additions & 0 deletions lib/public/Share/IManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
use OCP\Files\Folder;
use OCP\Files\Node;

use OCP\IUser;
use OCP\Share\Exceptions\GenericShareException;
use OCP\Share\Exceptions\ShareNotFound;

Expand Down Expand Up @@ -447,6 +448,16 @@ public function limitEnumerationToPhone(): bool;
*/
public function allowEnumerationFullMatch(): bool;

/**
* Check if the current user can enumerate the target user
*
* @param IUser|null $currentUser
* @param IUser $targetUser
* @return bool
* @since 23.0.0
*/
public function currentUserCanEnumerateTargetUser(?IUser $currentUser, IUser $targetUser): bool;

/**
* Check if sharing is disabled for the given user
*
Expand Down
Loading

0 comments on commit a99efca

Please sign in to comment.