kopia lustrzana https://github.com/collective/icalendar
Merge pull request #581 from ennamarie19/master
Add fixes for OSS-Fuzz bugs and test casespull/580/head
commit
11eb89b8cd
|
@ -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)
|
||||
-------------------
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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.
|
||||
"""
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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'
|
Ładowanie…
Reference in New Issue