浏览代码

Merge pull request #5201 from strager/import-to-key-file

allow key-import+BORG_KEY_FILE to create key files
TW 5 年之前
父节点
当前提交
8e846935a2
共有 5 个文件被更改,包括 61 次插入8 次删除
  1. 5 0
      docs/usage/key.rst
  2. 9 0
      src/borg/archiver.py
  3. 26 4
      src/borg/crypto/key.py
  4. 1 4
      src/borg/crypto/keymanager.py
  5. 20 0
      src/borg/testsuite/archiver.py

+ 5 - 0
docs/usage/key.rst

@@ -26,6 +26,11 @@ Examples
     Remember your passphrase. Your data will be inaccessible without it.
     Remember your passphrase. Your data will be inaccessible without it.
     Key updated
     Key updated
 
 
+    # Import a previously-exported key into the specified
+    # key file (creating or overwriting the output key)
+    # (keyfile repositories only)
+    $ BORG_KEY_FILE=/path/to/output-key borg key import /path/to/repo /path/to/exported
+
 Fully automated using environment variables:
 Fully automated using environment variables:
 
 
 ::
 ::

+ 9 - 0
src/borg/archiver.py

@@ -3869,6 +3869,15 @@ class Archiver:
         If the ``--paper`` option is given, the import will be an interactive
         If the ``--paper`` option is given, the import will be an interactive
         process in which each line is checked for plausibility before
         process in which each line is checked for plausibility before
         proceeding to the next line. For this format PATH must not be given.
         proceeding to the next line. For this format PATH must not be given.
+
+        For repositories using keyfile encryption, the key file which ``borg key
+        import`` writes to depends on several factors. If the ``BORG_KEY_FILE``
+        environment variable is set and non-empty, ``borg key import`` creates
+        or overwrites that file named by ``$BORG_KEY_FILE``. Otherwise, ``borg
+        key import`` searches in the ``$BORG_KEYS_DIR`` directory for a key file
+        associated with the repository. If a key file is found in
+        ``$BORG_KEYS_DIR``, ``borg key import`` overwrites it; otherwise, ``borg
+        key import`` creates a new key file in ``$BORG_KEYS_DIR``.
         """)
         """)
         subparser = key_parsers.add_parser('import', parents=[common_parser], add_help=False,
         subparser = key_parsers.add_parser('import', parents=[common_parser], add_help=False,
                                           description=self.do_key_import.__doc__,
                                           description=self.do_key_import.__doc__,

+ 26 - 4
src/borg/crypto/key.py

@@ -712,10 +712,25 @@ class KeyfileKey(ID_HMAC_SHA_256, KeyfileKeyBase):
             return filename
             return filename
 
 
     def find_key(self):
     def find_key(self):
+        keyfile = self._find_key_file_from_environment()
+        if keyfile is not None:
+            return self.sanity_check(keyfile, self.repository.id)
+        keyfile = self._find_key_in_keys_dir()
+        if keyfile is not None:
+            return keyfile
+        raise KeyfileNotFoundError(self.repository._location.canonical_path(), get_keys_dir())
+
+    def get_existing_or_new_target(self, args):
+        keyfile = self._find_key_file_from_environment()
+        if keyfile is not None:
+            return keyfile
+        keyfile = self._find_key_in_keys_dir()
+        if keyfile is not None:
+            return keyfile
+        return self._get_new_target_in_keys_dir(args)
+
+    def _find_key_in_keys_dir(self):
         id = self.repository.id
         id = self.repository.id
-        keyfile = os.environ.get('BORG_KEY_FILE')
-        if keyfile:
-            return self.sanity_check(os.path.abspath(keyfile), id)
         keys_dir = get_keys_dir()
         keys_dir = get_keys_dir()
         for name in os.listdir(keys_dir):
         for name in os.listdir(keys_dir):
             filename = os.path.join(keys_dir, name)
             filename = os.path.join(keys_dir, name)
@@ -723,12 +738,19 @@ class KeyfileKey(ID_HMAC_SHA_256, KeyfileKeyBase):
                 return self.sanity_check(filename, id)
                 return self.sanity_check(filename, id)
             except (KeyfileInvalidError, KeyfileMismatchError):
             except (KeyfileInvalidError, KeyfileMismatchError):
                 pass
                 pass
-        raise KeyfileNotFoundError(self.repository._location.canonical_path(), get_keys_dir())
 
 
     def get_new_target(self, args):
     def get_new_target(self, args):
+        keyfile = self._find_key_file_from_environment()
+        if keyfile is not None:
+            return keyfile
+        return self._get_new_target_in_keys_dir(args)
+
+    def _find_key_file_from_environment(self):
         keyfile = os.environ.get('BORG_KEY_FILE')
         keyfile = os.environ.get('BORG_KEY_FILE')
         if keyfile:
         if keyfile:
             return os.path.abspath(keyfile)
             return os.path.abspath(keyfile)
+
+    def _get_new_target_in_keys_dir(self, args):
         filename = args.location.to_key_filename()
         filename = args.location.to_key_filename()
         path = filename
         path = filename
         i = 1
         i = 1

+ 1 - 4
src/borg/crypto/keymanager.py

@@ -61,10 +61,7 @@ class KeyManager:
     def store_keyblob(self, args):
     def store_keyblob(self, args):
         if self.keyblob_storage == KeyBlobStorage.KEYFILE:
         if self.keyblob_storage == KeyBlobStorage.KEYFILE:
             k = KeyfileKey(self.repository)
             k = KeyfileKey(self.repository)
-            try:
-                target = k.find_key()
-            except KeyfileNotFoundError:
-                target = k.get_new_target(args)
+            target = k.get_existing_or_new_target(args)
 
 
             self.store_keyfile(target)
             self.store_keyfile(target)
         elif self.keyblob_storage == KeyBlobStorage.REPO:
         elif self.keyblob_storage == KeyBlobStorage.REPO:

+ 20 - 0
src/borg/testsuite/archiver.py

@@ -2821,6 +2821,26 @@ class ArchiverTestCase(ArchiverTestCaseBase):
 
 
         assert key_contents2 == key_contents
         assert key_contents2 == key_contents
 
 
+    def test_key_import_keyfile_with_borg_key_file(self):
+        self.cmd('init', self.repository_location, '--encryption', 'keyfile')
+
+        exported_key_file = os.path.join(self.output_path, 'exported')
+        self.cmd('key', 'export', self.repository_location, exported_key_file)
+
+        key_file = os.path.join(self.keys_path, os.listdir(self.keys_path)[0])
+        with open(key_file, 'r') as fd:
+            key_contents = fd.read()
+        os.unlink(key_file)
+
+        imported_key_file = os.path.join(self.output_path, 'imported')
+        with environment_variable(BORG_KEY_FILE=imported_key_file):
+            self.cmd('key', 'import', self.repository_location, exported_key_file)
+        assert not os.path.isfile(key_file), '"borg key import" should respect BORG_KEY_FILE'
+
+        with open(imported_key_file, 'r') as fd:
+            imported_key_contents = fd.read()
+        assert imported_key_contents == key_contents
+
     def test_key_export_repokey(self):
     def test_key_export_repokey(self):
         export_file = self.output_path + '/exported'
         export_file = self.output_path + '/exported'
         self.cmd('init', self.repository_location, '--encryption', 'repokey')
         self.cmd('init', self.repository_location, '--encryption', 'repokey')