import { describe, expect, it } from "vitest"; import { createDavFixture, davRequest } from "@tests/worker/helpers/dav"; import { fetchWorker } from "@tests/worker/helpers/http"; import { withEnvBinding } from "@tests/worker/helpers/env"; import { event, reportBody, uid } from "./helpers"; describe("CalDAV report limits and origins", () => { it("matches category text filters and expands recurring calendar-data", async () => { const fixture = await createDavFixture(["caldav.full"]); const categoryUid = uid(); expect( await fetchWorker( davRequest(fixture, "/calendars/default/category.ics", { method: "PUT", body: event({ uid: categoryUid, summary: "Categorized", categories: ["Focus", "Team"] }), }), ), ).toMatchObject({ status: 201 }); const categoryQuery = await fetchWorker( davRequest(fixture, "/calendars/default/", { method: "REPORT", headers: { "content-type": "application/xml", depth: "1" }, body: reportBody( "calendar-query", 'focus', ), }), ); expect(categoryQuery.status).toBe(207); expect(await categoryQuery.text()).toContain("/calendars/default/category.ics"); const recurrenceUid = uid(); const recurring = [ "BEGIN:VCALENDAR", "VERSION:2.0", "PRODID:-//dab//tests//EN", "BEGIN:VEVENT", `UID:${recurrenceUid}`, "DTSTAMP:20260101T000000Z", "SUMMARY:Daily", "DTSTART:20260521T120000Z", "DTEND:20260521T130000Z", "RRULE:FREQ=DAILY;COUNT=3", "END:VEVENT", "BEGIN:VEVENT", `UID:${recurrenceUid}`, "DTSTAMP:20260101T000000Z", "RECURRENCE-ID:20260522T120000Z", "SUMMARY:Moved Daily", "DTSTART:20260522T150000Z", "DTEND:20260522T160000Z", "END:VEVENT", "END:VCALENDAR", "", ].join("\r\n"); expect( await fetchWorker( davRequest(fixture, "/calendars/default/recurring.ics", { method: "PUT", body: recurring, }), ), ).toMatchObject({ status: 201 }); const recurrenceQuery = await fetchWorker( davRequest(fixture, "/calendars/default/", { method: "REPORT", headers: { "content-type": "application/xml", depth: "1" }, body: reportBody( "calendar-query", '', ), }), ); expect(recurrenceQuery.status).toBe(207); const recurrenceXml = await recurrenceQuery.text(); expect(recurrenceXml).toContain("/calendars/default/recurring.ics"); expect(recurrenceXml).toContain("RECURRENCE-ID:20260522T120000Z"); expect(recurrenceXml).toContain("SUMMARY:Moved Daily"); expect(recurrenceXml).not.toContain("RRULE:FREQ=DAILY"); }); it("applies the configured REPORT result limit to calendar-query and calendar-multiget", async () => { const fixture = await createDavFixture(["caldav.full"]); const firstName = `limited-a-${crypto.randomUUID()}.ics`; const secondName = `limited-b-${crypto.randomUUID()}.ics`; expect( await fetchWorker( davRequest(fixture, `/calendars/default/${firstName}`, { method: "PUT", body: event({ uid: uid(), summary: "Limited A" }), }), ), ).toMatchObject({ status: 201 }); expect( await fetchWorker( davRequest(fixture, `/calendars/default/${secondName}`, { method: "PUT", body: event({ uid: uid(), summary: "Limited B" }), }), ), ).toMatchObject({ status: 201 }); await withEnvBinding("MAX_REPORT_RESULTS", "1", async () => { // RFC 4791 7.8: when a calendar-query result set exceeds the configured // limit, return a DAV:number-of-matches-within-limits precondition error. const query = await fetchWorker( davRequest(fixture, "/calendars/default/", { method: "REPORT", headers: { "content-type": "application/xml", depth: "1" }, body: reportBody( "calendar-query", '', ), }), ); expect(query.status).toBe(403); await expect(query.text()).resolves.toContain("number-of-matches-within-limits"); const multiget = await fetchWorker( davRequest(fixture, "/calendars/default/", { method: "REPORT", headers: { "content-type": "application/xml" }, body: reportBody( "calendar-multiget", `/calendars/default/${firstName}/calendars/default/${secondName}`, ), }), ); expect(multiget.status).toBe(403); }); }); it("rejects calendar-multiget absolute hrefs outside the subject origin", async () => { const fixture = await createDavFixture(["caldav.full"]); const name = `absolute-origin-${crypto.randomUUID()}.ics`; const eventUid = uid(); expect( await fetchWorker( davRequest(fixture, `/calendars/default/${name}`, { method: "PUT", body: event({ uid: eventUid, summary: "Absolute Origin" }), }), ), ).toMatchObject({ status: 201 }); const multiget = await fetchWorker( davRequest(fixture, "/calendars/default/", { method: "REPORT", headers: { "content-type": "application/xml" }, body: reportBody( "calendar-multiget", `https://other.example.test/calendars/default/${name}`, ), }), ); expect(multiget.status).toBe(207); const xml = await multiget.text(); expect(xml).toContain(`https://other.example.test/calendars/default/${name}`); expect(xml).toContain("HTTP/1.1 404 Not Found"); expect(xml).not.toContain(eventUid); }); });