Browse Source

key_cmds converted

bigtedde 1 year ago
parent
commit
3cccf19671
1 changed files with 259 additions and 227 deletions
  1. 259 227
      src/borg/testsuite/archiver/key_cmds.py

+ 259 - 227
src/borg/testsuite/archiver/key_cmds.py

@@ -1,5 +1,4 @@
 import os
-import unittest
 from binascii import unhexlify, b2a_base64, a2b_base64
 
 import pytest
@@ -13,294 +12,327 @@ from ...helpers import msgpack
 from ...repository import Repository
 from .. import environment_variable
 from .. import key
-from . import (
-    ArchiverTestCaseBase,
-    ArchiverTestCaseBinaryBase,
-    RemoteArchiverTestCaseBase,
-    RK_ENCRYPTION,
-    KF_ENCRYPTION,
-    BORG_EXES,
-)
-
-
-class ArchiverTestCase(ArchiverTestCaseBase):
-    def test_change_passphrase(self):
-        self.cmd(f"--repo={self.repository_location}", "rcreate", RK_ENCRYPTION)
-        os.environ["BORG_NEW_PASSPHRASE"] = "newpassphrase"
-        # here we have both BORG_PASSPHRASE and BORG_NEW_PASSPHRASE set:
-        self.cmd(f"--repo={self.repository_location}", "key", "change-passphrase")
-        os.environ["BORG_PASSPHRASE"] = "newpassphrase"
-        self.cmd(f"--repo={self.repository_location}", "rlist")
-
-    def test_change_location_to_keyfile(self):
-        self.cmd(f"--repo={self.repository_location}", "rcreate", RK_ENCRYPTION)
-        log = self.cmd(f"--repo={self.repository_location}", "rinfo")
-        assert "(repokey" in log
-        self.cmd(f"--repo={self.repository_location}", "key", "change-location", "keyfile")
-        log = self.cmd(f"--repo={self.repository_location}", "rinfo")
-        assert "(key file" in log
+from . import RK_ENCRYPTION, KF_ENCRYPTION, cmd, _extract_repository_id, _set_repository_id
 
-    def test_change_location_to_b2keyfile(self):
-        self.cmd(f"--repo={self.repository_location}", "rcreate", "--encryption=repokey-blake2-aes-ocb")
-        log = self.cmd(f"--repo={self.repository_location}", "rinfo")
-        assert "(repokey BLAKE2b" in log
-        self.cmd(f"--repo={self.repository_location}", "key", "change-location", "keyfile")
-        log = self.cmd(f"--repo={self.repository_location}", "rinfo")
-        assert "(key file BLAKE2b" in log
 
-    def test_change_location_to_repokey(self):
-        self.cmd(f"--repo={self.repository_location}", "rcreate", KF_ENCRYPTION)
-        log = self.cmd(f"--repo={self.repository_location}", "rinfo")
-        assert "(key file" in log
-        self.cmd(f"--repo={self.repository_location}", "key", "change-location", "repokey")
-        log = self.cmd(f"--repo={self.repository_location}", "rinfo")
-        assert "(repokey" in log
+def pytest_generate_tests(metafunc):
+    # Generate tests for different scenarios: local repository, remote repository, and using the borg binary.
+    if "archivers" in metafunc.fixturenames:
+        metafunc.parametrize("archivers", ["archiver", "remote_archiver", "binary_archiver"])
 
-    def test_change_location_to_b2repokey(self):
-        self.cmd(f"--repo={self.repository_location}", "rcreate", "--encryption=keyfile-blake2-aes-ocb")
-        log = self.cmd(f"--repo={self.repository_location}", "rinfo")
-        assert "(key file BLAKE2b" in log
-        self.cmd(f"--repo={self.repository_location}", "key", "change-location", "repokey")
-        log = self.cmd(f"--repo={self.repository_location}", "rinfo")
-        assert "(repokey BLAKE2b" in log
 
-    def test_key_export_keyfile(self):
-        export_file = self.output_path + "/exported"
-        self.cmd(f"--repo={self.repository_location}", "rcreate", KF_ENCRYPTION)
-        repo_id = self._extract_repository_id(self.repository_path)
-        self.cmd(f"--repo={self.repository_location}", "key", "export", export_file)
+def test_change_passphrase(archivers, request):
+    archiver = request.getfixturevalue(archivers)
+    repo_location = archiver.repository_location
+    cmd(archiver, f"--repo={repo_location}", "rcreate", RK_ENCRYPTION)
+    os.environ["BORG_NEW_PASSPHRASE"] = "newpassphrase"
+    # here we have both BORG_PASSPHRASE and BORG_NEW_PASSPHRASE set:
+    cmd(archiver, f"--repo={repo_location}", "key", "change-passphrase")
+    os.environ["BORG_PASSPHRASE"] = "newpassphrase"
+    cmd(archiver, f"--repo={repo_location}", "rlist")
 
-        with open(export_file) as fd:
-            export_contents = fd.read()
 
-        assert export_contents.startswith("BORG_KEY " + bin_to_hex(repo_id) + "\n")
+def test_change_location_to_keyfile(archivers, request):
+    archiver = request.getfixturevalue(archivers)
+    repo_location = archiver.repository_location
+    cmd(archiver, f"--repo={repo_location}", "rcreate", RK_ENCRYPTION)
+    log = cmd(archiver, f"--repo={repo_location}", "rinfo")
+    assert "(repokey" in log
+    cmd(archiver, f"--repo={repo_location}", "key", "change-location", "keyfile")
+    log = cmd(archiver, f"--repo={repo_location}", "rinfo")
+    assert "(key file" in log
 
-        key_file = self.keys_path + "/" + os.listdir(self.keys_path)[0]
 
-        with open(key_file) as fd:
-            key_contents = fd.read()
+def test_change_location_to_b2keyfile(archivers, request):
+    archiver = request.getfixturevalue(archivers)
+    repo_location = archiver.repository_location
+    cmd(archiver, f"--repo={repo_location}", "rcreate", "--encryption=repokey-blake2-aes-ocb")
+    log = cmd(archiver, f"--repo={repo_location}", "rinfo")
+    assert "(repokey BLAKE2b" in log
+    cmd(archiver, f"--repo={repo_location}", "key", "change-location", "keyfile")
+    log = cmd(archiver, f"--repo={repo_location}", "rinfo")
+    assert "(key file BLAKE2b" in log
 
-        assert key_contents == export_contents
 
-        os.unlink(key_file)
+def test_change_location_to_repokey(archivers, request):
+    archiver = request.getfixturevalue(archivers)
+    repo_location = archiver.repository_location
+    cmd(archiver, f"--repo={repo_location}", "rcreate", KF_ENCRYPTION)
+    log = cmd(archiver, f"--repo={repo_location}", "rinfo")
+    assert "(key file" in log
+    cmd(archiver, f"--repo={repo_location}", "key", "change-location", "repokey")
+    log = cmd(archiver, f"--repo={repo_location}", "rinfo")
+    assert "(repokey" in log
 
-        self.cmd(f"--repo={self.repository_location}", "key", "import", export_file)
 
-        with open(key_file) as fd:
-            key_contents2 = fd.read()
+def test_change_location_to_b2repokey(archivers, request):
+    archiver = request.getfixturevalue(archivers)
+    repo_location = archiver.repository_location
+    cmd(archiver, f"--repo={repo_location}", "rcreate", "--encryption=keyfile-blake2-aes-ocb")
+    log = cmd(archiver, f"--repo={repo_location}", "rinfo")
+    assert "(key file BLAKE2b" in log
+    cmd(archiver, f"--repo={repo_location}", "key", "change-location", "repokey")
+    log = cmd(archiver, f"--repo={repo_location}", "rinfo")
+    assert "(repokey BLAKE2b" in log
 
-        assert key_contents2 == key_contents
 
-    def test_key_import_keyfile_with_borg_key_file(self):
-        self.cmd(f"--repo={self.repository_location}", "rcreate", KF_ENCRYPTION)
+def test_key_export_keyfile(archivers, request):
+    archiver = request.getfixturevalue(archivers)
+    repo_location, repo_path, keys_path = archiver.repository_location, archiver.repository_path, archiver.keys_path
+    export_file = archiver.output_path + "/exported"
+    cmd(archiver, f"--repo={repo_location}", "rcreate", KF_ENCRYPTION)
+    repo_id = _extract_repository_id(repo_path)
+    cmd(archiver, f"--repo={repo_location}", "key", "export", export_file)
 
-        exported_key_file = os.path.join(self.output_path, "exported")
-        self.cmd(f"--repo={self.repository_location}", "key", "export", exported_key_file)
+    with open(export_file) as fd:
+        export_contents = fd.read()
 
-        key_file = os.path.join(self.keys_path, os.listdir(self.keys_path)[0])
-        with open(key_file) as fd:
-            key_contents = fd.read()
-        os.unlink(key_file)
+    assert export_contents.startswith("BORG_KEY " + bin_to_hex(repo_id) + "\n")
 
-        imported_key_file = os.path.join(self.output_path, "imported")
-        with environment_variable(BORG_KEY_FILE=imported_key_file):
-            self.cmd(f"--repo={self.repository_location}", "key", "import", exported_key_file)
-        assert not os.path.isfile(key_file), '"borg key import" should respect BORG_KEY_FILE'
+    key_file = keys_path + "/" + os.listdir(keys_path)[0]
 
-        with open(imported_key_file) as fd:
-            imported_key_contents = fd.read()
-        assert imported_key_contents == key_contents
+    with open(key_file) as fd:
+        key_contents = fd.read()
 
-    def test_key_export_repokey(self):
-        export_file = self.output_path + "/exported"
-        self.cmd(f"--repo={self.repository_location}", "rcreate", RK_ENCRYPTION)
-        repo_id = self._extract_repository_id(self.repository_path)
-        self.cmd(f"--repo={self.repository_location}", "key", "export", export_file)
+    assert key_contents == export_contents
 
-        with open(export_file) as fd:
-            export_contents = fd.read()
+    os.unlink(key_file)
 
-        assert export_contents.startswith("BORG_KEY " + bin_to_hex(repo_id) + "\n")
+    cmd(archiver, f"--repo={repo_location}", "key", "import", export_file)
 
-        with Repository(self.repository_path) as repository:
-            repo_key = AESOCBRepoKey(repository)
-            repo_key.load(None, Passphrase.env_passphrase())
+    with open(key_file) as fd:
+        key_contents2 = fd.read()
 
-        backup_key = AESOCBKeyfileKey(key.TestKey.MockRepository())
-        backup_key.load(export_file, Passphrase.env_passphrase())
+    assert key_contents2 == key_contents
 
-        assert repo_key.crypt_key == backup_key.crypt_key
 
-        with Repository(self.repository_path) as repository:
-            repository.save_key(b"")
+def test_key_import_keyfile_with_borg_key_file(archivers, request):
+    archiver = request.getfixturevalue(archivers)
+    repo_location, keys_path, output_path = archiver.repository_location, archiver.keys_path, archiver.output_path
+    cmd(archiver, f"--repo={repo_location}", "rcreate", KF_ENCRYPTION)
 
-        self.cmd(f"--repo={self.repository_location}", "key", "import", export_file)
+    exported_key_file = os.path.join(output_path, "exported")
+    cmd(archiver, f"--repo={repo_location}", "key", "export", exported_key_file)
 
-        with Repository(self.repository_path) as repository:
-            repo_key2 = AESOCBRepoKey(repository)
-            repo_key2.load(None, Passphrase.env_passphrase())
+    key_file = os.path.join(keys_path, os.listdir(keys_path)[0])
+    with open(key_file) as fd:
+        key_contents = fd.read()
+    os.unlink(key_file)
 
-        assert repo_key2.crypt_key == repo_key2.crypt_key
+    imported_key_file = os.path.join(output_path, "imported")
+    with environment_variable(BORG_KEY_FILE=imported_key_file):
+        cmd(archiver, f"--repo={repo_location}", "key", "import", exported_key_file)
+    assert not os.path.isfile(key_file), '"borg key import" should respect BORG_KEY_FILE'
 
-    def test_key_export_qr(self):
-        export_file = self.output_path + "/exported.html"
-        self.cmd(f"--repo={self.repository_location}", "rcreate", RK_ENCRYPTION)
-        repo_id = self._extract_repository_id(self.repository_path)
-        self.cmd(f"--repo={self.repository_location}", "key", "export", "--qr-html", export_file)
+    with open(imported_key_file) as fd:
+        imported_key_contents = fd.read()
+    assert imported_key_contents == key_contents
 
-        with open(export_file, encoding="utf-8") as fd:
-            export_contents = fd.read()
 
-        assert bin_to_hex(repo_id) in export_contents
-        assert export_contents.startswith("<!doctype html>")
-        assert export_contents.endswith("</html>\n")
+def test_key_export_repokey(archivers, request):
+    archiver = request.getfixturevalue(archivers)
+    repo_location, repo_path, output_path = archiver.repository_location, archiver.repository_path, archiver.output_path
+    export_file = output_path + "/exported"
+    cmd(archiver, f"--repo={repo_location}", "rcreate", RK_ENCRYPTION)
+    repo_id = _extract_repository_id(repo_path)
+    cmd(archiver, f"--repo={repo_location}", "key", "export", export_file)
 
-    def test_key_export_directory(self):
-        export_directory = self.output_path + "/exported"
-        os.mkdir(export_directory)
+    with open(export_file) as fd:
+        export_contents = fd.read()
 
-        self.cmd(f"--repo={self.repository_location}", "rcreate", RK_ENCRYPTION)
+    assert export_contents.startswith("BORG_KEY " + bin_to_hex(repo_id) + "\n")
 
-        self.cmd(f"--repo={self.repository_location}", "key", "export", export_directory, exit_code=EXIT_ERROR)
+    with Repository(repo_path) as repository:
+        repo_key = AESOCBRepoKey(repository)
+        repo_key.load(None, Passphrase.env_passphrase())
 
-    def test_key_export_qr_directory(self):
-        export_directory = self.output_path + "/exported"
-        os.mkdir(export_directory)
+    backup_key = AESOCBKeyfileKey(key.TestKey.MockRepository())
+    backup_key.load(export_file, Passphrase.env_passphrase())
 
-        self.cmd(f"--repo={self.repository_location}", "rcreate", RK_ENCRYPTION)
+    assert repo_key.crypt_key == backup_key.crypt_key
 
-        self.cmd(
-            f"--repo={self.repository_location}", "key", "export", "--qr-html", export_directory, exit_code=EXIT_ERROR
-        )
+    with Repository(repo_path) as repository:
+        repository.save_key(b"")
 
-    def test_key_import_errors(self):
-        export_file = self.output_path + "/exported"
-        self.cmd(f"--repo={self.repository_location}", "rcreate", KF_ENCRYPTION)
+    cmd(archiver, f"--repo={repo_location}", "key", "import", export_file)
 
-        self.cmd(f"--repo={self.repository_location}", "key", "import", export_file, exit_code=EXIT_ERROR)
+    with Repository(repo_path) as repository:
+        repo_key2 = AESOCBRepoKey(repository)
+        repo_key2.load(None, Passphrase.env_passphrase())
 
-        with open(export_file, "w") as fd:
-            fd.write("something not a key\n")
+    assert repo_key2.crypt_key == repo_key2.crypt_key
 
-        if self.FORK_DEFAULT:
-            self.cmd(f"--repo={self.repository_location}", "key", "import", export_file, exit_code=2)
-        else:
-            with pytest.raises(NotABorgKeyFile):
-                self.cmd(f"--repo={self.repository_location}", "key", "import", export_file)
 
-        with open(export_file, "w") as fd:
-            fd.write("BORG_KEY a0a0a0\n")
+def test_key_export_qr(archivers, request):
+    archiver = request.getfixturevalue(archivers)
+    repo_location, repo_path, output_path = archiver.repository_location, archiver.repository_path, archiver.output_path
+    export_file = output_path + "/exported.html"
+    cmd(archiver, f"--repo={repo_location}", "rcreate", RK_ENCRYPTION)
+    repo_id = _extract_repository_id(repo_path)
+    cmd(archiver, f"--repo={repo_location}", "key", "export", "--qr-html", export_file)
 
-        if self.FORK_DEFAULT:
-            self.cmd(f"--repo={self.repository_location}", "key", "import", export_file, exit_code=2)
-        else:
-            with pytest.raises(RepoIdMismatch):
-                self.cmd(f"--repo={self.repository_location}", "key", "import", export_file)
+    with open(export_file, encoding="utf-8") as fd:
+        export_contents = fd.read()
 
-    def test_key_export_paperkey(self):
-        repo_id = "e294423506da4e1ea76e8dcdf1a3919624ae3ae496fddf905610c351d3f09239"
+    assert bin_to_hex(repo_id) in export_contents
+    assert export_contents.startswith("<!doctype html>")
+    assert export_contents.endswith("</html>\n")
 
-        export_file = self.output_path + "/exported"
-        self.cmd(f"--repo={self.repository_location}", "rcreate", KF_ENCRYPTION)
-        self._set_repository_id(self.repository_path, unhexlify(repo_id))
 
-        key_file = self.keys_path + "/" + os.listdir(self.keys_path)[0]
+def test_key_export_directory(archivers, request):
+    archiver = request.getfixturevalue(archivers)
+    repo_location, output_path = archiver.repository_location, archiver.output_path
+    export_directory = output_path + "/exported"
+    os.mkdir(export_directory)
+    cmd(archiver, f"--repo={repo_location}", "rcreate", RK_ENCRYPTION)
+    cmd(archiver, f"--repo={repo_location}", "key", "export", export_directory, exit_code=EXIT_ERROR)
 
-        with open(key_file, "w") as fd:
-            fd.write(CHPOKeyfileKey.FILE_ID + " " + repo_id + "\n")
-            fd.write(b2a_base64(b"abcdefghijklmnopqrstu").decode())
 
-        self.cmd(f"--repo={self.repository_location}", "key", "export", "--paper", export_file)
+def test_key_export_qr_directory(archivers, request):
+    archiver = request.getfixturevalue(archivers)
+    repo_location, output_path = archiver.repository_location, archiver.output_path
+    export_directory = output_path + "/exported"
+    os.mkdir(export_directory)
+    cmd(archiver, f"--repo={repo_location}", "rcreate", RK_ENCRYPTION)
+    cmd(archiver, f"--repo={repo_location}", "key", "export", "--qr-html", export_directory, exit_code=EXIT_ERROR)
 
-        with open(export_file) as fd:
-            export_contents = fd.read()
 
-        assert (
-            export_contents
-            == """To restore key use borg key import --paper /path/to/repo
+def test_key_import_errors(archivers, request):
+    archiver = request.getfixturevalue(archivers)
+    repo_location, output_path = archiver.repository_location, archiver.output_path
+    export_file = output_path + "/exported"
+    cmd(archiver, f"--repo={repo_location}", "rcreate", KF_ENCRYPTION)
+
+    cmd(archiver, f"--repo={repo_location}", "key", "import", export_file, exit_code=EXIT_ERROR)
+
+    with open(export_file, "w") as fd:
+        fd.write("something not a key\n")
+
+    if archiver.FORK_DEFAULT:
+        cmd(archiver, f"--repo={repo_location}", "key", "import", export_file, exit_code=2)
+    else:
+        with pytest.raises(NotABorgKeyFile):
+            cmd(archiver, f"--repo={repo_location}", "key", "import", export_file)
+
+    with open(export_file, "w") as fd:
+        fd.write("BORG_KEY a0a0a0\n")
+
+    if archiver.FORK_DEFAULT:
+        cmd(archiver, f"--repo={repo_location}", "key", "import", export_file, exit_code=2)
+    else:
+        with pytest.raises(RepoIdMismatch):
+            cmd(archiver, f"--repo={repo_location}", "key", "import", export_file)
+
+
+def test_key_export_paperkey(archivers, request):
+    archiver = request.getfixturevalue(archivers)
+    repo_location, repo_path, output_path = archiver.repository_location, archiver.repository_path, archiver.output_path
+    repo_id = "e294423506da4e1ea76e8dcdf1a3919624ae3ae496fddf905610c351d3f09239"
+
+    export_file = output_path + "/exported"
+    cmd(archiver, f"--repo={repo_location}", "rcreate", KF_ENCRYPTION)
+    _set_repository_id(repo_path, unhexlify(repo_id))
+
+    key_file = archiver.keys_path + "/" + os.listdir(archiver.keys_path)[0]
+
+    with open(key_file, "w") as fd:
+        fd.write(CHPOKeyfileKey.FILE_ID + " " + repo_id + "\n")
+        fd.write(b2a_base64(b"abcdefghijklmnopqrstu").decode())
+
+    cmd(archiver, f"--repo={repo_location}", "key", "export", "--paper", export_file)
+
+    with open(export_file) as fd:
+        export_contents = fd.read()
+
+    assert (
+        export_contents
+        == """To restore key use borg key import --paper /path/to/repo
 
 BORG PAPER KEY v1
 id: 2 / e29442 3506da 4e1ea7 / 25f62a 5a3d41 - 02
  1: 616263 646566 676869 6a6b6c 6d6e6f 707172 - 6d
  2: 737475 - 88
 """
-        )
-
-    def test_key_import_paperkey(self):
-        repo_id = "e294423506da4e1ea76e8dcdf1a3919624ae3ae496fddf905610c351d3f09239"
-        self.cmd(f"--repo={self.repository_location}", "rcreate", KF_ENCRYPTION)
-        self._set_repository_id(self.repository_path, unhexlify(repo_id))
-
-        key_file = self.keys_path + "/" + os.listdir(self.keys_path)[0]
-        with open(key_file, "w") as fd:
-            fd.write(AESOCBKeyfileKey.FILE_ID + " " + repo_id + "\n")
-            fd.write(b2a_base64(b"abcdefghijklmnopqrstu").decode())
-
-        typed_input = (
-            b"2 / e29442 3506da 4e1ea7 / 25f62a 5a3d41  02\n"  # Forgot to type "-"
-            b"2 / e29442 3506da 4e1ea7  25f62a 5a3d41 - 02\n"  # Forgot to type second "/"
-            b"2 / e29442 3506da 4e1ea7 / 25f62a 5a3d42 - 02\n"  # Typo (..42 not ..41)
-            b"2 / e29442 3506da 4e1ea7 / 25f62a 5a3d41 - 02\n"  # Correct! Congratulations
-            b"616263 646566 676869 6a6b6c 6d6e6f 707172 - 6d\n"
-            b"\n\n"  # Abort [yN] => N
-            b"737475 88\n"  # missing "-"
-            b"73747i - 88\n"  # typo
-            b"73747 - 88\n"  # missing nibble
-            b"73 74 75  -  89\n"  # line checksum mismatch
-            b"00a1 - 88\n"  # line hash collision - overall hash mismatch, have to start over
-            b"2 / e29442 3506da 4e1ea7 / 25f62a 5a3d41 - 02\n"
-            b"616263 646566 676869 6a6b6c 6d6e6f 707172 - 6d\n"
-            b"73 74 75  -  88\n"
-        )
-
-        # In case that this has to change, here is a quick way to find a colliding line hash:
-        #
-        # from hashlib import sha256
-        # hash_fn = lambda x: sha256(b'\x00\x02' + x).hexdigest()[:2]
-        # for i in range(1000):
-        #     if hash_fn(i.to_bytes(2, byteorder='big')) == '88':  # 88 = line hash
-        #         print(i.to_bytes(2, 'big'))
-        #         break
-
-        self.cmd(f"--repo={self.repository_location}", "key", "import", "--paper", input=typed_input)
-
-        # Test abort paths
-        typed_input = b"\ny\n"
-        self.cmd(f"--repo={self.repository_location}", "key", "import", "--paper", input=typed_input)
-        typed_input = b"2 / e29442 3506da 4e1ea7 / 25f62a 5a3d41 - 02\n\ny\n"
-        self.cmd(f"--repo={self.repository_location}", "key", "import", "--paper", input=typed_input)
-
-    def test_init_defaults_to_argon2(self):
-        """https://github.com/borgbackup/borg/issues/747#issuecomment-1076160401"""
-        self.cmd(f"--repo={self.repository_location}", "rcreate", RK_ENCRYPTION)
-        with Repository(self.repository_path) as repository:
-            key = msgpack.unpackb(a2b_base64(repository.load_key()))
+    )
+
+
+def test_key_import_paperkey(archivers, request):
+    archiver = request.getfixturevalue(archivers)
+    repo_location, repo_path, keys_path = archiver.repository_location, archiver.repository_path, archiver.keys_path
+    repo_id = "e294423506da4e1ea76e8dcdf1a3919624ae3ae496fddf905610c351d3f09239"
+    cmd(archiver, f"--repo={repo_location}", "rcreate", KF_ENCRYPTION)
+    _set_repository_id(repo_path, unhexlify(repo_id))
+
+    key_file = keys_path + "/" + os.listdir(keys_path)[0]
+    with open(key_file, "w") as fd:
+        fd.write(AESOCBKeyfileKey.FILE_ID + " " + repo_id + "\n")
+        fd.write(b2a_base64(b"abcdefghijklmnopqrstu").decode())
+
+    typed_input = (
+        b"2 / e29442 3506da 4e1ea7 / 25f62a 5a3d41  02\n"  # Forgot to type "-"
+        b"2 / e29442 3506da 4e1ea7  25f62a 5a3d41 - 02\n"  # Forgot to type second "/"
+        b"2 / e29442 3506da 4e1ea7 / 25f62a 5a3d42 - 02\n"  # Typo (..42 not ..41)
+        b"2 / e29442 3506da 4e1ea7 / 25f62a 5a3d41 - 02\n"  # Correct! Congratulations
+        b"616263 646566 676869 6a6b6c 6d6e6f 707172 - 6d\n"
+        b"\n\n"  # Abort [yN] => N
+        b"737475 88\n"  # missing "-"
+        b"73747i - 88\n"  # typo
+        b"73747 - 88\n"  # missing nibble
+        b"73 74 75  -  89\n"  # line checksum mismatch
+        b"00a1 - 88\n"  # line hash collision - overall hash mismatch, have to start over
+        b"2 / e29442 3506da 4e1ea7 / 25f62a 5a3d41 - 02\n"
+        b"616263 646566 676869 6a6b6c 6d6e6f 707172 - 6d\n"
+        b"73 74 75  -  88\n"
+    )
+
+    # In case that this has to change, here is a quick way to find a colliding line hash:
+    #
+    # from hashlib import sha256
+    # hash_fn = lambda x: sha256(b'\x00\x02' + x).hexdigest()[:2]
+    # for i in range(1000):
+    #     if hash_fn(i.to_bytes(2, byteorder='big')) == '88':  # 88 = line hash
+    #         print(i.to_bytes(2, 'big'))
+    #         break
+
+    cmd(archiver, f"--repo={repo_location}", "key", "import", "--paper", input=typed_input)
+
+    # Test abort paths
+    typed_input = b"\ny\n"
+    cmd(archiver, f"--repo={repo_location}", "key", "import", "--paper", input=typed_input)
+    typed_input = b"2 / e29442 3506da 4e1ea7 / 25f62a 5a3d41 - 02\n\ny\n"
+    cmd(archiver, f"--repo={repo_location}", "key", "import", "--paper", input=typed_input)
+
+
+def test_init_defaults_to_argon2(archivers, request):
+    """https://github.com/borgbackup/borg/issues/747#issuecomment-1076160401"""
+    archiver = request.getfixturevalue(archivers)
+    repo_location, repo_path = archiver.repository_location, archiver.repository_path
+    cmd(archiver, f"--repo={repo_location}", "rcreate", RK_ENCRYPTION)
+    with Repository(repo_path) as repository:
+        key = msgpack.unpackb(a2b_base64(repository.load_key()))
         assert key["algorithm"] == "argon2 chacha20-poly1305"
 
-    def test_change_passphrase_does_not_change_algorithm_argon2(self):
-        self.cmd(f"--repo={self.repository_location}", "rcreate", RK_ENCRYPTION)
-        os.environ["BORG_NEW_PASSPHRASE"] = "newpassphrase"
 
-        self.cmd(f"--repo={self.repository_location}", "key", "change-passphrase")
+def test_change_passphrase_does_not_change_algorithm_argon2(archivers, request):
+    archiver = request.getfixturevalue(archivers)
+    repo_location, repo_path = archiver.repository_location, archiver.repository_path
 
-        with Repository(self.repository_path) as repository:
-            key = msgpack.unpackb(a2b_base64(repository.load_key()))
-            assert key["algorithm"] == "argon2 chacha20-poly1305"
+    cmd(archiver, f"--repo={repo_location}", "rcreate", RK_ENCRYPTION)
+    os.environ["BORG_NEW_PASSPHRASE"] = "newpassphrase"
+    cmd(archiver, f"--repo={repo_location}", "key", "change-passphrase")
 
-    def test_change_location_does_not_change_algorithm_argon2(self):
-        self.cmd(f"--repo={self.repository_location}", "rcreate", KF_ENCRYPTION)
-
-        self.cmd(f"--repo={self.repository_location}", "key", "change-location", "repokey")
-
-        with Repository(self.repository_path) as repository:
-            key = msgpack.unpackb(a2b_base64(repository.load_key()))
-            assert key["algorithm"] == "argon2 chacha20-poly1305"
+    with Repository(repo_path) as repository:
+        key = msgpack.unpackb(a2b_base64(repository.load_key()))
+        assert key["algorithm"] == "argon2 chacha20-poly1305"
 
 
-class RemoteArchiverTestCase(RemoteArchiverTestCaseBase, ArchiverTestCase):
-    """run the same tests, but with a remote repository"""
+def test_change_location_does_not_change_algorithm_argon2(archivers, request):
+    archiver = request.getfixturevalue(archivers)
+    repo_location, repo_path = archiver.repository_location, archiver.repository_path
 
+    cmd(archiver, f"--repo={repo_location}", "rcreate", KF_ENCRYPTION)
+    cmd(archiver, f"--repo={repo_location}", "key", "change-location", "repokey")
 
-@unittest.skipUnless("binary" in BORG_EXES, "no borg.exe available")
-class ArchiverTestCaseBinary(ArchiverTestCaseBinaryBase, ArchiverTestCase):
-    """runs the same tests, but via the borg binary"""
+    with Repository(repo_path) as repository:
+        key = msgpack.unpackb(a2b_base64(repository.load_key()))
+        assert key["algorithm"] == "argon2 chacha20-poly1305"