Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Deleting requires removing self.webdav.root from list results and not re-encoding (corrupting) encoded items. #130

Open
Poikilos opened this issue Oct 29, 2022 · 0 comments

Comments

@Poikilos
Copy link

Poikilos commented Oct 29, 2022

  • webdav3-client python3 version: 3.14.6
    • uses requests version: 2.25.1
  • Nextcloud server version(s) affected: 19.0.5, 19.0.13, 20.0.14, 21.0.9, 22.2.10, 23.0.10, 24.0.6

In the client.clean method, the leading slash must be removed. :edit: but that still doesn't let me delete files from trash in Nextcloud.

Steps to reproduce issue

  1. Make a file called Some_Scribus_File_autosave_08_08_2021_02_23.sla in Nextcloud. Ensure it synchronizes or upload it directly to the web interface.
  2. Delete it.
  3. Run the script at https://github.com/poikilos/nextcloudops as follows: python3 nextcloudops.py --scrub-scribus

Actual Behavior

Currently, the path given to client's "clean" method is transformed into a Urn instance, which prepends a slash. However, does not match the Nextcloud API documentation.

:edit: The nextcloudops.py removes the leading slash manually as per the Nextcloud documentation, but the file doesn't get deleted either way. Files can be listed but not deleted. self.client.verify = False in my delete method doesn't help.

Expected Behavior

The client's clean command should allow deleting files from the trash.

The correct call is execute_request(action='clean', path=urn.quote()[1:]), otherwise the resource is not found. I'm not sure what other methods are affected, but this fix is the only way I can delete files in Nextcloud may not use the API according to the documentation.

Starting with "DELETE remote.php/dav" exactly (regardless of whether nextcloud is in domain/nextcloud) is verified by the API documentation: https://docs.nextcloud.com/server/19/developer_manual/client_apis/WebDAV/basic.html#deleting-files-and-folders-rfc4918

For now, I did a workaround by using execute_request in https://github.com/poikilos/nextcloudops

  • which proves the change works on my Nextcloud instance even with the location for the site being example.com/nextcloud
  • but the res.text is an html page with:

Nextcloud
Error
App not installed:

Nextcloud – a safe home for all your data

So the solution is not known. This issue may only apply to deleting things from trash, but that is an important use case since listing and deleting anything else is easy to do without a program in contrast to scrubbing the trash selectively like my project above does.

Already tried

  • DELETE remote.php/dav/trashbin/$USER/trash/$filename (exactly as shown in the Nextcloud WebDAV API documentation)
  • adding more parts of the path before remote.php, with or without a leading slash by changing the string after creating the Urn instance (see instances of fails in my code in my repo above)
  • clean(rel_url) where rel_url starts with /trashbin or trashbin

Solving:

It turns out the URL is both mangled and url encoded twice if using the output from the list function.

It works when that is resolved.

Potential solutions are below.
(where "path" refers to a result obtained using client.list)

Approach 1

The caller (if wontfix) must manually parse items:

  • remove /nextcloud/ if present
  • remove remote.php/dav/ if present
  • urllib.parse import unquote
  • path = unquote
  • The user must send the path to clean formatted like: /trashbin/USER/trash/FILENAME (current behavior)

additions to help with that:

  • Detect an encoded url (check for "%" maybe) and show a warning, but continue encoding in case not detected properly.
  • check for the API route ("remote.php") in the URL, and if present, show an error saying the path must be relative to the API.

Approach 2

If URL starts with self.webdav.root assume item is output from list and:

  1. remove webdav_root from the start
  2. maybe don't encode the URL (assume it is output from list that is already encoded)
  3. Return a response so the caller can see what is going on (for example, 204 not 200 is expected when deleting a file from Nextcloud).

With both 1&2, it works fine (tested):

    @wrap_connection_error
    def clean(self, remote_path):
        root = self.webdav.root
        if (root is not None) and remote_path.startswith(root):
            # It is a full path relative to hostname.
            remote_path = remote_path[len(root):]
            urn_quoted = remote_path
            # ^ Assume full paths are from list() (already quoted).
            #   Re-encoding with quote() would corrupt %20 into %2520.
        else:
            urn = Urn(remote_path)
            urn_quoted = urn.quote()
        print("[client] urn_quoted={}".format(urn_quoted))
        return self.execute_request(action='clean', path=urn_quoted)
@Poikilos Poikilos changed the title Deleting requires removing the leading slash and starting the URL with remote.php Deleting requires removing self.webdav.root from list results and not re-encoding (corrupting) encoded items. Oct 31, 2022
Poikilos added a commit to Poikilos/webdav-client-python-3 that referenced this issue Oct 31, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant