mirror of
https://github.com/borgbackup/borg.git
synced 2026-02-20 00:10:35 -05:00
Improve handling when defining a passphrase or debugging passphrase issues, fixes #8496 Setting `BORG_DEBUG_PASSPHRASE=YES` enables passphrase debug logging to stderr, showing passphrase, hex utf-8 byte sequence and related env vars if a wrong passphrase was encountered. Setting `BORG_DISPLAY_PASSHRASE=YES` now always shows passphrase and its hex utf-8 byte sequence.
This commit is contained in:
parent
5b141e2077
commit
40df2f3c49
3 changed files with 75 additions and 14 deletions
|
|
@ -371,10 +371,12 @@ class FlexiKey:
|
|||
passphrase = Passphrase.getpass(prompt)
|
||||
if key.load(target, passphrase):
|
||||
break
|
||||
Passphrase.display_debug_info(passphrase)
|
||||
else:
|
||||
raise PasswordRetriesExceeded
|
||||
else:
|
||||
if not key.load(target, passphrase):
|
||||
Passphrase.display_debug_info(passphrase)
|
||||
raise PassphraseWrong
|
||||
key.init_ciphers(manifest_data)
|
||||
key._passphrase = passphrase
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import os
|
|||
import shlex
|
||||
import subprocess
|
||||
import sys
|
||||
import textwrap
|
||||
|
||||
from . import bin_to_hex
|
||||
from . import Error
|
||||
|
|
@ -109,20 +110,39 @@ class Passphrase(str):
|
|||
retry=True,
|
||||
env_var_override="BORG_DISPLAY_PASSPHRASE",
|
||||
):
|
||||
print('Your passphrase (between double-quotes): "%s"' % passphrase, file=sys.stderr)
|
||||
print("Make sure the passphrase displayed above is exactly what you wanted.", file=sys.stderr)
|
||||
try:
|
||||
passphrase.encode("ascii")
|
||||
except UnicodeEncodeError:
|
||||
print(
|
||||
"Your passphrase (UTF-8 encoding in hex): %s" % bin_to_hex(passphrase.encode("utf-8")),
|
||||
file=sys.stderr,
|
||||
)
|
||||
print(
|
||||
"As you have a non-ASCII passphrase, it is recommended to keep the "
|
||||
"UTF-8 encoding in hex together with the passphrase at a safe place.",
|
||||
file=sys.stderr,
|
||||
)
|
||||
pw_msg = textwrap.dedent(
|
||||
f"""\
|
||||
Your passphrase (between double-quotes): "{passphrase}"
|
||||
Make sure the passphrase displayed above is exactly what you wanted.
|
||||
Your passphrase (UTF-8 encoding in hex): {bin_to_hex(passphrase.encode("utf-8"))}
|
||||
It is recommended to keep the UTF-8 encoding in hex together with the passphrase at a safe place.
|
||||
In case you should ever run into passphrase issues, it could sometimes help debugging them.
|
||||
"""
|
||||
)
|
||||
print(pw_msg, file=sys.stderr)
|
||||
|
||||
@staticmethod
|
||||
def display_debug_info(passphrase):
|
||||
def fmt_var(env_var):
|
||||
env_var_value = os.environ.get(env_var)
|
||||
if env_var_value is not None:
|
||||
return f'{env_var} = "{env_var_value}"'
|
||||
else:
|
||||
return f"# {env_var} is not set"
|
||||
|
||||
if os.environ.get("BORG_DEBUG_PASSPHRASE") == "YES":
|
||||
passphrase_info = textwrap.dedent(
|
||||
f"""\
|
||||
Incorrect passphrase!
|
||||
Passphrase used (between double-quotes): "{passphrase}"
|
||||
Same, UTF-8 encoded, in hex: {bin_to_hex(passphrase.encode('utf-8'))}
|
||||
Relevant Environment Variables:
|
||||
{fmt_var("BORG_PASSPHRASE")}
|
||||
{fmt_var("BORG_PASSCOMMAND")}
|
||||
{fmt_var("BORG_PASSPHRASE_FD")}
|
||||
"""
|
||||
)
|
||||
print(passphrase_info, file=sys.stderr)
|
||||
|
||||
@classmethod
|
||||
def new(cls, allow_empty=False):
|
||||
|
|
|
|||
|
|
@ -1408,6 +1408,45 @@ class TestPassphrase:
|
|||
def test_passphrase_repr(self):
|
||||
assert "secret" not in repr(Passphrase("secret"))
|
||||
|
||||
def test_passphrase_wrong_debug(self, capsys, monkeypatch):
|
||||
passphrase = "wrong_passphrase"
|
||||
monkeypatch.setenv("BORG_DEBUG_PASSPHRASE", "YES")
|
||||
monkeypatch.setenv("BORG_PASSPHRASE", "env_passphrase")
|
||||
monkeypatch.setenv("BORG_PASSCOMMAND", "command")
|
||||
monkeypatch.setenv("BORG_PASSPHRASE_FD", "fd_value")
|
||||
|
||||
Passphrase.display_debug_info(passphrase)
|
||||
|
||||
out, err = capsys.readouterr()
|
||||
assert "Incorrect passphrase!" in err
|
||||
assert passphrase in err
|
||||
assert bin_to_hex(passphrase.encode("utf-8")) in err
|
||||
assert 'BORG_PASSPHRASE = "env_passphrase"' in err
|
||||
assert 'BORG_PASSCOMMAND = "command"' in err
|
||||
assert 'BORG_PASSPHRASE_FD = "fd_value"' in err
|
||||
|
||||
monkeypatch.delenv("BORG_DEBUG_PASSPHRASE", raising=False)
|
||||
Passphrase.display_debug_info(passphrase)
|
||||
out, err = capsys.readouterr()
|
||||
|
||||
assert "Incorrect passphrase!" not in err
|
||||
assert passphrase not in err
|
||||
|
||||
def test_verification(self, capsys, monkeypatch):
|
||||
passphrase = "test_passphrase"
|
||||
hex_value = passphrase.encode("utf-8").hex()
|
||||
|
||||
monkeypatch.setenv("BORG_DISPLAY_PASSPHRASE", "no")
|
||||
Passphrase.verification(passphrase)
|
||||
out, err = capsys.readouterr()
|
||||
assert passphrase not in err
|
||||
|
||||
monkeypatch.setenv("BORG_DISPLAY_PASSPHRASE", "yes")
|
||||
Passphrase.verification(passphrase)
|
||||
out, err = capsys.readouterr()
|
||||
assert passphrase in err
|
||||
assert hex_value in err
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"ec_range,ec_class",
|
||||
|
|
|
|||
Loading…
Reference in a new issue