URI: 
       tkeystore: improve check_password. - electrum - Electrum Bitcoin wallet
  HTML git clone https://git.parazyd.org/electrum
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
       ---
   DIR commit 9eb152ed98ca056d7de264dca81aa4719ba14945
   DIR parent 9b4414fb2ea87dbb3ce410fc030af0c23c0bcd79
  HTML Author: SomberNight <somber.night@protonmail.com>
       Date:   Fri, 11 Sep 2020 13:09:30 +0200
       
       keystore: improve check_password.
       
       and add tests that exercise it
       
       maybe fixes #4128
       
       Diffstat:
         M electrum/bitcoin.py                 |      16 +++++++++-------
         M electrum/keystore.py                |      14 ++++++++++----
         M electrum/tests/test_wallet.py       |      38 +++++++++++++++++++++++++++++--
       
       3 files changed, 55 insertions(+), 13 deletions(-)
       ---
   DIR diff --git a/electrum/bitcoin.py b/electrum/bitcoin.py
       t@@ -497,6 +497,9 @@ __b43chars = b'0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ$*+-./:'
        assert len(__b43chars) == 43
        
        
       +class BaseDecodeError(BitcoinException): pass
       +
       +
        def base_encode(v: bytes, *, base: int) -> str:
            """ encode v, which is a string of bytes, to base58."""
            assert_bytes(v)
       t@@ -544,7 +547,7 @@ def base_decode(v: Union[bytes, str], *, base: int, length: int = None) -> Optio
            for c in v[::-1]:
                digit = chars.find(bytes([c]))
                if digit == -1:
       -            raise ValueError('Forbidden character {} for base {}'.format(c, base))
       +            raise BaseDecodeError('Forbidden character {} for base {}'.format(c, base))
                # naive but slow variant:   long_value += digit * (base**i)
                long_value += digit * power_of_base
                power_of_base *= base
       t@@ -567,7 +570,7 @@ def base_decode(v: Union[bytes, str], *, base: int, length: int = None) -> Optio
            return bytes(result)
        
        
       -class InvalidChecksum(Exception):
       +class InvalidChecksum(BaseDecodeError):
            pass
        
        
       t@@ -633,18 +636,17 @@ def deserialize_privkey(key: str) -> Tuple[str, bytes, bool]:
                    raise BitcoinException('unknown script type: {}'.format(txin_type))
            try:
                vch = DecodeBase58Check(key)
       -    except BaseException:
       +    except Exception as e:
                neutered_privkey = str(key)[:3] + '..' + str(key)[-2:]
       -        raise BitcoinException("cannot deserialize privkey {}"
       -                               .format(neutered_privkey))
       +        raise BaseDecodeError(f"cannot deserialize privkey {neutered_privkey}") from e
        
            if txin_type is None:
                # keys exported in version 3.0.x encoded script type in first byte
                prefix_value = vch[0] - constants.net.WIF_PREFIX
                try:
                    txin_type = WIF_SCRIPT_TYPES_INV[prefix_value]
       -        except KeyError:
       -            raise BitcoinException('invalid prefix ({}) for WIF key (1)'.format(vch[0]))
       +        except KeyError as e:
       +            raise BitcoinException('invalid prefix ({}) for WIF key (1)'.format(vch[0])) from None
            else:
                # all other keys must have a fixed first byte
                if vch[0] != constants.net.WIF_PREFIX:
   DIR diff --git a/electrum/keystore.py b/electrum/keystore.py
       t@@ -32,7 +32,7 @@ from functools import lru_cache
        from abc import ABC, abstractmethod
        
        from . import bitcoin, ecc, constants, bip32
       -from .bitcoin import deserialize_privkey, serialize_privkey
       +from .bitcoin import deserialize_privkey, serialize_privkey, BaseDecodeError
        from .transaction import Transaction, PartialTransaction, PartialTxInput, PartialTxOutput, TxInput
        from .bip32 import (convert_bip32_path_to_list_of_uint32, BIP32_PRIME,
                            is_xpub, is_xprv, BIP32Node, normalize_bip32_derivation,
       t@@ -251,8 +251,10 @@ class Imported_KeyStore(Software_KeyStore):
        
            def get_private_key(self, pubkey: str, password):
                sec = pw_decode(self.keypairs[pubkey], password, version=self.pw_hash_version)
       -        txin_type, privkey, compressed = deserialize_privkey(sec)
       -        # this checks the password
       +        try:
       +            txin_type, privkey, compressed = deserialize_privkey(sec)
       +        except BaseDecodeError as e:
       +            raise InvalidPassword() from e
                if pubkey != ecc.ECPrivkey(privkey).get_public_key_hex(compressed=compressed):
                    raise InvalidPassword()
                return privkey, compressed
       t@@ -529,7 +531,11 @@ class BIP32_KeyStore(Xpub, Deterministic_KeyStore):
        
            def check_password(self, password):
                xprv = pw_decode(self.xprv, password, version=self.pw_hash_version)
       -        if BIP32Node.from_xkey(xprv).chaincode != self.get_bip32_node_for_xpub().chaincode:
       +        try:
       +            bip32node = BIP32Node.from_xkey(xprv)
       +        except BaseDecodeError as e:
       +            raise InvalidPassword() from e
       +        if bip32node.chaincode != self.get_bip32_node_for_xpub().chaincode:
                    raise InvalidPassword()
        
            def update_password(self, old_password, new_password):
   DIR diff --git a/electrum/tests/test_wallet.py b/electrum/tests/test_wallet.py
       t@@ -10,9 +10,9 @@ from io import StringIO
        from electrum.storage import WalletStorage
        from electrum.wallet_db import FINAL_SEED_VERSION
        from electrum.wallet import (Abstract_Wallet, Standard_Wallet, create_new_wallet,
       -                             restore_wallet_from_text, Imported_Wallet)
       +                             restore_wallet_from_text, Imported_Wallet, Wallet)
        from electrum.exchange_rate import ExchangeBase, FxThread
       -from electrum.util import TxMinedInfo
       +from electrum.util import TxMinedInfo, InvalidPassword
        from electrum.bitcoin import COIN
        from electrum.wallet_db import WalletDB
        from electrum.simple_config import SimpleConfig
       t@@ -229,3 +229,37 @@ class TestCreateRestoreWallet(WalletTestCase):
                # also test addr deletion
                wallet.delete_address('bc1qnp78h78vp92pwdwq5xvh8eprlga5q8gu66960c')
                self.assertEqual(1, len(wallet.get_receiving_addresses()))
       +
       +
       +class TestWalletPassword(WalletTestCase):
       +
       +    def test_update_password_of_imported_wallet(self):
       +        wallet_str = '{"addr_history":{"1364Js2VG66BwRdkaoxAaFtdPb1eQgn8Dr":[],"15CyDgLffJsJgQrhcyooFH4gnVDG82pUrA":[],"1Exet2BhHsFxKTwhnfdsBMkPYLGvobxuW6":[]},"addresses":{"change":[],"receiving":["1364Js2VG66BwRdkaoxAaFtdPb1eQgn8Dr","1Exet2BhHsFxKTwhnfdsBMkPYLGvobxuW6","15CyDgLffJsJgQrhcyooFH4gnVDG82pUrA"]},"keystore":{"keypairs":{"0344b1588589958b0bcab03435061539e9bcf54677c104904044e4f8901f4ebdf5":"L2sED74axVXC4H8szBJ4rQJrkfem7UMc6usLCPUoEWxDCFGUaGUM","0389508c13999d08ffae0f434a085f4185922d64765c0bff2f66e36ad7f745cc5f":"L3Gi6EQLvYw8gEEUckmqawkevfj9s8hxoQDFveQJGZHTfyWnbk1U","04575f52b82f159fa649d2a4c353eb7435f30206f0a6cb9674fbd659f45082c37d559ffd19bea9c0d3b7dcc07a7b79f4cffb76026d5d4dff35341efe99056e22d2":"5JyVyXU1LiRXATvRTQvR9Kp8Rx1X84j2x49iGkjSsXipydtByUq"},"type":"imported"},"pruned_txo":{},"seed_version":13,"stored_height":-1,"transactions":{},"tx_fees":{},"txi":{},"txo":{},"use_encryption":false,"verified_tx3":{},"wallet_type":"standard","winpos-qt":[100,100,840,405]}'
       +        db = WalletDB(wallet_str, manual_upgrades=False)
       +        storage = WalletStorage(self.wallet_path)
       +        wallet = Wallet(db, storage, config=self.config)
       +
       +        wallet.check_password(None)
       +
       +        wallet.update_password(None, "1234")
       +
       +        with self.assertRaises(InvalidPassword):
       +            wallet.check_password(None)
       +        with self.assertRaises(InvalidPassword):
       +            wallet.check_password("wrong password")
       +        wallet.check_password("1234")
       +
       +    def test_update_password_of_standard_wallet(self):
parazyd.org:70 /git/electrum/commit/9eb152ed98ca056d7de264dca81aa4719ba14945.gph:152: line too long