URI: 
       tTrezor: Implement resetting a device - electrum - Electrum Bitcoin wallet
  HTML git clone https://git.parazyd.org/electrum
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
       ---
   DIR commit 87363c8301acc0689c0e0a4c59219fdd40b16a07
   DIR parent 13154d4ce765aa7c30707081ad0a9b5b66d7dc9e
  HTML Author: Neil Booth <kyuupichan@gmail.com>
       Date:   Sun,  3 Jan 2016 13:32:33 +0900
       
       Trezor: Implement resetting a device
       
       Diffstat:
         M gui/qt/installwizard.py             |      52 +++++++++++++++++++++++++++++++
         M lib/wizard.py                       |      10 ++++++++++
         M plugins/trezor/client.py            |       4 ++--
         M plugins/trezor/plugin.py            |      33 +++++++++++++++++++++----------
         M plugins/trezor/qt_generic.py        |       3 ++-
       
       5 files changed, 89 insertions(+), 13 deletions(-)
       ---
   DIR diff --git a/gui/qt/installwizard.py b/gui/qt/installwizard.py
       t@@ -384,3 +384,55 @@ class InstallWizard(WindowModalDialog, WizardBase):
                self.set_layout(vbox)
                if not self.exec_():
                    raise UserCancelled
       +
       +    def request_trezor_reset_settings(self, device):
       +        vbox = QVBoxLayout()
       +
       +        main_label = QLabel(_("Choose how to initialize your %s device:")
       +                            % device)
       +        vbox.addWidget(main_label)
       +
       +        msg = _("Select your seed length and strength:")
       +        choices = [
       +            _("12 words (low)"),
       +            _("18 words (medium)"),
       +            _("24 words (high)"),
       +        ]
       +        gb = QGroupBox(msg)
       +        vbox1 = QVBoxLayout()
       +        gb.setLayout(vbox1)
       +        bg = QButtonGroup()
       +        for i, choice in enumerate(choices):
       +            rb = QRadioButton(gb)
       +            rb.setText(choice)
       +            bg.addButton(rb)
       +            bg.setId(rb, i)
       +            vbox1.addWidget(rb)
       +        rb.setChecked(True)
       +        vbox.addWidget(gb)
       +
       +        label = QLabel(_("Enter a label to name your device:"))
       +        name = QLineEdit()
       +        hl = QHBoxLayout()
       +        hl.addWidget(label)
       +        hl.addWidget(name)
       +        hl.addStretch(2)
       +        vbox.addLayout(hl)
       +
       +        cb_pin = QCheckBox(_('Enable PIN protection'))
       +        cb_pin.setChecked(True)
       +        vbox.addWidget(cb_pin)
       +
       +        cb_phrase = QCheckBox(_('Enable Passphrase protection'))
       +        cb_phrase.setChecked(False)
       +        vbox.addWidget(cb_phrase)
       +
       +        vbox.addStretch(1)
       +        vbox.addLayout(Buttons(CancelButton(self), OkButton(self, _('Next'))))
       +        self.set_layout(vbox)
       +
       +        if not self.exec_():
       +            raise UserCancelled
       +
       +        return (bg.checkedId(), unicode(name.text()),
       +                cb_pin.isChecked(), cb_phrase.isChecked())
   DIR diff --git a/lib/wizard.py b/lib/wizard.py
       t@@ -103,6 +103,16 @@ class WizardBase(PrintError):
                dynamic feedback.  If not provided, Wallet.is_any is used."""
                raise NotImplementedError
        
       +    def request_trezor_reset_settings(self, device):
       +        """Ask the user how they want to initialize a trezor compatible
       +        device.  device is the device kind, e.g. "Keepkey", to be used
       +        in dialog messages.  Returns a 4-tuple: (strength, label,
       +        pinprotection, passphraseprotection).  Strength is 0, 1 or 2
       +        for a 12, 18 or 24 word seed, respectively.  Label is a name
       +        to give the device.  PIN protection and passphrase protection
       +        are booleans and should default to True and False respectively."""
       +        raise NotImplementedError
       +
            def request_many(self, n, xpub_hot=None):
                """If xpub_hot is provided, a new wallet is being created.  Request N
                master public keys for cosigners; xpub_hot is the master xpub
   DIR diff --git a/plugins/trezor/client.py b/plugins/trezor/client.py
       t@@ -154,8 +154,8 @@ def trezor_client_class(protocol_mixin, base_client, proto):
        
            cls = TrezorClient
            for method in ['apply_settings', 'change_pin', 'get_address',
       -                   'get_public_node', 'sign_message', 'sign_tx',
       -                   'wipe_device']:
       +                   'get_public_node', 'reset_device', 'sign_message',
       +                   'sign_tx', 'wipe_device']:
                setattr(cls, method, wrapper(getattr(cls, method)))
        
            return cls
   DIR diff --git a/plugins/trezor/plugin.py b/plugins/trezor/plugin.py
       t@@ -220,19 +220,32 @@ class TrezorCompatiblePlugin(BasePlugin):
                self.print_error("clear session:", client)
                client.clear_session()
        
       +    def initialize_device(self, wallet, wizard):
       +        (strength, label, pin_protection, passphrase_protection) \
       +            = wizard.request_trezor_reset_settings(self.device)
       +
       +        assert strength in range(0, 3)
       +        strength = 64 * (strength + 2)    # 128, 192 or 256
       +        language = ''
       +
       +        client = self.client(wallet)
       +        client.reset_device(True, strength, passphrase_protection,
       +                            pin_protection, label, language)
       +
       +
            def select_device(self, wallet, wizard):
       -        '''Called when creating a new wallet.  Select the device
       -        to use.'''
       +        '''Called when creating a new wallet.  Select the device to use.  If
       +        the device is uninitialized, go through the intialization
       +        process.'''
                clients = list(self.clients)
       -        if not len(clients):
       -            return
       -        if len(clients) > 1:
       -            labels = [client.label() for client in clients]
       -            msg = _("Please select which %s device to use:") % self.device
       -            client = clients[wizard.query_choice(msg, labels)]
       -        else:
       -            client = clients[0]
       +        suffixes = [_("An unnamed device (wiped)"), _(" (initialized)")]
       +        labels = [client.label() + suffixes[client.is_initialized()]
       +                  for client in clients]
       +        msg = _("Please select which %s device to use:") % self.device
       +        client = clients[wizard.query_choice(msg, labels)]
                self.pair_wallet(wallet, client)
       +        if not client.is_initialized():
       +            self.initialize_device(wallet, wizard)
        
            def pair_wallet(self, wallet, client):
                self.print_error("pairing wallet %s to device %s" % (wallet, client))
   DIR diff --git a/plugins/trezor/qt_generic.py b/plugins/trezor/qt_generic.py
       t@@ -59,7 +59,8 @@ class QtHandler(PrintError):
                return self.passphrase
        
            def pin_dialog(self, msg):
       -        # Needed e.g. when renaming label and haven't entered PIN
       +        # Needed e.g. when resetting a device
       +        self.clear_dialog()
                dialog = WindowModalDialog(self.window_stack[-1], _("Enter PIN"))
                matrix = self.pin_matrix_widget_class()
                vbox = QVBoxLayout()