natelindev / tsdav

WebDAV, CALDAV, and CARDDAV client for Nodejs and the Browser
https://tsdav.vercel.app
MIT License
232 stars 38 forks source link

Issue Fetching vcards from Yahoo carddav server #2

Closed boxymoron closed 3 years ago

boxymoron commented 3 years ago

Hello,

I have a requirement to fetch a list of contacts/emails from a yahoo user/email account. After much research I found that Yahoo deprecated their old Contacts API and is now using CardDAV, but theres virtually no documentation online about Yahoo's implementation (I assume because CardDAV is a standard protocol).

I'm having issues using tsDAV to retrieve a list of contacts from Yahoo and could use some help.

So far I've been able to authenticate successfully with Yahoo OAuth and can retrieve an AddressBook with fetchAddressBooks(), but I can't seem to be able to fetch VCards or issue an addressBookQuery successfully.

Code:

...initialize client
const addressBook = await client.fetchAddressBooks();

const vCards = await client.fetchVCards({//This fails with a 400 error
  addressBook: addressBook[0],
});

const addressbooks = await client.addressBookQuery({//This fails with a 400 error
        url: addressBook[0].url,
        props: [
          { name: 'getetag', namespace: DAVNamespace.DAV }, 
        ],
        depth: '1'
      });

Here's what I'm seeing in the logs for the call to client.fetchVCards():

I added log statements in request.js to see the url, headers, and body (before marshalled to xml). One interesting thing is that the log statements gets called twice in a row with a different body for the same call to fetchVCards(). Not sure if this is correct behavior.

Request:

  tsdav:addressBook Fetching vcards from https://carddav.address.yahoo.com/dav/username/Contacts/ +200ms
url:  https://carddav.address.yahoo.com/dav/username/Contacts/
headers:  {
  authorization: 'Bearer ...',
  depth: '1'
}
body:  {
  "addressbook-query": {
    "_attributes": {
      "xmlns:card": "urn:ietf:params:xml:ns:carddav",
      "xmlns:d": "DAV:"
    },
    "d:prop": {
      "d:getetag": {}
    },
    "filter": {
      "prop-filter": {
        "_attributes": {
          "name": "FN"
        }
      }
    }
  }
}
url:  https://carddav.address.yahoo.com/dav/username/Contacts/
headers:  {
  authorization: 'Bearer ...',
  depth: '1'
}
body:  {
  "addressbook-multiget": {
    "_attributes": {
      "xmlns:d": "DAV:",
      "xmlns:card": "urn:ietf:params:xml:ns:carddav"
    },
    "d:prop": {
      "d:getetag": {},
      "card:address-data": {}
    },
    "d:href": [] <---- This is empty, and the error below says that hrefs need to be specified, but not sure what these hrefs are supposed to be???
  }
}

Response:

vCards[
  {
    "res": {
      "href": "https://carddav.address.yahoo.com/dav/username/Contacts/",
      "ok": false,
      "status": 400,
      "statusText": "Bad Request",
      "raw": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?><error xmlns:ns1=\"http://www.yahooapis.com/v1/base.rng\" xml:lang=\"en-US\"><ns1:description>Bad Request</ns1:description><ns1:detail>One or more hrefs need to be specified in the request</ns1:detail></error>"
    },
    "url": "https://carddav.address.yahoo.com/dav/username/Contacts/"
  }
]

And here is the log for the call to addressBookQuery():

url:  https://carddav.address.yahoo.com/dav/username/Contacts/
headers:  {
  authorization: 'Bearer  ...',
  depth: '1'
}
body:  {<-- The IETF standard example (https://datatracker.ietf.org/doc/html/rfc6352#section-8.6) looks similar to this, so I assume it should work???
  "addressbook-query": {
    "_attributes": {
      "xmlns:card": "urn:ietf:params:xml:ns:carddav",
      "xmlns:d": "DAV:"
    },
    "d:prop": {
      "d:getetag": {},
      "card:href": [
        "https://carddav.address.yahoo.com/dav/username/Contacts/"
      ]
    },
    "filter": {
      "prop-filter": {
        "_attributes": {
          "name": "FN"
        }
      }
    }
  }
}

Response:

addressbooks: [
  {
    "href": "https://carddav.address.yahoo.com/dav/username/Contacts/",
    "ok": false,
    "status": 400,
    "statusText": "Bad Request",
    "raw": ""
  }
]

Is it possible that the Yahoo CardDAV implementation is broken (non-standards compliant)??

Any help is greatly appreciated.

natelindev commented 3 years ago

I'll try to see if it works with Yahoo, I've tested it only with apple and google. If it's a bug within this lib I'll let you know.

natelindev commented 3 years ago

After some investigation, it seems like yahoo's carddav API lacks some required parts of the carddav spec

Support for the CARDDAV:addressbook-query REPORT is REQUIRED.

accroding to my test yahoo's carddav api does not support this report, therefore it's impossible for client to know the urls of the vcard objects inside a given addressbook.

However, if for example, all vcards on this addressBook were created by your application and you can store the urls somewhere, you can technically create/edit/delete the vcard objects with this client.

natelindev commented 3 years ago

Also another client, DAVx marked carddav api of yahoo unusable. So I don't think it's a bug of tsdav

boxymoron commented 3 years ago

Thanks for the prompt response. So basically the Yahoo CardDAV implementation is broken/non-standards compliant.