From e7d7014c30951a1f8c6587bfb8df2d637a0941e4 Mon Sep 17 00:00:00 2001 From: nfebe Date: Mon, 17 Nov 2025 19:41:32 +0100 Subject: [PATCH] fix(sharing): Inherit correct share atrributes 4 federated storage When creating public shares from federated storage, getById() can return an empty array if the storage isn't in the mount cache (e.g., unscanned federated shares). This causes the inheritance check loop to skip entirely, leaving restrictive defaults that incorrectly hide the download button. Add fallback to use the node already set on the share object during creation when getById() returns empty. Signed-off-by: nfebe --- .../lib/Controller/ShareAPIController.php | 14 ++++++++- .../Controller/ShareAPIControllerTest.php | 29 +++++++++++++++++++ 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/apps/files_sharing/lib/Controller/ShareAPIController.php b/apps/files_sharing/lib/Controller/ShareAPIController.php index fb8a702cbd4..2e5ec8ada34 100644 --- a/apps/files_sharing/lib/Controller/ShareAPIController.php +++ b/apps/files_sharing/lib/Controller/ShareAPIController.php @@ -2098,10 +2098,22 @@ class ShareAPIController extends OCSController { $canDownload = false; $hideDownload = true; - $userExplicitlySetHideDownload = $share->getHideDownload(); // Capture user's explicit choice + $userExplicitlySetHideDownload = $share->getHideDownload(); $userFolder = $this->rootFolder->getUserFolder($share->getSharedBy()); $nodes = $userFolder->getById($share->getNodeId()); + + // Fallback: getById fails for federated storage when mount cache is incomplete. + // Use node already set on share during creation. + if (empty($nodes)) { + try { + $node = $share->getNode(); + $nodes = [$node]; + } catch (\Exception $e) { + return; + } + } + foreach ($nodes as $node) { // Owner always can download it - so allow it, but respect their explicit choice about hiding downloads if ($node->getOwner()?->getUID() === $share->getSharedBy()) { diff --git a/apps/files_sharing/tests/Controller/ShareAPIControllerTest.php b/apps/files_sharing/tests/Controller/ShareAPIControllerTest.php index 30a946c7847..5c7774de704 100644 --- a/apps/files_sharing/tests/Controller/ShareAPIControllerTest.php +++ b/apps/files_sharing/tests/Controller/ShareAPIControllerTest.php @@ -5648,4 +5648,33 @@ class ShareAPIControllerTest extends TestCase { $this->invokePrivate($ocs, 'checkInheritedAttributes', [$share]); } + + public function testFederatedStorageFallbackWhenGetByIdEmpty(): void { + $ocs = $this->mockFormatShare(); + + $share = $this->createMock(IShare::class); + $node = $this->createMock(File::class); + $userFolder = $this->createMock(Folder::class); + $owner = $this->createMock(IUser::class); + $storage = $this->createMock(\OCA\Files_Sharing\External\Storage::class); + + $share->method('getSharedBy')->willReturn('sharedByUser'); + $share->method('getNodeId')->willReturn(42); + $share->method('getHideDownload')->willReturn(false); + $share->method('getNode')->willReturn($node); + $node->method('getOwner')->willReturn($owner); + $owner->method('getUID')->willReturn('differentOwner'); + $node->method('getStorage')->willReturn($storage); + $storage->method('instanceOfStorage')->willReturnMap([ + [SharedStorage::class, false], + [\OCA\Files_Sharing\External\Storage::class, true] + ]); + + $userFolder->method('getById')->with(42)->willReturn([]); + $this->rootFolder->method('getUserFolder')->with('sharedByUser')->willReturn($userFolder); + + $share->expects($this->once())->method('setHideDownload')->with(false); + + $this->invokePrivate($ocs, 'checkInheritedAttributes', [$share]); + } }