|
51 | 51 | from pip._internal.pep425tags import Pep425Tag
|
52 | 52 | from pip._internal.req import InstallRequirement
|
53 | 53 | from pip._internal.download import PipSession
|
| 54 | + from pip._internal.utils import Hashes |
54 | 55 |
|
55 | 56 | SecureOrigin = Tuple[str, str, Optional[str]]
|
56 | 57 | BuildTag = Tuple[Any, ...] # either empty tuple or Tuple[int, str]
|
@@ -386,12 +387,28 @@ def iter_applicable(self):
|
386 | 387 | # Again, converting version to str to deal with debundling.
|
387 | 388 | return (c for c in self.iter_all() if str(c.version) in self._versions)
|
388 | 389 |
|
389 |
| - def get_best(self): |
390 |
| - # type: () -> Optional[InstallationCandidate] |
| 390 | + def get_best(self, hashes=None): |
| 391 | + # type: (Optional[Hashes]) -> Optional[InstallationCandidate] |
391 | 392 | """Return the best candidate available, or None if no applicable
|
392 | 393 | candidates are found.
|
393 | 394 | """
|
394 | 395 | candidates = list(self.iter_applicable())
|
| 396 | + if hashes: |
| 397 | + # If we are in hash-checking mode, filter out candidates that will |
| 398 | + # fail the hash check. This prevents HashMismatch errors when a new |
| 399 | + # distribution is uploaded for an old release. |
| 400 | + def test_against_hashes(candidate): |
| 401 | + link = candidate.location |
| 402 | + is_match = hashes.test_against_hash(link.hash_name, link.hash) |
| 403 | + if not is_match: |
| 404 | + logger.warning( |
| 405 | + "candidate %s ignored: hash %s:%s not among provided " |
| 406 | + "hashes", |
| 407 | + link.filename, link.hash_name, link.hash, |
| 408 | + ) |
| 409 | + return is_match |
| 410 | + |
| 411 | + candidates = [c for c in candidates if test_against_hashes(c)] |
395 | 412 | return self._evaluator.get_best_candidate(candidates)
|
396 | 413 |
|
397 | 414 |
|
@@ -764,7 +781,9 @@ def find_requirement(self, req, upgrade):
|
764 | 781 | Raises DistributionNotFound or BestVersionAlreadyInstalled otherwise
|
765 | 782 | """
|
766 | 783 | candidates = self.find_candidates(req.name, req.specifier)
|
767 |
| - best_candidate = candidates.get_best() |
| 784 | + # Get any hashes supplied by the user to filter candidates. |
| 785 | + hashes = req.hashes(trust_internet=False) |
| 786 | + best_candidate = candidates.get_best(hashes) |
768 | 787 |
|
769 | 788 | installed_version = None # type: Optional[_BaseVersion]
|
770 | 789 | if req.satisfied_by is not None:
|
|
0 commit comments