瀏覽代碼

Added BORG_PASSCOMMAND environment variable (#2573)

(cherry picked from commit 578b76af3ab5ed09dfb8bfc4bd581b2be849a129)
TuXicc 8 年之前
父節點
當前提交
8c1da1adda
共有 4 個文件被更改,包括 45 次插入8 次删除
  1. 27 3
      borg/key.py
  2. 5 5
      docs/faq.rst
  3. 5 0
      docs/quickstart.rst
  4. 8 0
      docs/usage.rst

+ 27 - 3
borg/key.py

@@ -2,6 +2,7 @@ from binascii import hexlify, a2b_base64, b2a_base64
 import configparser
 import configparser
 import getpass
 import getpass
 import os
 import os
+import subprocess
 import sys
 import sys
 import textwrap
 import textwrap
 from hmac import HMAC, compare_digest
 from hmac import HMAC, compare_digest
@@ -23,7 +24,11 @@ PREFIX = b'\0' * 8
 
 
 
 
 class PassphraseWrong(Error):
 class PassphraseWrong(Error):
-    """passphrase supplied in BORG_PASSPHRASE is incorrect"""
+    """passphrase supplied in BORG_PASSPHRASE or by BORG_PASSCOMMAND is incorrect."""
+
+
+class PasscommandFailure(Error):
+    """passcommand supplied in BORG_PASSCOMMAND failed: {}"""
 
 
 
 
 class PasswordRetriesExceeded(Error):
 class PasswordRetriesExceeded(Error):
@@ -303,11 +308,30 @@ class AESKeyBase(KeyBase):
 
 
 class Passphrase(str):
 class Passphrase(str):
     @classmethod
     @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:
         if passphrase is not None:
             return cls(passphrase)
             return cls(passphrase)
 
 
+    @classmethod
+    def env_passphrase(cls, default=None):
+        passphrase = cls._env_passphrase('BORG_PASSPHRASE', default)
+        if passphrase is not None:
+            return passphrase
+        passphrase = cls.env_passcommand()
+        if passphrase is not None:
+            return passphrase
+
+    @classmethod
+    def env_passcommand(cls, default=None):
+        passcommand = os.environ.get('BORG_PASSCOMMAND', None)
+        if passcommand is not None:
+            try:
+                passphrase = subprocess.check_output(passcommand.split(), universal_newlines=True)
+            except (subprocess.CalledProcessError, FileNotFoundError) as e:
+                raise PasscommandFailure(e)
+            return cls(passphrase.rstrip('\n'))
+
     @classmethod
     @classmethod
     def getpass(cls, prompt):
     def getpass(cls, prompt):
         return cls(getpass.getpass(prompt))
         return cls(getpass.getpass(prompt))

+ 5 - 5
docs/faq.rst

@@ -123,11 +123,11 @@ none.
 How can I specify the encryption passphrase programmatically?
 How can I specify the encryption passphrase programmatically?
 -------------------------------------------------------------
 -------------------------------------------------------------
 
 
-The encryption passphrase can be specified programmatically using the
-`BORG_PASSPHRASE` environment variable. This is convenient when setting up
-automated encrypted backups. Another option is to use
-key file based encryption with a blank passphrase. See
-:ref:`encrypted_repos` for more details.
+The encryption passphrase or a command to retrieve the passphrase can be
+specified programmatically using the `BORG_PASSPHRASE` or `BORG_PASSCOMMAND`
+environment variables. This is convenient when setting up automated encrypted
+backups. Another option is to use key file based encryption with a blank passphrase.
+See :ref:`encrypted_repos` for more details.
 
 
 .. _password_env:
 .. _password_env:
 .. note:: Be careful how you set the environment; using the ``env``
 .. note:: Be careful how you set the environment; using the ``env``

+ 5 - 0
docs/quickstart.rst

@@ -112,6 +112,11 @@ certain number of old archives::
     #!/bin/sh
     #!/bin/sh
     REPOSITORY=username@remoteserver.com:backup
     REPOSITORY=username@remoteserver.com:backup
 
 
+    # Setting this, so you won't be asked for your repository passphrase:
+    export BORG_PASSPHRASE='XYZl0ngandsecurepa_55_phrasea&&123'
+    # or this to ask an external program to supply the passphrase:
+    export BORG_PASSCOMMAND='pass show backup'
+
     # Backup all of /home and /var/www except a few
     # Backup all of /home and /var/www except a few
     # excluded directories
     # excluded directories
     borg create -v --stats                          \
     borg create -v --stats                          \

+ 8 - 0
docs/usage.rst

@@ -147,6 +147,14 @@ General:
         can either leave it away or abbreviate as `::`, if a positional parameter is required.
         can either leave it away or abbreviate as `::`, if a positional parameter is required.
     BORG_PASSPHRASE
     BORG_PASSPHRASE
         When set, use the value to answer the passphrase question for encrypted repositories.
         When set, use the value to answer the passphrase question for encrypted repositories.
+        It is used when a passphrase is needed to access an encrypted repo as well as when a new
+        passphrase should be initially set when initializing an encrypted repo.
+    BORG_PASSCOMMAND
+        When set, use the standard output of the command (trailing newlines are stripped) to answer the
+        passphrase question for encrypted repositories.
+        It is used when a passphrase is needed to access an encrypted repo as well as when a new
+        passphrase should be initially set when initializing an encrypted repo.
+        If BORG_PASSPHRASE is also set, it takes precedence.
     BORG_DISPLAY_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.
         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
     BORG_LOGGING_CONF