diff options
Diffstat (limited to 'lib/private/User')
-rw-r--r-- | lib/private/User/DisabledUserException.php | 10 | ||||
-rw-r--r-- | lib/private/User/DisplayNameCache.php | 6 | ||||
-rw-r--r-- | lib/private/User/LazyUser.php | 4 | ||||
-rw-r--r-- | lib/private/User/Listeners/UserChangedListener.php | 2 | ||||
-rw-r--r-- | lib/private/User/Manager.php | 26 | ||||
-rw-r--r-- | lib/private/User/Session.php | 23 | ||||
-rw-r--r-- | lib/private/User/User.php | 26 |
7 files changed, 75 insertions, 22 deletions
diff --git a/lib/private/User/DisabledUserException.php b/lib/private/User/DisabledUserException.php new file mode 100644 index 00000000000..db8a23d2027 --- /dev/null +++ b/lib/private/User/DisabledUserException.php @@ -0,0 +1,10 @@ +<?php + +/** + * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-only + */ +namespace OC\User; + +class DisabledUserException extends LoginException { +} diff --git a/lib/private/User/DisplayNameCache.php b/lib/private/User/DisplayNameCache.php index 34db783de68..40e1c752589 100644 --- a/lib/private/User/DisplayNameCache.php +++ b/lib/private/User/DisplayNameCache.php @@ -11,6 +11,7 @@ use OCP\EventDispatcher\Event; use OCP\EventDispatcher\IEventListener; use OCP\ICache; use OCP\ICacheFactory; +use OCP\IUser; use OCP\IUserManager; use OCP\User\Events\UserChangedEvent; use OCP\User\Events\UserDeletedEvent; @@ -37,6 +38,11 @@ class DisplayNameCache implements IEventListener { if (isset($this->cache[$userId])) { return $this->cache[$userId]; } + + if (strlen($userId) > IUser::MAX_USERID_LENGTH) { + return null; + } + $displayName = $this->memCache->get($userId); if ($displayName) { $this->cache[$userId] = $displayName; diff --git a/lib/private/User/LazyUser.php b/lib/private/User/LazyUser.php index 715265f6a39..501169019d4 100644 --- a/lib/private/User/LazyUser.php +++ b/lib/private/User/LazyUser.php @@ -160,6 +160,10 @@ class LazyUser implements IUser { return $this->getUser()->getQuota(); } + public function getQuotaBytes(): int|float { + return $this->getUser()->getQuotaBytes(); + } + public function setQuota($quota) { $this->getUser()->setQuota($quota); } diff --git a/lib/private/User/Listeners/UserChangedListener.php b/lib/private/User/Listeners/UserChangedListener.php index 983a4e81233..8f618950255 100644 --- a/lib/private/User/Listeners/UserChangedListener.php +++ b/lib/private/User/Listeners/UserChangedListener.php @@ -28,7 +28,7 @@ class UserChangedListener implements IEventListener { if (!($event instanceof UserChangedEvent)) { return; } - + $user = $event->getUser(); $feature = $event->getFeature(); $oldValue = $event->getOldValue(); diff --git a/lib/private/User/Manager.php b/lib/private/User/Manager.php index 1f23a9ae9fd..097fd9a0dc8 100644 --- a/lib/private/User/Manager.php +++ b/lib/private/User/Manager.php @@ -118,6 +118,10 @@ class Manager extends PublicEmitter implements IUserManager { return $this->cachedUsers[$uid]; } + if (strlen($uid) > IUser::MAX_USERID_LENGTH) { + return null; + } + $cachedBackend = $this->cache->get(sha1($uid)); if ($cachedBackend !== null && isset($this->backends[$cachedBackend])) { // Cache has the info of the user backend already, so ask that one directly @@ -177,6 +181,10 @@ class Manager extends PublicEmitter implements IUserManager { * @return bool */ public function userExists($uid) { + if (strlen($uid) > IUser::MAX_USERID_LENGTH) { + return false; + } + $user = $this->get($uid); return ($user !== null); } @@ -312,9 +320,9 @@ class Manager extends PublicEmitter implements IUserManager { $users, function (IUser $user) use ($search): bool { try { - return mb_stripos($user->getUID(), $search) !== false || - mb_stripos($user->getDisplayName(), $search) !== false || - mb_stripos($user->getEMailAddress() ?? '', $search) !== false; + return mb_stripos($user->getUID(), $search) !== false + || mb_stripos($user->getDisplayName(), $search) !== false + || mb_stripos($user->getEMailAddress() ?? '', $search) !== false; } catch (NoUserException $ex) { $this->logger->error('Error while filtering disabled users', ['exception' => $ex, 'userUID' => $user->getUID()]); return false; @@ -692,14 +700,14 @@ class Manager extends PublicEmitter implements IUserManager { public function validateUserId(string $uid, bool $checkDataDirectory = false): void { $l = Server::get(IFactory::class)->get('lib'); - // Check the name for bad characters + // Check the ID for bad characters // Allowed are: "a-z", "A-Z", "0-9", spaces and "_.@-'" if (preg_match('/[^a-zA-Z0-9 _.@\-\']/', $uid)) { throw new \InvalidArgumentException($l->t('Only the following characters are allowed in an Login:' . ' "a-z", "A-Z", "0-9", spaces and "_.@-\'"')); } - // No empty username + // No empty user ID if (trim($uid) === '') { throw new \InvalidArgumentException($l->t('A valid Login must be provided')); } @@ -709,11 +717,17 @@ class Manager extends PublicEmitter implements IUserManager { throw new \InvalidArgumentException($l->t('Login contains whitespace at the beginning or at the end')); } - // Username only consists of 1 or 2 dots (directory traversal) + // User ID only consists of 1 or 2 dots (directory traversal) if ($uid === '.' || $uid === '..') { throw new \InvalidArgumentException($l->t('Login must not consist of dots only')); } + // User ID is too long + if (strlen($uid) > IUser::MAX_USERID_LENGTH) { + // TRANSLATORS User ID is too long + throw new \InvalidArgumentException($l->t('Username is too long')); + } + if (!$this->verifyUid($uid, $checkDataDirectory)) { throw new \InvalidArgumentException($l->t('Login is invalid because files already exist for this user')); } diff --git a/lib/private/User/Session.php b/lib/private/User/Session.php index 27570822ef2..e7bfcf56407 100644 --- a/lib/private/User/Session.php +++ b/lib/private/User/Session.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors * SPDX-FileCopyrightText: 2016 ownCloud, Inc. @@ -319,7 +320,7 @@ class Session implements IUserSession, Emitter { // disabled users can not log in // injecting l10n does not work - there is a circular dependency between session and \OCP\L10N\IFactory $message = \OCP\Util::getL10N('lib')->t('Account disabled'); - throw new LoginException($message); + throw new DisabledUserException($message); } if ($regenerateSessionId) { @@ -967,6 +968,7 @@ class Session implements IUserSession, Emitter { if ($webRoot === '') { $webRoot = '/'; } + $domain = $this->config->getSystemValueString('cookie_domain'); $maxAge = $this->config->getSystemValueInt('remember_login_cookie_lifetime', 60 * 60 * 24 * 15); \OC\Http\CookieHelper::setCookie( @@ -974,7 +976,7 @@ class Session implements IUserSession, Emitter { $username, $maxAge, $webRoot, - '', + $domain, $secureCookie, true, \OC\Http\CookieHelper::SAMESITE_LAX @@ -984,7 +986,7 @@ class Session implements IUserSession, Emitter { $token, $maxAge, $webRoot, - '', + $domain, $secureCookie, true, \OC\Http\CookieHelper::SAMESITE_LAX @@ -995,7 +997,7 @@ class Session implements IUserSession, Emitter { $this->session->getId(), $maxAge, $webRoot, - '', + $domain, $secureCookie, true, \OC\Http\CookieHelper::SAMESITE_LAX @@ -1011,18 +1013,19 @@ class Session implements IUserSession, Emitter { public function unsetMagicInCookie() { //TODO: DI for cookies and IRequest $secureCookie = OC::$server->getRequest()->getServerProtocol() === 'https'; + $domain = $this->config->getSystemValueString('cookie_domain'); unset($_COOKIE['nc_username']); //TODO: DI unset($_COOKIE['nc_token']); unset($_COOKIE['nc_session_id']); - setcookie('nc_username', '', $this->timeFactory->getTime() - 3600, OC::$WEBROOT, '', $secureCookie, true); - setcookie('nc_token', '', $this->timeFactory->getTime() - 3600, OC::$WEBROOT, '', $secureCookie, true); - setcookie('nc_session_id', '', $this->timeFactory->getTime() - 3600, OC::$WEBROOT, '', $secureCookie, true); + setcookie('nc_username', '', $this->timeFactory->getTime() - 3600, OC::$WEBROOT, $domain, $secureCookie, true); + setcookie('nc_token', '', $this->timeFactory->getTime() - 3600, OC::$WEBROOT, $domain, $secureCookie, true); + setcookie('nc_session_id', '', $this->timeFactory->getTime() - 3600, OC::$WEBROOT, $domain, $secureCookie, true); // old cookies might be stored under /webroot/ instead of /webroot // and Firefox doesn't like it! - setcookie('nc_username', '', $this->timeFactory->getTime() - 3600, OC::$WEBROOT . '/', '', $secureCookie, true); - setcookie('nc_token', '', $this->timeFactory->getTime() - 3600, OC::$WEBROOT . '/', '', $secureCookie, true); - setcookie('nc_session_id', '', $this->timeFactory->getTime() - 3600, OC::$WEBROOT . '/', '', $secureCookie, true); + setcookie('nc_username', '', $this->timeFactory->getTime() - 3600, OC::$WEBROOT . '/', $domain, $secureCookie, true); + setcookie('nc_token', '', $this->timeFactory->getTime() - 3600, OC::$WEBROOT . '/', $domain, $secureCookie, true); + setcookie('nc_session_id', '', $this->timeFactory->getTime() - 3600, OC::$WEBROOT . '/', $domain, $secureCookie, true); } /** diff --git a/lib/private/User/User.php b/lib/private/User/User.php index f04977314e2..1f908918b20 100644 --- a/lib/private/User/User.php +++ b/lib/private/User/User.php @@ -11,7 +11,6 @@ use InvalidArgumentException; use OC\Accounts\AccountManager; use OC\Avatar\AvatarManager; use OC\Hooks\Emitter; -use OC_Helper; use OCP\Accounts\IAccountManager; use OCP\Comments\ICommentsManager; use OCP\EventDispatcher\IEventDispatcher; @@ -155,6 +154,7 @@ class User implements IUser { */ public function setSystemEMailAddress(string $mailAddress): void { $oldMailAddress = $this->getSystemEMailAddress(); + $mailAddress = mb_strtolower(trim($mailAddress)); if ($mailAddress === '') { $this->config->deleteUserValue($this->uid, 'settings', 'email'); @@ -177,6 +177,7 @@ class User implements IUser { * @inheritDoc */ public function setPrimaryEMailAddress(string $mailAddress): void { + $mailAddress = mb_strtolower(trim($mailAddress)); if ($mailAddress === '') { $this->config->deleteUserValue($this->uid, 'settings', 'primary_email'); return; @@ -515,14 +516,16 @@ class User implements IUser { * @inheritDoc */ public function getSystemEMailAddress(): ?string { - return $this->config->getUserValue($this->uid, 'settings', 'email', null); + $email = $this->config->getUserValue($this->uid, 'settings', 'email', null); + return $email ? mb_strtolower(trim($email)) : null; } /** * @inheritDoc */ public function getPrimaryEMailAddress(): ?string { - return $this->config->getUserValue($this->uid, 'settings', 'primary_email', null); + $email = $this->config->getUserValue($this->uid, 'settings', 'primary_email', null); + return $email ? mb_strtolower(trim($email)) : null; } /** @@ -559,6 +562,19 @@ class User implements IUser { return $quota; } + public function getQuotaBytes(): int|float { + $quota = $this->getQuota(); + if ($quota === 'none') { + return \OCP\Files\FileInfo::SPACE_UNLIMITED; + } + + $bytes = \OCP\Util::computerFileSize($quota); + if ($bytes === false) { + return \OCP\Files\FileInfo::SPACE_UNKNOWN; + } + return $bytes; + } + /** * set the users' quota * @@ -570,11 +586,11 @@ class User implements IUser { public function setQuota($quota) { $oldQuota = $this->config->getUserValue($this->uid, 'files', 'quota', ''); if ($quota !== 'none' and $quota !== 'default') { - $bytesQuota = OC_Helper::computerFileSize($quota); + $bytesQuota = \OCP\Util::computerFileSize($quota); if ($bytesQuota === false) { throw new InvalidArgumentException('Failed to set quota to invalid value ' . $quota); } - $quota = OC_Helper::humanFileSize($bytesQuota); + $quota = \OCP\Util::humanFileSize($bytesQuota); } if ($quota !== $oldQuota) { $this->config->setUserValue($this->uid, 'files', 'quota', $quota); |