1 parent
1b12899ff6
commit
a3ac2a68fe
33 files changed
+5422
-28
No files matched your search
@@ -0,0 +1,147 @@
|
||||
# CalDAV / CardDAV server
|
||||
|
||||
RustBox can serve each account's calendar and contacts over CalDAV (RFC 4791) and
|
||||
CardDAV (RFC 6352). The DAV view and the webmail use the same tables, so an event
|
||||
created on a phone appears in the webmail calendar and a contact edited in the
|
||||
webmail appears on the phone after its next sync.
|
||||
|
||||
The server is **off by default**.
|
||||
|
||||
## Enabling
|
||||
|
||||
```toml
|
||||
[dav]
|
||||
enabled = true
|
||||
auth_cache_secs = 300 # remember a successful login for 5 minutes (0 = always ask IMAP)
|
||||
max_resource_size = 8388608 # largest accepted event / vCard in bytes
|
||||
calendar_name = "Calendar"
|
||||
addressbook_name = "Contacts"
|
||||
```
|
||||
|
||||
Environment overrides use the usual form: `DAV__ENABLED=true`, `DAV__AUTH_CACHE_SECS=60`.
|
||||
|
||||
Run RustBox behind HTTPS when DAV is enabled: clients send the mail password with
|
||||
every request (HTTP Basic).
|
||||
|
||||
## URLs
|
||||
|
||||
Below `<base_path>/dav` (with the default base path: `https://mail.example.com/dav/`):
|
||||
|
||||
| Resource | Path |
|
||||
| :--- | :--- |
|
||||
| Service root (for discovery) | `/dav/` |
|
||||
| Principal | `/dav/principals/<login>/` |
|
||||
| Calendar home | `/dav/calendars/<login>/` |
|
||||
| Calendar | `/dav/calendars/<login>/default/` |
|
||||
| Address book home | `/dav/addressbooks/<login>/` |
|
||||
| Address book | `/dav/addressbooks/<login>/default/` |
|
||||
|
||||
`/.well-known/caldav` and `/.well-known/carddav` redirect to `<base_path>/dav/`
|
||||
(RFC 6764). They are registered at the host root even when RustBox runs under a
|
||||
base path; a reverse proxy that only forwards the base path must forward these two
|
||||
paths as well.
|
||||
|
||||
`<login>` is the IMAP login the client authenticates with (normally the e-mail
|
||||
address). A client may only open its own collections; other logins get `403`.
|
||||
|
||||
## Authentication
|
||||
|
||||
HTTP Basic with the IMAP login and password. RustBox checks them against the
|
||||
configured `imap_host` exactly like the webmail login and protects the endpoint
|
||||
with the same brute-force guard (`[login_rate_limit]`). A successful login is cached
|
||||
in memory for `auth_cache_secs`, keyed by a hash of login and password, so changing
|
||||
the mail password takes effect for DAV within that time. The tenant database is
|
||||
created on the first DAV login, so DAV works for accounts that never opened the
|
||||
webmail.
|
||||
|
||||
## Supported protocol
|
||||
|
||||
- `OPTIONS` (no authentication), `PROPFIND` (Depth 0/1), `PROPPATCH` (answered with
|
||||
`403` per property: collection properties are fixed), `GET`/`HEAD`, `PUT`, `DELETE`.
|
||||
- `REPORT`: `calendar-query` (VEVENT with optional `time-range`),
|
||||
`calendar-multiget`, `addressbook-query` (prop-filter / text-match, `anyof`/`allof`,
|
||||
`limit`), `addressbook-multiget`. Other reports (for example `sync-collection`)
|
||||
return `403 DAV:supported-report`; `sync-token` is not advertised, so clients fall
|
||||
back to CTag polling.
|
||||
- Strong ETags (hash of the served object) with `If-Match` / `If-None-Match`,
|
||||
and a collection CTag (`CS:getctag`) that changes on every change, including
|
||||
webmail edits and deletions.
|
||||
- One calendar (VEVENT only; `supported-calendar-component-set` lists VEVENT) and
|
||||
one address book (vCard 3.0 and 4.0) per account. `MKCALENDAR` / `MKCOL` return
|
||||
`403`. Tasks (VTODO) are not supported.
|
||||
- RFC 4791 UID uniqueness: a second resource with an existing UID is refused with
|
||||
`CALDAV:no-uid-conflict` — except that an event created in the webmail (for
|
||||
example from an e-mail invitation) is adopted, so accepting an invitation on a
|
||||
phone does not duplicate it.
|
||||
|
||||
## How data is mapped
|
||||
|
||||
Objects uploaded by a client are stored verbatim (`dav_data`) under the client's
|
||||
resource name (`dav_name`) and decoded into the webmail columns:
|
||||
|
||||
| iCalendar | Webmail field |
|
||||
| :--- | :--- |
|
||||
| `SUMMARY`, `DESCRIPTION`, `LOCATION` | title, description, location |
|
||||
| `DTSTART` / `DTEND` / `DURATION` | start / end (times with `TZID` are converted to UTC; dates make an all-day event) |
|
||||
| `RRULE` | recurrence rule |
|
||||
| `ATTENDEE`, `ORGANIZER` | attendees, organizer |
|
||||
| `STATUS`, `URL`, `COLOR` | status, meeting link, colour |
|
||||
| first two `VALARM` triggers before the start | reminders |
|
||||
|
||||
Only the master component is decoded; recurrence overrides (`RECURRENCE-ID`),
|
||||
`EXDATE`, `VTIMEZONE` and unknown properties stay in the stored object and are
|
||||
served back unchanged.
|
||||
|
||||
| vCard | Webmail field |
|
||||
| :--- | :--- |
|
||||
| `FN` (or `N`) | name |
|
||||
| `EMAIL` (preferred first) | e-mail and further addresses |
|
||||
| `TEL`, `ADR` | phone numbers, postal addresses |
|
||||
| `ORG`, `TITLE`, `NOTE`, `URL`, `BDAY` | company, job title, notes, website, birthday |
|
||||
| embedded `PHOTO` (JPEG/PNG/GIF/WebP up to 3 MB) | contact photo |
|
||||
|
||||
Cards without an e-mail address are accepted. Since migration V055 several
|
||||
contacts may share an e-mail address.
|
||||
|
||||
When an event or contact that came from a DAV client is edited in the webmail,
|
||||
only the properties whose value actually changed are rewritten in the stored
|
||||
object (plus `DTSTAMP`/`LAST-MODIFIED`/`SEQUENCE` or `REV`); time zones, exceptions,
|
||||
alarms the webmail does not model and vendor properties are kept. Events and
|
||||
contacts created in the webmail are served as `<id>.ics` / `<id>.vcf` with a
|
||||
generated object (iCalendar 2.0 / vCard 3.0).
|
||||
|
||||
## Clients
|
||||
|
||||
- **ActivePush** (Exchange ActiveSync gateway): no code changes are needed, only
|
||||
the backend URLs. Its default paths already match RustBox:
|
||||
|
||||
```toml
|
||||
[caldav]
|
||||
enabled = true
|
||||
base_url = "https://mail.example.com"
|
||||
path = "/dav/calendars/%u/"
|
||||
|
||||
[carddav]
|
||||
enabled = true
|
||||
base_url = "https://mail.example.com"
|
||||
path = "/dav/addressbooks/%u/"
|
||||
```
|
||||
|
||||
With a RustBox `base_path` (for example `/mail`) prefix the paths:
|
||||
`/mail/dav/calendars/%u/`. ActivePush authenticates with the same login and
|
||||
password the phone uses, which must be the IMAP login RustBox accepts. Tasks stay
|
||||
disabled because the calendar advertises VEVENT only; creating extra calendar or
|
||||
contact folders from the phone is refused.
|
||||
- **DAVx⁵, Thunderbird, Apple Calendar/Contacts, Evolution**: use the server URL
|
||||
`https://mail.example.com/` (discovery through `.well-known`) or
|
||||
`https://mail.example.com/dav/`, and the mail login and password.
|
||||
|
||||
## Limits
|
||||
|
||||
- Recurring events are not expanded server side: a `time-range` query returns a
|
||||
recurring event whenever its first occurrence starts before the end of the range.
|
||||
- ETags and the CTag are computed from the objects on each request; this is cheap
|
||||
for personal calendars and address books (thousands of entries) but means a CTag
|
||||
poll reads the whole collection.
|
||||
- Contact groups are not exported as group vCards.
|
||||
- Contacts photos added in the webmail are not included in generated vCards.
|
||||
Reference in new issue
Block a user