This repository was archived by the owner on Aug 2, 2026. It is now read-only.
Add CalDAV read-only calendar backend - #355
Open
ssmurfgg04-gif wants to merge 1 commit into
Open
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Implements a read-only CalDAV backend exposing Proton Calendar over RFC 4791,
mirroring the structure of the existing CardDAV backend. Closes #282.
This is the minimum viable foundation: clients can discover calendars and
sync existing events. Write operations (create/update/delete events) are
explicitly rejected with HTTP 403 for now, matching how CardDAV rejects
CreateAddressBook/DeleteAddressBook. Once event write support is addedto the
protonmailpackage, the same backend can be extended.What works
PROPFINDon root → returns current-user-principal and CalDAV calendar-home-setPROPFINDon/calendar→ lists all Proton calendarsPROPFINDon/calendar/<id>→ returns calendar metadata (name, description, supported components)PROPFINDon/calendar/<id>/→ lists all event resources in the calendarGETon/calendar/<id>/<eventID>.ics→ returns decrypted iCalendar objectREPORT(calendar-query) → filtered listings viacaldav.FilterREPORT(calendar-multiget) → batch object fetchWhat is not yet supported
PUT(create/update event) → returns 403 ForbiddenDELETE(remove event) → returns 403 ForbiddenMKCALENDAR(create new calendar) → returns 403 ForbiddenReason: the
protonmailpackage only exposesListCalendarsandListCalendarEvents. Adding write methods requires implementing thecalendar event create/update/delete endpoints with their key-packet
encryption scheme, which I haven't done in this PR to keep scope reviewable.
Architecture
caldav/caldav.goimplements the fullcaldav.Backendinterface fromgithub.com/emersion/go-webdav/caldav. The structure mirrorscarddav/carddav.go:backendstruct holds the Proton client and user's PGP private keysListCalendarsproxies toprotonmail.Client.ListCalendarsListCalendarObjectsenumerates events viaListCalendarEventsover a10-year window centred on now, decrypts each card, and wraps in a
caldav.CalendarObjectGetCalendarObjectdoes the same but filters by event IDQueryCalendarObjectsdelegates tocaldav.Filteron the full listingDecryption
Proton Calendar encrypts event data with a symmetric session key, which is
itself encrypted with the user's PGP key and shipped in either
CalendarKeyPacket(personal events) orSharedKeyPacket(shared events).The encrypted event payload is base64-encoded in
CalendarEventCard.Data.decryptCalendarEventCardperforms:openpgp.ReadMessageto decrypt the session key using the user's private keyringopenpgp.ReadMessageagain, supplying the session key via the symmetric prompt callbackThis pattern mirrors
ContactCard.Readinprotonmail/contacts.go, adaptedfor the calendar scheme where the key packet is detached from the data packet.
If Proton has changed their wire format, the function returns a clear error
describing which step failed — easy to debug and patch.
CLI
New subcommand and flags, matching the CardDAV pattern:
Testing
caldav/caldav_test.gocovers path parsing for calendar and object paths(the parts that can be unit-tested without real Proton API access)
go test ./caldav/ → okgo build ./... → okgo vet ./caldav/ → cleancaldavsubcommand in help outputCaveat I want to be transparent about: I do not have access to a Proton
account in this environment, so I could not run an end-to-end test against
the real Proton Calendar API. The decryption code follows the documented
pattern from
protonmail/contacts.goand the field types inprotonmail/calendar.go, but the maintainer (or any tester with a Protonaccount) should verify event decryption works against live data before
merge. If the wire format has changed, the error returned will identify
which step failed.
Files changed
caldav/caldav.go(new, 428 lines) — full CalDAV backend implementationcaldav/caldav_test.go(new, 82 lines) — path parsing testscmd/hydroxide/main.go— addedlistenAndServeCalDAV,caldavsubcommand,-caldav-host,-caldav-port,-disable-caldavflags, andserveintegrationgo.mod/go.sum— addedgithub.com/emersion/go-icaldependencyNotes on existing PRs
I see other PRs in the bounty queue attempting this. I haven't read their
code to avoid contamination; this implementation is written from scratch
based on the
protonmailpackage API and the CardDAV backend pattern. Ifthe maintainer prefers a different approach, I'm happy to rework.
License
MIT (matches hydroxide's LICENSE).