mirror of
https://salsa.debian.org/freeipa-team/freeipa.git
synced 2026-11-02 20:30:26 -06:00
handle Y2038 in timestamp to datetime conversions
According to datetime.utcfromtimestamp() method documentation[1], this and similar methods fail for dates past 2038 and can be replaced by the following expression on the POSIX compliant systems: datetime(1970, 1, 1, tzinfo=timezone.utc) + timedelta(seconds=timestamp) Make sure to use a method that at least allows to import the timestamps properly to datetime objects on 32-bit platforms. [1] https://docs.python.org/3/library/datetime.html#datetime.datetime.utcfromtimestamp Fixes: https://pagure.io/freeipa/issue/8378 Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com> Reviewed-By: Rob Crittenden <rcritten@redhat.com> Reviewed-By: Christian Heimes <cheimes@redhat.com>
This commit is contained in:
1 parent
a3c648bd92
commit
1f6ca418ee
6 files changed
+61
-21
No files matched your search
+6
-3
@@ -22,6 +22,7 @@ import datetime
|
||||
import email.utils
|
||||
from calendar import timegm
|
||||
from urllib.parse import urlparse
|
||||
from ipapython.ipautil import datetime_from_utctimestamp
|
||||
|
||||
|
||||
'''
|
||||
@@ -184,7 +185,7 @@ class Cookie:
|
||||
# use the RFC 1123 parsing function which uses only English
|
||||
|
||||
try:
|
||||
dt = datetime.datetime(*email.utils.parsedate(s)[0:6])
|
||||
dt = email.utils.parsedate_to_datetime(s)
|
||||
except Exception as e:
|
||||
raise ValueError("unable to parse expires datetime '%s': %s" % (s, e))
|
||||
|
||||
@@ -390,7 +391,7 @@ class Cookie:
|
||||
elif isinstance(value, datetime.datetime):
|
||||
self._timestamp = value
|
||||
elif isinstance(value, (int, float)):
|
||||
self._timestamp = datetime.datetime.utcfromtimestamp(value)
|
||||
self._timestamp = datetime_from_utctimestamp(value, units=1)
|
||||
elif isinstance(value, str):
|
||||
self._timestamp = Cookie.parse_datetime(value)
|
||||
else:
|
||||
@@ -415,8 +416,10 @@ class Cookie:
|
||||
self._expires = None
|
||||
elif isinstance(value, datetime.datetime):
|
||||
self._expires = value
|
||||
if self._expires.tzinfo is None:
|
||||
self._expires.replace(tzinfo=datetime.timezone.utc)
|
||||
elif isinstance(value, (int, float)):
|
||||
self._expires = datetime.datetime.utcfromtimestamp(value)
|
||||
self._expires = datetime_from_utctimestamp(value, units=1)
|
||||
elif isinstance(value, str):
|
||||
self._expires = Cookie.parse_datetime(value)
|
||||
else:
|
||||
|
||||
@@ -1647,3 +1647,27 @@ def rmtree(path):
|
||||
shutil.rmtree(path)
|
||||
except Exception as e:
|
||||
logger.error('Error removing %s: %s', path, str(e))
|
||||
|
||||
|
||||
def datetime_from_utctimestamp(t, units=1):
|
||||
"""
|
||||
Convert a timestamp or a time.struct_time to a datetime.datetime
|
||||
object down to seconds, with UTC timezone
|
||||
|
||||
The conversion is safe for year 2038 problem
|
||||
|
||||
:param t: int or float timestamp in (milli)seconds since UNIX epoch
|
||||
or time.struct_time
|
||||
:param units: normalizing factor for the timestamp
|
||||
(1 for seconds, 1000 for milliseconds)
|
||||
defaults to 1
|
||||
:return: datetime.datetime object in UTC timezone
|
||||
"""
|
||||
if isinstance(t, time.struct_time):
|
||||
v = int(time.mktime(t))
|
||||
elif isinstance(t, (float, int)):
|
||||
v = int(t)
|
||||
else:
|
||||
raise TypeError(t)
|
||||
epoch = datetime.datetime(1970, 1, 1, tzinfo=datetime.timezone.utc)
|
||||
return epoch + datetime.timedelta(seconds=v // units)
|
||||
Reference in new issue
Block a user