Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
hhhrrrttt222111
GitHub Repository: hhhrrrttt222111/Dorkify
Path: blob/master/venv/Lib/site-packages/pip/_internal/utils/hashes.py
811 views
1
from __future__ import absolute_import
2
3
import hashlib
4
5
from pip._vendor.six import iteritems, iterkeys, itervalues
6
7
from pip._internal.exceptions import (
8
HashMismatch,
9
HashMissing,
10
InstallationError,
11
)
12
from pip._internal.utils.misc import read_chunks
13
from pip._internal.utils.typing import MYPY_CHECK_RUNNING
14
15
if MYPY_CHECK_RUNNING:
16
from typing import (
17
Dict, List, BinaryIO, NoReturn, Iterator
18
)
19
from pip._vendor.six import PY3
20
if PY3:
21
from hashlib import _Hash
22
else:
23
from hashlib import _hash as _Hash
24
25
26
# The recommended hash algo of the moment. Change this whenever the state of
27
# the art changes; it won't hurt backward compatibility.
28
FAVORITE_HASH = 'sha256'
29
30
31
# Names of hashlib algorithms allowed by the --hash option and ``pip hash``
32
# Currently, those are the ones at least as collision-resistant as sha256.
33
STRONG_HASHES = ['sha256', 'sha384', 'sha512']
34
35
36
class Hashes(object):
37
"""A wrapper that builds multiple hashes at once and checks them against
38
known-good values
39
40
"""
41
def __init__(self, hashes=None):
42
# type: (Dict[str, List[str]]) -> None
43
"""
44
:param hashes: A dict of algorithm names pointing to lists of allowed
45
hex digests
46
"""
47
self._allowed = {} if hashes is None else hashes
48
49
@property
50
def digest_count(self):
51
# type: () -> int
52
return sum(len(digests) for digests in self._allowed.values())
53
54
def is_hash_allowed(
55
self,
56
hash_name, # type: str
57
hex_digest, # type: str
58
):
59
# type: (...) -> bool
60
"""Return whether the given hex digest is allowed."""
61
return hex_digest in self._allowed.get(hash_name, [])
62
63
def check_against_chunks(self, chunks):
64
# type: (Iterator[bytes]) -> None
65
"""Check good hashes against ones built from iterable of chunks of
66
data.
67
68
Raise HashMismatch if none match.
69
70
"""
71
gots = {}
72
for hash_name in iterkeys(self._allowed):
73
try:
74
gots[hash_name] = hashlib.new(hash_name)
75
except (ValueError, TypeError):
76
raise InstallationError(
77
'Unknown hash name: {}'.format(hash_name)
78
)
79
80
for chunk in chunks:
81
for hash in itervalues(gots):
82
hash.update(chunk)
83
84
for hash_name, got in iteritems(gots):
85
if got.hexdigest() in self._allowed[hash_name]:
86
return
87
self._raise(gots)
88
89
def _raise(self, gots):
90
# type: (Dict[str, _Hash]) -> NoReturn
91
raise HashMismatch(self._allowed, gots)
92
93
def check_against_file(self, file):
94
# type: (BinaryIO) -> None
95
"""Check good hashes against a file-like object
96
97
Raise HashMismatch if none match.
98
99
"""
100
return self.check_against_chunks(read_chunks(file))
101
102
def check_against_path(self, path):
103
# type: (str) -> None
104
with open(path, 'rb') as file:
105
return self.check_against_file(file)
106
107
def __nonzero__(self):
108
# type: () -> bool
109
"""Return whether I know any known-good hashes."""
110
return bool(self._allowed)
111
112
def __bool__(self):
113
# type: () -> bool
114
return self.__nonzero__()
115
116
117
class MissingHashes(Hashes):
118
"""A workalike for Hashes used when we're missing a hash for a requirement
119
120
It computes the actual hash of the requirement and raises a HashMissing
121
exception showing it to the user.
122
123
"""
124
def __init__(self):
125
# type: () -> None
126
"""Don't offer the ``hashes`` kwarg."""
127
# Pass our favorite hash in to generate a "gotten hash". With the
128
# empty list, it will never match, so an error will always raise.
129
super(MissingHashes, self).__init__(hashes={FAVORITE_HASH: []})
130
131
def _raise(self, gots):
132
# type: (Dict[str, _Hash]) -> NoReturn
133
raise HashMissing(gots[FAVORITE_HASH].hexdigest())
134
135