Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(dav): Ensure share properties are also set on public remote endpoint #46987

Merged
merged 2 commits into from
Aug 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions apps/dav/appinfo/v2/publicremote.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
use OC\Files\Storage\Wrapper\PermissionsMask;
use OC\Files\View;
use OCA\DAV\Storage\PublicOwnerWrapper;
use OCA\DAV\Storage\PublicShareWrapper;
use OCA\FederatedFileSharing\FederatedShareProvider;
use OCP\EventDispatcher\IEventDispatcher;
use OCP\Files\Mount\IMountManager;
Expand Down Expand Up @@ -98,6 +99,12 @@
return new PublicOwnerWrapper(['storage' => $storage, 'owner' => $share->getShareOwner()]);
});

// Ensure that also private shares have the `getShare` method
/** @psalm-suppress MissingClosureParamType */
Filesystem::addStorageWrapper('getShare', function ($mountPoint, $storage) use ($share) {
return new PublicShareWrapper(['storage' => $storage, 'share' => $share]);
}, 0);

/** @psalm-suppress InternalMethod */
Filesystem::logWarningWhenAddingStorageWrapper($previousLog);

Expand Down
1 change: 1 addition & 0 deletions apps/dav/composer/composer/autoload_classmap.php
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,7 @@
'OCA\\DAV\\SetupChecks\\NeedsSystemAddressBookSync' => $baseDir . '/../lib/SetupChecks/NeedsSystemAddressBookSync.php',
'OCA\\DAV\\SetupChecks\\WebdavEndpoint' => $baseDir . '/../lib/SetupChecks/WebdavEndpoint.php',
'OCA\\DAV\\Storage\\PublicOwnerWrapper' => $baseDir . '/../lib/Storage/PublicOwnerWrapper.php',
'OCA\\DAV\\Storage\\PublicShareWrapper' => $baseDir . '/../lib/Storage/PublicShareWrapper.php',
'OCA\\DAV\\SystemTag\\SystemTagList' => $baseDir . '/../lib/SystemTag/SystemTagList.php',
'OCA\\DAV\\SystemTag\\SystemTagMappingNode' => $baseDir . '/../lib/SystemTag/SystemTagMappingNode.php',
'OCA\\DAV\\SystemTag\\SystemTagNode' => $baseDir . '/../lib/SystemTag/SystemTagNode.php',
Expand Down
1 change: 1 addition & 0 deletions apps/dav/composer/composer/autoload_static.php
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,7 @@ class ComposerStaticInitDAV
'OCA\\DAV\\SetupChecks\\NeedsSystemAddressBookSync' => __DIR__ . '/..' . '/../lib/SetupChecks/NeedsSystemAddressBookSync.php',
'OCA\\DAV\\SetupChecks\\WebdavEndpoint' => __DIR__ . '/..' . '/../lib/SetupChecks/WebdavEndpoint.php',
'OCA\\DAV\\Storage\\PublicOwnerWrapper' => __DIR__ . '/..' . '/../lib/Storage/PublicOwnerWrapper.php',
'OCA\\DAV\\Storage\\PublicShareWrapper' => __DIR__ . '/..' . '/../lib/Storage/PublicShareWrapper.php',
'OCA\\DAV\\SystemTag\\SystemTagList' => __DIR__ . '/..' . '/../lib/SystemTag/SystemTagList.php',
'OCA\\DAV\\SystemTag\\SystemTagMappingNode' => __DIR__ . '/..' . '/../lib/SystemTag/SystemTagMappingNode.php',
'OCA\\DAV\\SystemTag\\SystemTagNode' => __DIR__ . '/..' . '/../lib/SystemTag/SystemTagNode.php',
Expand Down
9 changes: 3 additions & 6 deletions apps/dav/lib/Connector/Sabre/FilesPlugin.php
Original file line number Diff line number Diff line change
Expand Up @@ -345,17 +345,14 @@
return $node->getNode()->getInternalPath() === '' ? 'true' : 'false';
});

$propFind->handle(self::SHARE_NOTE, function () use ($node, $httpRequest): ?string {
$propFind->handle(self::SHARE_NOTE, function () use ($node): ?string {
$user = $this->userSession->getUser();
if ($user === null) {
return null;
}
return $node->getNoteFromShare(
$user->getUID()
$user?->getUID()
Fixed Show fixed Hide fixed
);
});

$propFind->handle(self::DATA_FINGERPRINT_PROPERTYNAME, function () use ($node) {
$propFind->handle(self::DATA_FINGERPRINT_PROPERTYNAME, function () {
Dismissed Show dismissed Hide dismissed
return $this->config->getSystemValue('data-fingerprint', '');
});
$propFind->handle(self::CREATIONDATE_PROPERTYNAME, function () use ($node) {
Expand Down
52 changes: 24 additions & 28 deletions apps/dav/lib/Connector/Sabre/Node.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
use OCP\Files\DavUtil;
use OCP\Files\FileInfo;
use OCP\Files\IRootFolder;
use OCP\Files\NotFoundException;
use OCP\Files\Storage\ISharedStorage;
use OCP\Files\StorageNotAvailableException;
use OCP\Share\Exceptions\ShareNotFound;
use OCP\Share\IManager;
Expand Down Expand Up @@ -261,8 +263,8 @@ public function getSharePermissions($user) {
$storage = null;
}

if ($storage && $storage->instanceOfStorage('\OCA\Files_Sharing\SharedStorage')) {
/** @var \OCA\Files_Sharing\SharedStorage $storage */
if ($storage && $storage->instanceOfStorage(ISharedStorage::class)) {
/** @var ISharedStorage $storage */
$permissions = (int)$storage->getShare()->getPermissions();
} else {
$permissions = $this->info->getPermissions();
Expand Down Expand Up @@ -298,16 +300,15 @@ public function getSharePermissions($user) {
* @return array
*/
public function getShareAttributes(): array {
$attributes = [];

try {
$storage = $this->info->getStorage();
} catch (StorageNotAvailableException $e) {
$storage = null;
$storage = $this->node->getStorage();
} catch (NotFoundException $e) {
return [];
}

if ($storage && $storage->instanceOfStorage(\OCA\Files_Sharing\SharedStorage::class)) {
/** @var \OCA\Files_Sharing\SharedStorage $storage */
$attributes = [];
if ($storage->instanceOfStorage(ISharedStorage::class)) {
/** @var ISharedStorage $storage */
$attributes = $storage->getShare()->getAttributes();
if ($attributes === null) {
return [];
Expand All @@ -319,29 +320,24 @@ public function getShareAttributes(): array {
return $attributes;
}

/**
* @param string $user
* @return string
*/
public function getNoteFromShare($user) {
if ($user === null) {
return '';
public function getNoteFromShare(?string $user): ?string {
try {
$storage = $this->node->getStorage();
} catch (NotFoundException) {
return null;
}

// Retrieve note from the share object already loaded into
// memory, to avoid additional database queries.
$storage = $this->getNode()->getStorage();
if (!$storage->instanceOfStorage(\OCA\Files_Sharing\SharedStorage::class)) {
return '';
if ($storage->instanceOfStorage(ISharedStorage::class)) {
/** @var ISharedStorage $storage */
$share = $storage->getShare();
if ($user === $share->getShareOwner()) {
// Note is only for recipient not the owner
return null;
}
return $share->getNote();
}
/** @var \OCA\Files_Sharing\SharedStorage $storage */

$share = $storage->getShare();
$note = $share->getNote();
if ($share->getShareOwner() !== $user) {
return $note;
}
return '';
return null;
}

/**
Expand Down
5 changes: 3 additions & 2 deletions apps/dav/lib/DAV/ViewOnlyPlugin.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
use OCA\Files_Versions\Sabre\VersionFile;
use OCP\Files\Folder;
use OCP\Files\NotFoundException;
use OCP\Files\Storage\ISharedStorage;
use Sabre\DAV\Exception\NotFound;
use Sabre\DAV\Server;
use Sabre\DAV\ServerPlugin;
Expand Down Expand Up @@ -81,11 +82,11 @@ public function checkViewOnly(RequestInterface $request): bool {

$storage = $node->getStorage();

if (!$storage->instanceOfStorage(\OCA\Files_Sharing\SharedStorage::class)) {
if (!$storage->instanceOfStorage(ISharedStorage::class)) {
return true;
}
// Extract extra permissions
/** @var \OCA\Files_Sharing\SharedStorage $storage */
/** @var ISharedStorage $storage */
$share = $storage->getShare();

$attributes = $share->getAttributes();
Expand Down
39 changes: 39 additions & 0 deletions apps/dav/lib/Storage/PublicShareWrapper.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<?php

declare(strict_types=1);

/**
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
namespace OCA\DAV\Storage;

use OC\Files\Storage\Wrapper\Wrapper;
use OCP\Files\Storage\ISharedStorage;
use OCP\Share\IShare;

class PublicShareWrapper extends Wrapper implements ISharedStorage {

private IShare $share;

/**
* @param array $arguments ['storage' => $storage, 'share' => $share]
*
* $storage: The storage the permissions mask should be applied on
* $share: The share to use in case no share is found
*/
public function __construct($arguments) {
parent::__construct($arguments);
$this->share = $arguments['share'];
}

public function getShare(): IShare {
$storage = parent::getWrapperStorage();
if (method_exists($storage, 'getShare')) {
/** @var ISharedStorage $storage */
return $storage->getShare();
}

return $this->share;
}
}
14 changes: 10 additions & 4 deletions apps/dav/tests/unit/Connector/Sabre/NodeTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

use OC\Files\FileInfo;
use OC\Files\Mount\MountPoint;
use OC\Files\Node\Folder;
use OC\Files\View;
use OC\Share20\ShareAttributes;
use OCA\Files_Sharing\SharedMount;
Expand All @@ -21,6 +22,7 @@
use OCP\ICache;
use OCP\Share\IManager;
use OCP\Share\IShare;
use PHPUnit\Framework\MockObject\MockObject;

/**
* Class NodeTest
Expand Down Expand Up @@ -201,14 +203,16 @@ public function testShareAttributes(): void {

$share->expects($this->once())->method('getAttributes')->willReturn($attributes);

$info = $this->getMockBuilder(FileInfo::class)
/** @var Folder&MockObject $info */
$info = $this->getMockBuilder(Folder::class)
->disableOriginalConstructor()
->setMethods(['getStorage', 'getType'])
->onlyMethods(['getStorage', 'getType'])
->getMock();

$info->method('getStorage')->willReturn($storage);
$info->method('getType')->willReturn(FileInfo::TYPE_FOLDER);

/** @var View&MockObject $view */
$view = $this->getMockBuilder(View::class)
->disableOriginalConstructor()
->getMock();
Expand All @@ -225,14 +229,16 @@ public function testShareAttributesNonShare(): void {

$shareManager = $this->getMockBuilder(IManager::class)->disableOriginalConstructor()->getMock();

$info = $this->getMockBuilder(FileInfo::class)
/** @var Folder&MockObject */
$info = $this->getMockBuilder(Folder::class)
->disableOriginalConstructor()
->setMethods(['getStorage', 'getType'])
->onlyMethods(['getStorage', 'getType'])
->getMock();

$info->method('getStorage')->willReturn($storage);
$info->method('getType')->willReturn(FileInfo::TYPE_FOLDER);

/** @var View&MockObject */
$view = $this->getMockBuilder(View::class)
->disableOriginalConstructor()
->getMock();
Expand Down
5 changes: 3 additions & 2 deletions apps/dav/tests/unit/DAV/ViewOnlyPluginTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
use OCA\Files_Versions\Versions\IVersion;
use OCP\Files\File;
use OCP\Files\Folder;
use OCP\Files\Storage\ISharedStorage;
use OCP\Files\Storage\IStorage;
use OCP\IUser;
use OCP\Share\IAttributes;
Expand Down Expand Up @@ -65,7 +66,7 @@ public function testCanGetNonShared(): void {

$storage = $this->createMock(IStorage::class);
$file->method('getStorage')->willReturn($storage);
$storage->method('instanceOfStorage')->with(SharedStorage::class)->willReturn(false);
$storage->method('instanceOfStorage')->with(ISharedStorage::class)->willReturn(false);

$this->assertTrue($this->plugin->checkViewOnly($this->request));
}
Expand Down Expand Up @@ -140,7 +141,7 @@ public function testCanGet(bool $isVersion, ?bool $attrEnabled, bool $expectCanD
$nodeInfo->expects($this->once())
->method('getStorage')
->willReturn($storage);
$storage->method('instanceOfStorage')->with(SharedStorage::class)->willReturn(true);
$storage->method('instanceOfStorage')->with(ISharedStorage::class)->willReturn(true);
$storage->method('getShare')->willReturn($share);

$extAttr = $this->createMock(IAttributes::class);
Expand Down
3 changes: 3 additions & 0 deletions apps/files_sharing/lib/ISharedStorage.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,8 @@

use OCP\Files\Storage\IStorage;

/**
* @deprecated 30.0.0 use `\OCP\Files\Storage\ISharedStorage` instead
*/
interface ISharedStorage extends IStorage {
}
5 changes: 3 additions & 2 deletions apps/files_sharing/lib/SharedStorage.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,16 @@
use OC\Files\Storage\Wrapper\Wrapper;
use OC\User\NoUserException;
use OCA\Files_External\Config\ConfigAdapter;
use OCA\Files_Sharing\ISharedStorage as LegacyISharedStorage;
use OCP\Constants;
use OCP\Files\Cache\ICacheEntry;
use OCP\Files\Config\IUserMountCache;
use OCP\Files\Folder;
use OCP\Files\IHomeStorage;
use OCP\Files\IRootFolder;
use OCP\Files\Node;
use OCP\Files\NotFoundException;
use OCP\Files\Storage\IDisableEncryptionStorage;
use OCP\Files\Storage\ISharedStorage;
use OCP\Files\Storage\IStorage;
use OCP\Lock\ILockingProvider;
use OCP\Share\IShare;
Expand All @@ -35,7 +36,7 @@
/**
* Convert target path to source path and pass the function call to the correct storage provider
*/
class SharedStorage extends \OC\Files\Storage\Wrapper\Jail implements ISharedStorage, IDisableEncryptionStorage {
class SharedStorage extends \OC\Files\Storage\Wrapper\Jail implements LegacyISharedStorage, ISharedStorage, IDisableEncryptionStorage {
Dismissed Show dismissed Hide dismissed
github-advanced-security[bot] marked this conversation as resolved.
Dismissed
Show resolved Hide resolved
/** @var \OCP\Share\IShare */
private $superShare;

Expand Down
7 changes: 3 additions & 4 deletions apps/files_versions/lib/Versions/LegacyVersionsBackend.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@
use Exception;
use OC\Files\View;
use OCA\DAV\Connector\Sabre\Exception\Forbidden;
use OCA\Files_Sharing\ISharedStorage;
use OCA\Files_Sharing\SharedStorage;
use OCA\Files_Versions\Db\VersionEntity;
use OCA\Files_Versions\Db\VersionsMapper;
use OCA\Files_Versions\Storage;
Expand All @@ -24,6 +22,7 @@
use OCP\Files\IRootFolder;
use OCP\Files\Node;
use OCP\Files\NotFoundException;
use OCP\Files\Storage\ISharedStorage;
use OCP\Files\Storage\IStorage;
use OCP\IUser;
use OCP\IUserManager;
Expand All @@ -48,7 +47,7 @@ public function useBackendForStorage(IStorage $storage): bool {
public function getVersionsForFile(IUser $user, FileInfo $file): array {
$storage = $file->getStorage();

if ($storage->instanceOfStorage(SharedStorage::class)) {
if ($storage->instanceOfStorage(ISharedStorage::class)) {
$owner = $storage->getOwner('');
$user = $this->userManager->get($owner);

Expand Down Expand Up @@ -192,7 +191,7 @@ public function getVersionFile(IUser $user, FileInfo $sourceFile, $revision): Fi

// Shared files have their versions in the owners root folder so we need to obtain them from there
if ($storage->instanceOfStorage(ISharedStorage::class) && $owner) {
/** @var SharedStorage $storage */
/** @var ISharedStorage $storage */
$userFolder = $this->rootFolder->getUserFolder($owner->getUID());
$user = $owner;
$ownerPathInStorage = $sourceFile->getInternalPath();
Expand Down
22 changes: 22 additions & 0 deletions build/integration/dav_features/dav-v2-public.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
# SPDX-License-Identifier: AGPL-3.0-or-later
Feature: dav-v2-public
Background:
Given using api version "1"

Scenario: See note to recipient in public shares
Given using new dav path
And As an "admin"
And user "user0" exists
And user "user1" exists
And As an "user1"
And user "user1" created a folder "/testshare"
And as "user1" creating a share with
| path | testshare |
| shareType | 3 |
| permissions | 1 |
| note | Hello |
And As an "user0"
Given using new public dav path
When Requesting share note on dav endpoint
Then the single response should contain a property "{http://nextcloud.org/ns}note" with value "Hello"
Loading
Loading