mirror of
https://github.com/Kozea/Radicale.git
synced 2025-06-26 16:45:52 +00:00
Merge pull request #1783 from pbiering/issue-1782
Implement timerange filter for VALARM
This commit is contained in:
commit
c0fd66eda6
9 changed files with 129 additions and 17 deletions
|
@ -1,7 +1,7 @@
|
||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
## 3.5.4.dev
|
## 3.5.4.dev
|
||||||
* Improve: item filter enhanced for 3rd level supporting VALARM and VFREEBUSY (only component existence so far)
|
* Improve: item filter enhanced for 3rd level supporting VALARM and honoring TRIGGER (offset or absolute)
|
||||||
|
|
||||||
## 3.5.3
|
## 3.5.3
|
||||||
* Add: [auth] htpasswd: support for Argon2 hashes
|
* Add: [auth] htpasswd: support for Argon2 hashes
|
||||||
|
|
|
@ -177,7 +177,7 @@ def xml_report(base_prefix: str, path: str, xml_request: Optional[ET.Element],
|
||||||
|
|
||||||
props: Union[ET.Element, List]
|
props: Union[ET.Element, List]
|
||||||
if root.find(xmlutils.make_clark("D:prop")) is not None:
|
if root.find(xmlutils.make_clark("D:prop")) is not None:
|
||||||
props = root.find(xmlutils.make_clark("D:prop")) # type: ignore[assignment]
|
props = root.find(xmlutils.make_clark("D:prop")) # type: ignore[assignment]
|
||||||
else:
|
else:
|
||||||
props = []
|
props = []
|
||||||
|
|
||||||
|
|
|
@ -96,7 +96,7 @@ class Auth(auth.BaseAuth):
|
||||||
self._has_bcrypt = False
|
self._has_bcrypt = False
|
||||||
self._has_argon2 = False
|
self._has_argon2 = False
|
||||||
self._htpasswd_ok = False
|
self._htpasswd_ok = False
|
||||||
self._htpasswd_not_ok_reminder_seconds = 60 # currently hardcoded
|
self._htpasswd_not_ok_reminder_seconds = 60 # currently hardcoded
|
||||||
(self._htpasswd_ok, self._htpasswd_bcrypt_use, self._htpasswd_argon2_use, self._htpasswd, self._htpasswd_size, self._htpasswd_mtime_ns) = self._read_htpasswd(True, False)
|
(self._htpasswd_ok, self._htpasswd_bcrypt_use, self._htpasswd_argon2_use, self._htpasswd, self._htpasswd_size, self._htpasswd_mtime_ns) = self._read_htpasswd(True, False)
|
||||||
self._lock = threading.Lock()
|
self._lock = threading.Lock()
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,8 @@
|
||||||
|
|
||||||
import imaplib
|
import imaplib
|
||||||
import ssl
|
import ssl
|
||||||
|
import sys
|
||||||
|
from typing import Union
|
||||||
|
|
||||||
from radicale import auth
|
from radicale import auth
|
||||||
from radicale.log import logger
|
from radicale.log import logger
|
||||||
|
@ -49,7 +51,10 @@ class Auth(auth.BaseAuth):
|
||||||
|
|
||||||
def _login(self, login, password) -> str:
|
def _login(self, login, password) -> str:
|
||||||
try:
|
try:
|
||||||
connection: imaplib.IMAP4 | imaplib.IMAP4_SSL
|
if sys.version_info < (3, 10):
|
||||||
|
connection: Union[imaplib.IMAP4, imaplib.IMAP4_SSL]
|
||||||
|
else:
|
||||||
|
connection: imaplib.IMAP4 | imaplib.IMAP4_SSL
|
||||||
if self._security == "tls":
|
if self._security == "tls":
|
||||||
connection = imaplib.IMAP4_SSL(
|
connection = imaplib.IMAP4_SSL(
|
||||||
host=self._host, port=self._port,
|
host=self._host, port=self._port,
|
||||||
|
|
|
@ -21,11 +21,12 @@
|
||||||
|
|
||||||
|
|
||||||
import math
|
import math
|
||||||
|
import sys
|
||||||
import xml.etree.ElementTree as ET
|
import xml.etree.ElementTree as ET
|
||||||
from datetime import date, datetime, timedelta, timezone
|
from datetime import date, datetime, timedelta, timezone
|
||||||
from itertools import chain
|
from itertools import chain
|
||||||
from typing import (Callable, Iterable, Iterator, List, Optional, Sequence,
|
from typing import (Callable, Iterable, Iterator, List, Optional, Sequence,
|
||||||
Tuple)
|
Tuple, Union)
|
||||||
|
|
||||||
import vobject
|
import vobject
|
||||||
|
|
||||||
|
@ -39,6 +40,11 @@ DATETIME_MAX: datetime = datetime.max.replace(tzinfo=timezone.utc)
|
||||||
TIMESTAMP_MIN: int = math.floor(DATETIME_MIN.timestamp())
|
TIMESTAMP_MIN: int = math.floor(DATETIME_MIN.timestamp())
|
||||||
TIMESTAMP_MAX: int = math.ceil(DATETIME_MAX.timestamp())
|
TIMESTAMP_MAX: int = math.ceil(DATETIME_MAX.timestamp())
|
||||||
|
|
||||||
|
if sys.version_info < (3, 10):
|
||||||
|
TRIGGER = Union[datetime, None]
|
||||||
|
else:
|
||||||
|
TRIGGER = datetime | None
|
||||||
|
|
||||||
|
|
||||||
def date_to_datetime(d: date) -> datetime:
|
def date_to_datetime(d: date) -> datetime:
|
||||||
"""Transform any date to a UTC datetime.
|
"""Transform any date to a UTC datetime.
|
||||||
|
@ -88,8 +94,7 @@ def comp_match(item: "item.Item", filter_: ET.Element, level: int = 0) -> bool:
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# TODO: Improve filtering for VALARM and VFREEBUSY
|
# TODO: Filtering VFREEBUSY is not implemented
|
||||||
# so far only filtering based on existence of such component is implemented
|
|
||||||
# HACK: the filters are tested separately against all components
|
# HACK: the filters are tested separately against all components
|
||||||
|
|
||||||
name = filter_.get("name", "").upper()
|
name = filter_.get("name", "").upper()
|
||||||
|
@ -117,10 +122,11 @@ def comp_match(item: "item.Item", filter_: ET.Element, level: int = 0) -> bool:
|
||||||
return False
|
return False
|
||||||
if ((level == 0 and name != "VCALENDAR") or
|
if ((level == 0 and name != "VCALENDAR") or
|
||||||
(level == 1 and name not in ("VTODO", "VEVENT", "VJOURNAL")) or
|
(level == 1 and name not in ("VTODO", "VEVENT", "VJOURNAL")) or
|
||||||
(level == 2 and name not in ("VALARM", "VFREEBUSY"))):
|
(level == 2 and name not in ("VALARM"))):
|
||||||
logger.warning("Filtering %s is not supported", name)
|
logger.warning("Filtering %s is not supported", name)
|
||||||
return True
|
return True
|
||||||
# Point #3 and #4 of rfc4791-9.7.1
|
# Point #3 and #4 of rfc4791-9.7.1
|
||||||
|
trigger = None
|
||||||
if level == 0:
|
if level == 0:
|
||||||
components = [item.vobject_item]
|
components = [item.vobject_item]
|
||||||
elif level == 1:
|
elif level == 1:
|
||||||
|
@ -128,15 +134,19 @@ def comp_match(item: "item.Item", filter_: ET.Element, level: int = 0) -> bool:
|
||||||
elif level == 2:
|
elif level == 2:
|
||||||
components = list(getattr(item.vobject_item, "%s_list" % tag.lower()))
|
components = list(getattr(item.vobject_item, "%s_list" % tag.lower()))
|
||||||
for comp in components:
|
for comp in components:
|
||||||
if not hasattr(comp, name.lower()):
|
subcomp = getattr(comp, name.lower(), None)
|
||||||
|
if not subcomp:
|
||||||
return False
|
return False
|
||||||
|
if hasattr(subcomp, "trigger"):
|
||||||
|
# rfc4791-7.8.5:
|
||||||
|
trigger = subcomp.trigger.value
|
||||||
for child in filter_:
|
for child in filter_:
|
||||||
if child.tag == xmlutils.make_clark("C:prop-filter"):
|
if child.tag == xmlutils.make_clark("C:prop-filter"):
|
||||||
if not any(prop_match(comp, child, "C")
|
if not any(prop_match(comp, child, "C")
|
||||||
for comp in components):
|
for comp in components):
|
||||||
return False
|
return False
|
||||||
elif child.tag == xmlutils.make_clark("C:time-range"):
|
elif child.tag == xmlutils.make_clark("C:time-range"):
|
||||||
if not time_range_match(item.vobject_item, filter_[0], tag):
|
if not time_range_match(item.vobject_item, filter_[0], tag, trigger):
|
||||||
return False
|
return False
|
||||||
elif child.tag == xmlutils.make_clark("C:comp-filter"):
|
elif child.tag == xmlutils.make_clark("C:comp-filter"):
|
||||||
if not comp_match(item, child, level=level + 1):
|
if not comp_match(item, child, level=level + 1):
|
||||||
|
@ -166,7 +176,7 @@ def prop_match(vobject_item: vobject.base.Component,
|
||||||
# Point #3 and #4 of rfc4791-9.7.2
|
# Point #3 and #4 of rfc4791-9.7.2
|
||||||
for child in filter_:
|
for child in filter_:
|
||||||
if ns == "C" and child.tag == xmlutils.make_clark("C:time-range"):
|
if ns == "C" and child.tag == xmlutils.make_clark("C:time-range"):
|
||||||
if not time_range_match(vobject_item, child, name):
|
if not time_range_match(vobject_item, child, name, None):
|
||||||
return False
|
return False
|
||||||
elif child.tag == xmlutils.make_clark("%s:text-match" % ns):
|
elif child.tag == xmlutils.make_clark("%s:text-match" % ns):
|
||||||
if not text_match(vobject_item, child, name, ns):
|
if not text_match(vobject_item, child, name, ns):
|
||||||
|
@ -180,9 +190,10 @@ def prop_match(vobject_item: vobject.base.Component,
|
||||||
|
|
||||||
|
|
||||||
def time_range_match(vobject_item: vobject.base.Component,
|
def time_range_match(vobject_item: vobject.base.Component,
|
||||||
filter_: ET.Element, child_name: str) -> bool:
|
filter_: ET.Element, child_name: str, trigger: TRIGGER) -> bool:
|
||||||
"""Check whether the component/property ``child_name`` of
|
"""Check whether the component/property ``child_name`` of
|
||||||
``vobject_item`` matches the time-range ``filter_``."""
|
``vobject_item`` matches the time-range ``filter_``."""
|
||||||
|
# supporting since 3.5.4 now optional trigger (either absolute or relative offset)
|
||||||
|
|
||||||
if not filter_.get("start") and not filter_.get("end"):
|
if not filter_.get("start") and not filter_.get("end"):
|
||||||
return False
|
return False
|
||||||
|
@ -193,6 +204,25 @@ def time_range_match(vobject_item: vobject.base.Component,
|
||||||
def range_fn(range_start: datetime, range_end: datetime,
|
def range_fn(range_start: datetime, range_end: datetime,
|
||||||
is_recurrence: bool) -> bool:
|
is_recurrence: bool) -> bool:
|
||||||
nonlocal matched
|
nonlocal matched
|
||||||
|
if trigger:
|
||||||
|
# if trigger is given, only check range_start
|
||||||
|
if isinstance(trigger, timedelta):
|
||||||
|
# trigger is a offset, apply to range_start
|
||||||
|
if start < range_start + trigger and range_start + trigger < end:
|
||||||
|
matched = True
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
elif isinstance(trigger, datetime):
|
||||||
|
# trigger is absolute, use instead of range_start
|
||||||
|
if start < trigger and trigger < end:
|
||||||
|
matched = True
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
logger.warning("item/filter/time_range_match/range_fn: unsupported data format of provided trigger=%r", trigger)
|
||||||
|
return True
|
||||||
if start < range_end and range_start < end:
|
if start < range_end and range_start < end:
|
||||||
matched = True
|
matched = True
|
||||||
return True
|
return True
|
||||||
|
|
15
radicale/tests/static/valarm1.ics
Normal file
15
radicale/tests/static/valarm1.ics
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
BEGIN:VCALENDAR
|
||||||
|
VERSION:2.0
|
||||||
|
PRODID:-//python-caldav//caldav//en_DK
|
||||||
|
BEGIN:VEVENT
|
||||||
|
SUMMARY:This is a test event
|
||||||
|
DTSTART:20151010T060000Z
|
||||||
|
DTEND:20161010T070000Z
|
||||||
|
DTSTAMP:20250515T073149Z
|
||||||
|
UID:a9cef952-315e-11f0-a30a-1c1bb5134174
|
||||||
|
BEGIN:VALARM
|
||||||
|
ACTION:AUDIO
|
||||||
|
TRIGGER:-PT15M
|
||||||
|
END:VALARM
|
||||||
|
END:VEVENT
|
||||||
|
END:VCALENDAR
|
15
radicale/tests/static/valarm2.ics
Normal file
15
radicale/tests/static/valarm2.ics
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
BEGIN:VCALENDAR
|
||||||
|
VERSION:2.0
|
||||||
|
PRODID:-//python-caldav//caldav//en_DK
|
||||||
|
BEGIN:VEVENT
|
||||||
|
SUMMARY:This is a test event
|
||||||
|
DTSTART:20151010T060000Z
|
||||||
|
DTEND:20161010T070000Z
|
||||||
|
DTSTAMP:20250515T073149Z
|
||||||
|
UID:a9cef952-315e-11f0-a30a-1c1bb5134175
|
||||||
|
BEGIN:VALARM
|
||||||
|
ACTION:AUDIO
|
||||||
|
TRIGGER;VALUE=DATE-TIME:20151010T033000Z
|
||||||
|
END:VALARM
|
||||||
|
END:VEVENT
|
||||||
|
END:VCALENDAR
|
|
@ -21,6 +21,7 @@ Radicale tests with simple requests.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import logging
|
||||||
import os
|
import os
|
||||||
import posixpath
|
import posixpath
|
||||||
from typing import Any, Callable, ClassVar, Iterable, List, Optional, Tuple
|
from typing import Any, Callable, ClassVar, Iterable, List, Optional, Tuple
|
||||||
|
@ -745,7 +746,7 @@ permissions: RrWw""")
|
||||||
) -> List[str]:
|
) -> List[str]:
|
||||||
filter_template = "<C:filter>%s</C:filter>"
|
filter_template = "<C:filter>%s</C:filter>"
|
||||||
create_collection_fn: Callable[[str], Any]
|
create_collection_fn: Callable[[str], Any]
|
||||||
if kind in ("event", "journal", "todo"):
|
if kind in ("event", "journal", "todo", "valarm"):
|
||||||
create_collection_fn = self.mkcalendar
|
create_collection_fn = self.mkcalendar
|
||||||
path = "/calendar.ics/"
|
path = "/calendar.ics/"
|
||||||
filename_template = "%s%d.ics"
|
filename_template = "%s%d.ics"
|
||||||
|
@ -764,10 +765,13 @@ permissions: RrWw""")
|
||||||
status, _, = self.delete(path, check=None)
|
status, _, = self.delete(path, check=None)
|
||||||
assert status in (200, 404)
|
assert status in (200, 404)
|
||||||
create_collection_fn(path)
|
create_collection_fn(path)
|
||||||
|
logging.warning("Upload items %r", items)
|
||||||
for i in items:
|
for i in items:
|
||||||
|
logging.warning("Upload %d", i)
|
||||||
filename = filename_template % (kind, i)
|
filename = filename_template % (kind, i)
|
||||||
event = get_file_content(filename)
|
event = get_file_content(filename)
|
||||||
self.put(posixpath.join(path, filename), event)
|
self.put(posixpath.join(path, filename), event)
|
||||||
|
logging.warning("Upload items finished")
|
||||||
filters_text = "".join(filter_template % f for f in filters)
|
filters_text = "".join(filter_template % f for f in filters)
|
||||||
_, responses = self.report(path, """\
|
_, responses = self.report(path, """\
|
||||||
<?xml version="1.0" encoding="utf-8" ?>
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
@ -1304,6 +1308,49 @@ permissions: RrWw""")
|
||||||
</C:comp-filter>"""], "todo", items=range(1, 9))
|
</C:comp-filter>"""], "todo", items=range(1, 9))
|
||||||
assert "/calendar.ics/todo7.ics" in answer
|
assert "/calendar.ics/todo7.ics" in answer
|
||||||
|
|
||||||
|
def test_time_range_filter_events_valarm(self) -> None:
|
||||||
|
"""Report request with time-range filter on events having absolute VALARM."""
|
||||||
|
answer = self._test_filter(["""\
|
||||||
|
<C:comp-filter name="VCALENDAR">
|
||||||
|
<C:comp-filter name="VEVENT">
|
||||||
|
<C:comp-filter name="VALARM">
|
||||||
|
<C:time-range start="20151010T030000Z" end="20151010T040000Z"/>
|
||||||
|
</C:comp-filter>
|
||||||
|
</C:comp-filter>
|
||||||
|
</C:comp-filter>"""], "valarm", items=[1, 2])
|
||||||
|
assert "/calendar.ics/valarm1.ics" not in answer
|
||||||
|
assert "/calendar.ics/valarm2.ics" in answer # absolute date
|
||||||
|
answer = self._test_filter(["""\
|
||||||
|
<C:comp-filter name="VCALENDAR">
|
||||||
|
<C:comp-filter name="VEVENT">
|
||||||
|
<C:comp-filter name="VALARM">
|
||||||
|
<C:time-range start="20151010T010000Z" end="20151010T020000Z"/>
|
||||||
|
</C:comp-filter>
|
||||||
|
</C:comp-filter>
|
||||||
|
</C:comp-filter>"""], "valarm", items=[1, 2])
|
||||||
|
assert "/calendar.ics/valarm1.ics" not in answer
|
||||||
|
assert "/calendar.ics/valarm2.ics" not in answer
|
||||||
|
answer = self._test_filter(["""\
|
||||||
|
<C:comp-filter name="VCALENDAR">
|
||||||
|
<C:comp-filter name="VEVENT">
|
||||||
|
<C:comp-filter name="VALARM">
|
||||||
|
<C:time-range start="20151010T080000Z" end="20151010T090000Z"/>
|
||||||
|
</C:comp-filter>
|
||||||
|
</C:comp-filter>
|
||||||
|
</C:comp-filter>"""], "valarm", items=[1, 2])
|
||||||
|
assert "/calendar.ics/valarm1.ics" not in answer
|
||||||
|
assert "/calendar.ics/valarm2.ics" not in answer
|
||||||
|
answer = self._test_filter(["""\
|
||||||
|
<C:comp-filter name="VCALENDAR">
|
||||||
|
<C:comp-filter name="VEVENT">
|
||||||
|
<C:comp-filter name="VALARM">
|
||||||
|
<C:time-range start="20151010T053000Z" end="20151010T055000Z"/>
|
||||||
|
</C:comp-filter>
|
||||||
|
</C:comp-filter>
|
||||||
|
</C:comp-filter>"""], "valarm", items=[1, 2])
|
||||||
|
assert "/calendar.ics/valarm1.ics" in answer # -15 min offset
|
||||||
|
assert "/calendar.ics/valarm2.ics" not in answer
|
||||||
|
|
||||||
def test_time_range_filter_todos_completed(self) -> None:
|
def test_time_range_filter_todos_completed(self) -> None:
|
||||||
answer = self._test_filter(["""\
|
answer = self._test_filter(["""\
|
||||||
<C:comp-filter name="VCALENDAR">
|
<C:comp-filter name="VCALENDAR">
|
||||||
|
|
|
@ -102,7 +102,7 @@ def ssl_context_options_by_protocol(protocol: str, ssl_context_options):
|
||||||
ssl_context_options |= ssl.OP_NO_TLSv1_3
|
ssl_context_options |= ssl.OP_NO_TLSv1_3
|
||||||
logger.debug("SSL cleared SSL context options: '0x%x'", ssl_context_options)
|
logger.debug("SSL cleared SSL context options: '0x%x'", ssl_context_options)
|
||||||
for entry in protocol.split():
|
for entry in protocol.split():
|
||||||
entry = entry.strip('+') # remove trailing '+'
|
entry = entry.strip('+') # remove trailing '+'
|
||||||
if entry == "ALL":
|
if entry == "ALL":
|
||||||
logger.debug("SSL context options, enable ALL (some maybe not supported by underlying OpenSSL, SSLv2 not enabled at all)")
|
logger.debug("SSL context options, enable ALL (some maybe not supported by underlying OpenSSL, SSLv2 not enabled at all)")
|
||||||
ssl_context_options &= ~ssl.OP_NO_SSLv3
|
ssl_context_options &= ~ssl.OP_NO_SSLv3
|
||||||
|
@ -162,7 +162,7 @@ def ssl_context_options_by_protocol(protocol: str, ssl_context_options):
|
||||||
|
|
||||||
def ssl_context_minimum_version_by_options(ssl_context_options):
|
def ssl_context_minimum_version_by_options(ssl_context_options):
|
||||||
logger.debug("SSL calculate minimum version by context options: '0x%x'", ssl_context_options)
|
logger.debug("SSL calculate minimum version by context options: '0x%x'", ssl_context_options)
|
||||||
ssl_context_minimum_version = ssl.TLSVersion.SSLv3 # default
|
ssl_context_minimum_version = ssl.TLSVersion.SSLv3 # default
|
||||||
if ((ssl_context_options & ssl.OP_NO_SSLv3) and (ssl_context_minimum_version == ssl.TLSVersion.SSLv3)):
|
if ((ssl_context_options & ssl.OP_NO_SSLv3) and (ssl_context_minimum_version == ssl.TLSVersion.SSLv3)):
|
||||||
ssl_context_minimum_version = ssl.TLSVersion.TLSv1
|
ssl_context_minimum_version = ssl.TLSVersion.TLSv1
|
||||||
if ((ssl_context_options & ssl.OP_NO_TLSv1) and (ssl_context_minimum_version == ssl.TLSVersion.TLSv1)):
|
if ((ssl_context_options & ssl.OP_NO_TLSv1) and (ssl_context_minimum_version == ssl.TLSVersion.TLSv1)):
|
||||||
|
@ -172,7 +172,7 @@ def ssl_context_minimum_version_by_options(ssl_context_options):
|
||||||
if ((ssl_context_options & ssl.OP_NO_TLSv1_2) and (ssl_context_minimum_version == ssl.TLSVersion.TLSv1_2)):
|
if ((ssl_context_options & ssl.OP_NO_TLSv1_2) and (ssl_context_minimum_version == ssl.TLSVersion.TLSv1_2)):
|
||||||
ssl_context_minimum_version = ssl.TLSVersion.TLSv1_3
|
ssl_context_minimum_version = ssl.TLSVersion.TLSv1_3
|
||||||
if ((ssl_context_options & ssl.OP_NO_TLSv1_3) and (ssl_context_minimum_version == ssl.TLSVersion.TLSv1_3)):
|
if ((ssl_context_options & ssl.OP_NO_TLSv1_3) and (ssl_context_minimum_version == ssl.TLSVersion.TLSv1_3)):
|
||||||
ssl_context_minimum_version = 0 # all disabled
|
ssl_context_minimum_version = 0 # all disabled
|
||||||
|
|
||||||
logger.debug("SSL context options: '0x%x' results in minimum version: %s", ssl_context_options, ssl_context_minimum_version)
|
logger.debug("SSL context options: '0x%x' results in minimum version: %s", ssl_context_options, ssl_context_minimum_version)
|
||||||
return ssl_context_minimum_version
|
return ssl_context_minimum_version
|
||||||
|
@ -180,7 +180,7 @@ def ssl_context_minimum_version_by_options(ssl_context_options):
|
||||||
|
|
||||||
def ssl_context_maximum_version_by_options(ssl_context_options):
|
def ssl_context_maximum_version_by_options(ssl_context_options):
|
||||||
logger.debug("SSL calculate maximum version by context options: '0x%x'", ssl_context_options)
|
logger.debug("SSL calculate maximum version by context options: '0x%x'", ssl_context_options)
|
||||||
ssl_context_maximum_version = ssl.TLSVersion.TLSv1_3 # default
|
ssl_context_maximum_version = ssl.TLSVersion.TLSv1_3 # default
|
||||||
if ((ssl_context_options & ssl.OP_NO_TLSv1_3) and (ssl_context_maximum_version == ssl.TLSVersion.TLSv1_3)):
|
if ((ssl_context_options & ssl.OP_NO_TLSv1_3) and (ssl_context_maximum_version == ssl.TLSVersion.TLSv1_3)):
|
||||||
ssl_context_maximum_version = ssl.TLSVersion.TLSv1_2
|
ssl_context_maximum_version = ssl.TLSVersion.TLSv1_2
|
||||||
if ((ssl_context_options & ssl.OP_NO_TLSv1_2) and (ssl_context_maximum_version == ssl.TLSVersion.TLSv1_2)):
|
if ((ssl_context_options & ssl.OP_NO_TLSv1_2) and (ssl_context_maximum_version == ssl.TLSVersion.TLSv1_2)):
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue