Skip to content

Commit 76a5a25

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 fc984ed commit 76a5a25

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
@@ -28,6 +28,7 @@
2828
use OCP\IConfig;
2929
use OCP\Lock\ILockingProvider;
3030
use Sabre\DAV\Exception\BadRequest;
31+
use Sabre\DAV\Exception\Forbidden;
3132
use Sabre\DAV\Exception\InsufficientStorage;
3233
use Sabre\DAV\Exception\MethodNotAllowed;
3334
use Sabre\DAV\Exception\NotFound;
@@ -106,18 +107,26 @@ public function forbiddenMethod(RequestInterface $request) {
106107
* @param string $path
107108
* @param bool $createIfNotExists
108109
* @return FutureFile|UploadFile|ICollection|INode
110+
* @throws Forbidden if the file already exists, but is not updateable
109111
*/
110112
private function getUploadFile(string $path, bool $createIfNotExists = false) {
111113
try {
112114
$actualFile = $this->server->tree->getNodeForPath($path);
113-
// Only directly upload to the target file if it is on the same storage
114-
// There may be further potential to optimize here by also uploading
115-
// to other storages directly. This would require to also carefully pick
116-
// the storage/path used in getStorage()
117-
if ($actualFile instanceof File && $this->uploadFolder->getStorage()->getId() === $actualFile->getNode()->getStorage()->getId()) {
118-
return $actualFile;
115+
if ($actualFile instanceof File) {
116+
$node = $actualFile->getNode();
117+
// check that the node has update permissions
118+
if (!$node->isUpdateable()) {
119+
throw new Forbidden();
120+
}
121+
// Only directly upload to the target file if it is on the same storage
122+
// There may be further potential to optimize here by also uploading
123+
// to other storages directly. This would require to also carefully pick
124+
// the storage/path used in getStorage()
125+
if ($this->uploadFolder->getStorage()->getId() === $node->getStorage()->getId()) {
126+
return $actualFile;
127+
}
119128
}
120-
} catch (NotFound $e) {
129+
} catch (NotFound) {
121130
// If there is no target file we upload to the upload folder first
122131
}
123132

build/integration/dav_features/webdav-related.feature

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -711,3 +711,23 @@ Feature: webdav-related
711711
When As an "user0"
712712
And Downloading file "/üäöé/äöü.txt"
713713
Then Downloaded content should be the created file
714+
715+
@s3-multipart
716+
Scenario: Cannot overwrite a file the user may not update with new chunking v2
717+
Given using new dav path
718+
And user "user0" exists
719+
And user "user1" exists
720+
And As an "user1"
721+
And user "user1" created a folder "/testshare"
722+
And User "user1" copies file "/welcome.txt" to "/testshare/test.txt"
723+
And as "user1" creating a share with
724+
| path | testshare |
725+
| shareType | 0 |
726+
| permissions | 5 |
727+
| shareWith | user0 |
728+
And user "user0" accepts last share
729+
And As an "user0"
730+
And user "user0" creates a file locally with "3" x 5 MB chunks
731+
When user "user0" creates a new chunking v2 upload with id "chunking-update" and destination "/testshare/test.txt"
732+
Then the HTTP status code should be "403"
733+
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
@@ -939,9 +939,17 @@ public function userCreatesANewChunkingv2UploadWithIdAndDestination($user, $id,
939939
$this->s3MultipartDestination = $this->getTargetDestination($user, $targetDestination);
940940
$this->newUploadId();
941941
$destination = '/uploads/' . $user . '/' . $this->getUploadId($id);
942-
$this->response = $this->makeDavRequest($user, 'MKCOL', $destination, [
943-
'Destination' => $this->s3MultipartDestination,
944-
], null, 'uploads');
942+
try {
943+
$this->response = $this->makeDavRequest($user, 'MKCOL', $destination, [
944+
'Destination' => $this->s3MultipartDestination,
945+
], null, 'uploads');
946+
} catch (\GuzzleHttp\Exception\ServerException $e) {
947+
// 5xx responses cause a server exception
948+
$this->response = $e->getResponse();
949+
} catch (\GuzzleHttp\Exception\ClientException $e) {
950+
// 4xx responses cause a client exception
951+
$this->response = $e->getResponse();
952+
}
945953
}
946954

947955
/**

0 commit comments

Comments
 (0)