Fix: text-match filter crashes on structured property (vCard N/ADR)

A CardDAV addressbook-query REPORT with a text-match prop-filter on a
structured property (e.g. N or ADR) returned HTTP 500. vobject parses
these into Name/Address objects rather than plain strings, so text_match
called .lower() on a non-string and raised AttributeError. Coerce
non-string values to their text representation before matching.

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
TowyTowy
2026-07-15 11:26:45 +02:00
parent 35567e53ba
commit f48dc47177
3 changed files with 18 additions and 0 deletions

View File

@@ -578,6 +578,11 @@ def text_match(vobject_item: vobject.base.Component,
match_type = filter_.get("match-type", match_type)
def match(value: str) -> bool:
if not isinstance(value, str):
# Some properties (e.g. N and ADR in vCard) are parsed by vobject
# into structured objects instead of plain strings. Use their text
# representation so text-match doesn't crash with AttributeError.
value = str(value)
value = value.lower()
if match_type == "equals":
return value == text

View File

@@ -1458,6 +1458,18 @@ permissions: RrWw""")
<C:text-match collation="i;unicode-casemap">test</C:text-match>
</C:prop-filter>"""], "contact", test="allof")
def test_addressbook_prop_filter_structured(self) -> None:
"""text-match on a structured property (N) that vobject parses into a
non-string value must not crash the REPORT."""
assert "/contacts.vcf/contact1.vcf" in self._test_filter(["""\
<C:prop-filter name="N">
<C:text-match collation="i;unicode-casemap">contact</C:text-match>
</C:prop-filter>"""], "contact")
assert "/contacts.vcf/contact1.vcf" not in self._test_filter(["""\
<C:prop-filter name="N">
<C:text-match collation="i;unicode-casemap">nonexistent</C:text-match>
</C:prop-filter>"""], "contact")
def test_calendar_empty_filter(self) -> None:
self._test_filter([""])