Browse Source

Merge pull request #7583 from ThomasWaldmann/security-dir-in-data

put security infos into data dir, fixes #5760
TW 2 years ago
parent
commit
7a13a98f04

+ 16 - 7
docs/faq.rst

@@ -410,13 +410,6 @@ How important is the $HOME/.config/borg directory?
 
 
 The Borg config directory has content that you should take care of:
 The Borg config directory has content that you should take care of:
 
 
-``security`` subdirectory
-  Each directory here represents one Borg repository by its ID and contains the last known status.
-  If a repository's status is different from this information at the beginning of BorgBackup
-  operation, Borg outputs warning messages and asks for confirmation, so make sure you do not lose
-  or manipulate these files. However, apart from those warnings, a loss of these files can be
-  recovered.
-
 ``keys`` subdirectory
 ``keys`` subdirectory
   All your borg keyfile keys are stored in this directory. Please note that
   All your borg keyfile keys are stored in this directory. Please note that
   borg repokey keys are stored inside the repository. You MUST make sure to have an
   borg repokey keys are stored inside the repository. You MUST make sure to have an
@@ -426,6 +419,22 @@ The Borg config directory has content that you should take care of:
 
 
 Make sure that only you have access to the Borg config directory.
 Make sure that only you have access to the Borg config directory.
 
 
+.. _home_data_borg:
+
+How important is the $HOME/.local/share/borg directory?
+-------------------------------------------------------
+
+The Borg data directory has content that you should take care of:
+
+``security`` subdirectory
+  Each directory here represents one Borg repository by its ID and contains the last known status.
+  If a repository's status is different from this information at the beginning of BorgBackup
+  operation, Borg outputs warning messages and asks for confirmation, so make sure you do not lose
+  or manipulate these files. However, apart from those warnings, a loss of these files can be
+  recovered.
+
+Make sure that only you have access to the Borg data directory.
+
 .. _cache_security:
 .. _cache_security:
 
 
 Do I need to take security precautions regarding the cache?
 Do I need to take security precautions regarding the cache?

+ 7 - 3
docs/usage/general/environment.rst.inc

@@ -145,10 +145,14 @@ Directories and files:
         `XDG env var`_ ``XDG_CONFIG_HOME`` is set, then ``$XDG_CONFIG_HOME/borg`` is being used instead.
         `XDG env var`_ ``XDG_CONFIG_HOME`` is set, then ``$XDG_CONFIG_HOME/borg`` is being used instead.
         This directory contains all borg configuration directories, see the FAQ
         This directory contains all borg configuration directories, see the FAQ
         for a security advisory about the data in this directory: :ref:`home_config_borg`
         for a security advisory about the data in this directory: :ref:`home_config_borg`
+    BORG_DATA_DIR
+        Defaults to ``$BORG_BASE_DIR/.local/share/borg``. If ``BORG_BASE_DIR`` is not explicitly set while
+        `XDG env var`_ ``XDG_DATA_HOME`` is set, then ``$XDG_DATA_HOME/borg`` is being used instead.
+        This directory contains all borg data directories, see the FAQ
+        for a security advisory about the data in this directory: :ref:`home_data_borg`
     BORG_SECURITY_DIR
     BORG_SECURITY_DIR
-        Defaults to ``$BORG_CONFIG_DIR/security``.
-        This directory contains information borg uses to track its usage of NONCES ("numbers used
-        once" - usually in encryption context) and other security relevant data.
+        Defaults to ``$BORG_DATA_DIR/security``.
+        This directory contains security relevant data.
     BORG_KEYS_DIR
     BORG_KEYS_DIR
         Defaults to ``$BORG_CONFIG_DIR/keys``.
         Defaults to ``$BORG_CONFIG_DIR/keys``.
         This directory contains keys for encrypted repositories.
         This directory contains keys for encrypted repositories.

+ 2 - 2
src/borg/cache.py

@@ -62,7 +62,7 @@ class SecurityManager:
 
 
     def __init__(self, repository):
     def __init__(self, repository):
         self.repository = repository
         self.repository = repository
-        self.dir = get_security_dir(repository.id_str)
+        self.dir = get_security_dir(repository.id_str, legacy=(repository.version == 1))
         self.cache_dir = cache_dir(repository)
         self.cache_dir = cache_dir(repository)
         self.key_type_file = os.path.join(self.dir, "key-type")
         self.key_type_file = os.path.join(self.dir, "key-type")
         self.location_file = os.path.join(self.dir, "location")
         self.location_file = os.path.join(self.dir, "location")
@@ -71,7 +71,7 @@ class SecurityManager:
     @staticmethod
     @staticmethod
     def destroy(repository, path=None):
     def destroy(repository, path=None):
         """destroy the security dir for ``repository`` or at ``path``"""
         """destroy the security dir for ``repository`` or at ``path``"""
-        path = path or get_security_dir(repository.id_str)
+        path = path or get_security_dir(repository.id_str, legacy=(repository.version == 1))
         if os.path.exists(path):
         if os.path.exists(path):
             shutil.rmtree(path)
             shutil.rmtree(path)
 
 

+ 1 - 1
src/borg/crypto/key.py

@@ -114,7 +114,7 @@ def key_factory(repository, manifest_chunk, *, ro_cls=RepoObj):
 
 
 
 
 def tam_required_file(repository):
 def tam_required_file(repository):
-    security_dir = get_security_dir(bin_to_hex(repository.id))
+    security_dir = get_security_dir(bin_to_hex(repository.id), legacy=(repository.version == 1))
     return os.path.join(security_dir, "tam_required")
     return os.path.join(security_dir, "tam_required")
 
 
 
 

+ 14 - 1
src/borg/helpers/fs.py

@@ -85,14 +85,27 @@ def get_security_dir(repository_id=None, *, legacy=False):
     """Determine where to store local security information."""
     """Determine where to store local security information."""
     security_dir = os.environ.get("BORG_SECURITY_DIR")
     security_dir = os.environ.get("BORG_SECURITY_DIR")
     if security_dir is None:
     if security_dir is None:
+        get_dir = get_config_dir if legacy else get_data_dir
         # note: do not just give this as default to the environment.get(), see issue #5979.
         # note: do not just give this as default to the environment.get(), see issue #5979.
-        security_dir = os.path.join(get_config_dir(legacy=legacy), "security")
+        security_dir = os.path.join(get_dir(legacy=legacy), "security")
     if repository_id:
     if repository_id:
         security_dir = os.path.join(security_dir, repository_id)
         security_dir = os.path.join(security_dir, repository_id)
     ensure_dir(security_dir)
     ensure_dir(security_dir)
     return security_dir
     return security_dir
 
 
 
 
+def get_data_dir(*, legacy=False):
+    """Determine where to store borg changing data on the client"""
+    assert legacy is False, "there is no legacy variant of the borg data dir"
+    data_dir = os.environ.get(
+        "BORG_DATA_DIR", join_base_dir(".local", "share", "borg", legacy=legacy) or platformdirs.user_data_dir("borg")
+    )
+
+    # Create path if it doesn't exist yet
+    ensure_dir(data_dir)
+    return data_dir
+
+
 def get_cache_dir(*, legacy=False):
 def get_cache_dir(*, legacy=False):
     """Determine where to repository keys and cache"""
     """Determine where to repository keys and cache"""
 
 

+ 6 - 4
src/borg/testsuite/helpers.py

@@ -740,11 +740,13 @@ def test_get_security_dir(monkeypatch):
         monkeypatch.setenv("BORG_SECURITY_DIR", "/var/tmp")
         monkeypatch.setenv("BORG_SECURITY_DIR", "/var/tmp")
         assert get_security_dir() == "/var/tmp"
         assert get_security_dir() == "/var/tmp"
     else:
     else:
-        monkeypatch.delenv("XDG_CONFIG_HOME", raising=False)
+        monkeypatch.delenv("XDG_DATA_HOME", raising=False)
         monkeypatch.delenv("BORG_SECURITY_DIR", raising=False)
         monkeypatch.delenv("BORG_SECURITY_DIR", raising=False)
-        assert get_security_dir() == os.path.join(home_dir, ".config", "borg", "security")
-        assert get_security_dir(repository_id="1234") == os.path.join(home_dir, ".config", "borg", "security", "1234")
-        monkeypatch.setenv("XDG_CONFIG_HOME", "/var/tmp/.config")
+        assert get_security_dir() == os.path.join(home_dir, ".local", "share", "borg", "security")
+        assert get_security_dir(repository_id="1234") == os.path.join(
+            home_dir, ".local", "share", "borg", "security", "1234"
+        )
+        monkeypatch.setenv("XDG_DATA_HOME", "/var/tmp/.config")
         assert get_security_dir() == os.path.join("/var/tmp/.config", "borg", "security")
         assert get_security_dir() == os.path.join("/var/tmp/.config", "borg", "security")
         monkeypatch.setenv("BORG_SECURITY_DIR", "/var/tmp")
         monkeypatch.setenv("BORG_SECURITY_DIR", "/var/tmp")
         assert get_security_dir() == "/var/tmp"
         assert get_security_dir() == "/var/tmp"

+ 1 - 0
src/borg/testsuite/key.py

@@ -115,6 +115,7 @@ class TestKey:
         _location = _Location()
         _location = _Location()
         id = bytes(32)
         id = bytes(32)
         id_str = bin_to_hex(id)
         id_str = bin_to_hex(id)
+        version = 2
 
 
         def save_key(self, data):
         def save_key(self, data):
             self.key_data = data
             self.key_data = data