caldav: handle PROPFIND on root

It seems like the Reminders app in iOS/macOS does this request as
the first thing when setting up an account, so it seems reasonable to
handle it for us.

This just returns the most basic current-user-principal now, but that
should hopefully be enough to continue the process.
This commit is contained in:
Dan Berglund 2023-07-06 12:12:07 +02:00 committed by GitHub
parent 46dbba12fe
commit 7dd64908d2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 56 additions and 2 deletions

View File

@ -371,6 +371,12 @@ func (b *backend) PropFind(r *http.Request, propfind *internal.PropFind, depth i
var resps []internal.Response var resps []internal.Response
switch resType { switch resType {
case resourceTypeRoot:
resp, err := b.propFindRoot(r.Context(), propfind)
if err != nil {
return nil, err
}
resps = append(resps, *resp)
case resourceTypeUserPrincipal: case resourceTypeUserPrincipal:
principalPath, err := b.Backend.CurrentUserPrincipal(r.Context()) principalPath, err := b.Backend.CurrentUserPrincipal(r.Context())
if err != nil { if err != nil {
@ -453,6 +459,23 @@ func (b *backend) PropFind(r *http.Request, propfind *internal.PropFind, depth i
return internal.NewMultiStatus(resps...), nil return internal.NewMultiStatus(resps...), nil
} }
func (b *backend) propFindRoot(ctx context.Context, propfind *internal.PropFind) (*internal.Response, error) {
principalPath, err := b.Backend.CurrentUserPrincipal(ctx)
if err != nil {
return nil, err
}
props := map[xml.Name]internal.PropFindFunc{
internal.CurrentUserPrincipalName: func(*internal.RawXMLValue) (interface{}, error) {
return &internal.CurrentUserPrincipal{Href: internal.Href{Path: principalPath}}, nil
},
internal.ResourceTypeName: func(*internal.RawXMLValue) (interface{}, error) {
return internal.NewResourceType(internal.CollectionName), nil
},
}
return internal.NewPropFindResponse(principalPath, propfind, props)
}
func (b *backend) propFindUserPrincipal(ctx context.Context, propfind *internal.PropFind) (*internal.Response, error) { func (b *backend) propFindUserPrincipal(ctx context.Context, propfind *internal.PropFind) (*internal.Response, error) {
principalPath, err := b.Backend.CurrentUserPrincipal(ctx) principalPath, err := b.Backend.CurrentUserPrincipal(ctx)
if err != nil { if err != nil {

View File

@ -50,6 +50,37 @@ func TestPropFindSupportedCalendarComponent(t *testing.T) {
} }
} }
var propFindUserPrincipal = `
<?xml version="1.0" encoding="UTF-8"?>
<A:propfind xmlns:A="DAV:">
<A:prop>
<A:current-user-principal/>
<A:principal-URL/>
<A:resourcetype/>
</A:prop>
</A:propfind>
`
func TestPropFindRoot(t *testing.T) {
req := httptest.NewRequest("PROPFIND", "/", strings.NewReader(propFindUserPrincipal))
req.Header.Set("Content-Type", "application/xml")
w := httptest.NewRecorder()
calendar := &Calendar{}
handler := Handler{Backend: testBackend{calendar: calendar}}
handler.ServeHTTP(w, req)
res := w.Result()
defer res.Body.Close()
data, err := ioutil.ReadAll(res.Body)
if err != nil {
t.Error(err)
}
resp := string(data)
if !strings.Contains(resp, `<current-user-principal xmlns="DAV:"><href>/user/</href></current-user-principal>`) {
t.Errorf("No user-principal returned when doing a PROPFIND against root, response:\n%s", resp)
}
}
type testBackend struct { type testBackend struct {
calendar *Calendar calendar *Calendar
} }
@ -59,11 +90,11 @@ func (t testBackend) Calendar(ctx context.Context) (*Calendar, error) {
} }
func (t testBackend) CalendarHomeSetPath(ctx context.Context) (string, error) { func (t testBackend) CalendarHomeSetPath(ctx context.Context) (string, error) {
return "", nil return "/user/calendars/", nil
} }
func (t testBackend) CurrentUserPrincipal(ctx context.Context) (string, error) { func (t testBackend) CurrentUserPrincipal(ctx context.Context) (string, error) {
return "", nil return "/user/", nil
} }
func (t testBackend) DeleteCalendarObject(ctx context.Context, path string) error { func (t testBackend) DeleteCalendarObject(ctx context.Context, path string) error {