commit c02daa56b0f48f8fd2e110e7d0ed6e434ff696e8
parent d69551f723f5b9ee94a6b5f3af7cf69aec1a78e0
Author: Neil Booth <kyuupichan@gmail.com>
Date: Sun, 27 Dec 2015 15:00:58 +0900
Finish merging keepkey / trezor implementations
Diffstat:
4 files changed, 126 insertions(+), 215 deletions(-)
diff --git a/plugins/keepkey/qt.py b/plugins/keepkey/qt.py
@@ -1,98 +1,6 @@
-from PyQt4.Qt import QVBoxLayout, QLabel, SIGNAL, QGridLayout, QInputDialog, QPushButton
-import PyQt4.QtCore as QtCore
-from electrum_gui.qt.util import *
-from electrum_gui.qt.main_window import StatusBarButton, ElectrumWindow
-
-from functools import partial
-import unicodedata
-
-from electrum.i18n import _
-from electrum.plugins import hook
-
-from plugins.trezor.qt_generic import QtHandler
+from plugins.trezor.qt_generic import QtPlugin
from keepkeylib.qt.pinmatrix import PinMatrixWidget
-from keepkey import KeepKeyPlugin, KeepKeyWallet
-
-class KeepKeyQtHandler(QtHandler):
- device = 'KeepKey'
- pin_matrix_widget_class = PinMatrixWidget
-
-class Plugin(KeepKeyPlugin):
-
- @hook
- def load_wallet(self, wallet, window):
- self.print_error("load_wallet")
- self.wallet = wallet
- self.wallet.plugin = self
- self.keepkey_button = StatusBarButton(QIcon(":icons/keepkey.png"), _("KeepKey"), partial(self.settings_dialog, window))
- if type(window) is ElectrumWindow:
- window.statusBar().addPermanentWidget(self.keepkey_button)
- if self.handler is None:
- self.handler = KeepKeyQtHandler(window)
- msg = self.wallet.sanity_check()
- if msg:
- window.show_error(msg)
-
- @hook
- def installwizard_load_wallet(self, wallet, window):
- if type(wallet) != KeepKeyWallet:
- return
- self.load_wallet(wallet, window)
-
- @hook
- def installwizard_restore(self, wizard, storage):
- if storage.get('wallet_type') != 'keepkey':
- return
- seed = wizard.enter_seed_dialog("Enter your KeepKey seed", None, func=lambda x:True)
- if not seed:
- return
- wallet = KeepKeyWallet(storage)
- self.wallet = wallet
- handler = KeepKeyQtHandler(wizard)
- passphrase = handler.get_passphrase(_("Please enter your KeepKey passphrase.") + '\n' + _("Press OK if you do not use one."))
- if passphrase is None:
- return
- password = wizard.password_dialog()
- wallet.add_seed(seed, password)
- wallet.add_cosigner_seed(seed, 'x/', password, passphrase)
- wallet.create_main_account(password)
- # disable keepkey plugin
- self.set_enabled(False)
- return wallet
-
- @hook
- def receive_menu(self, menu, addrs):
- if not self.wallet.is_watching_only() and self.atleast_version(1, 3) and len(addrs) == 1:
- menu.addAction(_("Show on TREZOR"), lambda: self.show_address(addrs[0]))
-
- def settings_dialog(self, window):
- try:
- device_id = self.get_client().get_device_id()
- except BaseException as e:
- window.show_message(str(e))
- return
- get_label = lambda: self.get_client().features.label
- update_label = lambda: current_label_label.setText("Label: %s" % get_label())
- d = WindowModalDialog(window, _("KeepKey Settings"))
- layout = QGridLayout(d)
- layout.addWidget(QLabel("KeepKey Options"),0,0)
- layout.addWidget(QLabel("ID:"),1,0)
- layout.addWidget(QLabel(" %s" % device_id),1,1)
-
- def modify_label():
- response = QInputDialog().getText(None, "Set New KeepKey Label", "New KeepKey Label: (upon submission confirm on KeepKey)")
- if not response[1]:
- return
- new_label = str(response[0])
- self.handler.show_message("Please confirm label change on KeepKey")
- status = self.get_client().apply_settings(label=new_label)
- self.handler.stop()
- update_label()
- current_label_label = QLabel()
- update_label()
- change_label_button = QPushButton("Modify")
- change_label_button.clicked.connect(modify_label)
- layout.addWidget(current_label_label,3,0)
- layout.addWidget(change_label_button,3,1)
- d.exec_()
+class Plugin(QtPlugin):
+ handler_class = KeepKeyQtHandler
+ icon_file = ":icons/keepkey.png"
diff --git a/plugins/trezor/plugin.py b/plugins/trezor/plugin.py
@@ -9,7 +9,7 @@ from electrum.transaction import deserialize, is_extended_pubkey
class TrezorCompatiblePlugin(BasePlugin):
# Derived classes provide:
#
- # class-static variables: client_class, firmware_URL,
+ # class-static variables: client_class, firmware_URL, handler_class,
# libraries_available, libraries_URL, minimum_firmware,
# wallet_class, ckd_public, types, HidTransport
diff --git a/plugins/trezor/qt.py b/plugins/trezor/qt.py
@@ -1,114 +1,6 @@
-from PyQt4.Qt import QVBoxLayout, QLabel, SIGNAL, QGridLayout, QInputDialog, QPushButton
-import PyQt4.QtCore as QtCore
-from electrum_gui.qt.util import *
-from electrum_gui.qt.main_window import StatusBarButton, ElectrumWindow
-
-from functools import partial
-import unicodedata
-
-from electrum.i18n import _
-from electrum.plugins import hook
-
-from plugins.trezor.qt_generic import QtHandler
-from trezor import TrezorPlugin, TrezorWallet
+from plugins.trezor.qt_generic import QtPlugin
from trezorlib.qt.pinmatrix import PinMatrixWidget
-class TrezorQtHandler(QtHandler):
- device = 'Trezor'
+class Plugin(QtPlugin):
pin_matrix_widget_class = PinMatrixWidget
-
-class Plugin(TrezorPlugin):
-
- @hook
- def load_wallet(self, wallet, window):
- self.print_error("load_wallet")
- self.wallet = wallet
- self.wallet.plugin = self
- self.trezor_button = StatusBarButton(QIcon(":icons/trezor.png"), _("Trezor"), partial(self.settings_dialog, window))
- if type(window) is ElectrumWindow:
- window.statusBar().addPermanentWidget(self.trezor_button)
- if self.handler is None:
- self.handler = TrezorQtHandler(window)
- msg = self.wallet.sanity_check()
- if msg:
- window.show_error(msg)
-
- @hook
- def installwizard_load_wallet(self, wallet, window):
- if type(wallet) != TrezorWallet:
- return
- self.load_wallet(wallet, window)
-
- @hook
- def installwizard_restore(self, wizard, storage):
- if storage.get('wallet_type') != 'trezor':
- return
- seed = wizard.enter_seed_dialog("Enter your Trezor seed", None, func=lambda x:True)
- if not seed:
- return
- wallet = TrezorWallet(storage)
- self.wallet = wallet
- handler = TrezorQtHandler(wizard)
- passphrase = handler.get_passphrase(_("Please enter your Trezor passphrase.") + '\n' + _("Press OK if you do not use one."))
- if passphrase is None:
- return
- password = wizard.password_dialog()
- wallet.add_seed(seed, password)
- wallet.add_cosigner_seed(seed, 'x/', password, passphrase)
- wallet.create_main_account(password)
- # disable trezor plugin
- self.set_enabled(False)
- return wallet
-
- @hook
- def receive_menu(self, menu, addrs):
- if not self.wallet.is_watching_only() and self.atleast_version(1, 3) and len(addrs) == 1:
- menu.addAction(_("Show on TREZOR"), lambda: self.show_address(addrs[0]))
-
- def show_address(self, address):
- if not self.wallet.check_proper_device():
- give_error('Wrong device or password')
- try:
- address_path = self.wallet.address_id(address)
- address_n = self.get_client().expand_path(address_path)
- except Exception, e:
- give_error(e)
- try:
- self.get_client().get_address('Bitcoin', address_n, True)
- except Exception, e:
- give_error(e)
- finally:
- self.handler.stop()
-
-
- def settings_dialog(self, window):
- try:
- device_id = self.get_client().get_device_id()
- except BaseException as e:
- window.show_message(str(e))
- return
- get_label = lambda: self.get_client().features.label
- update_label = lambda: current_label_label.setText("Label: %s" % get_label())
- d = WindowModalDialog(window, _("Trezor Settings"))
- layout = QGridLayout(d)
- layout.addWidget(QLabel("Trezor Options"),0,0)
- layout.addWidget(QLabel("ID:"),1,0)
- layout.addWidget(QLabel(" %s" % device_id),1,1)
-
- def modify_label():
- response = QInputDialog().getText(None, "Set New Trezor Label", "New Trezor Label: (upon submission confirm on Trezor)")
- if not response[1]:
- return
- new_label = str(response[0])
- self.handler.show_message("Please confirm label change on Trezor")
- status = self.get_client().apply_settings(label=new_label)
- self.handler.stop()
- update_label()
-
- current_label_label = QLabel()
- update_label()
- change_label_button = QPushButton("Modify")
- change_label_button.clicked.connect(modify_label)
- layout.addWidget(current_label_label,3,0)
- layout.addWidget(change_label_button,3,1)
- d.exec_()
+ icon_file = ":icons/trezor.png"
diff --git a/plugins/trezor/qt_generic.py b/plugins/trezor/qt_generic.py
@@ -1,30 +1,31 @@
+from functools import partial
from unicodedata import normalize
import threading
+from PyQt4.Qt import QGridLayout, QInputDialog, QPushButton
from PyQt4.Qt import QVBoxLayout, QLabel, SIGNAL
-import PyQt4.QtCore as QtCore
-from electrum_gui.qt.main_window import ElectrumWindow
+from trezor import TrezorPlugin
+from electrum_gui.qt.main_window import ElectrumWindow, StatusBarButton
from electrum_gui.qt.installwizard import InstallWizard
from electrum_gui.qt.password_dialog import PasswordDialog
from electrum_gui.qt.util import *
from electrum.i18n import _
+from electrum.plugins import hook
class QtHandler:
'''An interface between the GUI (here, QT) and the device handling
logic for handling I/O. This is a generic implementation of the
Trezor protocol; derived classes can customize it.'''
- # Derived classes must provide:
- # device a string, e.g. "Trezor"
- # pin_matrix_widget_class
-
- def __init__(self, win):
+ def __init__(self, win, pin_matrix_widget_class, device):
win.connect(win, SIGNAL('message_done'), self.dialog_stop)
win.connect(win, SIGNAL('message_dialog'), self.message_dialog)
win.connect(win, SIGNAL('pin_dialog'), self.pin_dialog)
win.connect(win, SIGNAL('passphrase_dialog'), self.passphrase_dialog)
self.win = win
+ self.pin_matrix_widget_class = pin_matrix_widget_class
+ self.device = device
self.done = threading.Event()
self.dialog = None
@@ -92,3 +93,113 @@ class QtHandler:
if self.dialog:
self.dialog.hide()
self.dialog = None
+
+
+class QtPlugin(TrezorPlugin):
+ # Derived classes must provide the following class-static variables:
+ # icon_file
+ # pin_matrix_widget_class
+
+ def create_handler(self, window):
+ return QtHandler(window, self.pin_matrix_widget_class, self.device)
+
+ @hook
+ def load_wallet(self, wallet, window):
+ self.print_error("load_wallet")
+ self.wallet = wallet
+ self.wallet.plugin = self
+ self.button = StatusBarButton(QIcon(self.icon_file), self.device,
+ partial(self.settings_dialog, window))
+ if type(window) is ElectrumWindow:
+ window.statusBar().addPermanentWidget(self.button)
+ if self.handler is None:
+ self.handler = self.create_handler(window)
+ msg = self.wallet.sanity_check()
+ if msg:
+ window.show_error(msg)
+
+ @hook
+ def installwizard_load_wallet(self, wallet, window):
+ if type(wallet) != self.wallet_class:
+ return
+ self.load_wallet(wallet, window)
+
+ @hook
+ def installwizard_restore(self, wizard, storage):
+ if storage.get('wallet_type') != self.wallet_class.wallet_type:
+ return
+ seed = wizard.enter_seed_dialog(_("Enter your %s seed") % self.device,
+ None, func=lambda x:True)
+ if not seed:
+ return
+ wallet = self.wallet_class(storage)
+ self.wallet = wallet
+ handler = self.create_handler(wizard)
+ msg = "\n".join([_("Please enter your %s passphrase.") % self.device,
+ _("Press OK if you do not use one.")])
+ passphrase = handler.get_passphrase(msg)
+ if passphrase is None:
+ return
+ password = wizard.password_dialog()
+ wallet.add_seed(seed, password)
+ wallet.add_cosigner_seed(seed, 'x/', password, passphrase)
+ wallet.create_main_account(password)
+ # disable plugin as this is a free-standing wallet
+ self.set_enabled(False)
+ return wallet
+
+ @hook
+ def receive_menu(self, menu, addrs):
+ if (not self.wallet.is_watching_only() and self.atleast_version(1, 3)
+ and len(addrs) == 1):
+ menu.addAction(_("Show on %s") % self.device,
+ lambda: self.show_address(addrs[0]))
+
+ def show_address(self, address):
+ self.wallet.check_proper_device()
+ try:
+ address_path = self.wallet.address_id(address)
+ address_n = self.get_client().expand_path(address_path)
+ except Exception, e:
+ self.give_error(e)
+ try:
+ self.get_client().get_address('Bitcoin', address_n, True)
+ except Exception, e:
+ self.give_error(e)
+ finally:
+ self.handler.stop()
+
+ def settings_dialog(self, window):
+ try:
+ device_id = self.get_client().get_device_id()
+ except BaseException as e:
+ window.show_error(str(e))
+ return
+ get_label = lambda: self.get_client().features.label
+ update_label = lambda: current_label.setText("Label: %s" % get_label())
+ d = WindowModalDialog(window, _("%s Settings") % self.device)
+ layout = QGridLayout(d)
+ layout.addWidget(QLabel(_("%s Options") % self.device), 0, 0)
+ layout.addWidget(QLabel("ID:"), 1, 0)
+ layout.addWidget(QLabel(" %s" % device_id), 1, 1)
+
+ def modify_label():
+ title = _("Set New %s Label") % self.device
+ msg = _("New Label: (upon submission confirm on %s)") % self.device
+ response = QInputDialog().getText(None, title, msg)
+ if not response[1]:
+ return
+ new_label = str(response[0])
+ msg = _("Please confirm label change on %s") % self.device
+ self.handler.show_message(msg)
+ status = self.get_client().apply_settings(label=new_label)
+ self.handler.stop()
+ update_label()
+
+ current_label = QLabel()
+ update_label()
+ change_label_button = QPushButton("Modify")
+ change_label_button.clicked.connect(modify_label)
+ layout.addWidget(current_label,3,0)
+ layout.addWidget(change_label_button,3,1)
+ d.exec_()