This repository has been archived by the owner on Dec 7, 2022. It is now read-only.
/
verification.py
125 lines (90 loc) · 3.83 KB
/
verification.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
"""
Functions for verifying files.
"""
import hashlib
from pulp.common import error_codes
from pulp.server.exceptions import PulpCodedException
# Number of bytes to read into RAM at a time when validating the checksum
VALIDATION_CHUNK_SIZE = 32 * 1024 * 1024
# Constants to pass in as the checksum type in verify_checksum
TYPE_MD5 = 'md5'
TYPE_SHA = 'sha'
TYPE_SHA1 = 'sha1'
TYPE_SHA256 = 'sha256'
HASHLIB_ALGORITHMS = (TYPE_MD5, TYPE_SHA, TYPE_SHA1, TYPE_SHA256)
CHECKSUM_FUNCTIONS = {
TYPE_MD5: hashlib.md5,
TYPE_SHA: hashlib.sha1,
TYPE_SHA1: hashlib.sha1,
TYPE_SHA256: hashlib.sha256,
}
class InvalidChecksumType(ValueError):
"""
Raised when the specified checksum isn't one of the supported TYPE_* constants.
"""
pass
class VerificationException(ValueError):
"""
Raised when the verification of a file fails.
"""
pass
def sanitize_checksum_type(checksum_type):
"""
Sanitize and validate the checksum type.
This function will always return the given checksum_type in lower case, unless it is sha, in
which case it will return "sha1". SHA and SHA-1 are the same algorithm, and so we prefer to use
"sha1", since it is a more specific name. For some unit types (such as RPM), this can cause
conflicts inside of Pulp when repos or uploads use a mix of sha and sha1. See
https://bugzilla.redhat.com/show_bug.cgi?id=1165355
This function also validates that the checksum_type is a recognized one from the list of known
hashing algorithms.
:param checksum_type: The checksum type we are sanitizing
:type checksum_type: basestring
:return: A sanitized checksum type, converting "sha" to "sha1", otherwise returning the given
checksum_type in lowercase.
:rtype: basestring
:raises PulpCodedException: if the checksum type is not recognized
"""
lowercase_checksum_type = checksum_type.lower()
if lowercase_checksum_type == "sha":
lowercase_checksum_type = "sha1"
if lowercase_checksum_type not in HASHLIB_ALGORITHMS:
raise PulpCodedException(error_code=error_codes.PLP1005, checksum_type=checksum_type)
return lowercase_checksum_type
def verify_size(file_object, expected_size):
"""
Returns whether or not the size of the contents of the given file-like object match
the expectation.
:param file_object: file-like object to verify
:param expected_size: size to verify the contents of file_object against
:type expected_size: int
:raises VerificationException: if the file did not pass the verification
"""
# Validate the size by seeking to the end to find the file size with tell()
file_object.seek(0, 2)
found_size = file_object.tell()
if found_size != expected_size:
raise VerificationException(found_size)
def verify_checksum(file_object, checksum_type, checksum_value):
"""
Returns whether or not the checksum of the contents of the given file-like object match
the expectation.
:param file_object: file-like object to verify
:type file_object: file-like object
:param checksum_type: type of checksum to calculate; must be one of the TYPE_* constants in
this module
:type checksum_type: str
:param checksum_value: expected checksum to verify against
:type checksum_value: str
:raises ValueError: if the checksum_type isn't one of the TYPE_* constants
"""
if checksum_type not in CHECKSUM_FUNCTIONS:
raise InvalidChecksumType('Unknown checksum type [%s]' % checksum_type)
hasher = CHECKSUM_FUNCTIONS[checksum_type]()
file_object.seek(0)
bits = file_object.read(VALIDATION_CHUNK_SIZE)
while bits:
hasher.update(bits)
bits = file_object.read(VALIDATION_CHUNK_SIZE)
if hasher.hexdigest() != checksum_value:
raise VerificationException(hasher.hexdigest())