From 5a910c0715dc4de3e73d2b4c87663e18ff5a73b7 Mon Sep 17 00:00:00 2001 From: Felix Fontein Date: Thu, 2 May 2024 15:58:28 +0200 Subject: [PATCH] ACME timestamp parser: do not choke on nanoseconds. --- plugins/module_utils/acme/backends.py | 23 +++++++++++++++++++ .../plugins/module_utils/acme/backend_data.py | 4 ++++ 2 files changed, 27 insertions(+) diff --git a/plugins/module_utils/acme/backends.py b/plugins/module_utils/acme/backends.py index 2db282667..2f7f5d01a 100644 --- a/plugins/module_utils/acme/backends.py +++ b/plugins/module_utils/acme/backends.py @@ -40,8 +40,31 @@ ) +_FRACTIONAL_MATCHER = re.compile(r'^(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2})(|\.\d+)(Z|[+-]\d{2}:?\d{2}.*)$') + + +def _reduce_fractional_digits(timestamp_str): + """ + Given a RFC 3339 timestamp that includes too many digits for the fractional seconds part, reduces these to at most 6. + """ + # RFC 3339 (https://www.rfc-editor.org/info/rfc3339) + m = _FRACTIONAL_MATCHER.match(timestamp_str) + if not m: + raise BackendException('Cannot parse ISO 8601 timestamp {0!r}'.format(timestamp_str)) + timestamp, fractional, timezone = m.groups() + if len(fractional) > 7: + # Python does not support anything smaller than microseconds + # (Golang supports nanoseconds, Boulder often emits more fractional digits, which Python chokes on) + fractional = fractional[:7] + return '%s%s%s' % (timestamp, fractional, timezone) + + def _parse_acme_timestamp(timestamp_str, with_timezone): + """ + Parses a RFC 3339 timestamp. + """ # RFC 3339 (https://www.rfc-editor.org/info/rfc3339) + timestamp_str = _reduce_fractional_digits(timestamp_str) for format in ('%Y-%m-%dT%H:%M:%SZ', '%Y-%m-%dT%H:%M:%S.%fZ', '%Y-%m-%dT%H:%M:%S%z', '%Y-%m-%dT%H:%M:%S.%f%z'): # Note that %z won't work with Python 2... https://stackoverflow.com/a/27829491 try: diff --git a/tests/unit/plugins/module_utils/acme/backend_data.py b/tests/unit/plugins/module_utils/acme/backend_data.py index eed1fb3fa..31d083a7c 100644 --- a/tests/unit/plugins/module_utils/acme/backend_data.py +++ b/tests/unit/plugins/module_utils/acme/backend_data.py @@ -117,6 +117,10 @@ def load_fixture(name): '2024-01-01T00:11:22.123Z', dict(year=2024, month=1, day=1, hour=0, minute=11, second=22, microsecond=123000), ), + ( + '2024-04-17T06:54:13.333333334Z', + dict(year=2024, month=4, day=17, hour=6, minute=54, second=13, microsecond=333333.334), + ), ] if sys.version_info >= (3, 5):