Pārlūkot izejas kodu

Merge pull request #8805 from ThomasWaldmann/check-ask-passphrase-early

check: ask for key passphrase early, fixes #1931
TW 1 mēnesi atpakaļ
vecāks
revīzija
9a61a86de3
2 mainītis faili ar 30 papildinājumiem un 17 dzēšanām
  1. 21 15
      src/borg/archive.py
  2. 9 2
      src/borg/archiver/check_cmd.py

+ 21 - 15
src/borg/archive.py

@@ -1659,6 +1659,7 @@ class RobustUnpacker:
 class ArchiveChecker:
     def __init__(self):
         self.error_found = False
+        self.key = None
 
     def check(
         self,
@@ -1696,7 +1697,8 @@ class ArchiveChecker:
         # Repository.check already did a full repository-level check and has built and cached a fresh chunkindex -
         # we can use that here, so we don't disable the caches (also no need to cache immediately, again):
         self.chunks = build_chunkindex_from_repo(self.repository, disable_caches=False, cache_immediately=False)
-        self.key = self.make_key(repository)
+        if self.key is None:
+            self.key = self.make_key(repository)
         self.repo_objs = RepoObj(self.key)
         if verify_data:
             self.verify_data()
@@ -1728,11 +1730,10 @@ class ArchiveChecker:
             logger.info("Archive consistency check complete, no problems found.")
         return self.repair or not self.error_found
 
-    def make_key(self, repository):
+    def make_key(self, repository, manifest_only=False):
         attempt = 0
 
         #  try the manifest first!
-        attempt += 1
         try:
             cdata = repository.get_manifest()
         except NoManifestError:
@@ -1744,19 +1745,24 @@ class ArchiveChecker:
                 # we get here, if the cdata we got has a corrupted key type byte
                 pass  # ignore it, just continue trying
 
-        for chunkid, _ in self.chunks.iteritems():
-            attempt += 1
-            if attempt > 999:
-                # we did a lot of attempts, but could not create the key via key_factory, give up.
-                break
-            cdata = repository.get(chunkid)
-            try:
-                return key_factory(repository, cdata)
-            except UnsupportedPayloadError:
-                # we get here, if the cdata we got has a corrupted key type byte
-                pass  # ignore it, just try the next chunk
+        if not manifest_only:
+            for chunkid, _ in self.chunks.iteritems():
+                attempt += 1
+                if attempt > 999:
+                    # we did a lot of attempts, but could not create the key via key_factory, give up.
+                    break
+                cdata = repository.get(chunkid)
+                try:
+                    return key_factory(repository, cdata)
+                except UnsupportedPayloadError:
+                    # we get here, if the cdata we got has a corrupted key type byte
+                    pass  # ignore it, just try the next chunk
+
         if attempt == 0:
-            msg = "make_key: repository has no chunks at all!"
+            if manifest_only:
+                msg = "make_key: failed to create the key (tried only the manifest)"
+            else:
+                msg = "make_key: repository has no chunks at all!"
         else:
             msg = "make_key: failed to create the key (tried %d chunks)" % attempt
         raise IntegrityError(msg)

+ 9 - 2
src/borg/archiver/check_cmd.py

@@ -2,7 +2,7 @@ import argparse
 from ._common import with_repository, Highlander
 from ..archive import ArchiveChecker
 from ..constants import *  # NOQA
-from ..helpers import set_ec, EXIT_WARNING, CancelledByUser, CommandError
+from ..helpers import set_ec, EXIT_WARNING, CancelledByUser, CommandError, IntegrityError
 from ..helpers import yes
 
 from ..logger import create_logger
@@ -44,10 +44,17 @@ class CheckMixIn:
             # archives check requires that a full repo check was done before and has built/cached a ChunkIndex.
             # also, there is no max_duration support in the archives check code anyway.
             raise CommandError("--repository-only is required for --max-duration support.")
+        if not args.repo_only:
+            # if we need the key later for the archives check, ask NOW for the passphrase! #1931
+            archive_checker = ArchiveChecker()
+            try:
+                archive_checker.key = archive_checker.make_key(repository, manifest_only=True)
+            except IntegrityError:
+                pass  # will try to make key later again
         if not args.archives_only:
             if not repository.check(repair=args.repair, max_duration=args.max_duration):
                 set_ec(EXIT_WARNING)
-        if not args.repo_only and not ArchiveChecker().check(
+        if not args.repo_only and not archive_checker.check(
             repository,
             verify_data=args.verify_data,
             repair=args.repair,