diff options
Diffstat (limited to 'apps/dav/lib/DAV')
-rw-r--r-- | apps/dav/lib/DAV/CustomPropertiesBackend.php | 10 | ||||
-rw-r--r-- | apps/dav/lib/DAV/GroupPrincipalBackend.php | 13 | ||||
-rw-r--r-- | apps/dav/lib/DAV/Sharing/Backend.php | 53 | ||||
-rw-r--r-- | apps/dav/lib/DAV/Sharing/SharingMapper.php | 24 | ||||
-rw-r--r-- | apps/dav/lib/DAV/Sharing/SharingService.php | 10 | ||||
-rw-r--r-- | apps/dav/lib/DAV/ViewOnlyPlugin.php | 13 |
6 files changed, 95 insertions, 28 deletions
diff --git a/apps/dav/lib/DAV/CustomPropertiesBackend.php b/apps/dav/lib/DAV/CustomPropertiesBackend.php index c41ecd8450e..f3fff11b3da 100644 --- a/apps/dav/lib/DAV/CustomPropertiesBackend.php +++ b/apps/dav/lib/DAV/CustomPropertiesBackend.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors * SPDX-FileCopyrightText: 2016 ownCloud, Inc. @@ -92,6 +93,11 @@ class CustomPropertiesBackend implements BackendInterface { '{http://nextcloud.org/ns}lock-time', '{http://nextcloud.org/ns}lock-timeout', '{http://nextcloud.org/ns}lock-token', + // photos + '{http://nextcloud.org/ns}realpath', + '{http://nextcloud.org/ns}nbItems', + '{http://nextcloud.org/ns}face-detections', + '{http://nextcloud.org/ns}face-preview-image', ]; /** @@ -277,8 +283,8 @@ class CustomPropertiesBackend implements BackendInterface { */ public function move($source, $destination) { $statement = $this->connection->prepare( - 'UPDATE `*PREFIX*properties` SET `propertypath` = ?' . - ' WHERE `userid` = ? AND `propertypath` = ?' + 'UPDATE `*PREFIX*properties` SET `propertypath` = ?' + . ' WHERE `userid` = ? AND `propertypath` = ?' ); $statement->execute([$this->formatPath($destination), $this->user->getUID(), $this->formatPath($source)]); $statement->closeCursor(); diff --git a/apps/dav/lib/DAV/GroupPrincipalBackend.php b/apps/dav/lib/DAV/GroupPrincipalBackend.php index 143fc7d69f1..77ba45182c9 100644 --- a/apps/dav/lib/DAV/GroupPrincipalBackend.php +++ b/apps/dav/lib/DAV/GroupPrincipalBackend.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors * SPDX-FileCopyrightText: 2016 ownCloud, Inc. @@ -50,8 +51,10 @@ class GroupPrincipalBackend implements BackendInterface { $principals = []; if ($prefixPath === self::PRINCIPAL_PREFIX) { - foreach ($this->groupManager->search('') as $user) { - $principals[] = $this->groupToPrincipal($user); + foreach ($this->groupManager->search('') as $group) { + if (!$group->hideFromCollaboration()) { + $principals[] = $this->groupToPrincipal($group); + } } } @@ -77,7 +80,7 @@ class GroupPrincipalBackend implements BackendInterface { $name = urldecode($elements[2]); $group = $this->groupManager->get($name); - if (!is_null($group)) { + if ($group !== null && !$group->hideFromCollaboration()) { return $this->groupToPrincipal($group); } @@ -186,6 +189,10 @@ class GroupPrincipalBackend implements BackendInterface { $groups = $this->groupManager->search($value, $searchLimit); $results[] = array_reduce($groups, function (array $carry, IGroup $group) use ($restrictGroups) { + if ($group->hideFromCollaboration()) { + return $carry; + } + $gid = $group->getGID(); // is sharing restricted to groups only? if ($restrictGroups !== false) { diff --git a/apps/dav/lib/DAV/Sharing/Backend.php b/apps/dav/lib/DAV/Sharing/Backend.php index 06a082628d3..d60f5cca7c6 100644 --- a/apps/dav/lib/DAV/Sharing/Backend.php +++ b/apps/dav/lib/DAV/Sharing/Backend.php @@ -64,8 +64,8 @@ abstract class Backend { } $principalparts[2] = urldecode($principalparts[2]); - if (($principalparts[1] === 'users' && !$this->userManager->userExists($principalparts[2])) || - ($principalparts[1] === 'groups' && !$this->groupManager->groupExists($principalparts[2]))) { + if (($principalparts[1] === 'users' && !$this->userManager->userExists($principalparts[2])) + || ($principalparts[1] === 'groups' && !$this->groupManager->groupExists($principalparts[2]))) { // User or group does not exist continue; } @@ -90,14 +90,6 @@ abstract class Backend { // Delete any possible direct shares (since the frontend does not separate between them) $this->service->deleteShare($shareable->getResourceId(), $principal); - - // Check if a user has a groupshare that they're trying to free themselves from - // If so we need to add a self::ACCESS_UNSHARED row - if (!str_contains($principal, 'group') - && $this->service->hasGroupShare($oldShares) - ) { - $this->service->unshare($shareable->getResourceId(), $principal); - } } } @@ -204,4 +196,45 @@ abstract class Backend { } return $acl; } + + public function unshare(IShareable $shareable, string $principalUri): bool { + $this->shareCache->clear(); + + $principal = $this->principalBackend->findByUri($principalUri, ''); + if (empty($principal)) { + return false; + } + + if ($shareable->getOwner() === $principal) { + return false; + } + + // Delete any possible direct shares (since the frontend does not separate between them) + $this->service->deleteShare($shareable->getResourceId(), $principal); + + $needsUnshare = $this->hasAccessByGroupOrCirclesMembership( + $shareable->getResourceId(), + $principal + ); + + if ($needsUnshare) { + $this->service->unshare($shareable->getResourceId(), $principal); + } + + return true; + } + + private function hasAccessByGroupOrCirclesMembership(int $resourceId, string $principal) { + $memberships = array_merge( + $this->principalBackend->getGroupMembership($principal, true), + $this->principalBackend->getCircleMembership($principal) + ); + + $shares = array_column( + $this->service->getShares($resourceId), + 'principaluri' + ); + + return count(array_intersect($memberships, $shares)) > 0; + } } diff --git a/apps/dav/lib/DAV/Sharing/SharingMapper.php b/apps/dav/lib/DAV/Sharing/SharingMapper.php index 0aec5b7fe81..e4722208189 100644 --- a/apps/dav/lib/DAV/Sharing/SharingMapper.php +++ b/apps/dav/lib/DAV/Sharing/SharingMapper.php @@ -110,4 +110,28 @@ class SharingMapper { ->andWhere($query->expr()->eq('type', $query->createNamedParameter($resourceType))) ->executeStatement(); } + + public function getSharesByPrincipals(array $principals, string $resourceType): array { + $query = $this->db->getQueryBuilder(); + $result = $query->select(['id', 'principaluri', 'type', 'access', 'resourceid']) + ->from('dav_shares') + ->where($query->expr()->in('principaluri', $query->createNamedParameter($principals, IQueryBuilder::PARAM_STR_ARRAY), IQueryBuilder::PARAM_STR_ARRAY)) + ->andWhere($query->expr()->eq('type', $query->createNamedParameter($resourceType))) + ->orderBy('id') + ->executeQuery(); + + $rows = $result->fetchAll(); + $result->closeCursor(); + + return $rows; + } + + public function deleteUnsharesByPrincipal(string $principal, string $resourceType): void { + $query = $this->db->getQueryBuilder(); + $query->delete('dav_shares') + ->where($query->expr()->eq('principaluri', $query->createNamedParameter($principal))) + ->andWhere($query->expr()->eq('type', $query->createNamedParameter($resourceType))) + ->andWhere($query->expr()->eq('access', $query->createNamedParameter(Backend::ACCESS_UNSHARED, IQueryBuilder::PARAM_INT))) + ->executeStatement(); + } } diff --git a/apps/dav/lib/DAV/Sharing/SharingService.php b/apps/dav/lib/DAV/Sharing/SharingService.php index b9ac36ea066..11459e12d74 100644 --- a/apps/dav/lib/DAV/Sharing/SharingService.php +++ b/apps/dav/lib/DAV/Sharing/SharingService.php @@ -50,14 +50,4 @@ abstract class SharingService { public function getSharesForIds(array $resourceIds): array { return $this->mapper->getSharesForIds($resourceIds, $this->getResourceType()); } - - /** - * @param array $oldShares - * @return bool - */ - public function hasGroupShare(array $oldShares): bool { - return !empty(array_filter($oldShares, function (array $share) { - return $share['{http://owncloud.org/ns}group-share'] === true; - })); - } } diff --git a/apps/dav/lib/DAV/ViewOnlyPlugin.php b/apps/dav/lib/DAV/ViewOnlyPlugin.php index 4c3b49a45b0..9b9615b8063 100644 --- a/apps/dav/lib/DAV/ViewOnlyPlugin.php +++ b/apps/dav/lib/DAV/ViewOnlyPlugin.php @@ -84,18 +84,25 @@ class ViewOnlyPlugin extends ServerPlugin { if (!$storage->instanceOfStorage(ISharedStorage::class)) { return true; } + // Extract extra permissions /** @var ISharedStorage $storage */ $share = $storage->getShare(); - $attributes = $share->getAttributes(); if ($attributes === null) { return true; } - // Check if read-only and on whether permission can download is both set and disabled. + // We have two options here, if download is disabled, but viewing is allowed, + // we still allow the GET request to return the file content. $canDownload = $attributes->getAttribute('permissions', 'download'); - if ($canDownload !== null && !$canDownload) { + if (!$share->canSeeContent()) { + throw new Forbidden('Access to this shared resource has been denied because its download permission is disabled.'); + } + + // If download is disabled, we disable the COPY and MOVE methods even if the + // shareapi_allow_view_without_download is set to true. + if ($request->getMethod() !== 'GET' && ($canDownload !== null && !$canDownload)) { throw new Forbidden('Access to this shared resource has been denied because its download permission is disabled.'); } } catch (NotFound $e) { |