tMove trezor-specific install wizard code to plugin - electrum - Electrum Bitcoin wallet HTML git clone https://git.parazyd.org/electrum DIR Log DIR Files DIR Refs DIR Submodules --- DIR commit 3e8598c245c55aaa408199bc56800224639bd892 DIR parent 54cdd551fead951b8c04624ea0b97090b3b10668 HTML Author: Neil Booth <kyuupichan@gmail.com> Date: Sat, 9 Jan 2016 15:20:31 +0900 Move trezor-specific install wizard code to plugin Diffstat: M gui/qt/installwizard.py | 85 ------------------------------- M lib/wizard.py | 18 ------------------ M plugins/trezor/plugin.py | 22 ++++++++++++---------- M plugins/trezor/qt_generic.py | 98 ++++++++++++++++++++++++++++++- 4 files changed, 107 insertions(+), 116 deletions(-) --- DIR diff --git a/gui/qt/installwizard.py b/gui/qt/installwizard.py t@@ -418,88 +418,3 @@ class InstallWizard(WindowModalDialog, WizardBase): self.set_layout(vbox) if not self.exec_(): raise UserCancelled - - def request_trezor_init_settings(self, method, device): - vbox = QVBoxLayout() - - main_label = QLabel(_("Initialization settings for your %s:") % device) - vbox.addWidget(main_label) - - OK_button = OkButton(self, _('Next')) - - if method in [self.TIM_NEW, self.TIM_RECOVER]: - gb = QGroupBox() - vbox1 = QVBoxLayout() - gb.setLayout(vbox1) - vbox.addWidget(gb) - gb.setTitle(_("Select your seed length:")) - choices = [ - _("12 words"), - _("18 words"), - _("24 words"), - ] - 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) - cb_pin = QCheckBox(_('Enable PIN protection')) - cb_pin.setChecked(True) - else: - text = QTextEdit() - text.setMaximumHeight(60) - if method == self.TIM_MNEMONIC: - msg = _("Enter your BIP39 mnemonic:") - else: - msg = _("Enter the master private key beginning with xprv:") - def set_enabled(): - OK_button.setEnabled(Wallet.is_xprv( - self.get_seed_text(text))) - text.textChanged.connect(set_enabled) - OK_button.setEnabled(False) - - vbox.addWidget(QLabel(msg)) - vbox.addWidget(text) - pin = QLineEdit() - pin.setValidator(QRegExpValidator(QRegExp('[1-9]{0,10}'))) - pin.setMaximumWidth(100) - hbox_pin = QHBoxLayout() - hbox_pin.addWidget(QLabel(_("Enter your PIN (digits 1-9):"))) - hbox_pin.addWidget(pin) - hbox_pin.addStretch(1) - - label = QLabel(_("Enter a label to name your device:")) - name = QLineEdit() - hl = QHBoxLayout() - hl.addWidget(label) - hl.addWidget(name) - hl.addStretch(1) - vbox.addLayout(hl) - - if method in [self.TIM_NEW, self.TIM_RECOVER]: - vbox.addWidget(cb_pin) - else: - vbox.addLayout(hbox_pin) - - cb_phrase = QCheckBox(_('Enable Passphrase protection')) - cb_phrase.setChecked(False) - vbox.addWidget(cb_phrase) - - vbox.addStretch(1) - vbox.addLayout(Buttons(CancelButton(self), OK_button)) - self.set_layout(vbox) - - if not self.exec_(): - raise UserCancelled - - if method in [self.TIM_NEW, self.TIM_RECOVER]: - item = bg.checkedId() - pin = cb_pin.isChecked() - else: - item = ' '.join(str(self.get_seed_text(text)).split()) - pin = str(pin.text()) - - return (item, unicode(name.text()), pin, cb_phrase.isChecked()) DIR diff --git a/lib/wizard.py b/lib/wizard.py t@@ -48,7 +48,6 @@ class WizardBase(PrintError): ('multisig', _("Multi-signature wallet")), ('hardware', _("Hardware wallet")), ] - TIM_NEW, TIM_RECOVER, TIM_MNEMONIC, TIM_PRIVKEY = range(0, 4) # Derived classes must set: # self.language_for_seed t@@ -103,23 +102,6 @@ class WizardBase(PrintError): dynamic feedback. If not provided, Wallet.is_any is used.""" raise NotImplementedError - def request_trezor_init_settings(self, method, device): - """Ask the user for the information needed to initialize a trezor- - compatible device. Method is one of the TIM_ trezor init - method constants. TIM_NEW and TIM_RECOVER should ask how many - seed words to use, and return 0, 1 or 2 for a 12, 18 or 24 - word seed respectively. TIM_MNEMONIC should ask for a - mnemonic. TIM_PRIVKEY should ask for a master private key. - All four methods should additionally ask for a name to label - the device, PIN information and whether passphrase protection is - to be enabled (True/False, default to False). For TIM_NEW and - TIM_RECOVER, the pin information is whether pin protection - is required (True/False, default to True); for TIM_MNEMONIC and - TIM_PRIVKEY is is the pin as a string of digits 1-9. - The result is a 4-tuple: (TIM specific data, label, pininfo, - passphraseprotection).""" - 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/plugin.py b/plugins/trezor/plugin.py t@@ -14,7 +14,9 @@ from electrum.transaction import (deserialize, is_extended_pubkey, from electrum.wallet import BIP32_HD_Wallet, BIP44_Wallet from electrum.util import ThreadJob from electrum.plugins import DeviceMgr -from electrum.wizard import WizardBase + +# Trezor initialization methods +TIM_NEW, TIM_RECOVER, TIM_MNEMONIC, TIM_PRIVKEY = range(0, 4) class DeviceDisconnectedError(Exception): pass t@@ -247,7 +249,7 @@ class TrezorCompatiblePlugin(BasePlugin, ThreadJob): if isinstance(wallet, self.wallet_class): self.device_manager().close_wallet(wallet) - def initialize_device(self, wallet, wizard): + def initialize_device(self, wallet): # Prevent timeouts during initialization wallet.last_operation = self.prevent_timeout t@@ -268,22 +270,22 @@ class TrezorCompatiblePlugin(BasePlugin, ThreadJob): _("Upload a master private key") ] - method = wizard.query_choice(msg, methods) + method = wallet.handler.query_choice(msg, methods) (item, label, pin_protection, passphrase_protection) \ - = wizard.request_trezor_init_settings(method, self.device) + = wallet.handler.request_trezor_init_settings(method, self.device) client = self.get_client(wallet) language = 'english' - if method == WizardBase.TIM_NEW: + if method == TIM_NEW: strength = 64 * (item + 2) # 128, 192 or 256 client.reset_device(True, strength, passphrase_protection, pin_protection, label, language) - elif method == WizardBase.TIM_RECOVER: + elif method == TIM_RECOVER: word_count = 6 * (item + 2) # 12, 18 or 24 client.recovery_device(word_count, passphrase_protection, pin_protection, label, language) - elif method == WizardBase.TIM_MNEMONIC: + elif method == TIM_MNEMONIC: pin = pin_protection # It's the pin, not a boolean client.load_device_by_mnemonic(str(item), pin, passphrase_protection, t@@ -293,7 +295,7 @@ class TrezorCompatiblePlugin(BasePlugin, ThreadJob): client.load_device_by_xprv(item, pin, passphrase_protection, label, language) - def select_device(self, wallet, wizard): + def select_device(self, wallet): '''Called when creating a new wallet. Select the device to use. If the device is uninitialized, go through the intialization process.''' t@@ -306,10 +308,10 @@ class TrezorCompatiblePlugin(BasePlugin, ThreadJob): labels = list(map(client_desc, clients)) msg = _("Please select which %s device to use:") % self.device - client = clients[wizard.query_choice(msg, labels)] + client = clients[wallet.handler.query_choice(msg, labels)] self.device_manager().pair_wallet(wallet, client) if not client.is_initialized(): - self.initialize_device(wallet, wizard) + self.initialize_device(wallet) def on_restore_wallet(self, wallet, wizard): assert isinstance(wallet, self.wallet_class) DIR diff --git a/plugins/trezor/qt_generic.py b/plugins/trezor/qt_generic.py t@@ -8,12 +8,13 @@ from PyQt4.Qt import QVBoxLayout, QLabel, SIGNAL from electrum_gui.qt.main_window import StatusBarButton from electrum_gui.qt.password_dialog import PasswordDialog from electrum_gui.qt.util import * -from plugin import TrezorCompatiblePlugin +from .plugin import TrezorCompatiblePlugin, TIM_NEW, TIM_RECOVER, TIM_MNEMONIC from electrum.i18n import _ from electrum.plugins import hook, DeviceMgr from electrum.util import PrintError -from electrum.wallet import BIP44_Wallet +from electrum.wallet import Wallet, BIP44_Wallet +from electrum.wizard import UserCancelled # By far the trickiest thing about this handler is the window stack; t@@ -134,6 +135,97 @@ class QtHandler(PrintError): finally: assert dialog == self.window_stack.pop() + def query_choice(self, msg, labels): + return self.win.query_choice(msg, labels) + + def request_trezor_init_settings(self, method, device): + wizard = self.win + + vbox = QVBoxLayout() + main_label = QLabel(_("Initialization settings for your %s:") % device) + vbox.addWidget(main_label) + OK_button = OkButton(wizard, _('Next')) + + def clean_text(widget): + text = unicode(widget.toPlainText()).strip() + return ' '.join(text.split()) + + if method in [TIM_NEW, TIM_RECOVER]: + gb = QGroupBox() + vbox1 = QVBoxLayout() + gb.setLayout(vbox1) + vbox.addWidget(gb) + gb.setTitle(_("Select your seed length:")) + choices = [ + _("12 words"), + _("18 words"), + _("24 words"), + ] + 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) + cb_pin = QCheckBox(_('Enable PIN protection')) + cb_pin.setChecked(True) + else: + text = QTextEdit() + text.setMaximumHeight(60) + if method == TIM_MNEMONIC: + msg = _("Enter your BIP39 mnemonic:") + else: + msg = _("Enter the master private key beginning with xprv:") + def set_enabled(): + OK_button.setEnabled(Wallet.is_xprv(clean_text(text))) + text.textChanged.connect(set_enabled) + OK_button.setEnabled(False) + + vbox.addWidget(QLabel(msg)) + vbox.addWidget(text) + pin = QLineEdit() + pin.setValidator(QRegExpValidator(QRegExp('[1-9]{0,10}'))) + pin.setMaximumWidth(100) + hbox_pin = QHBoxLayout() + hbox_pin.addWidget(QLabel(_("Enter your PIN (digits 1-9):"))) + hbox_pin.addWidget(pin) + hbox_pin.addStretch(1) + + label = QLabel(_("Enter a label to name your device:")) + name = QLineEdit() + hl = QHBoxLayout() + hl.addWidget(label) + hl.addWidget(name) + hl.addStretch(1) + vbox.addLayout(hl) + + if method in [TIM_NEW, TIM_RECOVER]: + vbox.addWidget(cb_pin) + else: + vbox.addLayout(hbox_pin) + + cb_phrase = QCheckBox(_('Enable Passphrase protection')) + cb_phrase.setChecked(False) + vbox.addWidget(cb_phrase) + + vbox.addStretch(1) + vbox.addLayout(Buttons(CancelButton(wizard), OK_button)) + + wizard.set_layout(vbox) + if not wizard.exec_(): + raise UserCancelled + + if method in [TIM_NEW, TIM_RECOVER]: + item = bg.checkedId() + pin = cb_pin.isChecked() + else: + item = ' '.join(str(clean_text(text)).split()) + pin = str(pin.text()) + + return (item, unicode(name.text()), pin, cb_phrase.isChecked()) + def qt_plugin_class(base_plugin_class): t@@ -159,7 +251,7 @@ def qt_plugin_class(base_plugin_class): def on_create_wallet(self, wallet, wizard): assert type(wallet) == self.wallet_class wallet.handler = self.create_handler(wizard) - self.select_device(wallet, wizard) + self.select_device(wallet) wallet.create_hd_account(None) @hook