diff --git a/docs/usage.rst b/docs/usage.rst index eab98cbec..912adf1f5 100644 --- a/docs/usage.rst +++ b/docs/usage.rst @@ -144,6 +144,13 @@ General: can either leave it away or abbreviate as `::`, if a positional parameter is required. BORG_PASSPHRASE When set, use the value to answer the passphrase question for encrypted repositories. + It is used when a passphrase is needed to access a encrypted repo as well as when a new + passphrase should be initially set when initializing an encrypted repo. + See also BORG_NEW_PASSPHRASE. + BORG_NEW_PASSPHRASE + When set, use the value to answer the passphrase question when a **new** passphrase is asked for. + This variable is checked first. If it is not set, BORG_PASSPHRASE will be checked also. + Main usecase for this is to fully automate ``borg change-passphrase``. BORG_DISPLAY_PASSPHRASE When set, use the value to answer the "display the passphrase for verification" question when defining a new passphrase for encrypted repositories. BORG_LOGGING_CONF @@ -649,6 +656,15 @@ Examples Remember your passphrase. Your data will be inaccessible without it. Key updated +Fully automated using environment variables: + +:: + + $ BORG_NEW_PASSPHRASE=old borg init repo + # now "old" is the current passphrase. + $ BORG_PASSPHRASE=old BORG_NEW_PASSPHRASE=new borg change-passphrase repo + # now "new" is the current passphrase. + .. include:: usage/serve.rst.inc diff --git a/src/borg/key.py b/src/borg/key.py index f5636ba38..eb9c7d941 100644 --- a/src/borg/key.py +++ b/src/borg/key.py @@ -247,11 +247,19 @@ class AESKeyBase(KeyBase): class Passphrase(str): @classmethod - def env_passphrase(cls, default=None): - passphrase = os.environ.get('BORG_PASSPHRASE', default) + def _env_passphrase(cls, env_var, default=None): + passphrase = os.environ.get(env_var, default) if passphrase is not None: return cls(passphrase) + @classmethod + def env_passphrase(cls, default=None): + return cls._env_passphrase('BORG_PASSPHRASE', default) + + @classmethod + def env_new_passphrase(cls, default=None): + return cls._env_passphrase('BORG_NEW_PASSPHRASE', default) + @classmethod def getpass(cls, prompt): return cls(getpass.getpass(prompt)) @@ -276,6 +284,9 @@ class Passphrase(str): @classmethod def new(cls, allow_empty=False): + passphrase = cls.env_new_passphrase() + if passphrase is not None: + return passphrase passphrase = cls.env_passphrase() if passphrase is not None: return passphrase diff --git a/src/borg/testsuite/archiver.py b/src/borg/testsuite/archiver.py index 39bc1e90a..6e8aa9c7a 100644 --- a/src/borg/testsuite/archiver.py +++ b/src/borg/testsuite/archiver.py @@ -1363,6 +1363,14 @@ class ArchiverTestCase(ArchiverTestCaseBase): size, csize = self._get_sizes('lzma', compressible=False) assert csize >= size + def test_change_passphrase(self): + self.cmd('init', self.repository_location) + os.environ['BORG_NEW_PASSPHRASE'] = 'newpassphrase' + # here we have both BORG_PASSPHRASE and BORG_NEW_PASSPHRASE set: + self.cmd('change-passphrase', self.repository_location) + os.environ['BORG_PASSPHRASE'] = 'newpassphrase' + self.cmd('list', self.repository_location) + def test_break_lock(self): self.cmd('init', self.repository_location) self.cmd('break-lock', self.repository_location)