Finish merging keepkey / trezor implementations

This commit is contained in:
Neil Booth 2015-12-27 15:00:58 +09:00
parent d69551f723
commit c02daa56b0
4 changed files with 126 additions and 215 deletions

View File

@ -1,98 +1,6 @@
from PyQt4.Qt import QVBoxLayout, QLabel, SIGNAL, QGridLayout, QInputDialog, QPushButton from plugins.trezor.qt_generic import QtPlugin
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 keepkeylib.qt.pinmatrix import PinMatrixWidget from keepkeylib.qt.pinmatrix import PinMatrixWidget
from keepkey import KeepKeyPlugin, KeepKeyWallet
class KeepKeyQtHandler(QtHandler): class Plugin(QtPlugin):
device = 'KeepKey' handler_class = KeepKeyQtHandler
pin_matrix_widget_class = PinMatrixWidget icon_file = ":icons/keepkey.png"
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_()

View File

@ -9,7 +9,7 @@ from electrum.transaction import deserialize, is_extended_pubkey
class TrezorCompatiblePlugin(BasePlugin): class TrezorCompatiblePlugin(BasePlugin):
# Derived classes provide: # 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, # libraries_available, libraries_URL, minimum_firmware,
# wallet_class, ckd_public, types, HidTransport # wallet_class, ckd_public, types, HidTransport

View File

@ -1,114 +1,6 @@
from PyQt4.Qt import QVBoxLayout, QLabel, SIGNAL, QGridLayout, QInputDialog, QPushButton from plugins.trezor.qt_generic import QtPlugin
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 trezorlib.qt.pinmatrix import PinMatrixWidget from trezorlib.qt.pinmatrix import PinMatrixWidget
class TrezorQtHandler(QtHandler): class Plugin(QtPlugin):
device = 'Trezor'
pin_matrix_widget_class = PinMatrixWidget pin_matrix_widget_class = PinMatrixWidget
icon_file = ":icons/trezor.png"
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_()

View File

@ -1,30 +1,31 @@
from functools import partial
from unicodedata import normalize from unicodedata import normalize
import threading import threading
from PyQt4.Qt import QGridLayout, QInputDialog, QPushButton
from PyQt4.Qt import QVBoxLayout, QLabel, SIGNAL from PyQt4.Qt import QVBoxLayout, QLabel, SIGNAL
import PyQt4.QtCore as QtCore from trezor import TrezorPlugin
from electrum_gui.qt.main_window import ElectrumWindow from electrum_gui.qt.main_window import ElectrumWindow, StatusBarButton
from electrum_gui.qt.installwizard import InstallWizard from electrum_gui.qt.installwizard import InstallWizard
from electrum_gui.qt.password_dialog import PasswordDialog from electrum_gui.qt.password_dialog import PasswordDialog
from electrum_gui.qt.util import * from electrum_gui.qt.util import *
from electrum.i18n import _ from electrum.i18n import _
from electrum.plugins import hook
class QtHandler: class QtHandler:
'''An interface between the GUI (here, QT) and the device handling '''An interface between the GUI (here, QT) and the device handling
logic for handling I/O. This is a generic implementation of the logic for handling I/O. This is a generic implementation of the
Trezor protocol; derived classes can customize it.''' Trezor protocol; derived classes can customize it.'''
# Derived classes must provide: def __init__(self, win, pin_matrix_widget_class, device):
# device a string, e.g. "Trezor"
# pin_matrix_widget_class
def __init__(self, win):
win.connect(win, SIGNAL('message_done'), self.dialog_stop) win.connect(win, SIGNAL('message_done'), self.dialog_stop)
win.connect(win, SIGNAL('message_dialog'), self.message_dialog) win.connect(win, SIGNAL('message_dialog'), self.message_dialog)
win.connect(win, SIGNAL('pin_dialog'), self.pin_dialog) win.connect(win, SIGNAL('pin_dialog'), self.pin_dialog)
win.connect(win, SIGNAL('passphrase_dialog'), self.passphrase_dialog) win.connect(win, SIGNAL('passphrase_dialog'), self.passphrase_dialog)
self.win = win self.win = win
self.pin_matrix_widget_class = pin_matrix_widget_class
self.device = device
self.done = threading.Event() self.done = threading.Event()
self.dialog = None self.dialog = None
@ -92,3 +93,113 @@ class QtHandler:
if self.dialog: if self.dialog:
self.dialog.hide() self.dialog.hide()
self.dialog = None 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_()