iCal (.ics) import / subscription for personal events #51
Labels
No labels
area/ai
area/backend
area/frontend
area/infra
area/scheduler
area/wled
good-first-issue
priority/high
priority/low
priority/medium
type/bug
type/chore
type/ci-cd
type/docs
type/feature
type/qa
v1.0.0
v1.1.0
v1.2.0
v2.0.0
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
rbrooks/Iris-WLED#51
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Complement to #16 (iCal export): let users bring birthdays, anniversaries, and family events in from their own calendars as user-defined events (priority 100).
.icsfile or subscribe to a URL (refreshed weekly by the scheduler)event_keyfrom the UID; handle yearly RRULEs via existing recurrence machineryDone — #121 merged, CI green.
.icsor subscribe to a URL — subscriptions refresh with the weekly candidate job, so an event added to a personal calendar this week gets a candidate scheme on the same run.event_keyfrom UID, yearly RRULEsgenerate_schemes_for_all_eventsalready covers every event in the table regardless of source.De-dup needed no schema change
Event ids are already
{event_key}_{year}, so derivingevent_keydeterministically from the UID makes a re-import collide on the primary key by construction — no UID column, and no second uniqueness rule to keep in step with the first. UIDs are hashed rather than sanitised, since real ones carry characters that are not id-safe and no meaning worth preserving.The detail that would have bitten quietly
priority_resolver._SOURCE_RANKdefaults an unrecognised source to 0, belowsystem. Adding"ical"without registering it there would have made every imported birthday lose a priority tie against a builtin holiday, silently. Registered level withuser; two tests fail if the entry is removed, which I checked rather than assumed.Upload and subscription differ on purpose
A subscription is authoritative — a refresh overwrites, because the remote calendar is where those events are edited. An upload never overwrites, because nothing will refresh it. Neither touches an event whose source is not
ical. Deleting a subscription keeps its events: they may already have approved schemes.Security review findings, all fixed in the same PR
A background review of the first commit found three issues, all real and all in new code:
fetch_icsfetched an operator-supplied URL server-side with redirects followed automatically, reaching sibling containers, host-only services and cloud metadata the operator may not be able to reach; parse failures land inlast_errorand render in the UI, so a blocked service's response could leak back through the error text. Now http(s) only, the host must resolve entirely to global addresses, and redirects are followed by hand so each hop is re-validated — an allowed host that 302s to a link-local address would otherwise walk straight past a check on the original URL. DNS rebinding remains possible; closing it needs the connection pinned to a vetted IP, which httpx does not expose cleanly. That limitation is stated in the docstring rather than implied away.MAX_ICS_BYTESwas compared againstresp.content, which materialises the whole body first. Now streamed and abandoned once the cap is passed.GET /subscriptionswasrequire_viewer. Private Google and Apple calendar links embed a secret in the path, so listing them handed viewers read access to someone's entire personal calendar. Nowrequire_admin.Resolution sits behind a seam so the guard is testable without the network. The stub resolves literals to themselves rather than mapping everything to a public address — a stub that mapped everything would let every private literal walk through the guard and make those tests worse than useless. Verified by neutering the guard: all seven SSRF cases fail without it.