diff --git a/apps/files_sharing/lib/Cache.php b/apps/files_sharing/lib/Cache.php index 143a9f719b9d1..08a48c398f07f 100644 --- a/apps/files_sharing/lib/Cache.php +++ b/apps/files_sharing/lib/Cache.php @@ -146,6 +146,9 @@ protected function formatCacheEntry($entry, $path = null) { try { if (isset($entry['permissions'])) { + // keep the unmasked permissions so a future scan or cross-storage + // copy doesn't persist the share-masked permissions in the cache + $entry['scan_permissions'] ??= $entry['permissions']; $entry['permissions'] &= $this->share->getPermissions(); } else { $entry['permissions'] = $this->storage->getPermissions($entry['path']); diff --git a/apps/files_sharing/tests/CacheTest.php b/apps/files_sharing/tests/CacheTest.php index e8c63e6fc126b..47ca960c7a119 100644 --- a/apps/files_sharing/tests/CacheTest.php +++ b/apps/files_sharing/tests/CacheTest.php @@ -556,6 +556,55 @@ public function testSearchShareJailedStorage(): void { $this->assertCount(1, $results); } + public function testSingleFileShareKeepsUnmaskedPermissionsAsScanPermissions(): void { + $sourceEntry = $this->ownerCache->get('files/container/shared single file.txt'); + + /** @var SharedStorage $sharedStorage */ + [$sharedStorage] = $this->user2View->resolvePath('shared single file.txt'); + $entry = $sharedStorage->getCache()->get(''); + + $mask = Constants::PERMISSION_ALL & ~(Constants::PERMISSION_CREATE | Constants::PERMISSION_DELETE); + $this->assertEquals($sourceEntry->getPermissions() & $mask, $entry->getPermissions()); + $this->assertEquals($sourceEntry->getPermissions(), $entry['scan_permissions']); + } + + public function testFolderShareKeepsUnmaskedPermissionsAsScanPermissions(): void { + self::loginHelper(self::TEST_FILES_SHARING_API_USER1); + + $rootFolder = \OC::$server->getUserFolder(self::TEST_FILES_SHARING_API_USER1); + $node = $rootFolder->get('container'); + $share = $this->shareManager->newShare(); + $share->setNode($node) + ->setShareType(IShare::TYPE_USER) + ->setSharedWith(self::TEST_FILES_SHARING_API_USER2) + ->setSharedBy(self::TEST_FILES_SHARING_API_USER1) + ->setPermissions(Constants::PERMISSION_READ | Constants::PERMISSION_SHARE); + $share = $this->shareManager->createShare($share); + $share->setStatus(IShare::STATUS_ACCEPTED); + $this->shareManager->updateShare($share); + Server::get(ISetupManager::class)->tearDown(); + + self::loginHelper(self::TEST_FILES_SHARING_API_USER2); + + /** @var SharedStorage $sharedStorage */ + [$sharedStorage] = $this->user2View->resolvePath('container'); + $sharedCache = $sharedStorage->getCache(); + $mask = Constants::PERMISSION_READ | Constants::PERMISSION_SHARE; + + $entry = $sharedCache->get('shareddir/bar.txt'); + $sourceEntry = $this->ownerCache->get('files/container/shareddir/bar.txt'); + $this->assertEquals($sourceEntry->getPermissions() & $mask, $entry->getPermissions()); + $this->assertEquals($sourceEntry->getPermissions(), $entry['scan_permissions']); + + $children = $sharedCache->getFolderContents('shareddir'); + $this->assertNotEmpty($children); + foreach ($children as $child) { + $sourceChild = $this->ownerCache->get('files/container/shareddir/' . $child->getName()); + $this->assertEquals($sourceChild->getPermissions() & $mask, $child->getPermissions()); + $this->assertEquals($sourceChild->getPermissions(), $child['scan_permissions']); + } + } + public function testWatcherRootChange(): void { $sourceStorage = new Temporary(); $sourceStorage->mkdir('shared');