Skip to content

Commit cfc7638

Browse files
author
Jussi Kukkonen
authored
Merge pull request #1451 from sechkova/hash-validation
api/metadata input validation: length and hashes
2 parents 39ed706 + 328f637 commit cfc7638

File tree

2 files changed

+27
-15
lines changed

2 files changed

+27
-15
lines changed

tests/test_api.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -569,7 +569,7 @@ def test_metadata_targets(self):
569569
hashes = {
570570
"sha256": "141f740f53781d1ca54b8a50af22cbf74e44c21a998fa2a8a05aaac2c002886b",
571571
"sha512": "ef5beafa16041bcdd2937140afebd485296cd54f7348ecd5a4d035c09759608de467a7ac0eb58753d0242df873c305e8bffad2454aa48f44480f15efae1cacd0"
572-
},
572+
}
573573

574574
fileinfo = TargetFile(length=28, hashes=hashes)
575575

tuf/api/metadata.py

+26-14
Original file line numberDiff line numberDiff line change
@@ -702,6 +702,19 @@ def _verify_length(
702702
f"expected length {expected_length}"
703703
)
704704

705+
@staticmethod
706+
def _validate_hashes(hashes: Dict[str, str]) -> None:
707+
if not hashes:
708+
raise ValueError("Hashes must be a non empty dictionary")
709+
for key, value in hashes.items():
710+
if not (isinstance(key, str) and isinstance(value, str)):
711+
raise TypeError("Hashes items must be strings")
712+
713+
@staticmethod
714+
def _validate_length(length: int) -> None:
715+
if length <= 0:
716+
raise ValueError(f"Length must be > 0, got {length}")
717+
705718

706719
class MetaFile(BaseFile):
707720
"""A container with information about a particular metadata file.
@@ -730,6 +743,14 @@ def __init__(
730743
hashes: Optional[Dict[str, str]] = None,
731744
unrecognized_fields: Optional[Mapping[str, Any]] = None,
732745
) -> None:
746+
747+
if version <= 0:
748+
raise ValueError(f"Metafile version must be > 0, got {version}")
749+
if length is not None:
750+
self._validate_length(length)
751+
if hashes is not None:
752+
self._validate_hashes(hashes)
753+
733754
self.version = version
734755
self.length = length
735756
self.hashes = hashes
@@ -742,12 +763,6 @@ def from_dict(cls, meta_dict: Dict[str, Any]) -> "MetaFile":
742763
length = meta_dict.pop("length", None)
743764
hashes = meta_dict.pop("hashes", None)
744765

745-
# Do some basic input validation
746-
if version <= 0:
747-
raise ValueError(f"Metafile version must be > 0, got {version}")
748-
if length is not None and length <= 0:
749-
raise ValueError(f"Metafile length must be > 0, got {length}")
750-
751766
# All fields left in the meta_dict are unrecognized.
752767
return cls(version, length, hashes, meta_dict)
753768

@@ -778,8 +793,7 @@ def verify_length_and_hashes(self, data: Union[bytes, BinaryIO]):
778793
if self.length is not None:
779794
self._verify_length(data, self.length)
780795

781-
# Skip the check in case of an empty dictionary too
782-
if self.hashes:
796+
if self.hashes is not None:
783797
self._verify_hashes(data, self.hashes)
784798

785799

@@ -1033,6 +1047,10 @@ def __init__(
10331047
hashes: Dict[str, str],
10341048
unrecognized_fields: Optional[Mapping[str, Any]] = None,
10351049
) -> None:
1050+
1051+
self._validate_length(length)
1052+
self._validate_hashes(hashes)
1053+
10361054
self.length = length
10371055
self.hashes = hashes
10381056
self.unrecognized_fields = unrecognized_fields or {}
@@ -1049,12 +1067,6 @@ def from_dict(cls, target_dict: Dict[str, Any]) -> "TargetFile":
10491067
length = target_dict.pop("length")
10501068
hashes = target_dict.pop("hashes")
10511069

1052-
# Do some basic validation checks
1053-
if length <= 0:
1054-
raise ValueError(f"Targetfile length must be > 0, got {length}")
1055-
if not hashes:
1056-
raise ValueError("Missing targetfile hashes")
1057-
10581070
# All fields left in the target_dict are unrecognized.
10591071
return cls(length, hashes, target_dict)
10601072

0 commit comments

Comments
 (0)