Просмотр исходного кода

Workaround for broken contact PHOTO from InfCloud

See issue #1205
Unrud 4 лет назад
Родитель
Сommit
75df1093be

+ 1 - 1
radicale/app/put.py

@@ -141,7 +141,7 @@ class ApplicationPartPut(ApplicationBase):
         content_type = environ.get("CONTENT_TYPE", "").split(";",
                                                              maxsplit=1)[0]
         try:
-            vobject_items = list(vobject.readComponents(content or ""))
+            vobject_items = radicale_item.read_components(content or "")
         except Exception as e:
             logger.warning(
                 "Bad PUT request on %r: %s", path, e, exc_info=True)

+ 11 - 0
radicale/item/__init__.py

@@ -27,6 +27,7 @@ import binascii
 import contextlib
 import math
 import os
+import re
 import sys
 from datetime import datetime, timedelta
 from hashlib import sha256
@@ -42,6 +43,16 @@ from radicale.item import filter as radicale_filter
 from radicale.log import logger
 
 
+def read_components(s: str) -> List[vobject.base.Component]:
+    """Wrapper for vobject.readComponents"""
+    # Workaround for bug in InfCloud
+    # PHOTO is a data URI
+    s = re.sub(r"^(PHOTO(?:;[^:\r\n]*)?;ENCODING=b(?:;[^:\r\n]*)?:)"
+               r"data:[^;,\r\n]*;base64,", r"\1", s,
+               flags=re.MULTILINE | re.IGNORECASE)
+    return list(vobject.readComponents(s))
+
+
 def predict_tag_of_parent_collection(
         vobject_items: Sequence[vobject.base.Component]) -> Optional[str]:
     """Returns the predicted tag or `None`"""

+ 2 - 4
radicale/storage/multifilesystem/get.py

@@ -21,8 +21,6 @@ import sys
 import time
 from typing import Iterable, Iterator, Optional, Tuple
 
-import vobject
-
 import radicale.item as radicale_item
 from radicale import pathutils
 from radicale.log import logger
@@ -93,8 +91,8 @@ class CollectionPartGet(CollectionPartCache, CollectionPartLock,
                     cache_content = self._load_item_cache(href, cache_hash)
                 if cache_content is None:
                     try:
-                        vobject_items = list(vobject.readComponents(
-                            raw_text.decode(self._encoding)))
+                        vobject_items = radicale_item.read_components(
+                            raw_text.decode(self._encoding))
                         radicale_item.check_and_sanitize_items(
                             vobject_items, tag=self.tag)
                         vobject_item, = vobject_items

+ 8 - 0
radicale/tests/static/contact_photo_with_data_uri.vcf

@@ -0,0 +1,8 @@
+BEGIN:VCARD
+VERSION:3.0
+UID:contact
+N:Contact;;;;
+FN:Contact
+NICKNAME:test
+PHOTO;ENCODING=b;TYPE=png:data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAAD0lEQVQIHQEEAPv/AP///wX+Av4DfRnGAAAAAElFTkSuQmCC
+END:VCARD

+ 6 - 0
radicale/tests/test_base.py

@@ -139,6 +139,12 @@ permissions: RrWw""")
         _, answer = self.get(path)
         assert "UID:contact1" in answer
 
+    def test_add_contact_photo_with_data_uri(self) -> None:
+        """Test workaround for broken PHOTO data from InfCloud"""
+        self.create_addressbook("/contacts.vcf/")
+        contact = get_file_content("contact_photo_with_data_uri.vcf")
+        self.put("/contacts.vcf/contact.vcf", contact)
+
     def test_add_contact_without_uid(self) -> None:
         """Add a contact without UID."""
         self.create_addressbook("/contacts.vcf/")