diff options
Diffstat (limited to 'lib/private')
-rw-r--r-- | lib/private/Calendar/Manager.php | 17 | ||||
-rw-r--r-- | lib/private/Federation/CloudIdManager.php | 79 | ||||
-rw-r--r-- | lib/private/Files/SetupManager.php | 8 | ||||
-rw-r--r-- | lib/private/Files/Storage/Wrapper/Quota.php | 71 | ||||
-rw-r--r-- | lib/private/Files/Stream/HashWrapper.php | 11 | ||||
-rw-r--r-- | lib/private/NavigationManager.php | 2 | ||||
-rw-r--r-- | lib/private/Repair/MoveUpdaterStepFile.php | 4 | ||||
-rw-r--r-- | lib/private/Server.php | 8 | ||||
-rw-r--r-- | lib/private/Settings/Manager.php | 7 | ||||
-rw-r--r-- | lib/private/User/Database.php | 4 | ||||
-rw-r--r-- | lib/private/User/Session.php | 8 | ||||
-rw-r--r-- | lib/private/User/User.php | 8 |
12 files changed, 189 insertions, 38 deletions
diff --git a/lib/private/Calendar/Manager.php b/lib/private/Calendar/Manager.php index f0b8e9fd50d..550ba36dd6b 100644 --- a/lib/private/Calendar/Manager.php +++ b/lib/private/Calendar/Manager.php @@ -330,12 +330,27 @@ class Manager implements IManager { // to the email address in the ORGANIZER. // We don't want to accept a CANCEL request from just anyone $organizer = substr($vEvent->{'ORGANIZER'}->getValue(), 7); - if (strcasecmp($sender, $organizer) !== 0 && strcasecmp($replyTo, $organizer) !== 0) { + $isNotOrganizer = ($replyTo !== null) ? (strcasecmp($sender, $organizer) !== 0 && strcasecmp($replyTo, $organizer) !== 0) : (strcasecmp($sender, $organizer) !== 0); + if ($isNotOrganizer) { $this->logger->warning('Sender must be the ORGANIZER of this event'); return false; } + //check if the event is in the future + /** @var DateTime $eventTime */ + $eventTime = $vEvent->{'DTSTART'}; + if ($eventTime->getDateTime()->getTimeStamp() < $this->timeFactory->getTime()) { // this might cause issues with recurrences + $this->logger->warning('Only events in the future are processed'); + return false; + } + + // Check if we have a calendar to work with $calendars = $this->getCalendarsForPrincipal($principalUri); + if (empty($calendars)) { + $this->logger->warning('Could not find any calendars for principal ' . $principalUri); + return false; + } + $found = null; // if the attendee has been found in at least one calendar event with the UID of the iMIP event // we process it. diff --git a/lib/private/Federation/CloudIdManager.php b/lib/private/Federation/CloudIdManager.php index 77bb9437ba2..e4e42cb1293 100644 --- a/lib/private/Federation/CloudIdManager.php +++ b/lib/private/Federation/CloudIdManager.php @@ -30,11 +30,17 @@ declare(strict_types=1); */ namespace OC\Federation; +use OCA\DAV\Events\CardUpdatedEvent; use OCP\Contacts\IManager; +use OCP\EventDispatcher\Event; +use OCP\EventDispatcher\IEventDispatcher; use OCP\Federation\ICloudId; use OCP\Federation\ICloudIdManager; +use OCP\ICache; +use OCP\ICacheFactory; use OCP\IURLGenerator; use OCP\IUserManager; +use OCP\User\Events\UserChangedEvent; class CloudIdManager implements ICloudIdManager { /** @var IManager */ @@ -43,11 +49,48 @@ class CloudIdManager implements ICloudIdManager { private $urlGenerator; /** @var IUserManager */ private $userManager; - - public function __construct(IManager $contactsManager, IURLGenerator $urlGenerator, IUserManager $userManager) { + private ICache $memCache; + /** @var array[] */ + private array $cache = []; + + public function __construct( + IManager $contactsManager, + IURLGenerator $urlGenerator, + IUserManager $userManager, + ICacheFactory $cacheFactory, + IEventDispatcher $eventDispatcher + ) { $this->contactsManager = $contactsManager; $this->urlGenerator = $urlGenerator; $this->userManager = $userManager; + $this->memCache = $cacheFactory->createDistributed('cloud_id_'); + $eventDispatcher->addListener(UserChangedEvent::class, [$this, 'handleUserEvent']); + $eventDispatcher->addListener(CardUpdatedEvent::class, [$this, 'handleCardEvent']); + } + + public function handleUserEvent(Event $event): void { + if ($event instanceof UserChangedEvent && $event->getFeature() === 'displayName') { + $userId = $event->getUser()->getUID(); + $key = $userId . '@local'; + unset($this->cache[$key]); + $this->memCache->remove($key); + } + } + + public function handleCardEvent(Event $event): void { + if ($event instanceof CardUpdatedEvent) { + $data = $event->getCardData()['carddata']; + foreach (explode("\r\n", $data) as $line) { + if (strpos($line, "CLOUD;") === 0) { + $parts = explode(':', $line, 2); + if (isset($parts[1])) { + $key = $parts[1]; + unset($this->cache[$key]); + $this->memCache->remove($key); + } + } + } + } } /** @@ -120,18 +163,42 @@ class CloudIdManager implements ICloudIdManager { * @return CloudId */ public function getCloudId(string $user, ?string $remote): ICloudId { - if ($remote === null) { + $isLocal = $remote === null; + if ($isLocal) { $remote = rtrim($this->removeProtocolFromUrl($this->urlGenerator->getAbsoluteURL('/')), '/'); $fixedRemote = $this->fixRemoteURL($remote); - $localUser = $this->userManager->get($user); - $displayName = !is_null($localUser) ? $localUser->getDisplayName() : ''; + $host = $fixedRemote; } else { - // TODO check what the correct url is for remote (asking the remote) + // note that for remote id's we don't strip the protocol for the remote we use to construct the CloudId + // this way if a user has an explicit non-https cloud id this will be preserved + // we do still use the version without protocol for looking up the display name $fixedRemote = $this->fixRemoteURL($remote); $host = $this->removeProtocolFromUrl($fixedRemote); + } + + $key = $user . '@' . ($isLocal ? 'local' : $host); + $cached = $this->cache[$key] ?? $this->memCache->get($key); + if ($cached) { + $this->cache[$key] = $cached; // put items from memcache into local cache + return new CloudId($cached['id'], $cached['user'], $cached['remote'], $cached['displayName']); + } + + if ($isLocal) { + $localUser = $this->userManager->get($user); + $displayName = $localUser ? $localUser->getDisplayName() : ''; + } else { $displayName = $this->getDisplayNameFromContact($user . '@' . $host); } $id = $user . '@' . $remote; + + $data = [ + 'id' => $id, + 'user' => $user, + 'remote' => $fixedRemote, + 'displayName' => $displayName, + ]; + $this->cache[$key] = $data; + $this->memCache->set($key, $data, 15 * 60); return new CloudId($id, $user, $fixedRemote, $displayName); } diff --git a/lib/private/Files/SetupManager.php b/lib/private/Files/SetupManager.php index 5782a5a72a6..d52a291cd99 100644 --- a/lib/private/Files/SetupManager.php +++ b/lib/private/Files/SetupManager.php @@ -172,10 +172,10 @@ class SetupManager { */ if ($storage->instanceOfStorage(HomeObjectStoreStorage::class) || $storage->instanceOfStorage(Home::class)) { if (is_object($storage->getUser())) { - $quota = OC_Util::getUserQuota($storage->getUser()); - if ($quota !== \OCP\Files\FileInfo::SPACE_UNLIMITED) { - return new Quota(['storage' => $storage, 'quota' => $quota, 'root' => 'files']); - } + $user = $storage->getUser(); + return new Quota(['storage' => $storage, 'quotaCallback' => function () use ($user) { + return OC_Util::getUserQuota($user); + }, 'root' => 'files']); } } diff --git a/lib/private/Files/Storage/Wrapper/Quota.php b/lib/private/Files/Storage/Wrapper/Quota.php index 4cd0a5e0b4a..8b129472eb0 100644 --- a/lib/private/Files/Storage/Wrapper/Quota.php +++ b/lib/private/Files/Storage/Wrapper/Quota.php @@ -33,40 +33,47 @@ namespace OC\Files\Storage\Wrapper; use OC\Files\Filesystem; +use OC\SystemConfig; use OCP\Files\Cache\ICacheEntry; +use OCP\Files\FileInfo; use OCP\Files\Storage\IStorage; class Quota extends Wrapper { - - /** - * @var int $quota - */ - protected $quota; - - /** - * @var string $sizeRoot - */ - protected $sizeRoot; - - private $config; + /** @var callable|null */ + protected $quotaCallback; + protected ?int $quota; + protected string $sizeRoot; + private SystemConfig $config; /** * @param array $parameters */ public function __construct($parameters) { parent::__construct($parameters); - $this->quota = $parameters['quota']; - $this->sizeRoot = isset($parameters['root']) ? $parameters['root'] : ''; - $this->config = \OC::$server->getSystemConfig(); + $this->quota = $parameters['quota'] ?? null; + $this->quotaCallback = $parameters['quotaCallback'] ?? null; + $this->sizeRoot = $parameters['root'] ?? ''; + $this->config = \OC::$server->get(SystemConfig::class); } /** * @return int quota value */ - public function getQuota() { + public function getQuota(): int { + if ($this->quota === null) { + $quotaCallback = $this->quotaCallback; + if ($quotaCallback === null) { + throw new \Exception("No quota or quota callback provider"); + } + $this->quota = $quotaCallback(); + } return $this->quota; } + private function hasQuota(): bool { + return $this->getQuota() !== FileInfo::SPACE_UNLIMITED; + } + /** * @param string $path * @param \OC\Files\Storage\Storage $storage @@ -100,7 +107,10 @@ class Quota extends Wrapper { * @return int|bool */ public function free_space($path) { - if ($this->quota < 0 || strpos($path, 'cache') === 0 || strpos($path, 'uploads') === 0) { + if (!$this->hasQuota()) { + return $this->storage->free_space($path); + } + if ($this->getQuota() < 0 || strpos($path, 'cache') === 0 || strpos($path, 'uploads') === 0) { return $this->storage->free_space($path); } else { $used = $this->getSize($this->sizeRoot); @@ -108,7 +118,7 @@ class Quota extends Wrapper { return \OCP\Files\FileInfo::SPACE_NOT_COMPUTED; } else { $free = $this->storage->free_space($path); - $quotaFree = max($this->quota - $used, 0); + $quotaFree = max($this->getQuota() - $used, 0); // if free space is known if ($free >= 0) { $free = min($free, $quotaFree); @@ -128,6 +138,9 @@ class Quota extends Wrapper { * @return int|false */ public function file_put_contents($path, $data) { + if (!$this->hasQuota()) { + return $this->storage->file_put_contents($path, $data); + } $free = $this->free_space($path); if ($free < 0 or strlen($data) < $free) { return $this->storage->file_put_contents($path, $data); @@ -144,6 +157,9 @@ class Quota extends Wrapper { * @return bool */ public function copy($source, $target) { + if (!$this->hasQuota()) { + return $this->storage->copy($source, $target); + } $free = $this->free_space($target); if ($free < 0 or $this->getSize($source) < $free) { return $this->storage->copy($source, $target); @@ -160,6 +176,9 @@ class Quota extends Wrapper { * @return resource|bool */ public function fopen($path, $mode) { + if (!$this->hasQuota()) { + return $this->storage->fopen($path, $mode); + } $source = $this->storage->fopen($path, $mode); // don't apply quota for part files @@ -202,6 +221,9 @@ class Quota extends Wrapper { * @return bool */ public function copyFromStorage(IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath) { + if (!$this->hasQuota()) { + return $this->storage->copyFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath); + } $free = $this->free_space($targetInternalPath); if ($free < 0 or $this->getSize($sourceInternalPath, $sourceStorage) < $free) { return $this->storage->copyFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath); @@ -217,6 +239,9 @@ class Quota extends Wrapper { * @return bool */ public function moveFromStorage(IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath) { + if (!$this->hasQuota()) { + return $this->storage->moveFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath); + } $free = $this->free_space($targetInternalPath); if ($free < 0 or $this->getSize($sourceInternalPath, $sourceStorage) < $free) { return $this->storage->moveFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath); @@ -226,8 +251,11 @@ class Quota extends Wrapper { } public function mkdir($path) { + if (!$this->hasQuota()) { + return $this->storage->mkdir($path); + } $free = $this->free_space($path); - if ($this->shouldApplyQuota($path) && $free === 0.0) { + if ($this->shouldApplyQuota($path) && $free == 0) { return false; } @@ -235,8 +263,11 @@ class Quota extends Wrapper { } public function touch($path, $mtime = null) { + if (!$this->hasQuota()) { + return $this->storage->touch($path, $mtime); + } $free = $this->free_space($path); - if ($free === 0.0) { + if ($free == 0) { return false; } diff --git a/lib/private/Files/Stream/HashWrapper.php b/lib/private/Files/Stream/HashWrapper.php index fd9bb3cdd0b..4060d74de7d 100644 --- a/lib/private/Files/Stream/HashWrapper.php +++ b/lib/private/Files/Stream/HashWrapper.php @@ -67,7 +67,16 @@ class HashWrapper extends Wrapper { public function stream_close() { if (is_callable($this->callback)) { - call_user_func($this->callback, hash_final($this->hash)); + // if the stream is closed as a result of the end-of-request GC, the hash context might be cleaned up before this stream + if ($this->hash instanceof \HashContext) { + try { + $hash = @hash_final($this->hash); + if ($hash) { + call_user_func($this->callback, $hash); + } + } catch (\Throwable $e) { + } + } // prevent further calls by potential PHP 7 GC ghosts $this->callback = null; } diff --git a/lib/private/NavigationManager.php b/lib/private/NavigationManager.php index bbf28d2c142..7fd76850816 100644 --- a/lib/private/NavigationManager.php +++ b/lib/private/NavigationManager.php @@ -228,7 +228,7 @@ class NavigationManager implements INavigationManager { 'id' => 'admin_settings', 'order' => 3, 'href' => $this->urlGenerator->linkToRoute('settings.AdminSettings.index', ['section' => 'overview']), - 'name' => $l->t('Admin settings'), + 'name' => $l->t('Administration settings'), 'icon' => $this->urlGenerator->imagePath('settings', 'admin.svg'), ]); } else { diff --git a/lib/private/Repair/MoveUpdaterStepFile.php b/lib/private/Repair/MoveUpdaterStepFile.php index bc7430d7a7f..020510804d7 100644 --- a/lib/private/Repair/MoveUpdaterStepFile.php +++ b/lib/private/Repair/MoveUpdaterStepFile.php @@ -43,14 +43,14 @@ class MoveUpdaterStepFile implements IRepairStep { } public function run(IOutput $output) { - $dataDir = $this->config->getSystemValue('datadirectory', \OC::$SERVERROOT . '/data'); + $updateDir = $this->config->getSystemValue('updatedirectory') ?? $this->config->getSystemValue('datadirectory', \OC::$SERVERROOT . '/data'); $instanceId = $this->config->getSystemValue('instanceid', null); if (!is_string($instanceId) || empty($instanceId)) { return; } - $updaterFolderPath = $dataDir . '/updater-' . $instanceId; + $updaterFolderPath = $updateDir . '/updater-' . $instanceId; $stepFile = $updaterFolderPath . '/.step'; if (file_exists($stepFile)) { $output->info('.step file exists'); diff --git a/lib/private/Server.php b/lib/private/Server.php index f18ac7b6534..c1a50cfcaff 100644 --- a/lib/private/Server.php +++ b/lib/private/Server.php @@ -1365,7 +1365,13 @@ class Server extends ServerContainer implements IServerContainer { }); $this->registerService(ICloudIdManager::class, function (ContainerInterface $c) { - return new CloudIdManager($c->get(\OCP\Contacts\IManager::class), $c->get(IURLGenerator::class), $c->get(IUserManager::class)); + return new CloudIdManager( + $c->get(\OCP\Contacts\IManager::class), + $c->get(IURLGenerator::class), + $c->get(IUserManager::class), + $c->get(ICacheFactory::class), + $c->get(IEventDispatcher::class), + ); }); $this->registerAlias(\OCP\GlobalScale\IConfig::class, \OC\GlobalScale\Config::class); diff --git a/lib/private/Settings/Manager.php b/lib/private/Settings/Manager.php index 05a286e4758..44f1df09c15 100644 --- a/lib/private/Settings/Manager.php +++ b/lib/private/Settings/Manager.php @@ -150,6 +150,13 @@ class Manager implements IManager { return $this->sections[$type]; } + public function getSection(string $type, string $sectionId): ?IIconSection { + if (isset($this->sections[$type]) && isset($this->sections[$type][$sectionId])) { + return $this->sections[$type][$sectionId]; + } + return null; + } + protected function isKnownDuplicateSectionId(string $sectionID): bool { return in_array($sectionID, [ 'connected-accounts', diff --git a/lib/private/User/Database.php b/lib/private/User/Database.php index 0b38f04bfe3..f106c2e8b6d 100644 --- a/lib/private/User/Database.php +++ b/lib/private/User/Database.php @@ -212,11 +212,13 @@ class Database extends ABackend implements * @param string $displayName The new display name * @return bool * + * @throws \InvalidArgumentException + * * Change the display name of a user */ public function setDisplayName(string $uid, string $displayName): bool { if (mb_strlen($displayName) > 64) { - return false; + throw new \InvalidArgumentException('Invalid displayname'); } $this->fixDI(); diff --git a/lib/private/User/Session.php b/lib/private/User/Session.php index 626ddca2dad..65a213d4bf8 100644 --- a/lib/private/User/Session.php +++ b/lib/private/User/Session.php @@ -865,6 +865,10 @@ class Session implements IUserSession, Emitter { $tokens = $this->config->getUserKeys($uid, 'login_token'); // test cookies token against stored tokens if (!in_array($currentToken, $tokens, true)) { + $this->logger->error('Tried to log in {uid} but could not verify token', [ + 'app' => 'core', + 'uid' => $uid, + ]); return false; } // replace successfully used token with a new one @@ -876,6 +880,10 @@ class Session implements IUserSession, Emitter { $sessionId = $this->session->getId(); $token = $this->tokenProvider->renewSessionToken($oldSessionId, $sessionId); } catch (SessionNotAvailableException $ex) { + $this->logger->warning('Could not renew session token for {uid} because the session is unavailable', [ + 'app' => 'core', + 'uid' => $uid, + ]); return false; } catch (InvalidTokenException $ex) { $this->logger->warning('Renewing session token failed', ['app' => 'core']); diff --git a/lib/private/User/User.php b/lib/private/User/User.php index 7f7d6273e30..f5d93dcd680 100644 --- a/lib/private/User/User.php +++ b/lib/private/User/User.php @@ -154,6 +154,9 @@ class User implements IUser { * * @param string $displayName * @return bool + * + * @since 25.0.0 Throw InvalidArgumentException + * @throws \InvalidArgumentException */ public function setDisplayName($displayName) { $displayName = trim($displayName); @@ -196,7 +199,7 @@ class User implements IUser { $this->setPrimaryEMailAddress(''); } - if ($oldMailAddress !== $mailAddress) { + if ($oldMailAddress !== strtolower($mailAddress)) { $this->triggerChange('eMailAddress', $mailAddress, $oldMailAddress); } } @@ -556,6 +559,9 @@ class User implements IUser { public function getCloudId() { $uid = $this->getUID(); $server = $this->urlGenerator->getAbsoluteURL('/'); + if (substr($server, -10) === '/index.php') { + $server = substr($server, 0, -10); + } $server = rtrim($this->removeProtocolFromUrl($server), '/'); return $uid . '@' . $server; } |