@@ -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)
 | 
			
		||||
 
 | 
			
		||||
@@ -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`"""
 | 
			
		||||
 
 | 
			
		||||
@@ -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
									
								
								radicale/tests/static/contact_photo_with_data_uri.vcf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								radicale/tests/static/contact_photo_with_data_uri.vcf
									
									
									
									
									
										Normal file
									
								
							@@ -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
 | 
			
		||||
@@ -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/")
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user