electrum

Electrum Bitcoin wallet
git clone https://git.parazyd.org/electrum
Log | Files | Refs | Submodules

commit 4a7cc1c65f8e27523c95b8442e7dc0624d0535f0
parent 9930d5fd6f6fd269614a58182ac49d21b358f8f1
Author: Neil <kyuupichan@gmail.com>
Date:   Sat, 30 Jan 2016 17:43:39 +0900

Merge pull request #1662 from LedgerHQ/ledger_plugin_redesign

Ledger plugin redesign
Diffstat:
Mplugins/ledger/ledger.py | 58+++++++++++++++++++---------------------------------------
Mplugins/ledger/qt.py | 47++++++++---------------------------------------
2 files changed, 27 insertions(+), 78 deletions(-)

diff --git a/plugins/ledger/ledger.py b/plugins/ledger/ledger.py @@ -9,7 +9,8 @@ from electrum.bitcoin import EncodeBase58Check, DecodeBase58Check, public_key_to from electrum.i18n import _ from electrum.plugins import BasePlugin, hook from electrum.transaction import deserialize -from electrum.wallet import BIP44_Wallet +from ..hw_wallet import BIP44_HW_Wallet + from electrum.util import format_satoshis_plain, print_error, print_msg import hashlib @@ -29,14 +30,14 @@ except ImportError: BTCHIP = False -class BTChipWallet(BIP44_Wallet): +class BTChipWallet(BIP44_HW_Wallet): wallet_type = 'btchip' device = 'Ledger' - restore_wallet_class = BIP44_Wallet + restore_wallet_class = BIP44_HW_Wallet max_change_outputs = 1 def __init__(self, storage): - BIP44_Wallet.__init__(self, storage) + BIP44_HW_Wallet.__init__(self, storage) # Errors and other user interaction is done through the wallet's # handler. The handler is per-window and preserved across # device reconnects @@ -49,7 +50,7 @@ class BTChipWallet(BIP44_Wallet): def give_error(self, message, clear_client = False): print_error(message) if not self.signing: - QMessageBox.warning(QDialog(), _('Warning'), _(message), _('OK')) + self.handler.show_error(message) else: self.signing = False if clear_client: @@ -57,30 +58,9 @@ class BTChipWallet(BIP44_Wallet): self.device_checked = False raise Exception(message) - def get_action(self): - pass - - def can_create_accounts(self): - return False - - def can_change_password(self): - return False - - def is_watching_only(self): - assert not self.has_seed() - return self.force_watching_only - def address_id(self, address): # Strip the leading "m/" - return BIP44_Wallet.address_id(self, address)[2:] - - def get_client(self, noPin=False): - return self.plugin.get_client(self, noPin=noPin) - - def derive_xkeys(self, root, derivation, password): - derivation = '/'.join(derivation.split('/')[1:]) - xpub = self.get_public_key(derivation) - return xpub, None + return BIP44_HW_Wallet.address_id(self, address)[2:] def get_public_key(self, bip32_path): # bip32_path is of the form 44'/0'/1' @@ -91,6 +71,9 @@ class BTChipWallet(BIP44_Wallet): self.handler.show_message("Computing master public key") try: splitPath = bip32_path.split('/') + if splitPath[0] == 'm': + splitPath = splitPath[1:] + bip32_path = bip32_path[2:] fingerprint = 0 if len(splitPath) > 1: prevPath = "/".join(splitPath[0:len(splitPath) - 1]) @@ -111,13 +94,10 @@ class BTChipWallet(BIP44_Wallet): except Exception, e: self.give_error(e, True) finally: - self.handler.stop() + self.handler.clear_dialog() return EncodeBase58Check(xpub) - def i4b(self, x): - return pack('>I', x) - def decrypt_message(self, pubkey, message, password): self.give_error("Not supported") @@ -142,7 +122,7 @@ class BTChipWallet(BIP44_Wallet): pin = pin.encode() client.bad = True self.device_checked = False - self.get_client(True) + self.plugin.get_client(self, True, True) signature = self.get_client().signMessageSign(pin) except BTChipException, e: if e.sw == 0x6a80: @@ -152,7 +132,7 @@ class BTChipWallet(BIP44_Wallet): except Exception, e: self.give_error(e, True) finally: - self.handler.stop() + self.handler.clear_dialog() client.bad = use2FA self.signing = False @@ -239,7 +219,7 @@ class BTChipWallet(BIP44_Wallet): transactionOutput = outputData['outputData'] if outputData['confirmationNeeded']: # TODO : handle different confirmation types. For the time being only supports keyboard 2FA - self.handler.stop() + self.handler.clear_dialog() if 'keycardData' in outputData: pin2 = "" for keycardIndex in range(len(outputData['keycardData'])): @@ -269,7 +249,7 @@ class BTChipWallet(BIP44_Wallet): pin = pin.encode() client.bad = True self.device_checked = False - self.get_client(True) + self.plugin.get_client(self, True, True) self.handler.show_message("Signing ...") else: # Sign input with the provided PIN @@ -282,7 +262,7 @@ class BTChipWallet(BIP44_Wallet): except Exception, e: self.give_error(e, True) finally: - self.handler.stop() + self.handler.clear_dialog() # Reformat transaction inputIndex = 0 @@ -306,7 +286,7 @@ class BTChipWallet(BIP44_Wallet): except Exception, e: self.give_error(e, True) finally: - self.handler.stop() + self.handler.clear_dialog() pubKeyDevice = compress_public_key(nodeData['publicKey']) self.device_checked = True if pubKey != pubKeyDevice: @@ -328,7 +308,7 @@ class BTChipWallet(BIP44_Wallet): "the transaction being signed into the text-editor.\r\n\r\n" \ "Check that summary and then enter the second factor code here.\r\n" \ "Before clicking OK, re-plug the device once more (unplug it and plug it again if you read the second factor code on the same computer)") - response = self.handler.prompt_auth(msg) + response = self.handler.get_word(msg) if response is None: return False, None, None return True, response, response @@ -380,7 +360,7 @@ class LedgerPlugin(BasePlugin): def close_wallet(self, wallet): self.client = None - def get_client(self, wallet, noPin=False): + def get_client(self, wallet, force_pair=True, noPin=False): aborted = False client = self.client if not client or client.bad: diff --git a/plugins/ledger/qt.py b/plugins/ledger/qt.py @@ -7,6 +7,7 @@ import PyQt4.QtCore as QtCore from electrum.i18n import _ from electrum.plugins import hook from .ledger import LedgerPlugin, BTChipWallet +from ..hw_wallet import QtHandlerBase class Plugin(LedgerPlugin): @@ -29,48 +30,16 @@ class Plugin(LedgerPlugin): # self.select_device(wallet) wallet.create_hd_account(None) -class BTChipQTHandler: +class BTChipQTHandler(QtHandlerBase): def __init__(self, win): - self.win = win - self.win.connect(win, SIGNAL('btchip_done'), self.dialog_stop) - self.win.connect(win, SIGNAL('btchip_message_dialog'), self.message_dialog) - self.win.connect(win, SIGNAL('btchip_auth_dialog'), self.auth_dialog) - self.done = threading.Event() + super(BTChipQTHandler, self).__init__(win, 'Ledger') - def stop(self): - self.win.emit(SIGNAL('btchip_done')) - def show_message(self, msg): - self.message = msg - self.win.emit(SIGNAL('btchip_message_dialog')) - - def prompt_auth(self, msg): - self.done.clear() - self.message = msg - self.win.emit(SIGNAL('btchip_auth_dialog')) - self.done.wait() - return self.response - - def auth_dialog(self): - response = QInputDialog.getText(None, "Ledger Wallet Authentication", self.message, QLineEdit.Password) + def word_dialog(self, msg): + response = QInputDialog.getText(self.top_level_window(), "Ledger Wallet Authentication", msg, QLineEdit.Password) if not response[1]: - self.response = None + self.word = None else: - self.response = str(response[0]) - self.done.set() - - def message_dialog(self): - self.d = QDialog() - self.d.setModal(1) - self.d.setWindowTitle('Ledger') - self.d.setWindowFlags(self.d.windowFlags() | QtCore.Qt.WindowStaysOnTopHint) - l = QLabel(self.message) - vbox = QVBoxLayout(self.d) - vbox.addWidget(l) - self.d.show() - - def dialog_stop(self): - if self.d is not None: - self.d.hide() - self.d = None + self.word = str(response[0]) + self.done.set()