Search code examples
iosauthenticationauthorizationcaldav

Is there any way to retrieve Apple DSID with an app specific password?


I'm working on a little project where I would like to fully sync my Apple Calendar with my web-app. I'm using two packages in python (caldav and icalendar) to view, create, update and delete events and then I'm using some GraphQL to prettify the data to my frontend. It's working quite nicely at the moment, but if I ever were to push this to production, there is one big problem. In the caldav-package, you need to supply a link to the client. It looks something like this:

https://pXX-caldav.icloud.com/<DSID>/calendars

Where pXX is different for every user and the DSID is something like Apples unique ID for your Apple account. The pXX is not very complicated to get, but the DSID is somewhat more of a pain. When you are retrieving calendars you need to also give the client an @icloud.com-account and an app specific password.

There are numerous articles that explains how to get the DSID by going to your Apple Calendar app and hacking about a little in the development-console. This works, but I can't have people do this if they sign up. Another way is to make a request to

https://setup.icloud.com/setup/ws/1/accountLogin

with your Apple credentials. This gives you back a whole lot of interesting information about your account, including DSID. It does however, only work with your real Apple ID and password, and I don't want people entering that information on any other site than Apple's own sites. I have tried going around this by using my app specific password, but with no luck.

Does anyone have any knowledge about how to get around this? If there really is no possible way, then I think maybe this project should be put on hold for now.


Solution

  • After a lot of hours researching, easiest answer: simple 'PROPFIND'-request to https://caldav.icloud.com

    import requests
    from bs4 import BeautifulSoup
    
    caldav_url = 'https://caldav.icloud.com'
    username = <APPLE_ID>
    password = <APP_SPECIFIC_PASSWORD>
    
    principal_query = """\
    <?xml version="1.0" encoding="utf-8"?>
    <propfind xmlns='DAV:'>
        <prop>
            <current-user-principal/>
        </prop>
    </propfind>
    """
    
    r = requests.request(
        'PROPFIND',
        url=caldav_url,
        data=principal_query,
        auth=requests.auth.HTTPBasicAuth(username, password),
        headers={'Content-Type': 'application/xml'},
        )
    
    soup = BeautifulSoup(r.text, 'lxml')
    principal_extension = soup.find('current-user-principal').find('href').get_text()
    
    print(principal_extension)
    // -> /<DSID>/principal/