commit 21ccb1e82de79ec5277e2f9ec55c30166d7c1475
parent f14c863a0acc089b68ef0cbe19d2104672e38956
Author: ThomasV <thomasv@gitorious>
Date: Sat, 4 Apr 2015 15:13:56 +0200
trezor plugin: move Qt callbacks in a handler
Diffstat:
M | plugins/trezor.py | | | 155 | ++++++++++++++++++++++++++++++++++++++++++------------------------------------- |
1 file changed, 83 insertions(+), 72 deletions(-)
diff --git a/plugins/trezor.py b/plugins/trezor.py
@@ -6,6 +6,7 @@ from sys import stderr
from time import sleep
from base64 import b64encode, b64decode
import unicodedata
+import threading
import electrum
from electrum.account import BIP32_Account
@@ -15,6 +16,7 @@ from electrum.plugins import BasePlugin, hook
from electrum.transaction import deserialize
from electrum.wallet import BIP32_HD_Wallet
from electrum.util import print_error
+from electrum.wallet import pw_decode, bip32_private_derivation, bip32_root
from electrum_gui.qt.util import *
@@ -37,20 +39,6 @@ def give_error(message):
raise Exception(message)
-def trezor_passphrase_dialog(msg):
- from electrum_gui.qt.password_dialog import make_password_dialog, run_password_dialog
- d = QDialog()
- d.setModal(1)
- d.setLayout(make_password_dialog(d, None, msg, False))
- confirmed, p, passphrase = run_password_dialog(d, None, None)
- if not confirmed:
- return None
- if passphrase is None:
- passphrase = '' # Even blank string is valid Trezor passphrase
- passphrase = unicodedata.normalize('NFKD', unicode(passphrase))
- return passphrase
-
-
class Plugin(BasePlugin):
def fullname(self):
@@ -103,10 +91,6 @@ class Plugin(BasePlugin):
return True
@hook
- def init_qt(self, gui):
- self.window = gui.main_window
-
- @hook
def close_wallet(self):
print_error("trezor: clear session")
if self.wallet and self.wallet.client:
@@ -115,6 +99,8 @@ class Plugin(BasePlugin):
@hook
def load_wallet(self, wallet):
+ self.twd = TrezorQtHandler(self.window)
+ self.wallet.twd = self.twd
if self.trezor_is_connected():
if not self.wallet.check_proper_device():
QMessageBox.information(self.window, _('Error'), _("This wallet does not match your Trezor device"), _('OK'))
@@ -132,9 +118,8 @@ class Plugin(BasePlugin):
return
wallet = TrezorWallet(storage)
self.wallet = wallet
- passphrase = trezor_passphrase_dialog(_("Please enter your Trezor passphrase.") + '\n' + _("Press OK if you do not use one."))
+ passphrase = self.twd.get_passphrase(_("Please enter your Trezor passphrase.") + '\n' + _("Press OK if you do not use one."))
if passphrase is None:
- QMessageBox.critical(None, _('Error'), _("Password request canceled"), _('OK'))
return
password = wizard.password_dialog()
wallet.add_seed(seed, password)
@@ -145,13 +130,6 @@ class Plugin(BasePlugin):
return wallet
@hook
- def send_tx(self, tx):
- tx.error = None
- try:
- self.wallet.trezor_sign(tx)
- except Exception as e:
- tx.error = str(e)
- @hook
def receive_menu(self, menu, addrs):
if not self.wallet.is_watching_only() and self.wallet.atleast_version(1, 3) and len(addrs) == 1:
menu.addAction(_("Show on TREZOR"), lambda: self.wallet.show_address(addrs[0]))
@@ -174,9 +152,9 @@ class Plugin(BasePlugin):
if not response[1]:
return
new_label = str(response[0])
- twd.start("Please confirm label change on Trezor")
+ self.twd.show_message("Please confirm label change on Trezor")
status = self.wallet.get_client().apply_settings(label=new_label)
- twd.stop()
+ self.twd.stop()
update_label()
current_label_label = QLabel()
@@ -192,7 +170,6 @@ class Plugin(BasePlugin):
return False
-from electrum.wallet import pw_decode, bip32_private_derivation, bip32_root
class TrezorWallet(BIP32_HD_Wallet):
wallet_type = 'trezor'
@@ -213,6 +190,11 @@ class TrezorWallet(BIP32_HD_Wallet):
def can_import(self):
return False
+ def can_sign_xpubkey(self, x_pubkey):
+ xpub, sequence = BIP32_Account.parse_xpubkey(x_pubkey)
+ print "z", xpub
+ return xpub in self.master_public_keys.values()
+
def can_export(self):
return False
@@ -236,6 +218,7 @@ class TrezorWallet(BIP32_HD_Wallet):
except:
give_error('Could not connect to your Trezor. Please verify the cable is connected and that no other app is using it.')
self.client = QtGuiTrezorClient(self.transport)
+ self.client.twd = self.twd
self.client.set_tx_api(self)
#self.client.clear_session()# TODO Doesn't work with firmware 1.1, returns proto.Failure
self.client.bad = False
@@ -306,7 +289,7 @@ class TrezorWallet(BIP32_HD_Wallet):
#except Exception, e:
# give_error(e)
#finally:
- # twd.emit(SIGNAL('trezor_done'))
+ # twd.stop()
#return str(decrypted_msg)
def show_address(self, address):
@@ -322,7 +305,7 @@ class TrezorWallet(BIP32_HD_Wallet):
except Exception, e:
give_error(e)
finally:
- twd.emit(SIGNAL('trezor_done'))
+ self.twd.stop()
def sign_message(self, address, message, password):
if not self.check_proper_device():
@@ -337,21 +320,16 @@ class TrezorWallet(BIP32_HD_Wallet):
except Exception, e:
give_error(e)
finally:
- twd.emit(SIGNAL('trezor_done'))
+ self.twd.stop()
b64_msg_sig = b64encode(msg_sig.signature)
return str(b64_msg_sig)
def sign_transaction(self, tx, password):
- # the tx is signed by trezor_sign, in the GUI thread
- if tx.error:
- raise BaseException(tx.error)
-
- def trezor_sign(self, tx):
if tx.is_complete():
return
if not self.check_proper_device():
give_error('Wrong device or password')
-
+ client = self.get_client()
inputs = self.tx_inputs(tx)
outputs = self.tx_outputs(tx)
try:
@@ -359,16 +337,15 @@ class TrezorWallet(BIP32_HD_Wallet):
except Exception, e:
give_error(e)
finally:
- twd.emit(SIGNAL('trezor_done'))
- values = [i['value'] for i in tx.inputs]
+ self.twd.stop()
+ #values = [i['value'] for i in tx.inputs]
raw = signed_tx.encode('hex')
tx.update(raw)
- for i, txinput in enumerate(tx.inputs):
- txinput['value'] = values[i]
+ #for i, txinput in enumerate(tx.inputs):
+ # txinput['value'] = values[i]
def tx_inputs(self, tx):
inputs = []
-
for txinput in tx.inputs:
txinputtype = types.TxInputType()
if ('is_coinbase' in txinput and txinput['is_coinbase']):
@@ -442,6 +419,7 @@ class TrezorWallet(BIP32_HD_Wallet):
def get_tx(self, tx_hash):
tx = self.transactions[tx_hash]
+ tx.deserialize()
return self.electrum_tx_to_txtype(tx)
def check_proper_device(self):
@@ -461,10 +439,10 @@ class TrezorWallet(BIP32_HD_Wallet):
return self.proper_device
-class TrezorQtGuiMixin(object):
+class TrezorGuiMixin(object):
def __init__(self, *args, **kwargs):
- super(TrezorQtGuiMixin, self).__init__(*args, **kwargs)
+ super(TrezorGuiMixin, self).__init__(*args, **kwargs)
def callback_ButtonRequest(self, msg):
if msg.code == 3:
@@ -477,7 +455,7 @@ class TrezorQtGuiMixin(object):
message = "Confirm address on Trezor device to continue"
else:
message = "Check Trezor device to continue"
- twd.start(message)
+ self.twd.show_message(message)
return proto.ButtonAck()
def callback_PinMatrixRequest(self, msg):
@@ -489,17 +467,15 @@ class TrezorQtGuiMixin(object):
desc = 'new PIN again'
else:
desc = 'PIN'
-
- pin = self.pin_dialog(msg="Please enter Trezor %s" % desc)
+ pin = self.twd.get_pin("Please enter Trezor %s" % desc)
if not pin:
return proto.Cancel()
return proto.PinMatrixAck(pin=pin)
def callback_PassphraseRequest(self, req):
msg = _("Please enter your Trezor passphrase.")
- passphrase = trezor_passphrase_dialog(msg)
+ passphrase = self.twd.get_passphrase(msg)
if passphrase is None:
- QMessageBox.critical(None, _('Error'), _("Password request canceled"), _('OK'))
return proto.Cancel()
return proto.PassphraseAck(passphrase=passphrase)
@@ -509,47 +485,85 @@ class TrezorQtGuiMixin(object):
word = raw_input()
return proto.WordAck(word=word)
- def pin_dialog(self, msg):
+
+class TrezorQtHandler:
+
+ def __init__(self, win):
+ self.win = win
+ self.win.connect(win, SIGNAL('trezor_done'), self.dialog_stop)
+ self.win.connect(win, SIGNAL('message_dialog'), self.message_dialog)
+ self.win.connect(win, SIGNAL('pin_dialog'), self.pin_dialog)
+ self.win.connect(win, SIGNAL('passphrase_dialog'), self.passphrase_dialog)
+ self.done = threading.Event()
+
+ def stop(self):
+ self.win.emit(SIGNAL('trezor_done'))
+
+ def show_message(self, msg):
+ self.message = msg
+ self.win.emit(SIGNAL('message_dialog'))
+
+ def get_pin(self, msg):
+ self.done.clear()
+ self.message = msg
+ self.win.emit(SIGNAL('pin_dialog'))
+ self.done.wait()
+ return self.response
+
+ def get_passphrase(self, msg):
+ self.done.clear()
+ self.message = msg
+ self.win.emit(SIGNAL('passphrase_dialog'))
+ self.done.wait()
+ return self.passphrase
+
+ def pin_dialog(self):
d = QDialog(None)
d.setModal(1)
d.setWindowTitle(_("Enter PIN"))
d.setWindowFlags(d.windowFlags() | QtCore.Qt.WindowStaysOnTopHint)
matrix = PinMatrixWidget()
-
vbox = QVBoxLayout()
- vbox.addWidget(QLabel(msg))
+ vbox.addWidget(QLabel(self.message))
vbox.addWidget(matrix)
vbox.addLayout(Buttons(CancelButton(d), OkButton(d)))
d.setLayout(vbox)
+ if not d.exec_():
+ self.response = None
+ self.response = str(matrix.get_value())
+ self.done.set()
- if not d.exec_(): return
- return str(matrix.get_value())
-
-class TrezorWaitingDialog(QThread):
- def __init__(self):
- QThread.__init__(self)
- self.waiting = False
+ def passphrase_dialog(self):
+ from electrum_gui.qt.password_dialog import make_password_dialog, run_password_dialog
+ d = QDialog()
+ d.setModal(1)
+ d.setLayout(make_password_dialog(d, None, self.message, False))
+ confirmed, p, passphrase = run_password_dialog(d, None, None)
+ if not confirmed:
+ QMessageBox.critical(None, _('Error'), _("Password request canceled"), _('OK'))
+ self.passphrase = None
+ else:
+ if passphrase is None:
+ passphrase = '' # Even blank string is valid Trezor passphrase
+ self.passphrase = unicodedata.normalize('NFKD', unicode(passphrase))
+ self.done.set()
- def start(self, message):
+ def message_dialog(self):
self.d = QDialog()
self.d.setModal(1)
self.d.setWindowTitle('Please Check Trezor Device')
self.d.setWindowFlags(self.d.windowFlags() | QtCore.Qt.WindowStaysOnTopHint)
- l = QLabel(message)
+ l = QLabel(self.message)
vbox = QVBoxLayout(self.d)
vbox.addWidget(l)
self.d.show()
- if not self.waiting:
- self.waiting = True
- self.d.connect(twd, SIGNAL('trezor_done'), self.stop)
- def stop(self):
+ def dialog_stop(self):
self.d.hide()
- self.waiting = False
if TREZOR:
- class QtGuiTrezorClient(ProtocolMixin, TrezorQtGuiMixin, BaseClient):
+ class QtGuiTrezorClient(ProtocolMixin, TrezorGuiMixin, BaseClient):
def call_raw(self, msg):
try:
resp = BaseClient.call_raw(self, msg)
@@ -558,6 +572,3 @@ if TREZOR:
raise
return resp
-
- twd = TrezorWaitingDialog()
-