Merge pull request #581 from ennamarie19/master

Add fixes for OSS-Fuzz bugs and test cases
pull/580/head
Nicco Kunzmann 2023-11-06 11:14:08 +00:00 zatwierdzone przez GitHub
commit 11eb89b8cd
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 4AEE18F83AFDEB23
5 zmienionych plików z 57 dodań i 4 usunięć

Wyświetl plik

@ -19,6 +19,9 @@ New features:
Bug fixes:
- ...
- Fixed index error in cal.py when attempting to pop from an empty stack
- Fixed type error in prop.py when attempting to join strings into a byte-string
- Caught Wrong Date Format in ical_fuzzer to resolve fuzzing coverage blocker
5.0.11 (2023-11-03)
-------------------

Wyświetl plik

@ -358,6 +358,10 @@ class Component(CaselessDict):
elif uname == 'END':
# we are done adding properties to this component
# so pop it from the stack and add it to the new top.
if not stack:
# The stack is currently empty, the input must be invalid
raise ValueError('END encountered without an accompanying BEGIN!')
component = stack.pop()
if not stack: # we are at the end
comps.append(component)

Wyświetl plik

@ -1,7 +1,26 @@
from typing import Any
SEQUENCE_TYPES = (list, tuple)
DEFAULT_ENCODING = 'utf-8'
def from_unicode(value: Any, encoding='utf-8') -> bytes:
"""
Converts a value to bytes, even if it already is bytes
:param value: The value to convert
:param encoding: The encoding to use in the conversion
:return: The bytes representation of the value
"""
if isinstance(value, bytes):
value = value
elif isinstance(value, str):
try:
value = value.encode(encoding)
except UnicodeEncodeError:
value = value.encode('utf-8', 'replace')
return value
def to_unicode(value, encoding='utf-8'):
"""Converts a value to unicode, even if it is already a unicode string.
"""

Wyświetl plik

@ -53,6 +53,7 @@ from icalendar.parser import unescape_char
from icalendar.parser_tools import DEFAULT_ENCODING
from icalendar.parser_tools import SEQUENCE_TYPES
from icalendar.parser_tools import to_unicode
from icalendar.parser_tools import from_unicode
from icalendar.timezone_cache import _timezone_cache
from icalendar.windows_to_olson import WINDOWS_TO_OLSON
@ -62,14 +63,12 @@ import pytz
import re
import time as _time
DURATION_REGEX = re.compile(r'([-+]?)P(?:(\d+)W)?(?:(\d+)D)?'
r'(?:T(?:(\d+)H)?(?:(\d+)M)?(?:(\d+)S)?)?$')
WEEKDAY_RULE = re.compile(r'(?P<signal>[+-]?)(?P<relative>[\d]{0,2})'
r'(?P<weekday>[\w]{2})$')
####################################################
# handy tzinfo classes you can use.
#
@ -174,6 +173,7 @@ class vBoolean(int):
class vCalAddress(str):
"""This just returns an unquoted string.
"""
def __new__(cls, value, encoding=DEFAULT_ENCODING):
value = to_unicode(value, encoding=encoding)
self = super().__new__(cls, value)
@ -194,6 +194,7 @@ class vCalAddress(str):
class vFloat(float):
"""Just a float.
"""
def __new__(cls, *args, **kwargs):
self = super().__new__(cls, *args, **kwargs)
self.params = Parameters()
@ -213,6 +214,7 @@ class vFloat(float):
class vInt(int):
"""Just an int.
"""
def __new__(cls, *args, **kwargs):
self = super().__new__(cls, *args, **kwargs)
self.params = Parameters()
@ -250,7 +252,7 @@ class vDDDLists:
self.dts = vDDD
def to_ical(self):
dts_ical = (dt.to_ical() for dt in self.dts)
dts_ical = (from_unicode(dt.to_ical()) for dt in self.dts)
return b",".join(dts_ical)
@staticmethod
@ -288,6 +290,7 @@ class vCategory:
"""self == other"""
return isinstance(other, vCategory) and self.cats == other.cats
class TimeBase:
"""Make classes with a datetime/date comparable."""
@ -366,6 +369,7 @@ class vDDDTypes(TimeBase):
"""repr(self)"""
return f"{self.__class__.__name__}({self.dt}, {self.params})"
class vDate(TimeBase):
"""Render and generates iCalendar date format.
"""
@ -516,6 +520,7 @@ class vDuration(TimeBase):
"""The time delta for compatibility."""
return self.td
class vPeriod(TimeBase):
"""A precise period of time.
"""
@ -588,6 +593,7 @@ class vPeriod(TimeBase):
"""Make this cooperate with the other vDDDTypes."""
return (self.start, (self.duration if self.by_duration else self.end))
class vWeekday(str):
"""This returns an unquoted weekday abbrevation.
"""
@ -830,11 +836,13 @@ class vGeo:
def __eq__(self, other):
return self.to_ical() == other.to_ical()
class vUTCOffset:
"""Renders itself as a utc offset.
"""
ignore_exceptions = False # if True, and we cannot parse this
ignore_exceptions = False # if True, and we cannot parse this
# component, we will silently ignore
# it, rather than let the exception
# propagate upwards
@ -896,6 +904,7 @@ class vInline(str):
has parameters. Conversion of inline values are handled by the Component
class, so no further processing is needed.
"""
def __new__(cls, value, encoding=DEFAULT_ENCODING):
value = to_unicode(value, encoding=encoding)
self = super().__new__(cls, value)

Wyświetl plik

@ -0,0 +1,18 @@
"""This file collects errors that the OSS FUZZ build has found."""
from datetime import time
from icalendar import Calendar
from icalendar.prop import vDDDLists
import pytest
def test_stack_is_empty():
"""If we get passed an invalid string, we expect to get a ValueError."""
with pytest.raises(ValueError):
Calendar.from_ical("END:CALENDAR")
def test_vdd_list_type_mismatch():
"""If we pass in a string type, we expect it to be converted to bytes"""
vddd_list = vDDDLists([time(hour=6, minute=6, second=6)])
assert vddd_list.to_ical() == b'060606'