Skip to content

Commit b9b1d35

Browse files
salmart-devbackportbot[bot]
authored andcommitted
fix: check node on same storage when uploading chunks
Signed-off-by: Salvatore Martire <4652631+salmart-dev@users.noreply.github.com>
1 parent b416323 commit b9b1d35

3 files changed

Lines changed: 47 additions & 10 deletions

File tree

apps/dav/lib/Upload/ChunkingV2Plugin.php

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
use OCP\IConfig;
3030
use OCP\Lock\ILockingProvider;
3131
use Sabre\DAV\Exception\BadRequest;
32+
use Sabre\DAV\Exception\Forbidden;
3233
use Sabre\DAV\Exception\InsufficientStorage;
3334
use Sabre\DAV\Exception\MethodNotAllowed;
3435
use Sabre\DAV\Exception\NotFound;
@@ -107,18 +108,26 @@ public function forbiddenMethod(RequestInterface $request) {
107108
* @param string $path
108109
* @param bool $createIfNotExists
109110
* @return FutureFile|UploadFile|ICollection|INode
111+
* @throws Forbidden if the file already exists, but is not updateable
110112
*/
111113
private function getUploadFile(string $path, bool $createIfNotExists = false) {
112114
try {
113115
$actualFile = $this->server->tree->getNodeForPath($path);
114-
// Only directly upload to the target file if it is on the same storage
115-
// There may be further potential to optimize here by also uploading
116-
// to other storages directly. This would require to also carefully pick
117-
// the storage/path used in getStorage()
118-
if ($actualFile instanceof File && $this->uploadFolder->getStorage()->getId() === $actualFile->getNode()->getStorage()->getId()) {
119-
return $actualFile;
116+
if ($actualFile instanceof File) {
117+
$node = $actualFile->getNode();
118+
// check that the node has update permissions
119+
if (!$node->isUpdateable()) {
120+
throw new Forbidden();
121+
}
122+
// Only directly upload to the target file if it is on the same storage
123+
// There may be further potential to optimize here by also uploading
124+
// to other storages directly. This would require to also carefully pick
125+
// the storage/path used in getStorage()
126+
if ($this->uploadFolder->getStorage()->getId() === $node->getStorage()->getId()) {
127+
return $actualFile;
128+
}
120129
}
121-
} catch (NotFound $e) {
130+
} catch (NotFound) {
122131
// If there is no target file we upload to the upload folder first
123132
}
124133

build/integration/dav_features/webdav-related.feature

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -737,3 +737,23 @@ Feature: webdav-related
737737
When As an "user0"
738738
And Downloading file "/üäöé/äöü.txt"
739739
Then Downloaded content should be the created file
740+
741+
@s3-multipart
742+
Scenario: Cannot overwrite a file the user may not update with new chunking v2
743+
Given using new dav path
744+
And user "user0" exists
745+
And user "user1" exists
746+
And As an "user1"
747+
And user "user1" created a folder "/testshare"
748+
And User "user1" copies file "/welcome.txt" to "/testshare/test.txt"
749+
And as "user1" creating a share with
750+
| path | testshare |
751+
| shareType | 0 |
752+
| permissions | 5 |
753+
| shareWith | user0 |
754+
And user "user0" accepts last share
755+
And As an "user0"
756+
And user "user0" creates a file locally with "3" x 5 MB chunks
757+
When user "user0" creates a new chunking v2 upload with id "chunking-update" and destination "/testshare/test.txt"
758+
Then the HTTP status code should be "403"
759+
And Downloaded content when downloading file "/testshare/test.txt" with range "bytes=0-6" should be "Welcome"

build/integration/features/bootstrap/WebDav.php

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -987,9 +987,17 @@ public function userCreatesANewChunkingv2UploadWithIdAndDestination($user, $id,
987987
$this->s3MultipartDestination = $this->getTargetDestination($user, $targetDestination);
988988
$this->newUploadId();
989989
$destination = '/uploads/' . $user . '/' . $this->getUploadId($id);
990-
$this->response = $this->makeDavRequest($user, 'MKCOL', $destination, [
991-
'Destination' => $this->s3MultipartDestination,
992-
], null, 'uploads');
990+
try {
991+
$this->response = $this->makeDavRequest($user, 'MKCOL', $destination, [
992+
'Destination' => $this->s3MultipartDestination,
993+
], null, 'uploads');
994+
} catch (\GuzzleHttp\Exception\ServerException $e) {
995+
// 5xx responses cause a server exception
996+
$this->response = $e->getResponse();
997+
} catch (\GuzzleHttp\Exception\ClientException $e) {
998+
// 4xx responses cause a client exception
999+
$this->response = $e->getResponse();
1000+
}
9931001
}
9941002

9951003
/**

0 commit comments

Comments
 (0)