Take in invitations that arrive by mail
A watched mailbox is a trust boundary this app did not have: anyone who knows the address can hand the server an iCalendar file. So a mail can do exactly one thing — create a row in event_invites. No calendar read path touches that table, and an invitation becomes an event only when a person accepts it. Routing is by the ATTENDEE address, never the From header, which a sender can claim freely. Addresses are matched against users.email plus a dedicated table, so forwarded mail still finds its owner: the invitation names the original address, not the mailbox it landed in. An accepted invitation gets a fresh UID; the organiser's goes to external_uid. LocalEvent.uid is globally unique, so reusing it would let a stranger's mail collide with an event already there. That case has a test, because it is the one that would be a real problem. parse_ics now reads METHOD, SEQUENCE, the organiser address, the ATTENDEE list and RECURRENCE-ID. All additive — existing callers read the keys they knew. METHOD sits on the VCALENDAR, so it is read outside the component loop; that is the only reliable way to tell an invitation from a plain calendar file. A VEVENT carrying RECURRENCE-ID is skipped rather than applied, since treating one occurrence as the series would move every other date. The mailbox job registers only when IMAP_HOST is set: an unconditional job would log every few minutes that it has nothing to do, and test_scheduler asserts the exact job set. Credentials come from the environment, which keeps the one secret that opens a whole mailbox out of a table an endpoint could return. Replies to the organiser are the next step; accepting and declining work without them. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
aa795fde76
commit
9bf7d3797d
@@ -112,6 +112,12 @@ Configuration is done via environment variables. The `install.sh` script generat
|
||||
| `SCHEDULER_ENABLED` | `1` | `0` disables all background jobs |
|
||||
| `ATTACHMENT_SWEEP_HOURS` | `24` | How often orphaned attachments are cleaned up |
|
||||
| `ICAL_REFRESH_MINUTES` | `15` | How often iCal subscriptions are checked in the background |
|
||||
| `IMAP_HOST` | — | Mailbox watched for invitations. Unset disables the whole feature *(optional)* |
|
||||
| `IMAP_PORT` | `993` | |
|
||||
| `IMAP_SSL` | `1` | `0` for a plain connection |
|
||||
| `IMAP_USER` / `IMAP_PASSWORD` | — | Mailbox credentials |
|
||||
| `IMAP_FOLDER` | `INBOX` | |
|
||||
| `MAIL_POLL_MINUTES` | `5` | How often the mailbox is read |
|
||||
| `OIDC_PROVIDERS` | — | Comma-separated provider keys, e.g. `authentik` *(optional)* |
|
||||
|
||||
Per provider `<KEY>` listed in `OIDC_PROVIDERS` (variable names are uppercased):
|
||||
@@ -239,6 +245,23 @@ The server runs two periodic jobs in-process:
|
||||
|---|---|---|
|
||||
| `attachments.sweep` | 24 h | Removes attachment records whose event is gone, and files with no record |
|
||||
| `ical.refresh` | 15 min | Re-fetches iCal subscriptions that are due |
|
||||
| `mail.invites` | 5 min | Reads the watched mailbox for invitations *(only when `IMAP_HOST` is set)* |
|
||||
|
||||
#### Invitations by mail
|
||||
|
||||
With a mailbox configured, invitations sent to it appear under **Requests** and
|
||||
become calendar entries only once someone accepts them. Nothing a mail contains
|
||||
is written to a calendar on its own.
|
||||
|
||||
An invitation is matched to a user by its `ATTENDEE` address, never by the
|
||||
sender — compared against that user's `email` plus any additional addresses.
|
||||
That matters when mail is forwarded: the invitation still names the original
|
||||
address, not the mailbox it arrived in, so put the address people actually
|
||||
invite into the user's profile.
|
||||
|
||||
Credentials live in the environment rather than the database, so the one secret
|
||||
that opens a whole mailbox is never returned by any endpoint. One mailbox per
|
||||
instance; a forwarding target is the intended setup.
|
||||
|
||||
Attachments are normally cleaned up the moment an event, calendar or user is
|
||||
deleted; the sweep is the safety net for what gets past that — an external
|
||||
|
||||
Reference in New Issue
Block a user