diff --git a/tests/acceptance/bootstrap/GuestLinkContext.php b/tests/acceptance/bootstrap/GuestLinkContext.php index 731b4085e3..af69cff8f7 100644 --- a/tests/acceptance/bootstrap/GuestLinkContext.php +++ b/tests/acceptance/bootstrap/GuestLinkContext.php @@ -21,6 +21,7 @@ use Behat\Behat\Context\Context; use Behat\Behat\Hook\Scope\BeforeScenarioScope; use Behat\Gherkin\Node\PyStringNode; +use Behat\Gherkin\Node\TableNode; use Behat\Step\Given; use Behat\Step\Then; use Behat\Step\When; @@ -552,7 +553,7 @@ class GuestLinkContext implements Context { null, 'MOVE', $path, - \array_merge($this->getSessionHeaders($guest), ['Destination' => $this->featureContext->getBaseUrl() . '/' . WebDavHelper::getDavPath(WebDavHelper::DAV_VERSION_SPACES, $folderId) . '/' . $newName]), + \array_merge($this->getSessionHeaders($guest), ['Destination' => $this->getDavUrl($folderId, $newName)]), $folderId, $this->featureContext->getStepLineRef(), null, @@ -590,7 +591,7 @@ class GuestLinkContext implements Context { null, 'MOVE', $path, - \array_merge($this->getSessionHeaders($guest), ['Destination' => $this->featureContext->getBaseUrl() . '/' . WebDavHelper::getDavPath(WebDavHelper::DAV_VERSION_SPACES, $spaceRootId) . '/' . $destination]), + \array_merge($this->getSessionHeaders($guest), ['Destination' => $this->getDavUrl($spaceRootId, $destination)]), $folderId, $this->featureContext->getStepLineRef(), null, @@ -599,6 +600,255 @@ class GuestLinkContext implements Context { ); } + /** + * @param string $id + * @param string $name + * + * @return string the WebDAV URL of a resource inside the resource with the given id + */ + private function getDavUrl(string $id, string $name): string { + return $this->featureContext->getBaseUrl() . '/' . WebDavHelper::getDavPath(WebDavHelper::DAV_VERSION_SPACES, $id) . '/' . $name; + } + + /** + * @param string $guest + * @param string $method COPY or MOVE + * @param string $path + * @param string $folderId + * @param string $destinationFolderId + * + * @return void + * @throws GuzzleException + */ + private function copyOrMoveIntoFolder( + string $guest, + string $method, + string $path, + string $folderId, + string $destinationFolderId + ): void { + $this->featureContext->setResponse( + WebDavHelper::makeDavRequest( + $this->featureContext->getBaseUrl(), + null, + null, + $method, + $path, + \array_merge($this->getSessionHeaders($guest), ['Destination' => $this->getDavUrl($destinationFolderId, \basename($path))]), + $folderId, + $this->featureContext->getStepLineRef(), + null, + WebDavHelper::DAV_VERSION_SPACES + ) + ); + } + + /** + * @param string $guest + * @param string $path + * @param string $folder + * @param string $space + * @param string $owner + * @param string $destinationFolder + * @param string $destinationSpace + * @param string $destinationOwner + * + * @return void + * @throws GuzzleException + */ + #[When('guest :guest copies :path inside folder :folder of space :space of user :owner to folder :destinationFolder of space :destinationSpace of user :destinationOwner using the WebDAV API')] + public function guestCopiesIntoFolder( + string $guest, + string $path, + string $folder, + string $space, + string $owner, + string $destinationFolder, + string $destinationSpace, + string $destinationOwner + ): void { + $this->copyOrMoveIntoFolder( + $guest, + 'COPY', + $path, + $this->spacesContext->getResourceId($owner, $space, $folder), + $this->spacesContext->getResourceId($destinationOwner, $destinationSpace, $destinationFolder) + ); + } + + /** + * @param string $guest + * @param string $path + * @param string $folder + * @param string $space + * @param string $owner + * @param string $destinationFolder + * @param string $destinationSpace + * @param string $destinationOwner + * + * @return void + * @throws GuzzleException + */ + #[When('guest :guest moves :path inside folder :folder of space :space of user :owner to folder :destinationFolder of space :destinationSpace of user :destinationOwner using the WebDAV API')] + public function guestMovesIntoFolder( + string $guest, + string $path, + string $folder, + string $space, + string $owner, + string $destinationFolder, + string $destinationSpace, + string $destinationOwner + ): void { + $this->copyOrMoveIntoFolder( + $guest, + 'MOVE', + $path, + $this->spacesContext->getResourceId($owner, $space, $folder), + $this->spacesContext->getResourceId($destinationOwner, $destinationSpace, $destinationFolder) + ); + } + + /** + * @param string $guest + * @param string $path + * @param string $folder + * @param string $space + * @param string $owner + * + * @return void + * @throws GuzzleException + */ + #[When('guest :guest deletes :path inside folder :folder of space :space of user :owner using the WebDAV API')] + public function guestDeletesInsideFolder(string $guest, string $path, string $folder, string $space, string $owner): void { + $this->featureContext->setResponse( + WebDavHelper::makeDavRequest( + $this->featureContext->getBaseUrl(), + null, + null, + 'DELETE', + $path, + $this->getSessionHeaders($guest), + $this->spacesContext->getResourceId($owner, $space, $folder), + $this->featureContext->getStepLineRef(), + null, + WebDavHelper::DAV_VERSION_SPACES + ) + ); + } + + /** + * @param string $guest + * @param string $folder + * @param string $space + * @param string $owner + * + * @return void + * @throws GuzzleException + */ + #[When('guest :guest tries to delete the shared folder :folder of space :space of user :owner using the WebDAV API')] + public function guestTriesToDeleteTheSharedFolder(string $guest, string $folder, string $space, string $owner): void { + $this->featureContext->setResponse( + WebDavHelper::makeDavRequest( + $this->featureContext->getBaseUrl(), + null, + null, + 'DELETE', + '', + $this->getSessionHeaders($guest), + $this->spacesContext->getResourceId($owner, $space, $folder), + $this->featureContext->getStepLineRef(), + null, + WebDavHelper::DAV_VERSION_SPACES + ) + ); + } + + /** + * @param string $guest + * @param string $folder + * @param string $space + * @param string $owner + * @param string $newName + * + * @return void + * @throws GuzzleException + */ + #[When('guest :guest tries to rename the shared folder :folder of space :space of user :owner to :newName using the WebDAV API')] + public function guestTriesToRenameTheSharedFolder( + string $guest, + string $folder, + string $space, + string $owner, + string $newName + ): void { + $spaceRootId = $this->spacesContext->getResourceId($owner, $space, ''); + $this->featureContext->setResponse( + WebDavHelper::makeDavRequest( + $this->featureContext->getBaseUrl(), + null, + null, + 'MOVE', + '', + \array_merge($this->getSessionHeaders($guest), ['Destination' => $this->getDavUrl($spaceRootId, $newName)]), + $this->spacesContext->getResourceId($owner, $space, $folder), + $this->featureContext->getStepLineRef(), + null, + WebDavHelper::DAV_VERSION_SPACES + ) + ); + } + + /** + * @param string $guest + * @param TableNode $resources with the columns resource, space and owner + * + * @return void + * @throws GuzzleException + */ + #[When('guest :guest downloads the archive of these resources using the archiver:')] + public function guestDownloadsTheArchiveOfTheseResources(string $guest, TableNode $resources): void { + $this->featureContext->verifyTableNodeColumns($resources, ['resource', 'space', 'owner']); + $ids = []; + foreach ($resources->getHash() as $row) { + $ids[] = 'id=' . \rawurlencode($this->spacesContext->getResourceId($row['owner'], $row['space'], $row['resource'])); + } + $this->downloadArchive($guest, $ids); + } + + /** + * @param string $guest + * @param string $space + * @param string $owner + * + * @return void + * @throws GuzzleException + */ + #[When('guest :guest downloads the archive of space :space of user :owner using the archiver')] + public function guestDownloadsTheArchiveOfSpace(string $guest, string $space, string $owner): void { + $this->downloadArchive($guest, ['id=' . \rawurlencode($this->spacesContext->getSpaceIdByName($owner, $space))]); + } + + /** + * @param string $guest + * @param string[] $query + * + * @return void + * @throws GuzzleException + */ + private function downloadArchive(string $guest, array $query): void { + $this->featureContext->setResponse( + HttpRequestHelper::sendRequest( + $this->featureContext->getBaseUrl() . '/archiver?' . \implode('&', $query), + $this->featureContext->getStepLineRef(), + 'GET', + null, + null, + $this->getSessionHeaders($guest), + ) + ); + } + /** * @param string $guest * @param string $method diff --git a/tests/acceptance/bootstrap/SpacesContext.php b/tests/acceptance/bootstrap/SpacesContext.php index 1d422b2f0c..1a863a510a 100644 --- a/tests/acceptance/bootstrap/SpacesContext.php +++ b/tests/acceptance/bootstrap/SpacesContext.php @@ -4675,4 +4675,250 @@ class SpacesContext implements Context { $schema ); } + + /** + * Sends a WebDAV request to the space of the owner of a received share, + * using the drive id that the sharee gets from the sharedWithMe list + * + * @param string $user + * @param string $method + * @param string $share + * @param string $path + * @param array $headers + * @param string|null $body + * + * @return void + * @throws GuzzleException + */ + private function sendRequestToSpaceOfShareOwner( + string $user, + string $method, + string $share, + string $path, + array $headers = [], + ?string $body = null + ): void { + $this->featureContext->setResponse( + WebDavHelper::makeDavRequest( + $this->featureContext->getBaseUrl(), + $this->featureContext->getActualUsername($user), + $this->featureContext->getPasswordForUser($user), + $method, + $path, + $headers, + $this->getSharesRemoteItemParentDriveId($user, $share), + $this->featureContext->getStepLineRef(), + $body, + WebDavHelper::DAV_VERSION_SPACES + ) + ); + } + + /** + * @param string $user + * @param string $share + * + * @return void + * @throws GuzzleException + */ + #[When('user :user lists the content of the space of the owner of share :share using the WebDAV API')] + public function userListsTheContentOfTheSpaceOfTheOwnerOfShare(string $user, string $share): void { + $this->sendRequestToSpaceOfShareOwner($user, 'PROPFIND', $share, '', ['Depth' => '1']); + } + + /** + * @param string $user + * @param string $file + * @param string $share + * + * @return void + * @throws GuzzleException + */ + #[When('user :user downloads file :file from the space of the owner of share :share using the WebDAV API')] + public function userDownloadsFileFromTheSpaceOfTheOwnerOfShare(string $user, string $file, string $share): void { + $this->sendRequestToSpaceOfShareOwner($user, 'GET', $share, $file); + } + + /** + * @param string $user + * @param string $content + * @param string $file + * @param string $share + * + * @return void + * @throws GuzzleException + */ + #[When('user :user uploads content :content to file :file in the space of the owner of share :share using the WebDAV API')] + public function userUploadsContentToFileInTheSpaceOfTheOwnerOfShare( + string $user, + string $content, + string $file, + string $share + ): void { + $this->sendRequestToSpaceOfShareOwner($user, 'PUT', $share, $file, [], $content); + } + + /** + * @param string $user + * @param string $folder + * @param string $share + * + * @return void + * @throws GuzzleException + */ + #[When('user :user creates folder :folder in the space of the owner of share :share using the WebDAV API')] + public function userCreatesFolderInTheSpaceOfTheOwnerOfShare(string $user, string $folder, string $share): void { + $this->sendRequestToSpaceOfShareOwner($user, 'MKCOL', $share, $folder); + } + + /** + * @param string $user + * @param string $file + * @param string $share + * + * @return void + * @throws GuzzleException + */ + #[When('user :user deletes file :file from the space of the owner of share :share using the WebDAV API')] + public function userDeletesFileFromTheSpaceOfTheOwnerOfShare(string $user, string $file, string $share): void { + $this->sendRequestToSpaceOfShareOwner($user, 'DELETE', $share, $file); + } + + /** + * @param string $user + * @param string $method COPY or MOVE + * @param string $file + * @param string $share + * @param string $destination + * + * @return void + * @throws GuzzleException + */ + private function copyOrMoveOutOfShareToSpaceOfShareOwner( + string $user, + string $method, + string $file, + string $share, + string $destination + ): void { + $driveId = $this->getSharesRemoteItemParentDriveId($user, $share); + $destinationUrl = $this->featureContext->getBaseUrl() . '/' + . WebDavHelper::getDavPath(WebDavHelper::DAV_VERSION_SPACES, $driveId) . '/' . $destination; + $this->featureContext->setResponse( + WebDavHelper::makeDavRequest( + $this->featureContext->getBaseUrl(), + $this->featureContext->getActualUsername($user), + $this->featureContext->getPasswordForUser($user), + $method, + $file, + ['Destination' => $destinationUrl], + $this->getSharesRemoteItemId($user, $share), + $this->featureContext->getStepLineRef(), + null, + WebDavHelper::DAV_VERSION_SPACES + ) + ); + } + + /** + * @param string $user + * @param string $file + * @param string $share + * @param string $destination + * + * @return void + * @throws GuzzleException + */ + #[When('user :user tries to copy file :file from share :share to :destination in the space of the owner using the WebDAV API')] + public function userTriesToCopyFileFromShareToTheSpaceOfTheOwner( + string $user, + string $file, + string $share, + string $destination + ): void { + $this->copyOrMoveOutOfShareToSpaceOfShareOwner($user, 'COPY', $file, $share, $destination); + } + + /** + * @param string $user + * @param string $file + * @param string $share + * @param string $destination + * + * @return void + * @throws GuzzleException + */ + #[When('user :user tries to move file :file from share :share to :destination in the space of the owner using the WebDAV API')] + public function userTriesToMoveFileFromShareToTheSpaceOfTheOwner( + string $user, + string $file, + string $share, + string $destination + ): void { + $this->copyOrMoveOutOfShareToSpaceOfShareOwner($user, 'MOVE', $file, $share, $destination); + } + + /** + * @param string $user + * @param string $file + * @param string $share + * @param string $destination + * @param string $destinationShare + * + * @return void + * @throws GuzzleException + */ + #[When('user :user moves file :file from share :share to :destination in share :destinationShare using the WebDAV API')] + public function userMovesFileFromShareToShare( + string $user, + string $file, + string $share, + string $destination, + string $destinationShare + ): void { + $destinationUrl = $this->featureContext->getBaseUrl() . '/' + . WebDavHelper::getDavPath( + WebDavHelper::DAV_VERSION_SPACES, + $this->getSharesRemoteItemId($user, $destinationShare) + ) . '/' . $destination; + $this->featureContext->setResponse( + WebDavHelper::makeDavRequest( + $this->featureContext->getBaseUrl(), + $this->featureContext->getActualUsername($user), + $this->featureContext->getPasswordForUser($user), + 'MOVE', + $file, + ['Destination' => $destinationUrl], + $this->getSharesRemoteItemId($user, $share), + $this->featureContext->getStepLineRef(), + null, + WebDavHelper::DAV_VERSION_SPACES + ) + ); + } + + /** + * @param string $user + * @param string $share + * + * @return void + * @throws GuzzleException + */ + #[When('user :user tries to delete the shared folder :share using the WebDAV API')] + public function userTriesToDeleteTheSharedFolder(string $user, string $share): void { + $this->featureContext->setResponse( + WebDavHelper::makeDavRequest( + $this->featureContext->getBaseUrl(), + $this->featureContext->getActualUsername($user), + $this->featureContext->getPasswordForUser($user), + 'DELETE', + '', + [], + $this->getSharesRemoteItemId($user, $share), + $this->featureContext->getStepLineRef(), + null, + WebDavHelper::DAV_VERSION_SPACES + ) + ); + } } diff --git a/tests/acceptance/expected-failures-decomposed-storage.md b/tests/acceptance/expected-failures-decomposed-storage.md index 955535d2da..bf441c2d44 100644 --- a/tests/acceptance/expected-failures-decomposed-storage.md +++ b/tests/acceptance/expected-failures-decomposed-storage.md @@ -151,7 +151,17 @@ #### [sharee (editor role) MOVE a file by file-id into shared sub-folder returns 502](https://github.com/owncloud/ocis/issues/7617) - [apiSpacesDavOperation/moveByFileId.feature:368](https://github.com/opencloud-eu/opencloud/blob/main/tests/acceptance/features/apiSpacesDavOperation/moveByFileId.feature#L368) -- [apiSpacesDavOperation/moveByFileId.feature:591](https://github.com/opencloud-eu/opencloud/blob/main/tests/acceptance/features/apiSpacesDavOperation/moveByFileId.feature#L591) +- [apiSpacesDavOperation/moveByFileId.feature:620](https://github.com/opencloud-eu/opencloud/blob/main/tests/acceptance/features/apiSpacesDavOperation/moveByFileId.feature#L620) + +#### [MOVE between spaces returns 502 but deletes the existing destination file](https://github.com/opencloud-eu/opencloud/issues/3767) + +- [apiGuestLink/guestLinkFileOperations.feature:242](https://github.com/opencloud-eu/opencloud/blob/main/tests/acceptance/features/apiGuestLink/guestLinkFileOperations.feature#L242) +- [apiSpacesDavOperation/moveByFileId.feature:471](https://github.com/opencloud-eu/opencloud/blob/main/tests/acceptance/features/apiSpacesDavOperation/moveByFileId.feature#L471) + +#### [Sharee with the Editor role can delete the shared folder of the owner using file-id](https://github.com/opencloud-eu/opencloud/issues/3770) + +- [apiGuestLink/guestLinkFileOperations.feature:110](https://github.com/opencloud-eu/opencloud/blob/main/tests/acceptance/features/apiGuestLink/guestLinkFileOperations.feature#L110) +- [apiSpacesDavOperation/deleteByFileId.feature:14](https://github.com/opencloud-eu/opencloud/blob/main/tests/acceptance/features/apiSpacesDavOperation/deleteByFileId.feature#L14) #### [MOVE a file into same folder with same name returns 404 instead of 403](https://github.com/owncloud/ocis/issues/1976) diff --git a/tests/acceptance/expected-failures-posix-storage.md b/tests/acceptance/expected-failures-posix-storage.md index ed7d0c54f4..ca30fb9558 100644 --- a/tests/acceptance/expected-failures-posix-storage.md +++ b/tests/acceptance/expected-failures-posix-storage.md @@ -151,7 +151,17 @@ #### [sharee (editor role) MOVE a file by file-id into shared sub-folder returns 502](https://github.com/owncloud/ocis/issues/7617) - [apiSpacesDavOperation/moveByFileId.feature:368](https://github.com/opencloud-eu/opencloud/blob/main/tests/acceptance/features/apiSpacesDavOperation/moveByFileId.feature#L368) -- [apiSpacesDavOperation/moveByFileId.feature:591](https://github.com/opencloud-eu/opencloud/blob/main/tests/acceptance/features/apiSpacesDavOperation/moveByFileId.feature#L591) +- [apiSpacesDavOperation/moveByFileId.feature:620](https://github.com/opencloud-eu/opencloud/blob/main/tests/acceptance/features/apiSpacesDavOperation/moveByFileId.feature#L620) + +#### [MOVE between spaces returns 502 but deletes the existing destination file](https://github.com/opencloud-eu/opencloud/issues/3767) + +- [apiGuestLink/guestLinkFileOperations.feature:242](https://github.com/opencloud-eu/opencloud/blob/main/tests/acceptance/features/apiGuestLink/guestLinkFileOperations.feature#L242) +- [apiSpacesDavOperation/moveByFileId.feature:471](https://github.com/opencloud-eu/opencloud/blob/main/tests/acceptance/features/apiSpacesDavOperation/moveByFileId.feature#L471) + +#### [Sharee with the Editor role can delete the shared folder of the owner using file-id](https://github.com/opencloud-eu/opencloud/issues/3770) + +- [apiGuestLink/guestLinkFileOperations.feature:110](https://github.com/opencloud-eu/opencloud/blob/main/tests/acceptance/features/apiGuestLink/guestLinkFileOperations.feature#L110) +- [apiSpacesDavOperation/deleteByFileId.feature:14](https://github.com/opencloud-eu/opencloud/blob/main/tests/acceptance/features/apiSpacesDavOperation/deleteByFileId.feature#L14) #### [MOVE a file into same folder with same name returns 404 instead of 403](https://github.com/owncloud/ocis/issues/1976) diff --git a/tests/acceptance/features/apiGuestLink/guestLinkFileOperations.feature b/tests/acceptance/features/apiGuestLink/guestLinkFileOperations.feature new file mode 100644 index 0000000000..31a4790b00 --- /dev/null +++ b/tests/acceptance/features/apiGuestLink/guestLinkFileOperations.feature @@ -0,0 +1,256 @@ +@email +Feature: file operations of a guest on shared resources + As a guest + I want to work with the resources shared with me + So that I can collaborate without an account, while the rest of the owner's files stay private + + Background: + Given user "Alice" has been created with default attributes + And user "Alice" has created folder "folderToShare" + And user "Alice" has uploaded file with content "inside" to "folderToShare/inside.txt" + And user "Alice" has sent the following resource share invitation: + | resource | folderToShare | + | space | Personal | + | sharee | guest@example.org | + | shareType | guest | + | permissionsRole | Editor | + And guest "guest@example.org" has verified the guest link from the last email + + + Scenario: guest works inside the shared folder + When guest "guest@example.org" lists the content of folder "folderToShare" of space "Personal" of user "Alice" using the WebDAV API + Then the HTTP status code should be "207" + When guest "guest@example.org" uploads content "uploaded by guest" to "new.txt" inside folder "folderToShare" of space "Personal" of user "Alice" using the WebDAV API + Then the HTTP status code should be "201" + When guest "guest@example.org" creates folder "newFolder" inside folder "folderToShare" of space "Personal" of user "Alice" using the WebDAV API + Then the HTTP status code should be "201" + When guest "guest@example.org" renames "inside.txt" inside folder "folderToShare" of space "Personal" of user "Alice" to "renamed.txt" using the WebDAV API + Then the HTTP status code should be "201" + And for user "Alice" the content of the file "folderToShare/new.txt" of the space "Personal" should be "uploaded by guest" + And as "Alice" folder "folderToShare/newFolder" should exist + And as "Alice" file "folderToShare/renamed.txt" should exist + And as "Alice" file "folderToShare/inside.txt" should not exist + + + Scenario: guest cannot move a file out of the shared folder + When guest "guest@example.org" tries to move "inside.txt" inside folder "folderToShare" of space "Personal" of user "Alice" to "stolen.txt" in the root of that space using the WebDAV API + Then the HTTP status code should be "409" + And as "Alice" file "folderToShare/inside.txt" should exist + And as "Alice" file "stolen.txt" should not exist + + + Scenario: guest session gives access to all shares of the same guest + Given user "Brian" has been created with default attributes + And user "Alice" has uploaded file with content "from Alice" to "aliceFile.txt" + And user "Brian" has uploaded file with content "from Brian" to "brianFile.txt" + And user "Alice" has sent the following resource share invitation: + | resource | aliceFile.txt | + | space | Personal | + | sharee | guest@example.org | + | shareType | guest | + | permissionsRole | Viewer | + And user "Brian" has sent the following resource share invitation: + | resource | brianFile.txt | + | space | Personal | + | sharee | guest@example.org | + | shareType | guest | + | permissionsRole | Viewer | + When guest "guest@example.org" downloads file "aliceFile.txt" shared from space "Personal" of user "Alice" using the WebDAV API + Then the HTTP status code should be "200" + And the downloaded content should be "from Alice" + When guest "guest@example.org" downloads file "brianFile.txt" shared from space "Personal" of user "Brian" using the WebDAV API + Then the HTTP status code should be "200" + And the downloaded content should be "from Brian" + When guest "guest@example.org" uploads content "changed by guest" to file "aliceFile.txt" shared from space "Personal" of user "Alice" using the WebDAV API + Then the HTTP status code should be "403" + When guest "guest@example.org" lists the shares shared with them using the Graph API + Then the HTTP status code should be "200" + And the JSON data of the response should match + """ + { + "type": "object", + "required": ["value"], + "properties": { + "value": { + "type": "array", + "minItems": 3, + "maxItems": 3, + "uniqueItems": true, + "items": { + "type": "object", + "required": ["name"], + "properties": { + "name": { "enum": ["folderToShare", "aliceFile.txt", "brianFile.txt"] } + } + } + } + } + } + """ + + + Scenario Outline: guest cannot manage the share + When guest "guest@example.org" sends HTTP method "" to the Graph endpoint "" of resource "folderToShare" of space "Personal" of user "Alice" + Then the HTTP status code should be "401" + Examples: + | method | endpoint | + | GET | permissions | + | POST | invite | + | POST | createLink | + + + Scenario: guest session with an invalid signature is rejected + Given the signature of the guest session of guest "guest@example.org" has been changed + When guest "guest@example.org" lists the shares shared with them using the Graph API + Then the HTTP status code should be "401" + When guest "guest@example.org" lists the content of folder "folderToShare" of space "Personal" of user "Alice" using the WebDAV API + Then the HTTP status code should be "401" + + @issue-3770 + Scenario: guest with the Editor role cannot delete the shared folder + When guest "guest@example.org" tries to delete the shared folder "folderToShare" of space "Personal" of user "Alice" using the WebDAV API + Then the HTTP status code should be "403" + And as "Alice" folder "folderToShare" should exist + And as "Alice" file "folderToShare/inside.txt" should exist + + + Scenario: guest cannot rename the shared folder + When guest "guest@example.org" tries to rename the shared folder "folderToShare" of space "Personal" of user "Alice" to "renamedFolder" using the WebDAV API + Then the HTTP status code should be "409" + And as "Alice" folder "folderToShare" should exist + And as "Alice" folder "renamedFolder" should not exist + + + Scenario: guest with the Viewer role cannot change the shared folder + Given user "Alice" has created folder "viewerFolder" + And user "Alice" has uploaded file with content "viewer" to "viewerFolder/viewer.txt" + And user "Alice" has sent the following resource share invitation: + | resource | viewerFolder | + | space | Personal | + | sharee | guest@example.org | + | shareType | guest | + | permissionsRole | Viewer | + When guest "guest@example.org" uploads content "uploaded by guest" to "new.txt" inside folder "viewerFolder" of space "Personal" of user "Alice" using the WebDAV API + Then the HTTP status code should be "403" + When guest "guest@example.org" creates folder "newFolder" inside folder "viewerFolder" of space "Personal" of user "Alice" using the WebDAV API + Then the HTTP status code should be "403" + When guest "guest@example.org" renames "viewer.txt" inside folder "viewerFolder" of space "Personal" of user "Alice" to "renamed.txt" using the WebDAV API + Then the HTTP status code should be "403" + When guest "guest@example.org" deletes "viewer.txt" inside folder "viewerFolder" of space "Personal" of user "Alice" using the WebDAV API + Then the HTTP status code should be "403" + And as "Alice" file "viewerFolder/viewer.txt" should exist + And as "Alice" file "viewerFolder/new.txt" should not exist + And as "Alice" folder "viewerFolder/newFolder" should not exist + + + Scenario: guest downloads the archive of the shared folder + Given user "Alice" has uploaded file with content "second" to "folderToShare/second.txt" + And user "Alice" has created folder "folderToShare/subFolder" + And user "Alice" has uploaded file with content "nested" to "folderToShare/subFolder/nested.txt" + When guest "guest@example.org" downloads the archive of these resources using the archiver: + | resource | space | owner | + | folderToShare | Personal | Alice | + Then the HTTP status code should be "200" + And the downloaded zip archive should contain these files: + | name | content | + | folderToShare/inside.txt | inside | + | folderToShare/second.txt | second | + | folderToShare/subFolder/nested.txt | nested | + + + Scenario: guest downloads the archive of the shared folders of different users + Given user "Brian" has been created with default attributes + And user "Brian" has created folder "brianFolder" + And user "Brian" has uploaded file with content "from Brian" to "brianFolder/brian.txt" + And user "Brian" has sent the following resource share invitation: + | resource | brianFolder | + | space | Personal | + | sharee | guest@example.org | + | shareType | guest | + | permissionsRole | Viewer | + When guest "guest@example.org" downloads the archive of these resources using the archiver: + | resource | space | owner | + | folderToShare | Personal | Alice | + | brianFolder | Personal | Brian | + Then the HTTP status code should be "200" + And the downloaded zip archive should contain these files: + | name | content | + | folderToShare/inside.txt | inside | + | brianFolder/brian.txt | from Brian | + + + Scenario: guest cannot download the archive of resources outside the shared folder + Given user "Alice" has uploaded file with content "private" to "private.txt" + When guest "guest@example.org" downloads the archive of space "Personal" of user "Alice" using the archiver + Then the HTTP status code should be "404" + When guest "guest@example.org" downloads the archive of these resources using the archiver: + | resource | space | owner | + | private.txt | Personal | Alice | + Then the HTTP status code should be "404" + When guest "guest@example.org" downloads the archive of these resources using the archiver: + | resource | space | owner | + | folderToShare | Personal | Alice | + | private.txt | Personal | Alice | + Then the HTTP status code should be "404" + + + Scenario: guest copies and moves files between the shares of different users + Given user "Brian" has been created with default attributes + And user "Alice" has created folder "editorFolder" + And user "Alice" has created folder "viewerFolder" + And user "Alice" has uploaded file with content "viewer" to "viewerFolder/viewer.txt" + And user "Brian" has created folder "brianFolder" + And user "Alice" has sent the following resource share invitation: + | resource | editorFolder | + | space | Personal | + | sharee | guest@example.org | + | shareType | guest | + | permissionsRole | Editor | + And user "Alice" has sent the following resource share invitation: + | resource | viewerFolder | + | space | Personal | + | sharee | guest@example.org | + | shareType | guest | + | permissionsRole | Viewer | + And user "Brian" has sent the following resource share invitation: + | resource | brianFolder | + | space | Personal | + | sharee | guest@example.org | + | shareType | guest | + | permissionsRole | Editor | + When guest "guest@example.org" copies "inside.txt" inside folder "folderToShare" of space "Personal" of user "Alice" to folder "editorFolder" of space "Personal" of user "Alice" using the WebDAV API + Then the HTTP status code should be "201" + When guest "guest@example.org" copies "viewer.txt" inside folder "viewerFolder" of space "Personal" of user "Alice" to folder "folderToShare" of space "Personal" of user "Alice" using the WebDAV API + Then the HTTP status code should be "201" + When guest "guest@example.org" copies "inside.txt" inside folder "folderToShare" of space "Personal" of user "Alice" to folder "viewerFolder" of space "Personal" of user "Alice" using the WebDAV API + Then the HTTP status code should be "403" + When guest "guest@example.org" moves "viewer.txt" inside folder "folderToShare" of space "Personal" of user "Alice" to folder "editorFolder" of space "Personal" of user "Alice" using the WebDAV API + Then the HTTP status code should be "201" + When guest "guest@example.org" moves "inside.txt" inside folder "folderToShare" of space "Personal" of user "Alice" to folder "brianFolder" of space "Personal" of user "Brian" using the WebDAV API + Then the HTTP status code should be "502" + When guest "guest@example.org" copies "inside.txt" inside folder "folderToShare" of space "Personal" of user "Alice" to folder "brianFolder" of space "Personal" of user "Brian" using the WebDAV API + Then the HTTP status code should be "201" + And for user "Alice" the content of the file "editorFolder/inside.txt" of the space "Personal" should be "inside" + And for user "Alice" the content of the file "editorFolder/viewer.txt" of the space "Personal" should be "viewer" + And for user "Brian" the content of the file "brianFolder/inside.txt" of the space "Personal" should be "inside" + And as "Alice" file "folderToShare/inside.txt" should exist + And as "Alice" file "folderToShare/viewer.txt" should not exist + And as "Alice" file "viewerFolder/viewer.txt" should exist + And as "Alice" file "viewerFolder/inside.txt" should not exist + + @issue-3767 + Scenario: guest moves a file into a share of another user over an existing file + Given user "Brian" has been created with default attributes + And user "Brian" has created folder "brianFolder" + And user "Brian" has uploaded file with content "from Brian" to "brianFolder/inside.txt" + And user "Brian" has sent the following resource share invitation: + | resource | brianFolder | + | space | Personal | + | sharee | guest@example.org | + | shareType | guest | + | permissionsRole | Editor | + When guest "guest@example.org" moves "inside.txt" inside folder "folderToShare" of space "Personal" of user "Alice" to folder "brianFolder" of space "Personal" of user "Brian" using the WebDAV API + Then the HTTP status code should be "502" + And for user "Brian" the content of the file "brianFolder/inside.txt" of the space "Personal" should be "from Brian" + And for user "Alice" the content of the file "folderToShare/inside.txt" of the space "Personal" should be "inside" + diff --git a/tests/acceptance/features/apiGuestLink/guestLinkSecurity.feature b/tests/acceptance/features/apiGuestLink/guestLinkSecurity.feature deleted file mode 100644 index f3caf62203..0000000000 --- a/tests/acceptance/features/apiGuestLink/guestLinkSecurity.feature +++ /dev/null @@ -1,108 +0,0 @@ -@email -Feature: guest link access is limited to the shared resource - As a user sharing a folder with a guest - I want the guest to only access the shared folder - So that the rest of my files stay private - - Background: - Given user "Alice" has been created with default attributes - And user "Alice" has created folder "folderToShare" - And user "Alice" has uploaded file with content "inside" to "folderToShare/inside.txt" - And user "Alice" has sent the following resource share invitation: - | resource | folderToShare | - | space | Personal | - | sharee | guest@example.org | - | shareType | guest | - | permissionsRole | Editor | - And guest "guest@example.org" has verified the guest link from the last email - - - Scenario: guest works inside the shared folder - When guest "guest@example.org" lists the content of folder "folderToShare" of space "Personal" of user "Alice" using the WebDAV API - Then the HTTP status code should be "207" - When guest "guest@example.org" uploads content "uploaded by guest" to "new.txt" inside folder "folderToShare" of space "Personal" of user "Alice" using the WebDAV API - Then the HTTP status code should be "201" - When guest "guest@example.org" creates folder "newFolder" inside folder "folderToShare" of space "Personal" of user "Alice" using the WebDAV API - Then the HTTP status code should be "201" - When guest "guest@example.org" renames "inside.txt" inside folder "folderToShare" of space "Personal" of user "Alice" to "renamed.txt" using the WebDAV API - Then the HTTP status code should be "201" - And for user "Alice" the content of the file "folderToShare/new.txt" of the space "Personal" should be "uploaded by guest" - And as "Alice" folder "folderToShare/newFolder" should exist - And as "Alice" file "folderToShare/renamed.txt" should exist - And as "Alice" file "folderToShare/inside.txt" should not exist - - - Scenario: guest cannot move a file out of the shared folder - When guest "guest@example.org" tries to move "inside.txt" inside folder "folderToShare" of space "Personal" of user "Alice" to "stolen.txt" in the root of that space using the WebDAV API - Then the HTTP status code should be "409" - And as "Alice" file "folderToShare/inside.txt" should exist - And as "Alice" file "stolen.txt" should not exist - - - Scenario: guest session gives access to all shares of the same guest - Given user "Brian" has been created with default attributes - And user "Alice" has uploaded file with content "from Alice" to "aliceFile.txt" - And user "Brian" has uploaded file with content "from Brian" to "brianFile.txt" - And user "Alice" has sent the following resource share invitation: - | resource | aliceFile.txt | - | space | Personal | - | sharee | guest@example.org | - | shareType | guest | - | permissionsRole | Viewer | - And user "Brian" has sent the following resource share invitation: - | resource | brianFile.txt | - | space | Personal | - | sharee | guest@example.org | - | shareType | guest | - | permissionsRole | Viewer | - When guest "guest@example.org" downloads file "aliceFile.txt" shared from space "Personal" of user "Alice" using the WebDAV API - Then the HTTP status code should be "200" - And the downloaded content should be "from Alice" - When guest "guest@example.org" downloads file "brianFile.txt" shared from space "Personal" of user "Brian" using the WebDAV API - Then the HTTP status code should be "200" - And the downloaded content should be "from Brian" - When guest "guest@example.org" uploads content "changed by guest" to file "aliceFile.txt" shared from space "Personal" of user "Alice" using the WebDAV API - Then the HTTP status code should be "403" - When guest "guest@example.org" lists the shares shared with them using the Graph API - Then the HTTP status code should be "200" - And the JSON data of the response should match - """ - { - "type": "object", - "required": ["value"], - "properties": { - "value": { - "type": "array", - "minItems": 3, - "maxItems": 3, - "uniqueItems": true, - "items": { - "type": "object", - "required": ["name"], - "properties": { - "name": { "enum": ["folderToShare", "aliceFile.txt", "brianFile.txt"] } - } - } - } - } - } - """ - - - Scenario Outline: guest cannot manage the share - When guest "guest@example.org" sends HTTP method "" to the Graph endpoint "" of resource "folderToShare" of space "Personal" of user "Alice" - Then the HTTP status code should be "401" - Examples: - | method | endpoint | - | GET | permissions | - | POST | invite | - | POST | createLink | - - - Scenario: guest session with an invalid signature is rejected - Given the signature of the guest session of guest "guest@example.org" has been changed - When guest "guest@example.org" lists the shares shared with them using the Graph API - Then the HTTP status code should be "401" - When guest "guest@example.org" lists the content of folder "folderToShare" of space "Personal" of user "Alice" using the WebDAV API - Then the HTTP status code should be "401" - diff --git a/tests/acceptance/features/apiSpacesDavOperation/deleteByFileId.feature b/tests/acceptance/features/apiSpacesDavOperation/deleteByFileId.feature new file mode 100644 index 0000000000..de98665201 --- /dev/null +++ b/tests/acceptance/features/apiSpacesDavOperation/deleteByFileId.feature @@ -0,0 +1,28 @@ +Feature: deleting resources using file id + As a user + I want to be able to delete resources using file id + So that I can remove unwanted data + + Background: + Given using spaces DAV path + And these users have been created with default attributes: + | username | + | Alice | + | Brian | + + @issue-3770 + Scenario: sharee with the Editor role tries to delete the shared folder using its id + Given user "Alice" has created folder "folderToShare" + And user "Alice" has uploaded file with content "inside" to "folderToShare/inside.txt" + And user "Alice" has sent the following resource share invitation: + | resource | folderToShare | + | space | Personal | + | sharee | Brian | + | shareType | user | + | permissionsRole | Editor | + And user "Brian" has a share "folderToShare" synced + When user "Brian" tries to delete the shared folder "folderToShare" using the WebDAV API + Then the HTTP status code should be "403" + And as "Alice" folder "folderToShare" should exist + And as "Alice" file "folderToShare/inside.txt" should exist + And as "Brian" folder "/Shares/folderToShare" should exist diff --git a/tests/acceptance/features/apiSpacesDavOperation/moveByFileId.feature b/tests/acceptance/features/apiSpacesDavOperation/moveByFileId.feature index 1b1be785ac..9354312800 100644 --- a/tests/acceptance/features/apiSpacesDavOperation/moveByFileId.feature +++ b/tests/acceptance/features/apiSpacesDavOperation/moveByFileId.feature @@ -467,6 +467,35 @@ Feature: moving/renaming file using file id | Viewer | Editor | | Viewer | Viewer | + @issue-3767 + Scenario: move a file from a shared folder into a shared folder of another user over an existing file + Given these users have been created with default attributes: + | username | + | Brian | + | Carol | + And user "Alice" has created folder "aliceShare" + And user "Alice" has uploaded file with content "from Alice" to "aliceShare/aliceFile.txt" + And user "Carol" has created folder "carolShare" + And user "Carol" has uploaded file with content "from Carol" to "carolShare/carolFile.txt" + And user "Alice" has sent the following resource share invitation: + | resource | aliceShare | + | space | Personal | + | sharee | Brian | + | shareType | user | + | permissionsRole | Editor | + And user "Brian" has a share "aliceShare" synced + And user "Carol" has sent the following resource share invitation: + | resource | carolShare | + | space | Personal | + | sharee | Brian | + | shareType | user | + | permissionsRole | Editor | + And user "Brian" has a share "carolShare" synced + When user "Brian" moves file "aliceFile.txt" from share "aliceShare" to "carolFile.txt" in share "carolShare" using the WebDAV API + Then the HTTP status code should be "502" + And for user "Carol" the content of the file "carolShare/carolFile.txt" of the space "Personal" should be "from Carol" + And for user "Alice" the content of the file "aliceShare/aliceFile.txt" of the space "Personal" should be "from Alice" + @issue-8124 Scenario Outline: move a file from share to personal space Given user "Brian" has been created with default attributes diff --git a/tests/acceptance/features/apiSpacesDavOperation/ownerSpaceByDriveId.feature b/tests/acceptance/features/apiSpacesDavOperation/ownerSpaceByDriveId.feature new file mode 100644 index 0000000000..9dd05562f7 --- /dev/null +++ b/tests/acceptance/features/apiSpacesDavOperation/ownerSpaceByDriveId.feature @@ -0,0 +1,49 @@ +Feature: access the space of the share owner using the drive id + As a user + I want the sharee to only access the shared resource + So that the rest of my space stays private + + Background: + Given using spaces DAV path + And these users have been created with default attributes: + | username | + | Alice | + | Brian | + And user "Alice" has created folder "folderToShare" + And user "Alice" has uploaded file with content "inside" to "folderToShare/inside.txt" + And user "Alice" has uploaded file with content "private" to "private.txt" + And user "Alice" has sent the following resource share invitation: + | resource | folderToShare | + | space | Personal | + | sharee | Brian | + | shareType | user | + | permissionsRole | Editor | + And user "Brian" has a share "folderToShare" synced + + + Scenario: sharee cannot access the space of the owner using its drive id + When user "Brian" lists the content of the space of the owner of share "folderToShare" using the WebDAV API + Then the HTTP status code should be "404" + When user "Brian" downloads file "private.txt" from the space of the owner of share "folderToShare" using the WebDAV API + Then the HTTP status code should be "404" + When user "Brian" uploads content "uploaded by Brian" to file "brian.txt" in the space of the owner of share "folderToShare" using the WebDAV API + Then the HTTP status code should be "404" + When user "Brian" creates folder "brianFolder" in the space of the owner of share "folderToShare" using the WebDAV API + Then the HTTP status code should be "404" + When user "Brian" deletes file "private.txt" from the space of the owner of share "folderToShare" using the WebDAV API + Then the HTTP status code should be "404" + And for user "Alice" the content of the file "private.txt" of the space "Personal" should be "private" + And for user "Alice" folder "/" of the space "Personal" should not contain these files: + | brian.txt | + | brianFolder | + + + Scenario: sharee cannot copy or move a file out of the shared folder into the space of the owner + When user "Brian" tries to copy file "inside.txt" from share "folderToShare" to "copied.txt" in the space of the owner using the WebDAV API + Then the HTTP status code should be "409" + When user "Brian" tries to move file "inside.txt" from share "folderToShare" to "moved.txt" in the space of the owner using the WebDAV API + Then the HTTP status code should be "409" + And for user "Alice" the content of the file "folderToShare/inside.txt" of the space "Personal" should be "inside" + And for user "Alice" folder "/" of the space "Personal" should not contain these files: + | copied.txt | + | moved.txt |