Explorar el Código

Merge branch 'master' of github.com:metallerok/Radicale into recurrence_all_day_comparsion

Georgiy hace 1 semana
padre
commit
c4362b6392

+ 1 - 0
CHANGELOG.md

@@ -4,6 +4,7 @@
 
 * Fix: MOVE failing with URL-encoded destination header
 * Improve: add workaround to remove empty lines in item to avoid reject by vobject parser
+* Improve: check/enforce RECURRENCE-ID MUST have the same value type as DTSTART in the recurring component (RFC 5545 3.8.4.4)
 
 ## 3.6.0
 

+ 17 - 0
radicale/app/report.py

@@ -656,6 +656,23 @@ def _split_overridden_vevents(
             vevent_recurrence = vevent
 
     if vevent_recurrence:
+        # RFC 5545 3.8.4.4: RECURRENCE-ID MUST have the same value type as DTSTART
+        # in the recurring component.
+        base_dtstart = vevent_recurrence.dtstart.value
+        expected_type = datetime.date
+        if isinstance(base_dtstart, datetime.datetime):
+            expected_type = datetime.datetime
+
+        for ov in vevents_overridden:
+            rid = ov.recurrence_id.value
+            if not isinstance(rid, expected_type):
+                raise ValueError(
+                    f"component with UID {vevent_recurrence.uid} has "
+                    f"incompatible RECURRENCE-ID value type: base DTSTART is "
+                    f"{type(base_dtstart).__name__}, but override RECURRENCE-ID is "
+                    f"{type(rid).__name__} ({ov.recurrence_id.value!r})"
+                )
+
         return (
             vevent_recurrence, sorted(
                 vevents_overridden,

+ 20 - 0
radicale/tests/static/event_mixed_recurrence_id_dt_type.ics

@@ -0,0 +1,20 @@
+BEGIN:VCALENDAR
+VERSION:2.0
+
+BEGIN:VEVENT
+DTSTART:20060102T120000Z
+DURATION:PT1H
+RRULE:FREQ=DAILY;COUNT=3
+SUMMARY:Recurring event
+UID:event_mixed_recurrence_id_dt_type
+END:VEVENT
+
+BEGIN:VEVENT
+DTSTART:20060103T140000Z
+DURATION:PT1H
+RECURRENCE-ID;VALUE=DATE:20060103
+SUMMARY:Override with wrong type
+UID:event_mixed_recurrence_id_dt_type
+END:VEVENT
+
+END:VCALENDAR

+ 40 - 0
radicale/tests/test_expand.py

@@ -699,6 +699,46 @@ permissions: RrWw""")
         assert status == 207
         assert len(responses) == 0
 
+    def test_report_with_incompatible_recurrence_id_dt_types(self, caplog) -> None:
+        """Test report with incompatible RECURRENCE-ID value types (RFC 5545 3.8.4.4)"""
+
+        import logging
+        caplog.set_level(logging.WARNING)
+
+        event_id = "event_mixed_recurrence_id_dt_type"
+        start = "20060103T000000Z"
+        end = "20060105T000000Z"
+
+        self.put("/calendar.ics/", get_file_content(f"{event_id}.ics"))
+
+        request = f"""<?xml version="1.0" encoding="utf-8" ?>
+        <C:calendar-query xmlns:D="DAV:" xmlns:C="urn:ietf:params:xml:ns:caldav">
+            <D:prop>
+                <C:calendar-data>
+                    <C:expand start="{start}" end="{end}"/>
+                </C:calendar-data>
+            </D:prop>
+            <C:filter>
+                <C:comp-filter name="VCALENDAR">
+                    <C:comp-filter name="VEVENT">
+                        <C:time-range start="{start}" end="{end}"/>
+                    </C:comp-filter>
+                </C:comp-filter>
+            </C:filter>
+        </C:calendar-query>
+        """
+
+        status, _, _ = self.request("REPORT", "/calendar.ics/", request)
+
+        assert status == 400
+
+        logs = caplog.messages
+        error_logs = [log for log in logs if "incompatible RECURRENCE-ID value type" in log]
+        assert len(error_logs) > 0
+        assert event_id in error_logs[0]
+        assert "base DTSTART is datetime" in error_logs[0]
+        assert "override RECURRENCE-ID is date" in error_logs[0]
+
     def test_report_with_expand_property_all_day_event_overridden(self) -> None:
         self._test_expand(
             "event_full_day_rrule_overridden",