nextcloud / notes

✎ Distraction-free notes and writing
https://apps.nextcloud.com/apps/notes
GNU Affero General Public License v3.0
623 stars 135 forks source link

Ignoring `readonly` attribute leads to `500` when origin is another instance #841

Open stefan-niedermann opened 2 years ago

stefan-niedermann commented 2 years ago

Steps to reproduce

  1. Create a folder with a text file on Nextcloud instance A
  2. Share this folder without write permissions to a user on Nextcloud instance B (via federated sharing)
  3. Move the folder in Nextcloud instance B into your /Notes folder
  4. Try editing and saving it on Nextcloud instance B

Expected behaviour

Http 403 should be returned

Actual behaviour

Http 500 will be returned

Screenshots

image

Server

Please complete the following information.

Nextcloud configuration:

``` If you have access to your command line run e.g.: sudo -u www-data php occ config:list system from within your Nextcloud installation folder ```

Client

Please complete the following information.

Log files

{
   "reqId":"YkIQE-M1vxwFYekKdJU9PgAAAB0",
   "level":3,
   "time":"2022-03-28T19:44:23+00:00",
   "remoteAddr":"2a01:c23:c1d5:a700:7801:4875:61b8:ec3b",
   "user":"userB",
   "app":"notes",
   "method":"PUT",
   "url":"/index.php/apps/notes/notes/227690",
   "message":"Controller failed with GuzzleHttp\\Exception\\ClientException",
   "userAgent":"Mozilla/5.0 (X11; Linux x86_64; rv:98.0) Gecko/20100101 Firefox/98.0",
   "version":"23.0.3.2",
   "exception":{
      "Exception":"GuzzleHttp\\Exception\\ClientException",
      "Message":"Client error: `PUT https://a.example.com/public.php/webdav/Shared%20note.md` resulted in a `403 Forbidden` response:\n<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<d:error xmlns:d=\"DAV:\" xmlns:s=\"http://sabredav.org/ns\">\n  <s:exception>Sabre\\DA (truncated...)\n",
      "Code":403,
      "Trace":[
         {
            "file":"/var/www/vhosts/b.example.com/b.example.com/3rdparty/guzzlehttp/guzzle/src/Middleware.php",
            "line":69,
            "function":"create",
            "class":"GuzzleHttp\\Exception\\RequestException",
            "type":"::"
         },
         {
            "file":"/var/www/vhosts/b.example.com/b.example.com/3rdparty/guzzlehttp/promises/src/Promise.php",
            "line":204,
            "function":"GuzzleHttp\\{closure}",
            "class":"GuzzleHttp\\Middleware",
            "type":"::",
            "args":[
               "*** sensitive parameters replaced ***"
            ]
         },
         {
            "file":"/var/www/vhosts/b.example.com/b.example.com/3rdparty/guzzlehttp/promises/src/Promise.php",
            "line":153,
            "function":"callHandler",
            "class":"GuzzleHttp\\Promise\\Promise",
            "type":"::"
         },
         {
            "file":"/var/www/vhosts/b.example.com/b.example.com/3rdparty/guzzlehttp/promises/src/TaskQueue.php",
            "line":48,
            "function":"GuzzleHttp\\Promise\\{closure}",
            "class":"GuzzleHttp\\Promise\\Promise",
            "type":"::",
            "args":[
               "*** sensitive parameters replaced ***"
            ]
         },
         {
            "file":"/var/www/vhosts/b.example.com/b.example.com/3rdparty/guzzlehttp/promises/src/Promise.php",
            "line":248,
            "function":"run",
            "class":"GuzzleHttp\\Promise\\TaskQueue",
            "type":"->"
         },
         {
            "file":"/var/www/vhosts/b.example.com/b.example.com/3rdparty/guzzlehttp/promises/src/Promise.php",
            "line":224,
            "function":"invokeWaitFn",
            "class":"GuzzleHttp\\Promise\\Promise",
            "type":"->"
         },
         {
            "file":"/var/www/vhosts/b.example.com/b.example.com/3rdparty/guzzlehttp/promises/src/Promise.php",
            "line":269,
            "function":"waitIfPending",
            "class":"GuzzleHttp\\Promise\\Promise",
            "type":"->"
         },
         {
            "file":"/var/www/vhosts/b.example.com/b.example.com/3rdparty/guzzlehttp/promises/src/Promise.php",
            "line":226,
            "function":"invokeWaitList",
            "class":"GuzzleHttp\\Promise\\Promise",
            "type":"->"
         },
         {
            "file":"/var/www/vhosts/b.example.com/b.example.com/3rdparty/guzzlehttp/promises/src/Promise.php",
            "line":62,
            "function":"waitIfPending",
            "class":"GuzzleHttp\\Promise\\Promise",
            "type":"->"
         },
         {
            "file":"/var/www/vhosts/b.example.com/b.example.com/3rdparty/guzzlehttp/guzzle/src/Client.php",
            "line":187,
            "function":"wait",
            "class":"GuzzleHttp\\Promise\\Promise",
            "type":"->"
         },
         {
            "file":"/var/www/vhosts/b.example.com/b.example.com/lib/private/Http/Client/Client.php",
            "line":329,
            "function":"request",
            "class":"GuzzleHttp\\Client",
            "type":"->"
         },
         {
            "file":"/var/www/vhosts/b.example.com/b.example.com/lib/private/Files/Storage/DAV.php",
            "line":515,
            "function":"put",
            "class":"OC\\Http\\Client\\Client",
            "type":"->"
         },
         {
            "file":"/var/www/vhosts/b.example.com/b.example.com/lib/private/Files/Storage/DAV.php",
            "line":422,
            "function":"uploadFile",
            "class":"OC\\Files\\Storage\\DAV",
            "type":"->"
         },
         {
            "file":"/var/www/vhosts/b.example.com/b.example.com/lib/private/Files/Storage/DAV.php",
            "line":413,
            "function":"writeBack",
            "class":"OC\\Files\\Storage\\DAV",
            "type":"->"
         },
         {
            "function":"OC\\Files\\Storage\\{closure}",
            "class":"OC\\Files\\Storage\\DAV",
            "type":"->",
            "args":[
               "*** sensitive parameters replaced ***"
            ]
         },
         {
            "file":"/var/www/vhosts/b.example.com/b.example.com/3rdparty/icewind/streams/src/CallbackWrapper.php",
            "line":119,
            "function":"call_user_func"
         },
         {
            "function":"stream_close",
            "class":"Icewind\\Streams\\CallbackWrapper",
            "type":"->"
         },
         {
            "file":"/var/www/vhosts/b.example.com/b.example.com/lib/private/Files/Storage/Common.php",
            "line":209,
            "function":"fclose"
         },
         {
            "file":"/var/www/vhosts/b.example.com/b.example.com/lib/private/Files/Storage/DAV.php",
            "line":494,
            "function":"file_put_contents",
            "class":"OC\\Files\\Storage\\Common",
            "type":"->"
         },
         {
            "file":"/var/www/vhosts/b.example.com/b.example.com/lib/private/Files/Storage/Wrapper/Wrapper.php",
            "line":258,
            "function":"file_put_contents",
            "class":"OC\\Files\\Storage\\DAV",
            "type":"->"
         },
         {
            "file":"/var/www/vhosts/b.example.com/b.example.com/lib/private/Files/Storage/Wrapper/Availability.php",
            "line":274,
            "function":"file_put_contents",
            "class":"OC\\Files\\Storage\\Wrapper\\Wrapper",
            "type":"->"
         },
         {
            "file":"/var/www/vhosts/b.example.com/b.example.com/lib/private/Files/Storage/Wrapper/Wrapper.php",
            "line":258,
            "function":"file_put_contents",
            "class":"OC\\Files\\Storage\\Wrapper\\Availability",
            "type":"->"
         },
         {
            "file":"/var/www/vhosts/b.example.com/b.example.com/lib/private/Files/View.php",
            "line":1169,
            "function":"file_put_contents",
            "class":"OC\\Files\\Storage\\Wrapper\\Wrapper",
            "type":"->"
         },
         {
            "file":"/var/www/vhosts/b.example.com/b.example.com/lib/private/Files/View.php",
            "line":706,
            "function":"basicOperation",
            "class":"OC\\Files\\View",
            "type":"->"
         },
         {
            "file":"/var/www/vhosts/b.example.com/b.example.com/lib/private/Files/Node/File.php",
            "line":71,
            "function":"file_put_contents",
            "class":"OC\\Files\\View",
            "type":"->"
         },
         {
            "file":"/var/www/vhosts/b.example.com/b.example.com/apps/notes/lib/Service/Note.php",
            "line":171,
            "function":"putContent",
            "class":"OC\\Files\\Node\\File",
            "type":"->"
         },
         {
            "file":"/var/www/vhosts/b.example.com/b.example.com/apps/notes/lib/Controller/NotesController.php",
            "line":226,
            "function":"setContent",
            "class":"OCA\\Notes\\Service\\Note",
            "type":"->"
         },
         {
            "file":"/var/www/vhosts/b.example.com/b.example.com/apps/notes/lib/Service/Util.php",
            "line":28,
            "function":"OCA\\Notes\\Controller\\{closure}",
            "class":"OCA\\Notes\\Controller\\NotesController",
            "type":"->",
            "args":[
               "*** sensitive parameters replaced ***"
            ]
         },
         {
            "file":"/var/www/vhosts/b.example.com/b.example.com/apps/notes/lib/Controller/Helper.php",
            "line":145,
            "function":"retryIfLocked",
            "class":"OCA\\Notes\\Service\\Util",
            "type":"::"
         },
         {
            "file":"/var/www/vhosts/b.example.com/b.example.com/apps/notes/lib/Controller/NotesController.php",
            "line":228,
            "function":"handleErrorResponse",
            "class":"OCA\\Notes\\Controller\\Helper",
            "type":"->"
         },
         {
            "file":"/var/www/vhosts/b.example.com/b.example.com/lib/private/AppFramework/Http/Dispatcher.php",
            "line":217,
            "function":"update",
            "class":"OCA\\Notes\\Controller\\NotesController",
            "type":"->",
            "args":[
               "*** sensitive parameters replaced ***"
            ]
         },
         {
            "file":"/var/www/vhosts/b.example.com/b.example.com/lib/private/AppFramework/Http/Dispatcher.php",
            "line":126,
            "function":"executeController",
            "class":"OC\\AppFramework\\Http\\Dispatcher",
            "type":"->"
         },
         {
            "file":"/var/www/vhosts/b.example.com/b.example.com/lib/private/AppFramework/App.php",
            "line":157,
            "function":"dispatch",
            "class":"OC\\AppFramework\\Http\\Dispatcher",
            "type":"->"
         },
         {
            "file":"/var/www/vhosts/b.example.com/b.example.com/lib/private/Route/Router.php",
            "line":302,
            "function":"main",
            "class":"OC\\AppFramework\\App",
            "type":"::"
         },
         {
            "file":"/var/www/vhosts/b.example.com/b.example.com/lib/base.php",
            "line":1006,
            "function":"match",
            "class":"OC\\Route\\Router",
            "type":"->"
         },
         {
            "file":"/var/www/vhosts/b.example.com/b.example.com/index.php",
            "line":36,
            "function":"handleRequest",
            "class":"OC",
            "type":"::"
         }
      ],
      "File":"/var/www/vhosts/b.example.com/b.example.com/3rdparty/guzzlehttp/guzzle/src/Exception/RequestException.php",
      "Line":113,
      "CustomMessage":"Controller failed with GuzzleHttp\\Exception\\ClientException"
   },
   "id":"6242101826d1c"
}
korelstar commented 2 years ago

That's an interesting use case, we don't have this in our CI tests, yet. At first sight, it looks like the Nextcloud framework says, that the file is writable - although it isn't. The Notes app calls OC\Files\Node\File.isUpdateable() for checking writability - which appears to not work in this case. Otherwise the Notes app would have opened the editor in read-only mode.

I would say that's a bug in Nextcloud server, but I'll try to reproduce this for further insights.