Skip to content

Commit 252663f

Browse files
committed
Extend handling of a new passphrases
Enable reading of a new passphrase not only from BORG_NEW_PASSPHRASE environement variable but also from a passcommandoor a file descriptor. If Passphrase.new() is called from FlexiKey.change_passphrase(), do not read a passphrase from regular sources (i.e. BORG_PASSPHRASE et al.) if it is available via one of the "new" ones (BORG_NEW_PASSPHRASE et al.). This makes it possible to change passphrases in fully non-interactive manner.
1 parent 5b01535 commit 252663f

File tree

2 files changed

+24
-15
lines changed

2 files changed

+24
-15
lines changed

src/borg/crypto/key.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -545,7 +545,7 @@ def _save(self, passphrase, algorithm):
545545

546546
def change_passphrase(self, passphrase=None):
547547
if passphrase is None:
548-
passphrase = Passphrase.new(allow_empty=True)
548+
passphrase = Passphrase.new(allow_empty=True, only_new=True)
549549
self.save(self.target, passphrase, algorithm=self._encrypted_key_algorithm)
550550

551551
@classmethod

src/borg/helpers/passphrase.py

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -47,21 +47,27 @@ def _env_passphrase(cls, env_var, default=None):
4747
return cls(passphrase)
4848

4949
@classmethod
50-
def env_passphrase(cls, default=None, other=False):
50+
def env_passphrase(cls, default=None, other=False, new=False):
51+
if other and new:
52+
raise ValueError("Only one of 'other' and 'new' may be true")
5153
env_var = "BORG_OTHER_PASSPHRASE" if other else "BORG_PASSPHRASE"
54+
env_var = "BORG_NEW_PASSPHRASE" if new else env_var
5255
passphrase = cls._env_passphrase(env_var, default)
5356
if passphrase is not None:
5457
return passphrase
55-
passphrase = cls.env_passcommand(other=other)
58+
passphrase = cls.env_passcommand(other=other, new=new)
5659
if passphrase is not None:
5760
return passphrase
58-
passphrase = cls.fd_passphrase(other=other)
61+
passphrase = cls.fd_passphrase(other=other, new=new)
5962
if passphrase is not None:
6063
return passphrase
6164

6265
@classmethod
63-
def env_passcommand(cls, default=None, other=False):
66+
def env_passcommand(cls, default=None, other=False, new=False):
67+
if other and new:
68+
raise ValueError("Only one of 'other' and 'new' may be true")
6469
env_var = "BORG_OTHER_PASSCOMMAND" if other else "BORG_PASSCOMMAND"
70+
env_var = "BORG_NEW_PASSCOMMAND" if other else env_var
6571
passcommand = os.environ.get(env_var, None)
6672
if passcommand is not None:
6773
# passcommand is a system command (not inside pyinstaller env)
@@ -73,8 +79,11 @@ def env_passcommand(cls, default=None, other=False):
7379
return cls(passphrase.rstrip("\n"))
7480

7581
@classmethod
76-
def fd_passphrase(cls, other=False):
82+
def fd_passphrase(cls, other=False, new=False):
83+
if other and new:
84+
raise ValueError("Only one of 'other' and 'new' may be true")
7785
env_var = "BORG_OTHER_PASSPHRASE_FD" if other else "BORG_PASSPHRASE_FD"
86+
env_var = "BORG_NEW_PASSPHRASE_FD" if new else env_var
7887
try:
7988
fd = int(os.environ.get(env_var))
8089
except (ValueError, TypeError):
@@ -83,10 +92,6 @@ def fd_passphrase(cls, other=False):
8392
passphrase = f.read()
8493
return cls(passphrase.rstrip("\n"))
8594

86-
@classmethod
87-
def env_new_passphrase(cls, default=None):
88-
return cls._env_passphrase("BORG_NEW_PASSPHRASE", default)
89-
9095
@classmethod
9196
def getpass(cls, prompt):
9297
try:
@@ -143,6 +148,9 @@ def fmt_var(env_var):
143148
{fmt_var("BORG_PASSPHRASE")}
144149
{fmt_var("BORG_PASSCOMMAND")}
145150
{fmt_var("BORG_PASSPHRASE_FD")}
151+
{fmt_var("BORG_NEW_PASSPHRASE")}
152+
{fmt_var("BORG_NEW_PASSCOMMAND")}
153+
{fmt_var("BORG_NEW_PASSPHRASE_FD")}
146154
{fmt_var("BORG_OTHER_PASSPHRASE")}
147155
{fmt_var("BORG_OTHER_PASSCOMMAND")}
148156
{fmt_var("BORG_OTHER_PASSPHRASE_FD")}
@@ -151,13 +159,14 @@ def fmt_var(env_var):
151159
print(passphrase_info, file=sys.stderr)
152160

153161
@classmethod
154-
def new(cls, allow_empty=False):
155-
passphrase = cls.env_new_passphrase()
156-
if passphrase is not None:
157-
return passphrase
158-
passphrase = cls.env_passphrase()
162+
def new(cls, allow_empty=False, only_new=False):
163+
passphrase = cls.env_passphrase(new=True)
159164
if passphrase is not None:
160165
return passphrase
166+
if not only_new:
167+
passphrase = cls.env_passphrase()
168+
if passphrase is not None:
169+
return passphrase
161170
for retry in range(1, 11):
162171
passphrase = cls.getpass("Enter new passphrase: ")
163172
if allow_empty or passphrase:

0 commit comments

Comments
 (0)