calrs 1.13.0 is the provider-expansion release: connecting a calendar no longer means CalDAV with basic auth. Microsoft Exchange (EWS) joins as a second backend behind a new provider trait, Google Calendar connects via OAuth2 with encrypted token storage, confirmed bookings can auto-generate video meeting links (Jitsi pattern or bring-your-own webhook), booking pages gain an opt-in self-hosted proof-of-work captcha, and an embed system lets you put your booking page on any website. Two headline features are community contributions.
Added
- Microsoft Exchange (EWS) backend (PR #103) — adds on-prem Exchange 2013/2016/2019 support via a minimal SOAP client in
src/ews/(autodiscover, GetFolder/FindItem/CreateItem/DeleteItem, iCal ↔ EWS field mapping). A new provider factory insrc/providers/abstracts CalDAV vs EWS behind a singleCalendarProvidertrait; the CalDAV path is unchanged. Source-add form gains a Backend dropdown with protocol-filtered presets. Migration 055 addsprovider_typeoncaldav_sources(defaults tocaldav, backward compatible) - Google Calendar (OAuth2) sources (PR #99) — admin configures the OAuth2 client ID/secret in the admin panel; users connect via "Add Google Calendar" on the sources page or
calrs source add-google. Access and refresh tokens are stored AES-256-GCM encrypted and refreshed proactively five minutes before expiry. Migration 053 - Auto-generated video meeting links (PR #128, phases 1+2 of #45) — new
Jitsi (auto-generated room)location type: every confirmed booking gets a fresh URL built from WordPress-style pattern tokens ({username},{event},{date},{random}; default{event}-{random}), with the pattern configurable org-wide and overridable per event type. Plus aWebhook (custom provider)location type for bring-your-own providers (Jitsi+JWT, Whereby, custom Meet): calrs POSTs booking details and uses the returned URL. Migration 056 - Booking captcha (PR #122, contributed by @florian-SV) — opt-in Cap integration: self-hosted proof-of-work captcha on booking pages, no third-party tracking. Without configuration the booking flow is byte-for-byte unchanged. The Cap secret is encrypted at rest (same AES-256-GCM pattern as OIDC secrets), and the CSP is rebuilt in memory on every admin save, no restart needed, scoped to booking form pages only
- Embed code generator (PR #125) — Cal.com-style embed system: a self-contained
embed.jsexposesCalrs.inline(auto-sizing iframe),Calrs.floatingButton(corner pill + modal), andCalrs.elementClick(data-attribute binding).?embed=1strips navigation chrome, autosizes viacalrs:resizepostMessages, accepts layout/theme/brand params, and switches the CSRF cookie toSameSite=None; Secureso cross-origin iframes work calrs config dump(PR #112, contributed by @mvalois) — dumps the full instance configuration as JSON (--prettysupported): 18 sections covering auth, SMTP, users, sources, event types with availability rules/overrides, teams, weights, watchers and frequency limits, plus a top-levelschema_version. Secrets and operational sync state are excluded by construction, with tests asserting they never appearCALRS_ALLOW_PRIVATE_HOSTS(PR #124, closes #123) — opt-in, comma-separated, exact-match allowlist letting specific CalDAV/EWS hosts resolve to private/reserved IPs (docker-compose stacks, self-hosted Exchange behind private addressing). The SSRF guard stays active for every non-listed host; scheme checks still apply. Reported and verified by @aburg
Fixed
- Google sync silently truncating the forward window (PR #99) — an unfiltered
calendar-queryREPORT left future events out of the local cache, making booked days look available. The full-fetch path now sends an RFC 4791time-rangefilter with a 90-day lookback, falling back to the unfiltered REPORT for servers that reject it; orphan cleanup is scoped to the same window so pre-window history is preserved - CalDAV write-back no longer gated on SMTP (PR #99) — all four guest booking handlers previously wrapped the CalDAV push inside an SMTP-config check, so bookings on instances without SMTP never reached the host's calendar. Confirmed bookings now push unconditionally; only email sends remain gated on SMTP. A dashboard warning surfaces when sources are enabled but none have a write target
- EWS: timed UTC events, all-day date offset, recurring series (PR #127) — follow-up correctness pass on the EWS backend
- Friendly email validation on booking forms (PR #129) — incomplete addresses like
user@domain(no TLD) pass HTML5 validation but failed server-side with a bare error page; guests now get a proper inline error
Internal
- Migrations 053–056 (
oauth2_caldav,captcha,provider_type,meeting_links) - Translation updates from Weblate (PR #131)
- 758 tests, all green (up from 671 in 1.12.0)