fix(calendar): negotiate Digest auth in CalDAV test endpoint (#1767)

POST /api/calendar/test issues a single PROPFIND with raw httpx
Basic auth. CalDAV servers configured for Digest (Baïkal default,
SabreDAV-based servers, Radicale with htdigest) reject Basic with
401, so the UI "Test connection" button surfaces "Auth failed —
check username/password" even when the URL and credentials are
correct.

src/caldav_sync.py (the real sync path) uses caldav.DAVClient,
which negotiates the scheme via niquests, so production sync
already works against these servers. The test endpoint just
doesn't match. Bring it to parity: keep the cheap Basic first
attempt, and on a 401-with-Digest-challenge retry once with
httpx.DigestAuth before deciding it's an auth failure.

Repro: configure CalDAV against a stock Baïkal install — test
button returns 401, sync succeeds.

Co-authored-by: Shatti2 <codered5678@gmail.com>
This commit is contained in:
Shatti2
2026-06-02 23:23:28 -05:00
committed by GitHub
parent ea1079e1df
commit 4ca3b38667

View File

@@ -629,6 +629,18 @@ def setup_calendar_routes() -> APIRouter:
headers={"Depth": "0", "Content-Type": "application/xml"},
content=propfind_body,
)
# If the server demands Digest (Baïkal default, SabreDAV-based
# servers, Radicale with htdigest), the Basic attempt above
# 401s. Retry once with httpx.DigestAuth so this test matches
# what the real sync does via caldav.DAVClient in
# src/caldav_sync.py (which negotiates the scheme).
if r.status_code == 401 and "digest" in r.headers.get("www-authenticate", "").lower():
r = await cx.request(
"PROPFIND", url,
auth=httpx.DigestAuth(user, pw),
headers={"Depth": "0", "Content-Type": "application/xml"},
content=propfind_body,
)
# 207 = Multi-Status — standard CalDAV success. 200 also
# acceptable. Anything else (401/403/404/5xx) means trouble.
if r.status_code in (200, 207):