URI: 
       tFinish merging keepkey / trezor implementations - electrum - Electrum Bitcoin wallet
  HTML git clone https://git.parazyd.org/electrum
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
       ---
   DIR commit c02daa56b0f48f8fd2e110e7d0ed6e434ff696e8
   DIR parent d69551f723f5b9ee94a6b5f3af7cf69aec1a78e0
  HTML Author: Neil Booth <kyuupichan@gmail.com>
       Date:   Sun, 27 Dec 2015 15:00:58 +0900
       
       Finish merging keepkey / trezor implementations
       
       Diffstat:
         M plugins/keepkey/qt.py               |     100 ++-----------------------------
         M plugins/trezor/plugin.py            |       2 +-
         M plugins/trezor/qt.py                |     114 +------------------------------
         M plugins/trezor/qt_generic.py        |     125 +++++++++++++++++++++++++++++--
       
       4 files changed, 126 insertions(+), 215 deletions(-)
       ---
   DIR diff --git a/plugins/keepkey/qt.py b/plugins/keepkey/qt.py
       t@@ -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"
   DIR diff --git a/plugins/trezor/plugin.py b/plugins/trezor/plugin.py
       t@@ -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
        
   DIR diff --git a/plugins/trezor/qt.py b/plugins/trezor/qt.py
       t@@ -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"
   DIR diff --git a/plugins/trezor/qt_generic.py b/plugins/trezor/qt_generic.py
       t@@ -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
        
       t@@ -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_()