Workaround for broken contact PHOTO from InfCloud

See issue #1205
This commit is contained in:
Unrud 2022-01-15 23:39:05 +01:00
parent 4a0bcde7a3
commit 75df1093be
5 changed files with 28 additions and 5 deletions

View File

@ -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)

View File

@ -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`"""

View File

@ -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

View 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

View File

@ -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/")