diff --git a/borg/key.py b/borg/key.py index 6e56de199..cf7f72a78 100644 --- a/borg/key.py +++ b/borg/key.py @@ -18,6 +18,10 @@ PREFIX = b'\0' * 8 +class PasswordRetriesExceeded(Error): + """exceeded the maximum password retries""" + + class UnsupportedPayloadError(Error): """Unsupported payload type {}. A newer version is required to access this repository.""" @@ -185,7 +189,7 @@ def new(cls, allow_empty=False): passphrase = cls.env_passphrase() if passphrase is not None: return passphrase - while True: + for retry in range(1, 11): passphrase = cls.getpass('Enter new passphrase: ') if allow_empty or passphrase: passphrase2 = cls.getpass('Enter same passphrase again: ') @@ -196,6 +200,8 @@ def new(cls, allow_empty=False): print('Passphrases do not match', file=sys.stderr) else: print('Passphrase must not be blank', file=sys.stderr) + else: + raise PasswordRetriesExceeded def __repr__(self): return '' @@ -231,7 +237,7 @@ def detect(cls, repository, manifest_data): passphrase = Passphrase.env_passphrase() if passphrase is None: passphrase = Passphrase.getpass(prompt) - while True: + for retry in range(1, 3): key.init(repository, passphrase) try: key.decrypt(None, manifest_data) @@ -240,6 +246,8 @@ def detect(cls, repository, manifest_data): return key except IntegrityError: passphrase = Passphrase.getpass(prompt) + else: + raise PasswordRetriesExceeded def change_passphrase(self): class ImmutablePassphraseError(Error): @@ -259,8 +267,12 @@ def detect(cls, repository, manifest_data): target = key.find_key() prompt = 'Enter passphrase for key %s: ' % target passphrase = Passphrase.env_passphrase(default='') - while not key.load(target, passphrase): + for retry in range(1, 4): + if key.load(target, passphrase): + break passphrase = Passphrase.getpass(prompt) + else: + raise PasswordRetriesExceeded num_blocks = num_aes_blocks(len(manifest_data) - 41) key.init_ciphers(PREFIX + long_to_bytes(key.extract_nonce(manifest_data) + num_blocks)) return key