From 0320a99ccc85ffc90c1cda40eda43d108463ae48 Mon Sep 17 00:00:00 2001 From: provokateurin Date: Wed, 15 Oct 2025 23:19:35 +0200 Subject: [PATCH 1/8] fix(publicremote): Always grant read and delete permission for chunked uploads to a share Signed-off-by: provokateurin --- apps/dav/appinfo/v2/publicremote.php | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/apps/dav/appinfo/v2/publicremote.php b/apps/dav/appinfo/v2/publicremote.php index e089fa7bb62..8d509e636a8 100644 --- a/apps/dav/appinfo/v2/publicremote.php +++ b/apps/dav/appinfo/v2/publicremote.php @@ -81,7 +81,7 @@ $linkCheckPlugin = new PublicLinkCheckPlugin(); $filesDropPlugin = new FilesDropPlugin(); /** @var string $baseuri defined in public.php */ -$server = $serverFactory->createServer(true, $baseuri, $requestUri, $authPlugin, function (\Sabre\DAV\Server $server) use ($authBackend, $linkCheckPlugin, $filesDropPlugin) { +$server = $serverFactory->createServer(true, $baseuri, $requestUri, $authPlugin, function (\Sabre\DAV\Server $server) use ($baseuri, $requestUri, $authBackend, $linkCheckPlugin, $filesDropPlugin) { // GET must be allowed for e.g. showing images and allowing Zip downloads if ($server->httpRequest->getMethod() !== 'GET') { // If this is *not* a GET request we only allow access to public DAV from AJAX or when Server2Server is allowed @@ -103,8 +103,16 @@ $server = $serverFactory->createServer(true, $baseuri, $requestUri, $authPlugin, $previousLog = Filesystem::logWarningWhenAddingStorageWrapper(false); /** @psalm-suppress MissingClosureParamType */ - Filesystem::addStorageWrapper('sharePermissions', function ($mountPoint, $storage) use ($share) { - return new PermissionsMask(['storage' => $storage, 'mask' => $share->getPermissions() | Constants::PERMISSION_SHARE]); + Filesystem::addStorageWrapper('sharePermissions', function ($mountPoint, $storage) use ($requestUri, $baseuri, $share) { + $mask = $share->getPermissions() | Constants::PERMISSION_SHARE; + + // For chunked uploads it is necessary to have read and delete permission, + // so the temporary directory, chunks and destination file can be read and delete after the assembly. + if (str_starts_with(substr($requestUri, strlen($baseuri) - 1), '/uploads/')) { + $mask |= Constants::PERMISSION_READ | Constants::PERMISSION_DELETE; + } + + return new PermissionsMask(['storage' => $storage, 'mask' => $mask]); }); /** @psalm-suppress MissingClosureParamType */ From f4f0a1a94b0db148abbf4f22c8346fa64aaf85e6 Mon Sep 17 00:00:00 2001 From: provokateurin Date: Wed, 15 Oct 2025 23:22:40 +0200 Subject: [PATCH 2/8] fix(FilesDropPlugin): Disable plugin for chunked uploads Signed-off-by: provokateurin --- apps/dav/lib/Files/Sharing/FilesDropPlugin.php | 12 ++++++++++++ .../tests/unit/Files/Sharing/FilesDropPluginTest.php | 7 ------- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/apps/dav/lib/Files/Sharing/FilesDropPlugin.php b/apps/dav/lib/Files/Sharing/FilesDropPlugin.php index a3dbd32ce6b..92e6159114f 100644 --- a/apps/dav/lib/Files/Sharing/FilesDropPlugin.php +++ b/apps/dav/lib/Files/Sharing/FilesDropPlugin.php @@ -42,6 +42,10 @@ class FilesDropPlugin extends ServerPlugin { } public function onMkcol(RequestInterface $request, ResponseInterface $response) { + if ($this->isChunkedUpload($request)) { + return; + } + if (!$this->enabled || $this->share === null) { return; } @@ -58,7 +62,15 @@ class FilesDropPlugin extends ServerPlugin { return false; } + private function isChunkedUpload(RequestInterface $request): bool { + return str_starts_with(substr($request->getUrl(), strlen($request->getBaseUrl()) - 1), '/uploads/'); + } + public function beforeMethod(RequestInterface $request, ResponseInterface $response) { + if ($this->isChunkedUpload($request)) { + return; + } + if (!$this->enabled || $this->share === null) { return; } diff --git a/apps/dav/tests/unit/Files/Sharing/FilesDropPluginTest.php b/apps/dav/tests/unit/Files/Sharing/FilesDropPluginTest.php index 1a7ab7179e1..2b9864be8d9 100644 --- a/apps/dav/tests/unit/Files/Sharing/FilesDropPluginTest.php +++ b/apps/dav/tests/unit/Files/Sharing/FilesDropPluginTest.php @@ -56,13 +56,6 @@ class FilesDropPluginTest extends TestCase { ->willReturn('token'); } - public function testNotEnabled(): void { - $this->request->expects($this->never()) - ->method($this->anything()); - - $this->plugin->beforeMethod($this->request, $this->response); - } - public function testValid(): void { $this->plugin->enable(); $this->plugin->setShare($this->share); From 309c1651be44adb17d2f7b2ddd057702078d8819 Mon Sep 17 00:00:00 2001 From: provokateurin Date: Wed, 15 Oct 2025 23:23:30 +0200 Subject: [PATCH 3/8] fix(FilesDropPlugin): Fix name conflict resolution for chunked uploads Signed-off-by: provokateurin --- .../dav/lib/Files/Sharing/FilesDropPlugin.php | 23 +++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/apps/dav/lib/Files/Sharing/FilesDropPlugin.php b/apps/dav/lib/Files/Sharing/FilesDropPlugin.php index 92e6159114f..d74449b7d1e 100644 --- a/apps/dav/lib/Files/Sharing/FilesDropPlugin.php +++ b/apps/dav/lib/Files/Sharing/FilesDropPlugin.php @@ -67,7 +67,10 @@ class FilesDropPlugin extends ServerPlugin { } public function beforeMethod(RequestInterface $request, ResponseInterface $response) { - if ($this->isChunkedUpload($request)) { + $isChunkedUpload = $this->isChunkedUpload($request); + + // For the final MOVE request of a chunked upload it is necessary to modify the Destination header. + if ($isChunkedUpload && $request->getMethod() !== 'MOVE') { return; } @@ -107,8 +110,16 @@ class FilesDropPlugin extends ServerPlugin { // full path along the way. We'll only handle conflict // resolution on file conflicts, but not on folders. - // e.g files/dCP8yn3N86EK9sL/Folder/image.jpg - $path = $request->getPath(); + if ($isChunkedUpload) { + $destination = $request->getHeader('destination'); + $baseUrl = $request->getBaseUrl(); + // e.g files/dCP8yn3N86EK9sL/Folder/image.jpg + $path = substr($destination, strpos($destination, $baseUrl) + strlen($baseUrl)); + } else { + // e.g files/dCP8yn3N86EK9sL/Folder/image.jpg + $path = $request->getPath(); + } + $token = $this->share->getToken(); // e.g files/dCP8yn3N86EK9sL @@ -199,7 +210,11 @@ class FilesDropPlugin extends ServerPlugin { $relativePath = substr($folder->getPath(), strlen($node->getPath())); $path = '/files/' . $token . '/' . $relativePath . '/' . $uniqueName; $url = rtrim($request->getBaseUrl(), '/') . str_replace('//', '/', $path); - $request->setUrl($url); + if ($isChunkedUpload) { + $request->setHeader('destination', $url); + } else { + $request->setUrl($url); + } } private function getPathSegments(string $path): array { From bcae49614e6e3b6734b50fea677732ed46d6d260 Mon Sep 17 00:00:00 2001 From: provokateurin Date: Wed, 15 Oct 2025 23:24:07 +0200 Subject: [PATCH 4/8] fix(FilesDropPlugin): Fix request method and nickname header checks Signed-off-by: provokateurin --- .../dav/lib/Files/Sharing/FilesDropPlugin.php | 22 ++++++------------- .../Files/Sharing/FilesDropPluginTest.php | 22 +------------------ .../features/bootstrap/FilesDropContext.php | 14 +----------- .../filesdrop_features/filesdrop.feature | 17 ++------------ 4 files changed, 11 insertions(+), 64 deletions(-) diff --git a/apps/dav/lib/Files/Sharing/FilesDropPlugin.php b/apps/dav/lib/Files/Sharing/FilesDropPlugin.php index d74449b7d1e..930f06cb232 100644 --- a/apps/dav/lib/Files/Sharing/FilesDropPlugin.php +++ b/apps/dav/lib/Files/Sharing/FilesDropPlugin.php @@ -83,21 +83,8 @@ class FilesDropPlugin extends ServerPlugin { return; } - // Retrieve the nickname from the request - $nickname = $request->hasHeader('X-NC-Nickname') - ? trim(urldecode($request->getHeader('X-NC-Nickname'))) - : null; - - if ($request->getMethod() !== 'PUT') { - // If uploading subfolders we need to ensure they get created - // within the nickname folder - if ($request->getMethod() === 'MKCOL') { - if (!$nickname) { - throw new BadRequest('A nickname header is required when uploading subfolders'); - } - } else { - throw new MethodNotAllowed('Only PUT is allowed on files drop'); - } + if ($request->getMethod() !== 'PUT' && $request->getMethod() !== 'MKCOL' && (!$isChunkedUpload || $request->getMethod() !== 'MOVE')) { + throw new MethodNotAllowed('Only PUT, MKCOL and MOVE are allowed on files drop'); } // If this is a folder creation request @@ -135,6 +122,11 @@ class FilesDropPlugin extends ServerPlugin { $isFileRequest = $attributes->getAttribute('fileRequest', 'enabled') === true; } + // Retrieve the nickname from the request + $nickname = $request->hasHeader('X-NC-Nickname') + ? trim(urldecode($request->getHeader('X-NC-Nickname'))) + : null; + // We need a valid nickname for file requests if ($isFileRequest && !$nickname) { throw new BadRequest('A nickname header is required for file requests'); diff --git a/apps/dav/tests/unit/Files/Sharing/FilesDropPluginTest.php b/apps/dav/tests/unit/Files/Sharing/FilesDropPluginTest.php index 2b9864be8d9..57e4b874fd6 100644 --- a/apps/dav/tests/unit/Files/Sharing/FilesDropPluginTest.php +++ b/apps/dav/tests/unit/Files/Sharing/FilesDropPluginTest.php @@ -13,7 +13,6 @@ use OCP\Files\NotFoundException; use OCP\Share\IAttributes; use OCP\Share\IShare; use PHPUnit\Framework\MockObject\MockObject; -use Sabre\DAV\Exception\BadRequest; use Sabre\DAV\Server; use Sabre\HTTP\RequestInterface; use Sabre\HTTP\ResponseInterface; @@ -105,32 +104,13 @@ class FilesDropPluginTest extends TestCase { $this->plugin->beforeMethod($this->request, $this->response); } - public function testNoMKCOLWithoutNickname(): void { + public function testMKCOL(): void { $this->plugin->enable(); $this->plugin->setShare($this->share); $this->request->method('getMethod') ->willReturn('MKCOL'); - $this->expectException(BadRequest::class); - - $this->plugin->beforeMethod($this->request, $this->response); - } - - public function testMKCOLWithNickname(): void { - $this->plugin->enable(); - $this->plugin->setShare($this->share); - - $this->request->method('getMethod') - ->willReturn('MKCOL'); - - $this->request->method('hasHeader') - ->with('X-NC-Nickname') - ->willReturn(true); - $this->request->method('getHeader') - ->with('X-NC-Nickname') - ->willReturn('nickname'); - $this->expectNotToPerformAssertions(); $this->plugin->beforeMethod($this->request, $this->response); diff --git a/build/integration/features/bootstrap/FilesDropContext.php b/build/integration/features/bootstrap/FilesDropContext.php index 0c437f28a72..af04503d7a1 100644 --- a/build/integration/features/bootstrap/FilesDropContext.php +++ b/build/integration/features/bootstrap/FilesDropContext.php @@ -57,7 +57,7 @@ class FilesDropContext implements Context, SnippetAcceptingContext { /** * @When Creating folder :folder in drop */ - public function creatingFolderInDrop($folder, $nickname = null) { + public function creatingFolderInDrop($folder) { $client = new Client(); $options = []; if (count($this->lastShareData->data->element) > 0) { @@ -73,22 +73,10 @@ class FilesDropContext implements Context, SnippetAcceptingContext { 'X-REQUESTED-WITH' => 'XMLHttpRequest', ]; - if ($nickname) { - $options['headers']['X-NC-NICKNAME'] = $nickname; - } - try { $this->response = $client->request('MKCOL', $fullUrl, $options); } catch (\GuzzleHttp\Exception\ClientException $e) { $this->response = $e->getResponse(); } } - - - /** - * @When Creating folder :folder in drop as :nickName - */ - public function creatingFolderInDropWithNickname($folder, $nickname) { - return $this->creatingFolderInDrop($folder, $nickname); - } } diff --git a/build/integration/filesdrop_features/filesdrop.feature b/build/integration/filesdrop_features/filesdrop.feature index 7618a31a1d0..d8a1464fa7d 100644 --- a/build/integration/filesdrop_features/filesdrop.feature +++ b/build/integration/filesdrop_features/filesdrop.feature @@ -46,7 +46,7 @@ Feature: FilesDrop When Dropping file "/folder/a.txt" with "abc" Then the HTTP status code should be "400" - Scenario: Files drop forbid MKCOL without a nickname + Scenario: Files drop allows MKCOL Given user "user0" exists And As an "user0" And user "user0" created a folder "/drop" @@ -57,19 +57,6 @@ Feature: FilesDrop And Updating last share with | permissions | 4 | When Creating folder "folder" in drop - Then the HTTP status code should be "400" - - Scenario: Files drop allows MKCOL with a nickname - Given user "user0" exists - And As an "user0" - And user "user0" created a folder "/drop" - And as "user0" creating a share with - | path | drop | - | shareType | 3 | - | publicUpload | true | - And Updating last share with - | permissions | 4 | - When Creating folder "folder" in drop as "nickname" Then the HTTP status code should be "201" Scenario: Files drop forbid subfolder creation without a nickname @@ -139,7 +126,7 @@ Feature: FilesDrop When Downloading file "/drop/Alice/folder (2)" Then the HTTP status code should be "200" And Downloaded content should be "its a file" - + Scenario: Put file same file multiple times via files drop Given user "user0" exists And As an "user0" From 9b438cc407e2d7b2054c7f693c28ab568bdfc2ca Mon Sep 17 00:00:00 2001 From: provokateurin Date: Tue, 18 Nov 2025 09:51:19 +0100 Subject: [PATCH 5/8] Revert "fix: temporarily disable public shares chunking capability" This reverts commit 365a040dc3254fa1261f304c7c06167c0f71d62f. Signed-off-by: provokateurin --- apps/dav/lib/Capabilities.php | 2 +- apps/dav/tests/unit/CapabilitiesTest.php | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/dav/lib/Capabilities.php b/apps/dav/lib/Capabilities.php index eb777769b61..f9bad25bf31 100644 --- a/apps/dav/lib/Capabilities.php +++ b/apps/dav/lib/Capabilities.php @@ -24,7 +24,7 @@ class Capabilities implements ICapability { $capabilities = [ 'dav' => [ 'chunking' => '1.0', - 'public_shares_chunking' => false, + 'public_shares_chunking' => true, ] ]; if ($this->config->getSystemValueBool('bulkupload.enabled', true)) { diff --git a/apps/dav/tests/unit/CapabilitiesTest.php b/apps/dav/tests/unit/CapabilitiesTest.php index 873500646c2..ad70d576d48 100644 --- a/apps/dav/tests/unit/CapabilitiesTest.php +++ b/apps/dav/tests/unit/CapabilitiesTest.php @@ -30,7 +30,7 @@ class CapabilitiesTest extends TestCase { $expected = [ 'dav' => [ 'chunking' => '1.0', - 'public_shares_chunking' => false, + 'public_shares_chunking' => true, ], ]; $this->assertSame($expected, $capabilities->getCapabilities()); @@ -50,7 +50,7 @@ class CapabilitiesTest extends TestCase { $expected = [ 'dav' => [ 'chunking' => '1.0', - 'public_shares_chunking' => false, + 'public_shares_chunking' => true, 'bulkupload' => '1.0', ], ]; @@ -71,7 +71,7 @@ class CapabilitiesTest extends TestCase { $expected = [ 'dav' => [ 'chunking' => '1.0', - 'public_shares_chunking' => false, + 'public_shares_chunking' => true, 'absence-supported' => true, 'absence-replacement' => true, ], From 281949faa41041cb641b190b81c8d6135eaa4278 Mon Sep 17 00:00:00 2001 From: provokateurin Date: Tue, 18 Nov 2025 10:26:33 +0100 Subject: [PATCH 6/8] fix(FilesDropPlugin): Also modify Destination header for PUT requests to satisfy the QuotaPlugin Signed-off-by: provokateurin --- apps/dav/lib/Files/Sharing/FilesDropPlugin.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/dav/lib/Files/Sharing/FilesDropPlugin.php b/apps/dav/lib/Files/Sharing/FilesDropPlugin.php index 930f06cb232..796950fb67f 100644 --- a/apps/dav/lib/Files/Sharing/FilesDropPlugin.php +++ b/apps/dav/lib/Files/Sharing/FilesDropPlugin.php @@ -69,8 +69,8 @@ class FilesDropPlugin extends ServerPlugin { public function beforeMethod(RequestInterface $request, ResponseInterface $response) { $isChunkedUpload = $this->isChunkedUpload($request); - // For the final MOVE request of a chunked upload it is necessary to modify the Destination header. - if ($isChunkedUpload && $request->getMethod() !== 'MOVE') { + // For the PUT and MOVE requests of a chunked upload it is necessary to modify the Destination header. + if ($isChunkedUpload && $request->getMethod() !== 'MOVE' && $request->getMethod() !== 'PUT') { return; } From b5ad0aad3a8c506735e3d870201743cc530f6594 Mon Sep 17 00:00:00 2001 From: provokateurin Date: Thu, 16 Oct 2025 12:26:35 +0200 Subject: [PATCH 7/8] fix(FilesDropPlugin): Allow MKCOL for file drop to upload folders Signed-off-by: provokateurin --- apps/dav/lib/Files/Sharing/FilesDropPlugin.php | 9 --------- 1 file changed, 9 deletions(-) diff --git a/apps/dav/lib/Files/Sharing/FilesDropPlugin.php b/apps/dav/lib/Files/Sharing/FilesDropPlugin.php index 796950fb67f..d414a337820 100644 --- a/apps/dav/lib/Files/Sharing/FilesDropPlugin.php +++ b/apps/dav/lib/Files/Sharing/FilesDropPlugin.php @@ -113,7 +113,6 @@ class FilesDropPlugin extends ServerPlugin { $rootPath = substr($path, 0, strpos($path, $token) + strlen($token)); // e.g /Folder/image.jpg $relativePath = substr($path, strlen($rootPath)); - $isRootUpload = substr_count($relativePath, '/') === 1; // Extract the attributes for the file request $isFileRequest = false; @@ -132,14 +131,6 @@ class FilesDropPlugin extends ServerPlugin { throw new BadRequest('A nickname header is required for file requests'); } - // We're only allowing the upload of - // long path with subfolders if a nickname is set. - // This prevents confusion when uploading files and help - // classify them by uploaders. - if (!$nickname && !$isRootUpload) { - throw new BadRequest('A nickname header is required when uploading subfolders'); - } - if ($nickname) { try { $node->verifyPath($nickname); From b737336e4d26889d64b478d4a11651e2f2f900c1 Mon Sep 17 00:00:00 2001 From: provokateurin Date: Thu, 16 Oct 2025 12:27:08 +0200 Subject: [PATCH 8/8] fix(FilesDropPlugin): Ensure all request for file request have a nickname Signed-off-by: provokateurin --- .../dav/lib/Files/Sharing/FilesDropPlugin.php | 34 +++++++------- .../Files/Sharing/FilesDropPluginTest.php | 47 +++++++++++++++++-- .../features/bootstrap/FilesDropContext.php | 14 +++++- .../filesdrop_features/filesdrop.feature | 36 ++++++++++++-- 4 files changed, 107 insertions(+), 24 deletions(-) diff --git a/apps/dav/lib/Files/Sharing/FilesDropPlugin.php b/apps/dav/lib/Files/Sharing/FilesDropPlugin.php index d414a337820..606f526b18b 100644 --- a/apps/dav/lib/Files/Sharing/FilesDropPlugin.php +++ b/apps/dav/lib/Files/Sharing/FilesDropPlugin.php @@ -87,6 +87,23 @@ class FilesDropPlugin extends ServerPlugin { throw new MethodNotAllowed('Only PUT, MKCOL and MOVE are allowed on files drop'); } + // Extract the attributes for the file request + $isFileRequest = false; + $attributes = $this->share->getAttributes(); + if ($attributes !== null) { + $isFileRequest = $attributes->getAttribute('fileRequest', 'enabled') === true; + } + + // Retrieve the nickname from the request + $nickname = $request->hasHeader('X-NC-Nickname') + ? trim(urldecode($request->getHeader('X-NC-Nickname'))) + : null; + + // We need a valid nickname for file requests + if ($isFileRequest && !$nickname) { + throw new BadRequest('A nickname header is required for file requests'); + } + // If this is a folder creation request // let's stop there and let the onMkcol handle it if ($request->getMethod() === 'MKCOL') { @@ -114,23 +131,6 @@ class FilesDropPlugin extends ServerPlugin { // e.g /Folder/image.jpg $relativePath = substr($path, strlen($rootPath)); - // Extract the attributes for the file request - $isFileRequest = false; - $attributes = $this->share->getAttributes(); - if ($attributes !== null) { - $isFileRequest = $attributes->getAttribute('fileRequest', 'enabled') === true; - } - - // Retrieve the nickname from the request - $nickname = $request->hasHeader('X-NC-Nickname') - ? trim(urldecode($request->getHeader('X-NC-Nickname'))) - : null; - - // We need a valid nickname for file requests - if ($isFileRequest && !$nickname) { - throw new BadRequest('A nickname header is required for file requests'); - } - if ($nickname) { try { $node->verifyPath($nickname); diff --git a/apps/dav/tests/unit/Files/Sharing/FilesDropPluginTest.php b/apps/dav/tests/unit/Files/Sharing/FilesDropPluginTest.php index 57e4b874fd6..a9c03e67a9c 100644 --- a/apps/dav/tests/unit/Files/Sharing/FilesDropPluginTest.php +++ b/apps/dav/tests/unit/Files/Sharing/FilesDropPluginTest.php @@ -13,6 +13,7 @@ use OCP\Files\NotFoundException; use OCP\Share\IAttributes; use OCP\Share\IShare; use PHPUnit\Framework\MockObject\MockObject; +use Sabre\DAV\Exception\BadRequest; use Sabre\DAV\Server; use Sabre\HTTP\RequestInterface; use Sabre\HTTP\ResponseInterface; @@ -23,6 +24,7 @@ class FilesDropPluginTest extends TestCase { private FilesDropPlugin $plugin; private Folder&MockObject $node; + private IAttributes&MockObject $attributes; private IShare&MockObject $share; private Server&MockObject $server; private RequestInterface&MockObject $request; @@ -45,10 +47,10 @@ class FilesDropPluginTest extends TestCase { $this->request = $this->createMock(RequestInterface::class); $this->response = $this->createMock(ResponseInterface::class); - $attributes = $this->createMock(IAttributes::class); + $this->attributes = $this->createMock(IAttributes::class); $this->share->expects($this->any()) ->method('getAttributes') - ->willReturn($attributes); + ->willReturn($this->attributes); $this->share ->method('getToken') @@ -104,7 +106,7 @@ class FilesDropPluginTest extends TestCase { $this->plugin->beforeMethod($this->request, $this->response); } - public function testMKCOL(): void { + public function testFileDropMKCOLWithoutNickname(): void { $this->plugin->enable(); $this->plugin->setShare($this->share); @@ -116,6 +118,45 @@ class FilesDropPluginTest extends TestCase { $this->plugin->beforeMethod($this->request, $this->response); } + public function testFileRequestNoMKCOLWithoutNickname(): void { + $this->plugin->enable(); + $this->plugin->setShare($this->share); + + $this->request->method('getMethod') + ->willReturn('MKCOL'); + + $this->attributes + ->method('getAttribute') + ->with('fileRequest', 'enabled') + ->willReturn(true); + + $this->expectException(BadRequest::class); + + $this->plugin->beforeMethod($this->request, $this->response); + } + + public function testFileRequestMKCOLWithNickname(): void { + $this->plugin->enable(); + $this->plugin->setShare($this->share); + + $this->request->method('getMethod') + ->willReturn('MKCOL'); + + $this->attributes + ->method('getAttribute') + ->with('fileRequest', 'enabled') + ->willReturn(true); + + $this->request->method('hasHeader') + ->with('X-NC-Nickname') + ->willReturn(true); + $this->request->method('getHeader') + ->with('X-NC-Nickname') + ->willReturn('nickname'); + + $this->plugin->beforeMethod($this->request, $this->response); + } + public function testSubdirPut(): void { $this->plugin->enable(); $this->plugin->setShare($this->share); diff --git a/build/integration/features/bootstrap/FilesDropContext.php b/build/integration/features/bootstrap/FilesDropContext.php index af04503d7a1..0c437f28a72 100644 --- a/build/integration/features/bootstrap/FilesDropContext.php +++ b/build/integration/features/bootstrap/FilesDropContext.php @@ -57,7 +57,7 @@ class FilesDropContext implements Context, SnippetAcceptingContext { /** * @When Creating folder :folder in drop */ - public function creatingFolderInDrop($folder) { + public function creatingFolderInDrop($folder, $nickname = null) { $client = new Client(); $options = []; if (count($this->lastShareData->data->element) > 0) { @@ -73,10 +73,22 @@ class FilesDropContext implements Context, SnippetAcceptingContext { 'X-REQUESTED-WITH' => 'XMLHttpRequest', ]; + if ($nickname) { + $options['headers']['X-NC-NICKNAME'] = $nickname; + } + try { $this->response = $client->request('MKCOL', $fullUrl, $options); } catch (\GuzzleHttp\Exception\ClientException $e) { $this->response = $e->getResponse(); } } + + + /** + * @When Creating folder :folder in drop as :nickName + */ + public function creatingFolderInDropWithNickname($folder, $nickname) { + return $this->creatingFolderInDrop($folder, $nickname); + } } diff --git a/build/integration/filesdrop_features/filesdrop.feature b/build/integration/filesdrop_features/filesdrop.feature index d8a1464fa7d..52a0399f4b4 100644 --- a/build/integration/filesdrop_features/filesdrop.feature +++ b/build/integration/filesdrop_features/filesdrop.feature @@ -33,7 +33,7 @@ Feature: FilesDrop And Downloading file "/drop/a (2).txt" Then Downloaded content should be "def" - Scenario: Files drop forbid directory without a nickname + Scenario: Files request forbid directory without a nickname Given user "user0" exists And As an "user0" And user "user0" created a folder "/drop" @@ -41,12 +41,26 @@ Feature: FilesDrop | path | drop | | shareType | 3 | | publicUpload | true | + | attributes | [{"scope":"fileRequest","key":"enabled","value":true}] | And Updating last share with | permissions | 4 | When Dropping file "/folder/a.txt" with "abc" Then the HTTP status code should be "400" - Scenario: Files drop allows MKCOL +Scenario: Files drop allow MKCOL without a nickname + Given user "user0" exists + And As an "user0" + And user "user0" created a folder "/drop" + And as "user0" creating a share with + | path | drop | + | shareType | 3 | + | publicUpload | true | + And Updating last share with + | permissions | 4 | + When Creating folder "folder" in drop + Then the HTTP status code should be "201" + + Scenario: Files request forbid MKCOL without a nickname Given user "user0" exists And As an "user0" And user "user0" created a folder "/drop" @@ -54,12 +68,27 @@ Feature: FilesDrop | path | drop | | shareType | 3 | | publicUpload | true | + | attributes | [{"scope":"fileRequest","key":"enabled","value":true}] | And Updating last share with | permissions | 4 | When Creating folder "folder" in drop + Then the HTTP status code should be "400" + + Scenario: Files request allows MKCOL with a nickname + Given user "user0" exists + And As an "user0" + And user "user0" created a folder "/drop" + And as "user0" creating a share with + | path | drop | + | shareType | 3 | + | publicUpload | true | + | attributes | [{"scope":"fileRequest","key":"enabled","value":true}] | + And Updating last share with + | permissions | 4 | + When Creating folder "folder" in drop as "nickname" Then the HTTP status code should be "201" - Scenario: Files drop forbid subfolder creation without a nickname + Scenario: Files request forbid subfolder creation without a nickname Given user "user0" exists And As an "user0" And user "user0" created a folder "/drop" @@ -67,6 +96,7 @@ Feature: FilesDrop | path | drop | | shareType | 3 | | publicUpload | true | + | attributes | [{"scope":"fileRequest","key":"enabled","value":true}] | And Updating last share with | permissions | 4 | When dropping file "/folder/a.txt" with "abc"