Răsfoiți Sursa

Merge pull request #2827 from milkey-mouse/backports7

Backports (7)
TW 8 ani în urmă
părinte
comite
68409aa10c
6 a modificat fișierele cu 91 adăugiri și 6 ștergeri
  1. 9 1
      borg/helpers.py
  2. 3 1
      borg/key.py
  3. 1 0
      borg/keymanager.py
  4. 48 3
      borg/testsuite/archiver.py
  5. 13 1
      borg/testsuite/xattr.py
  6. 17 0
      docs/installation.rst

+ 9 - 1
borg/helpers.py

@@ -183,8 +183,16 @@ def get_limited_unpacker(kind):
                          object_hook=StableDict,
                          object_hook=StableDict,
                          unicode_errors='surrogateescape',
                          unicode_errors='surrogateescape',
                          ))
                          ))
+    elif kind == 'key':
+        args.update(dict(use_list=True,  # default value
+                         max_array_len=0,  # not used
+                         max_map_len=10,  # EncryptedKey dict
+                         max_str_len=4000,  # inner key data
+                         object_hook=StableDict,
+                         unicode_errors='surrogateescape',
+                         ))
     else:
     else:
-        raise ValueError('kind must be "server", "client" or "manifest"')
+        raise ValueError('kind must be "server", "client", "manifest" or "key"')
     return msgpack.Unpacker(**args)
     return msgpack.Unpacker(**args)
 
 
 
 

+ 3 - 1
borg/key.py

@@ -481,7 +481,9 @@ class KeyfileKeyBase(AESKeyBase):
         return False
         return False
 
 
     def decrypt_key_file(self, data, passphrase):
     def decrypt_key_file(self, data, passphrase):
-        d = msgpack.unpackb(data)
+        unpacker = get_limited_unpacker('key')
+        unpacker.feed(data)
+        d = unpacker.unpack()
         assert d[b'version'] == 1
         assert d[b'version'] == 1
         assert d[b'algorithm'] == b'sha256'
         assert d[b'algorithm'] == b'sha256'
         key = passphrase.kdf(d[b'salt'], d[b'iterations'], 32)
         key = passphrase.kdf(d[b'salt'], d[b'iterations'], 32)

+ 1 - 0
borg/keymanager.py

@@ -172,6 +172,7 @@ class KeyManager:
                         (id_lines, id_repoid, id_complete_checksum) = data.split('/')
                         (id_lines, id_repoid, id_complete_checksum) = data.split('/')
                     except ValueError:
                     except ValueError:
                         print("the id line must contain exactly three '/', try again")
                         print("the id line must contain exactly three '/', try again")
+                        continue
                     if sha256_truncated(data.lower().encode('ascii'), 2) != checksum:
                     if sha256_truncated(data.lower().encode('ascii'), 2) != checksum:
                         print('line checksum did not match, try same line again')
                         print('line checksum did not match, try same line again')
                         continue
                         continue

+ 48 - 3
borg/testsuite/archiver.py

@@ -45,7 +45,7 @@ has_lchflags = hasattr(os, 'lchflags')
 src_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
 src_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
 
 
 
 
-def exec_cmd(*args, archiver=None, fork=False, exe=None, **kw):
+def exec_cmd(*args, archiver=None, fork=False, exe=None, input=b'', **kw):
     if fork:
     if fork:
         try:
         try:
             if exe is None:
             if exe is None:
@@ -54,7 +54,7 @@ def exec_cmd(*args, archiver=None, fork=False, exe=None, **kw):
                 borg = (exe, )
                 borg = (exe, )
             elif not isinstance(exe, tuple):
             elif not isinstance(exe, tuple):
                 raise ValueError('exe must be None, a tuple or a str')
                 raise ValueError('exe must be None, a tuple or a str')
-            output = subprocess.check_output(borg + args, stderr=subprocess.STDOUT)
+            output = subprocess.check_output(borg + args, stderr=subprocess.STDOUT, input=input)
             ret = 0
             ret = 0
         except subprocess.CalledProcessError as e:
         except subprocess.CalledProcessError as e:
             output = e.output
             output = e.output
@@ -63,7 +63,7 @@ def exec_cmd(*args, archiver=None, fork=False, exe=None, **kw):
     else:
     else:
         stdin, stdout, stderr = sys.stdin, sys.stdout, sys.stderr
         stdin, stdout, stderr = sys.stdin, sys.stdout, sys.stderr
         try:
         try:
-            sys.stdin = StringIO()
+            sys.stdin = StringIO(input.decode())
             sys.stdout = sys.stderr = output = StringIO()
             sys.stdout = sys.stderr = output = StringIO()
             if archiver is None:
             if archiver is None:
                 archiver = Archiver()
                 archiver = Archiver()
@@ -1502,6 +1502,51 @@ id: 2 / e29442 3506da 4e1ea7 / 25f62a 5a3d41 - 02
  2: 737475 - 88
  2: 737475 - 88
 """
 """
 
 
+    def test_key_import_paperkey(self):
+        repo_id = 'e294423506da4e1ea76e8dcdf1a3919624ae3ae496fddf905610c351d3f09239'
+        self.cmd('init', self.repository_location, '--encryption', 'keyfile')
+        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(KeyfileKey.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('key', 'import', '--paper', self.repository_location, input=typed_input)
+
+        # Test abort paths
+        typed_input = b'\ny\n'
+        self.cmd('key', 'import', '--paper', self.repository_location, input=typed_input)
+        typed_input = b'2 / e29442 3506da 4e1ea7 / 25f62a 5a3d41 - 02\n\ny\n'
+        self.cmd('key', 'import', '--paper', self.repository_location, input=typed_input)
+
 
 
 @unittest.skipUnless('binary' in BORG_EXES, 'no borg.exe available')
 @unittest.skipUnless('binary' in BORG_EXES, 'no borg.exe available')
 class ArchiverTestCaseBinary(ArchiverTestCase):
 class ArchiverTestCaseBinary(ArchiverTestCase):

+ 13 - 1
borg/testsuite/xattr.py

@@ -2,7 +2,9 @@ import os
 import tempfile
 import tempfile
 import unittest
 import unittest
 
 
-from ..xattr import is_enabled, getxattr, setxattr, listxattr, buffer
+import pytest
+
+from ..xattr import is_enabled, getxattr, setxattr, listxattr, buffer, split_lstring
 from . import BaseTestCase
 from . import BaseTestCase
 
 
 
 
@@ -58,3 +60,13 @@ class XattrTestCase(BaseTestCase):
         got_value = getxattr(self.tmpfile.name, 'user.big')
         got_value = getxattr(self.tmpfile.name, 'user.big')
         self.assert_equal(value, got_value)
         self.assert_equal(value, got_value)
         self.assert_equal(len(buffer), 128)
         self.assert_equal(len(buffer), 128)
+
+
+@pytest.mark.parametrize('lstring, splitted', (
+    (b'', []),
+    (b'\x00', [b'']),
+    (b'\x01a', [b'a']),
+    (b'\x01a\x02cd', [b'a', b'cd']),
+))
+def test_split_lstring(lstring, splitted):
+    assert split_lstring(lstring) == splitted

+ 17 - 0
docs/installation.rst

@@ -62,6 +62,9 @@ FreeBSD      `FreeBSD ports`_                              ``cd /usr/ports/archi
 Mageia       `cauldron`_                                   ``urpmi borgbackup``
 Mageia       `cauldron`_                                   ``urpmi borgbackup``
 NetBSD       `pkgsrc`_                                     ``pkg_add py-borgbackup``
 NetBSD       `pkgsrc`_                                     ``pkg_add py-borgbackup``
 NixOS        `.nix file`_                                  N/A
 NixOS        `.nix file`_                                  N/A
+OpenBSD      `OpenBSD ports`_                              ``pkg_add borgbackup``
+OpenIndiana  `OpenIndiana hipster repository`_             ``pkg install borg``
+openSUSE     `openSUSE official repository`_               ``zypper in borgbackup``
 OS X         `Brew cask`_                                  ``brew cask install borgbackup``
 OS X         `Brew cask`_                                  ``brew cask install borgbackup``
 Raspbian     `Raspbian testing`_                           ``apt install borgbackup``
 Raspbian     `Raspbian testing`_                           ``apt install borgbackup``
 Ubuntu       `Ubuntu packages`_, `Ubuntu PPA`_             ``apt install borgbackup``
 Ubuntu       `Ubuntu packages`_, `Ubuntu PPA`_             ``apt install borgbackup``
@@ -255,6 +258,20 @@ Install the dependencies with development headers::
     sudo dnf install gcc gcc-c++
     sudo dnf install gcc gcc-c++
     sudo dnf install fuse-devel fuse pkgconfig         # optional, for FUSE support
     sudo dnf install fuse-devel fuse pkgconfig         # optional, for FUSE support
 
 
+openSUSE Tumbleweed / Leap
+++++++++++++++++++++++++++
+
+Install the dependencies automatically using zypper::
+
+    sudo zypper source-install --build-deps-only borgbackup
+
+Alternatively, you can enumerate all build dependencies in the command line::
+
+    sudo zypper install python3 python3-devel \
+    libacl-devel liblz4-devel openssl-devel \
+    python3-Cython python3-Sphinx python3-msgpack-python \
+    python3-pytest python3-setuptools python3-setuptools_scm \
+    python3-sphinx_rtd_theme python3-llfuse gcc gcc-c++
 
 
 Mac OS X
 Mac OS X
 ++++++++
 ++++++++