mirror of
https://github.com/theupdateframework/python-tuf
synced 2026-05-24 10:08:28 +00:00
Remove iso8601 dependency
Our 'expires' strings are constrained by the ISO8601_DATETIME_SCHEMA
which matches regex '\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z'. This can be
parsed with just a datetime.strptime(): iso8601 module is not needed.
* Add formats.expiry_string_to_datetime() helper function
* Modify the 3 locations that used iso8601 and the api/metadata.py usage
of datetime.strptime()
* Remove related unnecessary logger setup
* Add the missing exception documentation to relevant functions (in many
cases the exception is rather unlikely as the schema has been verified
many times before this though...)
Fixes #1065
Signed-off-by: Jussi Kukkonen <jkukkonen@vmware.com>
This commit is contained in:
parent
f8606d9645
commit
2f69986e2b
9 changed files with 62 additions and 41 deletions
|
|
@ -6,7 +6,6 @@ cryptography==3.1.1 # via securesystemslib
|
|||
enum34==1.1.6 ; python_version < '3' # via cryptography
|
||||
idna==2.10 # via requests
|
||||
ipaddress==1.0.23 ; python_version < '3' # via cryptography
|
||||
iso8601==0.1.13
|
||||
pycparser==2.20 # via cffi
|
||||
pynacl==1.4.0 # via securesystemslib
|
||||
python-dateutil==2.8.1 # via securesystemslib
|
||||
|
|
|
|||
|
|
@ -44,4 +44,3 @@
|
|||
securesystemslib[colors, crypto, pynacl]
|
||||
requests
|
||||
six
|
||||
iso8601
|
||||
|
|
|
|||
1
setup.py
1
setup.py
|
|
@ -114,7 +114,6 @@
|
|||
},
|
||||
python_requires=">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4",
|
||||
install_requires = [
|
||||
'iso8601>=0.1.12',
|
||||
'requests>=2.19.1',
|
||||
'six>=1.11.0',
|
||||
'securesystemslib>=0.16.0'
|
||||
|
|
|
|||
|
|
@ -723,6 +723,23 @@ def test_build_dict_conforming_to_schema(self):
|
|||
|
||||
|
||||
|
||||
def test_expiry_string_to_datetime(self):
|
||||
dt = tuf.formats.expiry_string_to_datetime('1985-10-21T13:20:00Z')
|
||||
self.assertEqual(dt, datetime.datetime(1985, 10, 21, 13, 20, 0))
|
||||
dt = tuf.formats.expiry_string_to_datetime('2038-01-19T03:14:08Z')
|
||||
self.assertEqual(dt, datetime.datetime(2038, 1, 19, 3, 14, 8))
|
||||
|
||||
# First 3 fail via securesystemslib schema, last one because of strptime()
|
||||
invalid_inputs = [
|
||||
'2038-1-19T03:14:08Z', # leading zeros not optional
|
||||
'2038-01-19T031408Z', # strict time parsing
|
||||
'2038-01-19T03:14:08Z-06:00', # timezone not allowed
|
||||
'2038-13-19T03:14:08Z', # too many months
|
||||
]
|
||||
for invalid_input in invalid_inputs:
|
||||
with self.assertRaises(securesystemslib.exceptions.FormatError):
|
||||
tuf.formats.expiry_string_to_datetime(invalid_input)
|
||||
|
||||
|
||||
|
||||
def test_unix_timestamp_to_datetime(self):
|
||||
|
|
|
|||
|
|
@ -294,9 +294,8 @@ def from_dict(cls, signed_dict: JsonDict) -> 'Signed':
|
|||
# Convert 'expires' TUF metadata string to a datetime object, which is
|
||||
# what the constructor expects and what we store. The inverse operation
|
||||
# is implemented in 'to_dict'.
|
||||
signed_dict['expires'] = datetime.strptime(
|
||||
signed_dict['expires'],
|
||||
"%Y-%m-%dT%H:%M:%SZ").replace(tzinfo=None)
|
||||
signed_dict['expires'] = tuf.formats.expiry_string_to_datetime(
|
||||
signed_dict['expires'])
|
||||
# NOTE: We write the converted 'expires' back into 'signed_dict' above
|
||||
# so that we can pass it to the constructor as '**signed_dict' below,
|
||||
# along with other fields that belong to Signed subclasses.
|
||||
|
|
|
|||
|
|
@ -145,7 +145,6 @@
|
|||
import securesystemslib.keys
|
||||
import securesystemslib.util
|
||||
import six
|
||||
import iso8601
|
||||
import requests.exceptions
|
||||
|
||||
# The Timestamp role does not have signed metadata about it; otherwise we
|
||||
|
|
@ -163,11 +162,6 @@
|
|||
# See 'log.py' to learn how logging is handled in TUF.
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# Disable 'iso8601' logger messages to prevent 'iso8601' from clogging the
|
||||
# log file.
|
||||
iso8601_logger = logging.getLogger('iso8601')
|
||||
iso8601_logger.disabled = True
|
||||
|
||||
|
||||
class MultiRepoUpdater(object):
|
||||
"""
|
||||
|
|
@ -2377,7 +2371,8 @@ def _ensure_not_expired(self, metadata_object, metadata_rolename):
|
|||
<Exceptions>
|
||||
tuf.exceptions.ExpiredMetadataError:
|
||||
If 'metadata_rolename' has expired.
|
||||
|
||||
securesystemslib.exceptions.FormatError:
|
||||
If the expiration cannot be parsed correctly
|
||||
<Side Effects>
|
||||
None.
|
||||
|
||||
|
|
@ -2385,22 +2380,15 @@ def _ensure_not_expired(self, metadata_object, metadata_rolename):
|
|||
None.
|
||||
"""
|
||||
|
||||
# Extract the expiration time.
|
||||
expires = metadata_object['expires']
|
||||
|
||||
# If the current time has surpassed the expiration date, raise an
|
||||
# exception. 'expires' is in
|
||||
# 'securesystemslib.formats.ISO8601_DATETIME_SCHEMA' format (e.g.,
|
||||
# '1985-10-21T01:22:00Z'.) Convert it to a unix timestamp and compare it
|
||||
# Extract the expiration time. Convert it to a unix timestamp and compare it
|
||||
# against the current time.time() (also in Unix/POSIX time format, although
|
||||
# with microseconds attached.)
|
||||
current_time = int(time.time())
|
||||
|
||||
# Generate a user-friendly error message if 'expires' is less than the
|
||||
# current time (i.e., a local time.)
|
||||
expires_datetime = iso8601.parse_date(expires)
|
||||
expires_datetime = tuf.formats.expiry_string_to_datetime(
|
||||
metadata_object['expires'])
|
||||
expires_timestamp = tuf.formats.datetime_to_unix_timestamp(expires_datetime)
|
||||
|
||||
current_time = int(time.time())
|
||||
|
||||
if expires_timestamp < current_time:
|
||||
message = 'Metadata '+repr(metadata_rolename)+' expired on ' + \
|
||||
expires_datetime.ctime() + ' (UTC).'
|
||||
|
|
|
|||
|
|
@ -612,6 +612,37 @@ def build_dict_conforming_to_schema(schema, **kwargs):
|
|||
|
||||
|
||||
|
||||
|
||||
def expiry_string_to_datetime(expires):
|
||||
"""
|
||||
<Purpose>
|
||||
Convert an expiry string to a datetime object.
|
||||
<Arguments>
|
||||
expires:
|
||||
The expiry date-time string in the ISO8601 format that is defined
|
||||
in securesystemslib.ISO8601_DATETIME_SCHEMA. E.g. '2038-01-19T03:14:08Z'
|
||||
<Exceptions>
|
||||
securesystemslib.exceptions.FormatError, if 'expires' cannot be
|
||||
parsed correctly.
|
||||
<Side Effects>
|
||||
None.
|
||||
<Returns>
|
||||
A datetime object representing the expiry time.
|
||||
"""
|
||||
|
||||
# Raise 'securesystemslib.exceptions.FormatError' if there is a mismatch.
|
||||
securesystemslib.formats.ISO8601_DATETIME_SCHEMA.check_match(expires)
|
||||
|
||||
try:
|
||||
return datetime.datetime.strptime(expires, "%Y-%m-%dT%H:%M:%SZ")
|
||||
except ValueError as error:
|
||||
six.raise_from(securesystemslib.exceptions.FormatError(
|
||||
'Failed to parse ' + repr(expires) + ' as an expiry time'),
|
||||
error)
|
||||
|
||||
|
||||
|
||||
|
||||
def datetime_to_unix_timestamp(datetime_object):
|
||||
"""
|
||||
<Purpose>
|
||||
|
|
|
|||
|
|
@ -52,7 +52,6 @@
|
|||
import securesystemslib.hash
|
||||
import securesystemslib.interface
|
||||
import securesystemslib.util
|
||||
import iso8601
|
||||
import six
|
||||
|
||||
import securesystemslib.storage
|
||||
|
|
@ -61,11 +60,6 @@
|
|||
# See 'log.py' to learn how logging is handled in TUF.
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# Disable 'iso8601' logger messages to prevent 'iso8601' from clogging the
|
||||
# log file.
|
||||
iso8601_logger = logging.getLogger('iso8601')
|
||||
iso8601_logger.disabled = True
|
||||
|
||||
# The extension of TUF metadata.
|
||||
METADATA_EXTENSION = '.json'
|
||||
|
||||
|
|
@ -704,7 +698,8 @@ def _log_warning_if_expires_soon(rolename, expires_iso8601_timestamp,
|
|||
# unix timestamp, subtract from current time.time() (also in POSIX time)
|
||||
# and compare against 'seconds_remaining_to_warn'. Log a warning message
|
||||
# to console if 'rolename' expires soon.
|
||||
datetime_object = iso8601.parse_date(expires_iso8601_timestamp)
|
||||
datetime_object = tuf.formats.expiry_string_to_datetime(
|
||||
expires_iso8601_timestamp)
|
||||
expires_unix_timestamp = \
|
||||
tuf.formats.datetime_to_unix_timestamp(datetime_object)
|
||||
seconds_until_expires = expires_unix_timestamp - int(time.time())
|
||||
|
|
|
|||
|
|
@ -53,7 +53,6 @@
|
|||
import securesystemslib.keys
|
||||
import securesystemslib.formats
|
||||
import securesystemslib.util
|
||||
import iso8601
|
||||
import six
|
||||
|
||||
import securesystemslib.storage
|
||||
|
|
@ -1317,15 +1316,12 @@ def expiration(self):
|
|||
<Purpose>
|
||||
A getter method that returns the role's expiration datetime.
|
||||
|
||||
>>>
|
||||
>>>
|
||||
>>>
|
||||
|
||||
<Arguments>
|
||||
None.
|
||||
|
||||
<Exceptions>
|
||||
None.
|
||||
securesystemslib.exceptions.FormatError, if the expiration cannot be
|
||||
parsed correctly
|
||||
|
||||
<Side Effects>
|
||||
None.
|
||||
|
|
@ -1337,9 +1333,7 @@ def expiration(self):
|
|||
roleinfo = tuf.roledb.get_roleinfo(self.rolename, self._repository_name)
|
||||
expires = roleinfo['expires']
|
||||
|
||||
expires_datetime_object = iso8601.parse_date(expires)
|
||||
|
||||
return expires_datetime_object
|
||||
return tuf.formats.expiry_string_to_datetime(expires)
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue