diff --git a/gui/qt/installwizard.py b/gui/qt/installwizard.py index f095c41fa..846e5ba32 100644 --- a/gui/qt/installwizard.py +++ b/gui/qt/installwizard.py @@ -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()) diff --git a/lib/wizard.py b/lib/wizard.py index 40c45704e..d462cb17b 100644 --- a/lib/wizard.py +++ b/lib/wizard.py @@ -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 diff --git a/plugins/trezor/client.py b/plugins/trezor/client.py index 04ee35a46..223170c00 100644 --- a/plugins/trezor/client.py +++ b/plugins/trezor/client.py @@ -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 diff --git a/plugins/trezor/plugin.py b/plugins/trezor/plugin.py index 9ef4e2199..7055769cf 100644 --- a/plugins/trezor/plugin.py +++ b/plugins/trezor/plugin.py @@ -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)) diff --git a/plugins/trezor/qt_generic.py b/plugins/trezor/qt_generic.py index e5858884a..840682091 100644 --- a/plugins/trezor/qt_generic.py +++ b/plugins/trezor/qt_generic.py @@ -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()