From 43ee64495de43a2c5db6b5c656838087b93dc28a Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Mon, 8 Jun 2026 12:07:25 +0200 Subject: [PATCH 1/3] fix: use correct permissions mark for non-home storage public links Signed-off-by: Robin Appelman --- apps/dav/appinfo/v2/publicremote.php | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/apps/dav/appinfo/v2/publicremote.php b/apps/dav/appinfo/v2/publicremote.php index 22f1fdd4908..027314e6edc 100644 --- a/apps/dav/appinfo/v2/publicremote.php +++ b/apps/dav/appinfo/v2/publicremote.php @@ -7,6 +7,7 @@ */ use OC\Files\Filesystem; use OC\Files\Storage\Wrapper\DirPermissionsMask; +use OC\Files\Storage\Wrapper\PermissionsMask; use OC\Files\View; use OCA\DAV\Connector\Sabre\PublicAuth; use OCA\DAV\Connector\Sabre\ServerFactory; @@ -21,6 +22,7 @@ use OCP\App\IAppManager; use OCP\BeforeSabrePubliclyLoadedEvent; use OCP\Constants; use OCP\EventDispatcher\IEventDispatcher; +use OCP\Files\IHomeStorage; use OCP\Files\IRootFolder; use OCP\Files\Mount\IMountManager; use OCP\ICacheFactory; @@ -115,11 +117,15 @@ $server = $serverFactory->createServer(true, $baseuri, $requestUri, $authPlugin, $mask |= Constants::PERMISSION_READ | Constants::PERMISSION_DELETE; } - return new DirPermissionsMask([ - 'storage' => $storage, - 'mask' => $mask, - 'path' => 'files', - ]); + if ($storage instanceof IHomeStorage) { + return new DirPermissionsMask([ + 'storage' => $storage, + 'mask' => $mask, + 'path' => 'files', + ]); + } else { + return new PermissionsMask(['storage' => $storage, 'mask' => $mask]); + } }); /** @psalm-suppress MissingClosureParamType */ From f69b57cfc2f549472c10618584c59fca2a789a7e Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Mon, 8 Jun 2026 13:34:57 +0200 Subject: [PATCH 2/3] chore: psalm fix Signed-off-by: Robin Appelman --- lib/private/Files/Storage/Wrapper/DirPermissionsMask.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/private/Files/Storage/Wrapper/DirPermissionsMask.php b/lib/private/Files/Storage/Wrapper/DirPermissionsMask.php index 7989002496e..8d4dbbabbaa 100644 --- a/lib/private/Files/Storage/Wrapper/DirPermissionsMask.php +++ b/lib/private/Files/Storage/Wrapper/DirPermissionsMask.php @@ -10,8 +10,8 @@ declare(strict_types=1); namespace OC\Files\Storage\Wrapper; use OC\Files\Cache\Wrapper\CacheDirPermissionsMask; -use OC\Files\Storage\Storage; use OCP\Files\Cache\ICache; +use OCP\Files\Storage\IStorage; /** * While PermissionMask can mask a whole storage this can @@ -30,7 +30,7 @@ class DirPermissionsMask extends PermissionsMask { private readonly int $pathLength; /** - * @param array{storage: Storage, mask: int, path: string, ...} $parameters + * @param array{storage: IStorage, mask: int, path: string, ...} $parameters * @psalm-suppress MoreSpecificImplementedParamType * * $storage: The storage the permissions mask should be applied on From 3ee547354f6c9b5bf90ffbab3a4e9289e222e2de Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Mon, 8 Jun 2026 16:30:58 +0200 Subject: [PATCH 3/3] test: add test for uploading to publicly shared external storage Signed-off-by: Robin Appelman --- .../integration/features/bootstrap/WebDav.php | 17 ++++++++++++++ .../sharing_features/sharing-v1.feature | 23 ++++++++++++++++++- 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/build/integration/features/bootstrap/WebDav.php b/build/integration/features/bootstrap/WebDav.php index 8682472847a..be1eabb60a6 100644 --- a/build/integration/features/bootstrap/WebDav.php +++ b/build/integration/features/bootstrap/WebDav.php @@ -334,6 +334,23 @@ trait WebDav { } } + /** + * @When Uploading public file :filename with content :content + */ + public function uploadingPublicFile(string $filename, string $content) { + $token = $this->lastShareData->data->token; + $fullUrl = substr($this->baseUrl, 0, -4) . "public.php/dav/files/$token/$filename"; + + $client = new GClient(); + try { + $this->response = $client->request('PUT', $fullUrl, [ + 'body' => $content + ]); + } catch (\GuzzleHttp\Exception\ClientException $e) { + $this->response = $e->getResponse(); + } + } + /** * @Then /^as "([^"]*)" gets properties of (file|folder|entry) "([^"]*)" with$/ * @param string $user diff --git a/build/integration/sharing_features/sharing-v1.feature b/build/integration/sharing_features/sharing-v1.feature index dad3d6ee6fd..0200f7fda00 100644 --- a/build/integration/sharing_features/sharing-v1.feature +++ b/build/integration/sharing_features/sharing-v1.feature @@ -556,7 +556,28 @@ Feature: sharing And Share fields of last share match with | expiration | +3 days | - Scenario: getting all shares of a user using that user +Scenario: Writing to a read-only link share of an external storage + Given user "user0" exists + Then As an "user0" + When creating a share with + | path | local_storage | + | shareType | 3 | + And the OCS status code should be "100" + And the HTTP status code should be "200" + Then Uploading public file "foo.txt" with content "bar" + And the HTTP status code should be "403" + +Scenario: Writing to a read-write link share of an external storage + Given user "user0" exists + Then As an "user0" + When creating a share with + | path | local_storage | + | shareType | 3 | + | permissions | 7 | + Then Uploading public file "foo.txt" with content "bar" + And the HTTP status code should be "201" + +Scenario: getting all shares of a user using that user Given user "user0" exists And user "user1" exists When User "user1" deletes file "/textfile0.txt"