diff options
author | Andy Scherzinger <info@andy-scherzinger.de> | 2023-12-07 11:10:09 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-12-07 11:10:09 +0100 |
commit | 48b7eff03c84e2d8d6e44eccf4ff7bfcf2cccc44 (patch) | |
tree | 738b0d8a843b5a0b25c9607fbfcde3075c5749bb /lib/private | |
parent | 14b759d0d35113b4b50f00d3c8d7156d63de3387 (diff) | |
parent | 5e0f5645e67f48b0aef25396c1dbc9211a180310 (diff) | |
download | nextcloud-server-48b7eff03c84e2d8d6e44eccf4ff7bfcf2cccc44.tar.gz nextcloud-server-48b7eff03c84e2d8d6e44eccf4ff7bfcf2cccc44.zip |
Merge branch 'stable26' into backport/39044/stable26
Diffstat (limited to 'lib/private')
-rw-r--r-- | lib/private/AppFramework/Http/Request.php | 10 | ||||
-rw-r--r-- | lib/private/Authentication/TwoFactorAuth/Db/ProviderUserAssignmentDao.php | 37 | ||||
-rw-r--r-- | lib/private/DB/QueryBuilder/QueryBuilder.php | 2 | ||||
-rw-r--r-- | lib/private/Files/Cache/Wrapper/CacheJail.php | 2 | ||||
-rw-r--r-- | lib/private/Files/Config/UserMountCache.php | 2 | ||||
-rw-r--r-- | lib/private/Files/Mount/Manager.php | 19 | ||||
-rw-r--r-- | lib/private/Files/Storage/Local.php | 33 | ||||
-rw-r--r-- | lib/private/Files/Storage/Wrapper/Jail.php | 5 | ||||
-rw-r--r-- | lib/private/Files/Template/TemplateManager.php | 5 | ||||
-rw-r--r-- | lib/private/Log.php | 2 | ||||
-rw-r--r-- | lib/private/OCM/Model/OCMProvider.php | 34 | ||||
-rw-r--r-- | lib/private/OCM/Model/OCMResource.php | 18 | ||||
-rw-r--r-- | lib/private/Preview/Imaginary.php | 5 | ||||
-rw-r--r-- | lib/private/Security/RemoteHostValidator.php | 4 | ||||
-rw-r--r-- | lib/private/SystemConfig.php | 3 | ||||
-rw-r--r-- | lib/private/URLGenerator.php | 15 | ||||
-rw-r--r-- | lib/private/Updater/VersionCheck.php | 4 | ||||
-rw-r--r-- | lib/private/User/Session.php | 5 |
18 files changed, 138 insertions, 67 deletions
diff --git a/lib/private/AppFramework/Http/Request.php b/lib/private/AppFramework/Http/Request.php index 1f32d6c5461..a5039788197 100644 --- a/lib/private/AppFramework/Http/Request.php +++ b/lib/private/AppFramework/Http/Request.php @@ -597,9 +597,11 @@ class Request implements \ArrayAccess, \Countable, IRequest { // only have one default, so we cannot ship an insecure product out of the box ]); - foreach ($forwardedForHeaders as $header) { + // Read the x-forwarded-for headers and values in reverse order as per + // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-For#selecting_an_ip_address + foreach (array_reverse($forwardedForHeaders) as $header) { if (isset($this->server[$header])) { - foreach (explode(',', $this->server[$header]) as $IP) { + foreach (array_reverse(explode(',', $this->server[$header])) as $IP) { $IP = trim($IP); // remove brackets from IPv6 addresses @@ -607,6 +609,10 @@ class Request implements \ArrayAccess, \Countable, IRequest { $IP = substr($IP, 1, -1); } + if ($this->isTrustedProxy($trustedProxies, $IP)) { + continue; + } + if (filter_var($IP, FILTER_VALIDATE_IP) !== false) { return $IP; } diff --git a/lib/private/Authentication/TwoFactorAuth/Db/ProviderUserAssignmentDao.php b/lib/private/Authentication/TwoFactorAuth/Db/ProviderUserAssignmentDao.php index 19d80218562..66bb9df8271 100644 --- a/lib/private/Authentication/TwoFactorAuth/Db/ProviderUserAssignmentDao.php +++ b/lib/private/Authentication/TwoFactorAuth/Db/ProviderUserAssignmentDao.php @@ -25,8 +25,6 @@ declare(strict_types=1); */ namespace OC\Authentication\TwoFactorAuth\Db; -use Doctrine\DBAL\Exception\UniqueConstraintViolationException; -use OCP\DB\QueryBuilder\IQueryBuilder; use OCP\IDBConnection; use function array_map; @@ -70,25 +68,24 @@ class ProviderUserAssignmentDao { * Persist a new/updated (provider_id, uid, enabled) tuple */ public function persist(string $providerId, string $uid, int $enabled) { - $qb = $this->conn->getQueryBuilder(); - - try { - // Insert a new entry - $insertQuery = $qb->insert(self::TABLE_NAME)->values([ - 'provider_id' => $qb->createNamedParameter($providerId), - 'uid' => $qb->createNamedParameter($uid), - 'enabled' => $qb->createNamedParameter($enabled, IQueryBuilder::PARAM_INT), - ]); - - $insertQuery->execute(); - } catch (UniqueConstraintViolationException $ex) { - // There is already an entry -> update it - $updateQuery = $qb->update(self::TABLE_NAME) - ->set('enabled', $qb->createNamedParameter($enabled)) - ->where($qb->expr()->eq('provider_id', $qb->createNamedParameter($providerId))) - ->andWhere($qb->expr()->eq('uid', $qb->createNamedParameter($uid))); - $updateQuery->execute(); + $conn = $this->conn; + + // Insert a new entry + if ($conn->insertIgnoreConflict(self::TABLE_NAME, [ + 'provider_id' => $providerId, + 'uid' => $uid, + 'enabled' => $enabled, + ])) { + return; } + + // There is already an entry -> update it + $qb = $conn->getQueryBuilder(); + $updateQuery = $qb->update(self::TABLE_NAME) + ->set('enabled', $qb->createNamedParameter($enabled)) + ->where($qb->expr()->eq('provider_id', $qb->createNamedParameter($providerId))) + ->andWhere($qb->expr()->eq('uid', $qb->createNamedParameter($uid))); + $updateQuery->executeStatement(); } /** diff --git a/lib/private/DB/QueryBuilder/QueryBuilder.php b/lib/private/DB/QueryBuilder/QueryBuilder.php index 43ed68f5616..039596a8fba 100644 --- a/lib/private/DB/QueryBuilder/QueryBuilder.php +++ b/lib/private/DB/QueryBuilder/QueryBuilder.php @@ -866,7 +866,7 @@ class QueryBuilder implements IQueryBuilder { public function where(...$predicates) { if ($this->getQueryPart('where') !== null && $this->systemConfig->getValue('debug', false)) { // Only logging a warning, not throwing for now. - $e = new QueryException('Using where() on non-empty WHERE part, please verify it is intentional to not call whereAnd() or whereOr() instead. Otherwise consider creating a new query builder object or call resetQueryPart(\'where\') first.'); + $e = new QueryException('Using where() on non-empty WHERE part, please verify it is intentional to not call andWhere() or orWhere() instead. Otherwise consider creating a new query builder object or call resetQueryPart(\'where\') first.'); $this->logger->warning($e->getMessage(), ['exception' => $e]); } diff --git a/lib/private/Files/Cache/Wrapper/CacheJail.php b/lib/private/Files/Cache/Wrapper/CacheJail.php index c4446473833..6ad753f3b39 100644 --- a/lib/private/Files/Cache/Wrapper/CacheJail.php +++ b/lib/private/Files/Cache/Wrapper/CacheJail.php @@ -52,8 +52,6 @@ class CacheJail extends CacheWrapper { public function __construct($cache, $root) { parent::__construct($cache); $this->root = $root; - $this->connection = \OC::$server->getDatabaseConnection(); - $this->mimetypeLoader = \OC::$server->getMimeTypeLoader(); if ($cache instanceof CacheJail) { $this->unjailedRoot = $cache->getSourcePath($root); diff --git a/lib/private/Files/Config/UserMountCache.php b/lib/private/Files/Config/UserMountCache.php index aa362b0e970..69eb35d1cca 100644 --- a/lib/private/Files/Config/UserMountCache.php +++ b/lib/private/Files/Config/UserMountCache.php @@ -456,7 +456,7 @@ class UserMountCache implements IUserMountCache { }, $mounts); $mounts = array_combine($mountPoints, $mounts); - $current = $path; + $current = rtrim($path, '/'); // walk up the directory tree until we find a path that has a mountpoint set // the loop will return if a mountpoint is found or break if none are found while (true) { diff --git a/lib/private/Files/Mount/Manager.php b/lib/private/Files/Mount/Manager.php index ba933d8f20e..94304ff4838 100644 --- a/lib/private/Files/Mount/Manager.php +++ b/lib/private/Files/Mount/Manager.php @@ -10,6 +10,7 @@ declare(strict_types=1); * @author Robin Appelman <robin@icewind.nl> * @author Robin McCorkell <robin@mccorkell.me.uk> * @author Roeland Jago Douma <roeland@famdouma.nl> + * @author Jonas <jonas@freesources.org> * * @license AGPL-3.0 * @@ -33,6 +34,7 @@ use OCP\Cache\CappedMemoryCache; use OC\Files\Filesystem; use OC\Files\SetupManager; use OC\Files\SetupManagerFactory; +use OCP\Files\Config\ICachedMountInfo; use OCP\Files\Mount\IMountManager; use OCP\Files\Mount\IMountPoint; use OCP\Files\NotFoundException; @@ -235,4 +237,21 @@ class Manager implements IMountManager { }); } } + + /** + * Return the mount matching a cached mount info (or mount file info) + * + * @param ICachedMountInfo $info + * + * @return IMountPoint|null + */ + public function getMountFromMountInfo(ICachedMountInfo $info): ?IMountPoint { + $this->setupManager->setupForPath($info->getMountPoint()); + foreach ($this->mounts as $mount) { + if ($mount->getMountPoint() === $info->getMountPoint()) { + return $mount; + } + } + return null; + } } diff --git a/lib/private/Files/Storage/Local.php b/lib/private/Files/Storage/Local.php index 6dad028155b..c2865f79cba 100644 --- a/lib/private/Files/Storage/Local.php +++ b/lib/private/Files/Storage/Local.php @@ -73,6 +73,8 @@ class Local extends \OC\Files\Storage\Common { protected bool $unlinkOnTruncate; + protected bool $caseInsensitive = false; + public function __construct($arguments) { if (!isset($arguments['datadir']) || !is_string($arguments['datadir'])) { throw new \InvalidArgumentException('No data directory set for local storage'); @@ -92,6 +94,7 @@ class Local extends \OC\Files\Storage\Common { $this->config = \OC::$server->get(IConfig::class); $this->mimeTypeDetector = \OC::$server->get(IMimeTypeDetector::class); $this->defUMask = $this->config->getSystemValue('localstorage.umask', 0022); + $this->caseInsensitive = $this->config->getSystemValueBool('localstorage.case_insensitive', false); // support Write-Once-Read-Many file systems $this->unlinkOnTruncate = $this->config->getSystemValue('localstorage.unlink_on_truncate', false); @@ -155,6 +158,9 @@ class Local extends \OC\Files\Storage\Common { } public function is_dir($path) { + if ($this->caseInsensitive && !$this->file_exists($path)) { + return false; + } if (substr($path, -1) == '/') { $path = substr($path, 0, -1); } @@ -162,6 +168,9 @@ class Local extends \OC\Files\Storage\Common { } public function is_file($path) { + if ($this->caseInsensitive && !$this->file_exists($path)) { + return false; + } return is_file($this->getSourcePath($path)); } @@ -264,7 +273,13 @@ class Local extends \OC\Files\Storage\Common { } public function file_exists($path) { - return file_exists($this->getSourcePath($path)); + if ($this->caseInsensitive) { + $fullPath = $this->getSourcePath($path); + $content = scandir(dirname($fullPath), SCANDIR_SORT_NONE); + return is_array($content) && array_search(basename($fullPath), $content) !== false; + } else { + return file_exists($this->getSourcePath($path)); + } } public function filemtime($path) { @@ -375,7 +390,16 @@ class Local extends \OC\Files\Storage\Common { $this->checkTreeForForbiddenItems($this->getSourcePath($source)); } - return rename($this->getSourcePath($source), $this->getSourcePath($target)); + if (rename($this->getSourcePath($source), $this->getSourcePath($target))) { + if ($this->caseInsensitive) { + if (mb_strtolower($target) === mb_strtolower($source) && !$this->file_exists($target)) { + return false; + } + } + return true; + } + + return false; } public function copy($source, $target) { @@ -388,6 +412,11 @@ class Local extends \OC\Files\Storage\Common { } $result = copy($this->getSourcePath($source), $this->getSourcePath($target)); umask($oldMask); + if ($this->caseInsensitive) { + if (mb_strtolower($target) === mb_strtolower($source) && !$this->file_exists($target)) { + return false; + } + } return $result; } } diff --git a/lib/private/Files/Storage/Wrapper/Jail.php b/lib/private/Files/Storage/Wrapper/Jail.php index e21a2cba244..255c800d13f 100644 --- a/lib/private/Files/Storage/Wrapper/Jail.php +++ b/lib/private/Files/Storage/Wrapper/Jail.php @@ -396,10 +396,7 @@ class Jail extends Wrapper { * @return \OC\Files\Cache\Cache */ public function getCache($path = '', $storage = null) { - if (!$storage) { - $storage = $this->getWrapperStorage(); - } - $sourceCache = $this->getWrapperStorage()->getCache($this->getUnjailedPath($path), $storage); + $sourceCache = $this->getWrapperStorage()->getCache($this->getUnjailedPath($path)); return new CacheJail($sourceCache, $this->rootPath); } diff --git a/lib/private/Files/Template/TemplateManager.php b/lib/private/Files/Template/TemplateManager.php index 4603c14278f..e5cede4830e 100644 --- a/lib/private/Files/Template/TemplateManager.php +++ b/lib/private/Files/Template/TemplateManager.php @@ -274,6 +274,11 @@ class TemplateManager implements ITemplateManager { $isDefaultTemplates = $skeletonTemplatePath === $defaultTemplateDirectory; $userLang = $this->l10nFactory->getUserLanguage($this->userManager->get($this->userId)); + if ($skeletonTemplatePath === '') { + $this->setTemplatePath(''); + return ''; + } + try { $l10n = $this->l10nFactory->get('lib', $userLang); $userFolder = $this->rootFolder->getUserFolder($this->userId); diff --git a/lib/private/Log.php b/lib/private/Log.php index 3ba87526941..f6f057002b5 100644 --- a/lib/private/Log.php +++ b/lib/private/Log.php @@ -338,7 +338,7 @@ class Log implements ILogger, IDataLogger { unset($data['app']); unset($data['level']); $data = array_merge($serializer->serializeException($exception), $data); - $data = $this->interpolateMessage($data, $context['message'] ?? '--', 'CustomMessage'); + $data = $this->interpolateMessage($data, isset($context['message']) && $context['message'] !== '' ? $context['message'] : ('Exception thrown: ' . get_class($exception)), 'CustomMessage'); array_walk($context, [$this->normalizer, 'format']); diff --git a/lib/private/OCM/Model/OCMProvider.php b/lib/private/OCM/Model/OCMProvider.php index 44f4fbebc10..1a8d943f79f 100644 --- a/lib/private/OCM/Model/OCMProvider.php +++ b/lib/private/OCM/Model/OCMProvider.php @@ -26,27 +26,27 @@ declare(strict_types=1); namespace OC\OCM\Model; -use JsonSerializable; use OCP\OCM\Exceptions\OCMArgumentException; use OCP\OCM\Exceptions\OCMProviderException; use OCP\OCM\IOCMProvider; +use OCP\OCM\IOCMResource; /** * @since 28.0.0 */ -class OCMProvider implements IOCMProvider, JsonSerializable { +class OCMProvider implements IOCMProvider { private bool $enabled = false; private string $apiVersion = ''; private string $endPoint = ''; - /** @var OCMResource[] */ + /** @var IOCMResource[] */ private array $resourceTypes = []; /** * @param bool $enabled * - * @return OCMProvider + * @return $this */ - public function setEnabled(bool $enabled): self { + public function setEnabled(bool $enabled): static { $this->enabled = $enabled; return $this; @@ -62,9 +62,9 @@ class OCMProvider implements IOCMProvider, JsonSerializable { /** * @param string $apiVersion * - * @return OCMProvider + * @return $this */ - public function setApiVersion(string $apiVersion): self { + public function setApiVersion(string $apiVersion): static { $this->apiVersion = $apiVersion; return $this; @@ -80,9 +80,9 @@ class OCMProvider implements IOCMProvider, JsonSerializable { /** * @param string $endPoint * - * @return OCMProvider + * @return $this */ - public function setEndPoint(string $endPoint): self { + public function setEndPoint(string $endPoint): static { $this->endPoint = $endPoint; return $this; @@ -96,29 +96,29 @@ class OCMProvider implements IOCMProvider, JsonSerializable { } /** - * @param OCMResource $resource + * @param IOCMResource $resource * * @return $this */ - public function addResourceType(OCMResource $resource): self { + public function addResourceType(IOCMResource $resource): static { $this->resourceTypes[] = $resource; return $this; } /** - * @param OCMResource[] $resourceTypes + * @param IOCMResource[] $resourceTypes * - * @return OCMProvider + * @return $this */ - public function setResourceTypes(array $resourceTypes): self { + public function setResourceTypes(array $resourceTypes): static { $this->resourceTypes = $resourceTypes; return $this; } /** - * @return OCMResource[] + * @return IOCMResource[] */ public function getResourceTypes(): array { return $this->resourceTypes; @@ -151,11 +151,11 @@ class OCMProvider implements IOCMProvider, JsonSerializable { * * @param array $data * - * @return self + * @return $this * @throws OCMProviderException in case a descent provider cannot be generated from data * @see self::jsonSerialize() */ - public function import(array $data): self { + public function import(array $data): static { $this->setEnabled(is_bool($data['enabled'] ?? '') ? $data['enabled'] : false) ->setApiVersion((string)($data['apiVersion'] ?? '')) ->setEndPoint($data['endPoint'] ?? ''); diff --git a/lib/private/OCM/Model/OCMResource.php b/lib/private/OCM/Model/OCMResource.php index 12948aa8949..c4a91f2eabf 100644 --- a/lib/private/OCM/Model/OCMResource.php +++ b/lib/private/OCM/Model/OCMResource.php @@ -26,13 +26,12 @@ declare(strict_types=1); namespace OC\OCM\Model; -use JsonSerializable; use OCP\OCM\IOCMResource; /** * @since 28.0.0 */ -class OCMResource implements IOCMResource, JsonSerializable { +class OCMResource implements IOCMResource { private string $name = ''; /** @var string[] */ private array $shareTypes = []; @@ -42,9 +41,9 @@ class OCMResource implements IOCMResource, JsonSerializable { /** * @param string $name * - * @return OCMResource + * @return $this */ - public function setName(string $name): self { + public function setName(string $name): static { $this->name = $name; return $this; @@ -60,9 +59,9 @@ class OCMResource implements IOCMResource, JsonSerializable { /** * @param string[] $shareTypes * - * @return OCMResource + * @return $this */ - public function setShareTypes(array $shareTypes): self { + public function setShareTypes(array $shareTypes): static { $this->shareTypes = $shareTypes; return $this; @@ -80,7 +79,7 @@ class OCMResource implements IOCMResource, JsonSerializable { * * @return $this */ - public function setProtocols(array $protocols): self { + public function setProtocols(array $protocols): static { $this->protocols = $protocols; return $this; @@ -98,17 +97,16 @@ class OCMResource implements IOCMResource, JsonSerializable { * * @param array $data * - * @return self + * @return $this * @see self::jsonSerialize() */ - public function import(array $data): self { + public function import(array $data): static { return $this->setName((string)($data['name'] ?? '')) ->setShareTypes($data['shareTypes'] ?? []) ->setProtocols($data['protocols'] ?? []); } /** - * * @return array{ * name: string, * shareTypes: string[], diff --git a/lib/private/Preview/Imaginary.php b/lib/private/Preview/Imaginary.php index b26c2505a59..7b806491649 100644 --- a/lib/private/Preview/Imaginary.php +++ b/lib/private/Preview/Imaginary.php @@ -78,6 +78,9 @@ class Imaginary extends ProviderV2 { // Object store $stream = $file->fopen('r'); + if (!$stream || !is_resource($stream) || feof($stream)) { + return null; + } $httpClient = $this->service->newClient(); @@ -146,7 +149,7 @@ class Imaginary extends ProviderV2 { 'timeout' => 120, 'connect_timeout' => 3, ]); - } catch (\Exception $e) { + } catch (\Throwable $e) { $this->logger->error('Imaginary preview generation failed: ' . $e->getMessage(), [ 'exception' => $e, ]); diff --git a/lib/private/Security/RemoteHostValidator.php b/lib/private/Security/RemoteHostValidator.php index e48bd862472..dc6fdaf222a 100644 --- a/lib/private/Security/RemoteHostValidator.php +++ b/lib/private/Security/RemoteHostValidator.php @@ -60,6 +60,10 @@ final class RemoteHostValidator implements IRemoteHostValidator { } $host = idn_to_utf8(strtolower(urldecode($host))); + if ($host === false) { + return false; + } + // Remove brackets from IPv6 addresses if (strpos($host, '[') === 0 && substr($host, -1) === ']') { $host = substr($host, 1, -1); diff --git a/lib/private/SystemConfig.php b/lib/private/SystemConfig.php index a18c4c2a138..c104f001809 100644 --- a/lib/private/SystemConfig.php +++ b/lib/private/SystemConfig.php @@ -118,6 +118,9 @@ class SystemConfig { ], ], ], + 'onlyoffice' => [ + 'jwt_secret' => true, + ], ]; /** @var Config */ diff --git a/lib/private/URLGenerator.php b/lib/private/URLGenerator.php index a5a3609703b..9154ce591a1 100644 --- a/lib/private/URLGenerator.php +++ b/lib/private/URLGenerator.php @@ -116,16 +116,25 @@ class URLGenerator implements IURLGenerator { } public function linkToOCSRouteAbsolute(string $routeName, array $arguments = []): string { + // Returns `/subfolder/index.php/ocsapp/…` with `'htaccess.IgnoreFrontController' => false` in config.php + // And `/subfolder/ocsapp/…` with `'htaccess.IgnoreFrontController' => true` in config.php $route = $this->router->generate('ocs.'.$routeName, $arguments, false); - $indexPhpPos = strpos($route, '/index.php/'); - if ($indexPhpPos !== false) { - $route = substr($route, $indexPhpPos + 10); + // Cut off `/subfolder` + if (\OC::$WEBROOT !== '' && str_starts_with($route, \OC::$WEBROOT)) { + $route = substr($route, \strlen(\OC::$WEBROOT)); } + if (str_starts_with($route, '/index.php/')) { + $route = substr($route, 10); + } + + // Remove `ocsapp/` bit $route = substr($route, 7); + // Prefix with ocs/v2.php endpoint $route = '/ocs/v2.php' . $route; + // Turn into an absolute URL return $this->getAbsoluteURL($route); } diff --git a/lib/private/Updater/VersionCheck.php b/lib/private/Updater/VersionCheck.php index d4a3a843314..86cb2f624b0 100644 --- a/lib/private/Updater/VersionCheck.php +++ b/lib/private/Updater/VersionCheck.php @@ -123,7 +123,9 @@ class VersionCheck { */ protected function getUrlContent($url) { $client = $this->clientService->newClient(); - $response = $client->get($url); + $response = $client->get($url, [ + 'timeout' => 5, + ]); return $response->getBody(); } diff --git a/lib/private/User/Session.php b/lib/private/User/Session.php index 6b97f8925c3..baf516beba4 100644 --- a/lib/private/User/Session.php +++ b/lib/private/User/Session.php @@ -781,7 +781,7 @@ class Session implements IUserSession, Emitter { try { $dbToken = $this->tokenProvider->getToken($token); } catch (InvalidTokenException $ex) { - $this->logger->warning('Session token is invalid because it does not exist', [ + $this->logger->debug('Session token is invalid because it does not exist', [ 'app' => 'core', 'user' => $user, 'exception' => $ex, @@ -914,9 +914,10 @@ class Session implements IUserSession, Emitter { ]); return false; } catch (InvalidTokenException $ex) { - $this->logger->error('Renewing session token failed', [ + $this->logger->error('Renewing session token failed: ' . $ex->getMessage(), [ 'app' => 'core', 'user' => $uid, + 'exception' => $ex, ]); return false; } |