cdav-library icon indicating copy to clipboard operation
cdav-library copied to clipboard

propfind assumes DAV header always exists and causes null exception when missing

Open boxofrox opened this issue 1 year ago • 0 comments

Steps to reproduce

Trying to use caldav to sync Super-Productivity[1] app with Mailcow/SOGo[2] server calendar.

  1. Spin up dockerized mailcow. a. Create mail account. b. Login to mail account. c. Open calendar. d. Click on "3-dot" icon next to calendar name, select "Links to this Calendar" e. Copy authorized caldav url.
  2. Clone Super-Productivity repo: git clone [email protected]:johannesjo/super-productivity.git
  3. Set up dev environment: cd super-productivity; npm i @angular/cli; npm i
  4. Run dev app: npm run ng serve, then in another terminal npm start
  5. In Super-Productivity, find Inbox in Projects drawer (left side), select "Settings" from "3-dot" icon for Inbox.
  6. Expand CalDav Issue Integration. a. Enable caldav. b. Enter caldav url from step (1.e). E.g. https://mail.example.com/SOGo/dav c. Enter caldav path from step (1.e). E.g. Calendar/personal d. Enter username e. Enter password f. Enable four checkbox/toggles below: Show uncompleted..., Auto poll..., Auto add..., and Auto complete....
  7. Open dev tools with Ctrl-Shift-I.
  8. Select Console tab and observe "Caldav: Error: CALDAV NETWORK ERROR: TypeError: Cannot read properties of null (reading 'split')"

[1]: https://github.com/johannesjo/super-productivity
[2]: https://github.com/mailcow/mailcow-dockerized

Expected behavior

Expected no type error.

If library needs DAV header, then it should first make an OPTIONS request which must deliver a DAV header to comply with spec, then perform a subsequent PROPFIND request for other fields.

Actual behavior

"Caldav: Error: CALDAV NETWORK ERROR: TypeError: Cannot read properties of null (reading 'split')" crashes caldav sync in SuperProductivity.

Library version

1.1.0

Additional info

Suspect code

At index.js:155, request.propfind initiates the a PROPFIND request.

At index.js:158, _extractAdvertisedDavFeatures is called.

At index.js:541-542, the DAV: header is retrieved and sliced without a null check.

SOGo behavior

If I use curl to execute PROPFIND, SOGo never provides a DAV header. If I use curl to execute OPTIONS, SOGo provides a DAV header.

E.g.

(curl --user "name:pass" -s -X PROPFIND -H "Content-Type: application/xml" -D /dev/stderr https://mail.example.com/SOGo/dav/name%40example.com | xmllint -format -) 2>&1 | bat
───────┬──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
       │ STDIN
───────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
   1   │ HTTP/2 207
   2   │ server: nginx
   3   │ date: Sat, 02 Mar 2024 03:37:17 GMT
   4   │ content-type: text/xml; charset=utf-8
   5   │ content-length: 3883
   6   │ x-dav-error: 200 No error
   7   │ ms-author-via: DAV
   8   │ pragma: no-cache
   9   │ cache-control: no-cache
  10   │ x-frame-options: SAMEORIGIN
  11   │
  12   │ <?xml version="1.0" encoding="utf-8"?>
  13   │ <D:multistatus xmlns:ap="http://apache.org/dav/props/" xmlns:D="DAV:">
  14   │   <D:response>
  15   │     <D:href>/SOGo/dav/name%40example.com/freebusy.ifb</D:href>
  16   │     <D:propstat>
  17   │       <D:status>HTTP/1.1 200 OK</D:status>
  18   │       <D:prop>
  19   │         <D:getlastmodified>Fri, 01 Mar 2024 22:38:53 -0500</D:getlastmodified>
  20   │         <D:resourcetype/>
  21   │         <D:getcontenttype>text/calendar</D:getcontenttype>
  22   │         <D:displayname>freebusy.ifb</D:displayname>
  23   │         <D:href>/SOGo/dav/name%40example.com/freebusy.ifb</D:href>
  24   │         <ap:executable>0</ap:executable>
  25   │       </D:prop>
  26   │     </D:propstat>
  27   │   </D:response>
  ...  │
 158   │ </D:multistatus>
───────┴──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────


(curl --user "name:pass" -s -X OPTIONS -H "Content-Type: application/xml" -D /dev/stderr https://mail.example.com/SOGo/dav/name%40example.com) 2>&1 | bat
───────┬──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
       │ STDIN
───────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
   1   │ HTTP/2 200
   2   │ server: nginx
   3   │ date: Sat, 02 Mar 2024 03:40:04 GMT
   4   │ content-type: text/plain; charset=utf-8
   5   │ content-length: 0
   6   │ allow: GET, HEAD, POST, OPTIONS, MKCOL, MKCALENDAR, DELETE, PUT, LOCK, UNLOCK, COPY, MOVE, REPORT, PROPFIND, SEARCH
   7   │ dav: 1, 2, access-control, addressbook, calendar-access, calendar-schedule, calendar-auto-schedule, calendar-proxy, calendar-query-extended, extended-mkcol, calendarserver-principal-property-search
   8   │ strict-transport-security: max-age=15768000;
   9   │ x-content-type-options: nosniff
  10   │ x-xss-protection: 1; mode=block
  11   │ x-robots-tag: none
  12   │ x-download-options: noopen
  13   │ x-frame-options: SAMEORIGIN
  14   │ x-permitted-cross-domain-policies: none
  15   │ referrer-policy: strict-origin
  16   │
───────┴──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────

WebDAV Spec

According to the spec, PROPFIND uses DAV XML elements, but doesn't explicitly state a requirement/expectation for a DAV header [1].

Further along, the OPTIONS method is required to return the DAV header [2].

All DAV-compliant resources MUST return the DAV header with compliance-class "1" on all OPTIONS responses

Section F.3 makes the claim that DAV header can be used with requests [3]. I don't know whether "requests" in this context refers to other WebDAV methods.

The DAV header now allows non-IETF extensions through URIs in addition to compliance class tokens. It also can now be used in requests, although this specification does not define any associated semantics for the compliance classes defined in here (see Section 10.1).

[1]: http://www.webdav.org/specs/rfc4918.html#METHOD_PROPFIND
[2]: http://www.webdav.org/specs/rfc4918.html#HEADER_DAV
[3]: http://www.webdav.org/specs/rfc4918.html#n-other-changes

boxofrox avatar Mar 02 '24 03:03 boxofrox