diff --git a/lib/private/Share20/Manager.php b/lib/private/Share20/Manager.php index 13e2b55fe2ba4..d9fee81871804 100644 --- a/lib/private/Share20/Manager.php +++ b/lib/private/Share20/Manager.php @@ -157,14 +157,15 @@ protected function verifyPassword(?string $password): void { * @suppress PhanUndeclaredClassMethod */ protected function generalChecks(IShare $share): void { + $shareWith = $share->getSharedWith(); if ($share->getShareType() === IShare::TYPE_USER) { // We expect a valid user as sharedWith for user shares - if (!$this->userManager->userExists($share->getSharedWith())) { + if ($shareWith === null || !$this->userManager->userExists($shareWith)) { throw new \InvalidArgumentException($this->l->t('Share recipient is not a valid user')); } } elseif ($share->getShareType() === IShare::TYPE_GROUP) { // We expect a valid group as sharedWith for group shares - if (!$this->groupManager->groupExists($share->getSharedWith())) { + if ($shareWith === null || !$this->groupManager->groupExists($shareWith)) { throw new \InvalidArgumentException($this->l->t('Share recipient is not a valid group')); } } elseif ($share->getShareType() === IShare::TYPE_LINK) { diff --git a/lib/private/User/Manager.php b/lib/private/User/Manager.php index 81fe55db58e1d..c72d5f2e91442 100644 --- a/lib/private/User/Manager.php +++ b/lib/private/User/Manager.php @@ -118,25 +118,29 @@ public function clearBackends(): void { } /** - * get a user by user id - * - * @param string $uid - * @return User|null Either the user or null if the specified user does not exist + * {@inheritDoc} + * @param list $excludeBackends A list of IUserBackend::getBackendName() that need to be excluded from the search. */ #[\Override] - public function get($uid) { + public function get($uid, array $excludeBackends = []): ?\OCP\IUser { if (is_null($uid) || $uid === '' || $uid === false) { return null; } - if (isset($this->cachedUsers[$uid])) { //check the cache first to prevent having to loop over the backends - return $this->cachedUsers[$uid]; - } if (strlen($uid) > IUser::MAX_USERID_LENGTH) { return null; } + // check the cache first to prevent having to loop over the backends + if ($excludeBackends === [] && isset($this->cachedUsers[$uid])) { + return $this->cachedUsers[$uid]; + } + $cachedBackend = $this->cache->get(sha1($uid)); + if (in_array($cachedBackend, $excludeBackends)) { + $cachedBackend = null; + } + if ($cachedBackend !== null && isset($this->backends[$cachedBackend])) { // Cache has the info of the user backend already, so ask that one directly $backend = $this->backends[$cachedBackend]; @@ -151,6 +155,10 @@ public function get($uid) { continue; } + if (in_array($i, $excludeBackends)) { + continue; + } + if ($backend->userExists($uid)) { // Hash $uid to ensure that only valid characters are used for the cache key $this->cache->set(sha1($uid), $i, 300); @@ -193,19 +201,13 @@ public function getUserObject($uid, $backend, $cacheUser = true) { return $user; } - /** - * check if a user exists - * - * @param string $uid - * @return bool - */ #[\Override] - public function userExists($uid) { + public function userExists(string $uid, array $excludeBackends = []): bool { if (strlen($uid) > IUser::MAX_USERID_LENGTH) { return false; } - $user = $this->get($uid); + $user = $this->get($uid, $excludeBackends); return ($user !== null); } diff --git a/lib/public/IUserManager.php b/lib/public/IUserManager.php index f19685903baaf..0cd6daa399e49 100644 --- a/lib/public/IUserManager.php +++ b/lib/public/IUserManager.php @@ -69,7 +69,7 @@ public function clearBackends(); * @return \OCP\IUser|null Either the user or null if the specified user does not exist * @since 8.0.0 */ - public function get($uid); + public function get($uid): ?\OCP\IUser; /** * Get the display name of a user @@ -81,13 +81,14 @@ public function get($uid); public function getDisplayName(string $uid): ?string; /** - * check if a user exists + * Check if a user exists. * * @param string $uid + * @param list $excludeBackends A list of IUserBackend::getBackendName() that need to be excluded from the search. * @return bool * @since 8.0.0 */ - public function userExists($uid); + public function userExists(string $uid, array $excludeBackends = []): bool; /** * Check if the password is valid for the user diff --git a/tests/Core/Command/User/AddTest.php b/tests/Core/Command/User/AddTest.php index 59ce5ca0f908c..43b7aaea55601 100644 --- a/tests/Core/Command/User/AddTest.php +++ b/tests/Core/Command/User/AddTest.php @@ -109,6 +109,11 @@ public function testAddEmail( $this->mailHelper->expects($isEmailValid && $shouldSendEmail ? static::once() : static::never()) ->method('sendMail'); + $this->consoleInput->method('getArgument') + ->willReturnMap([ + ['uid', 'JohnDoe'], + ]); + $this->consoleInput->method('getOption') ->willReturnMap([ ['generate-password', 'true'], diff --git a/tests/lib/Share20/ManagerTest.php b/tests/lib/Share20/ManagerTest.php index 52d98569e2ff5..4c30716bf5a8c 100644 --- a/tests/lib/Share20/ManagerTest.php +++ b/tests/lib/Share20/ManagerTest.php @@ -1195,10 +1195,7 @@ public function testGeneralChecks(array $shareParams, ?string $exceptionMessage, $thrown = null; - $this->userManager->method('userExists')->willReturnMap([ - ['user0', true], - ['user1', true], - ]); + $this->userManager->method('userExists')->willReturnCallBack(fn (string $userId) => $userId === 'user0' || $userId === 'user1'); $user0 = $this->createMock(IUser::class); $user0