From 4cd50dd75a2613a3d631cefaf0bf88831786b6fd Mon Sep 17 00:00:00 2001 From: matejcik Date: Tue, 31 Mar 2020 12:22:59 +0200 Subject: [PATCH 1/2] trezor: bump lib version, implement new passphrase-on-device UI --- contrib/requirements/requirements-hw.txt | 2 +- electrum/plugins/trezor/__init__.py | 2 +- electrum/plugins/trezor/clientbase.py | 14 +++-- electrum/plugins/trezor/cmdline.py | 17 +++++- electrum/plugins/trezor/qt.py | 69 +++++++++++++++++++++++- electrum/plugins/trezor/trezor.py | 10 ++-- 6 files changed, 103 insertions(+), 11 deletions(-) diff --git a/contrib/requirements/requirements-hw.txt b/contrib/requirements/requirements-hw.txt index e4a9024c0..a442d7147 100644 --- a/contrib/requirements/requirements-hw.txt +++ b/contrib/requirements/requirements-hw.txt @@ -8,7 +8,7 @@ # see https://github.com/spesmilo/electrum/issues/5859 Cython>=0.27 -trezor[hidapi]>=0.11.5 +trezor[hidapi]>=0.12.0 safet>=0.1.5 keepkey>=6.3.1 btchip-python>=0.1.26 diff --git a/electrum/plugins/trezor/__init__.py b/electrum/plugins/trezor/__init__.py index 2d4267d78..6aff1e0f4 100644 --- a/electrum/plugins/trezor/__init__.py +++ b/electrum/plugins/trezor/__init__.py @@ -2,7 +2,7 @@ from electrum.i18n import _ fullname = 'Trezor Wallet' description = _('Provides support for Trezor hardware wallet') -requires = [('trezorlib','github.com/trezor/python-trezor')] +requires = [('trezorlib','pypi.org/project/trezor/')] registers_keystore = ('hardware', 'trezor', _("Trezor wallet")) available_for = ['qt', 'cmdline'] diff --git a/electrum/plugins/trezor/clientbase.py b/electrum/plugins/trezor/clientbase.py index 99059f442..66e32ad15 100644 --- a/electrum/plugins/trezor/clientbase.py +++ b/electrum/plugins/trezor/clientbase.py @@ -9,7 +9,7 @@ from electrum.bip32 import BIP32Node, convert_bip32_path_to_list_of_uint32 as pa from electrum.logging import Logger from electrum.plugins.hw_wallet.plugin import OutdatedHwFirmwareException, HardwareClientBase -from trezorlib.client import TrezorClient +from trezorlib.client import TrezorClient, PASSPHRASE_ON_DEVICE from trezorlib.exceptions import TrezorFailure, Cancelled, OutdatedFirmwareError from trezorlib.messages import WordRequestType, FailureType, RecoveryDeviceType, ButtonRequestType import trezorlib.btc @@ -30,8 +30,10 @@ MESSAGES = { _("Confirm the total amount spent and the transaction fee on your {} device"), ButtonRequestType.Address: _("Confirm wallet address on your {} device"), - ButtonRequestType.PassphraseType: + ButtonRequestType._Deprecated_ButtonRequest_PassphraseType: _("Choose on your {} device where to enter your passphrase"), + ButtonRequestType.PassphraseEntry: + _("Please enter your passphrase on the {} device"), 'default': _("Check your {} device to continue"), } @@ -259,7 +261,7 @@ class TrezorClientBase(HardwareClientBase, Logger): raise Cancelled return pin - def get_passphrase(self): + def get_passphrase(self, available_on_device): if self.creating_wallet: msg = _("Enter a passphrase to generate this wallet. Each time " "you use this wallet your {} will prompt you for the " @@ -267,7 +269,11 @@ class TrezorClientBase(HardwareClientBase, Logger): "access the bitcoins in the wallet.").format(self.device) else: msg = _("Enter the passphrase to unlock this wallet:") - passphrase = self.handler.get_passphrase(msg, self.creating_wallet) + + self.handler.passphrase_on_device = available_on_device + passphrase = self.handler.trezor_get_passphrase(msg, self.creating_wallet) + if passphrase is PASSPHRASE_ON_DEVICE: + return passphrase if passphrase is None: raise Cancelled passphrase = bip39_normalize_passphrase(passphrase) diff --git a/electrum/plugins/trezor/cmdline.py b/electrum/plugins/trezor/cmdline.py index e435aad13..5a7ee1596 100644 --- a/electrum/plugins/trezor/cmdline.py +++ b/electrum/plugins/trezor/cmdline.py @@ -1,7 +1,22 @@ from electrum.plugin import hook -from .trezor import TrezorPlugin +from electrum.i18n import _ +from electrum.util import print_stderr +from .trezor import TrezorPlugin, PASSPHRASE_ON_DEVICE from ..hw_wallet import CmdLineHandler +class TrezorCmdLineHandler(CmdLineHandler): + def __init__(self): + self.passphrase_on_device = False + super().__init__() + + def get_passphrase(self, msg, confirm): + import getpass + print_stderr(msg) + if self.passphrase_on_device and self.yes_no_question(_('Enter passphrase on device?')): + return PASSPHRASE_ON_DEVICE + else: + return getpass.getpass('') + class Plugin(TrezorPlugin): handler = CmdLineHandler() @hook diff --git a/electrum/plugins/trezor/qt.py b/electrum/plugins/trezor/qt.py index 3a8b2cba3..2438f27fe 100644 --- a/electrum/plugins/trezor/qt.py +++ b/electrum/plugins/trezor/qt.py @@ -16,7 +16,7 @@ from electrum.util import bh2u from ..hw_wallet.qt import QtHandlerBase, QtPluginBase from ..hw_wallet.plugin import only_hook_if_libraries_available from .trezor import (TrezorPlugin, TIM_NEW, TIM_RECOVER, TrezorInitSettings, - Capability, BackupType, RecoveryDeviceType) + PASSPHRASE_ON_DEVICE, Capability, BackupType, RecoveryDeviceType) PASSPHRASE_HELP_SHORT =_( @@ -119,6 +119,7 @@ class QtHandler(QtHandlerBase): self.close_matrix_dialog_signal.connect(self._close_matrix_dialog) self.pin_matrix_widget_class = pin_matrix_widget_class self.matrix_dialog = None + self.passphrase_on_device = False def get_pin(self, msg): self.done.clear() @@ -163,6 +164,72 @@ class QtHandler(QtHandlerBase): self.matrix_dialog.get_matrix(msg) self.done.set() + def passphrase_dialog(self, msg, confirm): + # If confirm is true, require the user to enter the passphrase twice + parent = self.top_level_window() + d = WindowModalDialog(parent, _('Enter Passphrase')) + + OK_button = OkButton(d, _('Enter Passphrase')) + OnDevice_button = QPushButton(_('Enter Passphrase on Device')) + + new_pw = QLineEdit() + new_pw.setEchoMode(2) + conf_pw = QLineEdit() + conf_pw.setEchoMode(2) + + vbox = QVBoxLayout() + label = QLabel(msg + "\n") + label.setWordWrap(True) + + grid = QGridLayout() + grid.setSpacing(8) + grid.setColumnMinimumWidth(0, 150) + grid.setColumnMinimumWidth(1, 100) + grid.setColumnStretch(1,1) + + vbox.addWidget(label) + + grid.addWidget(QLabel(_('Passphrase:')), 0, 0) + grid.addWidget(new_pw, 0, 1) + + if confirm: + grid.addWidget(QLabel(_('Confirm Passphrase:')), 1, 0) + grid.addWidget(conf_pw, 1, 1) + + vbox.addLayout(grid) + + def enable_OK(): + if not confirm: + ok = True + else: + ok = new_pw.text() == conf_pw.text() + OK_button.setEnabled(ok) + + new_pw.textChanged.connect(enable_OK) + conf_pw.textChanged.connect(enable_OK) + + vbox.addWidget(OK_button) + + if self.passphrase_on_device: + vbox.addWidget(OnDevice_button) + + d.setLayout(vbox) + + self.passphrase = None + + def ok_clicked(): + self.passphrase = new_pw.text() + + def on_device_clicked(): + self.passphrase = PASSPHRASE_ON_DEVICE + + OK_button.clicked.connect(ok_clicked) + OnDevice_button.clicked.connect(on_device_clicked) + OnDevice_button.clicked.connect(d.accept) + + d.exec_() + self.done.set() + class QtPlugin(QtPluginBase): # Derived classes must provide the following class-static variables: diff --git a/electrum/plugins/trezor/trezor.py b/electrum/plugins/trezor/trezor.py index 71341d91c..4a0bf9037 100644 --- a/electrum/plugins/trezor/trezor.py +++ b/electrum/plugins/trezor/trezor.py @@ -32,6 +32,8 @@ try: InputScriptType, OutputScriptType, MultisigRedeemScriptType, TxInputType, TxOutputType, TxOutputBinType, TransactionType, SignTx) + from trezorlib.client import PASSPHRASE_ON_DEVICE + TREZORLIB = True except Exception as e: _logger.exception('error importing trezorlib') @@ -52,6 +54,8 @@ except Exception as e: BackupType = _EnumMissing() RecoveryDeviceType = _EnumMissing() + PASSPHRASE_ON_DEVICE = object() + # Trezor initialization methods TIM_NEW, TIM_RECOVER = range(2) @@ -109,11 +113,11 @@ class TrezorPlugin(HW_PluginBase): # wallet_class, types firmware_URL = 'https://wallet.trezor.io' - libraries_URL = 'https://github.com/trezor/python-trezor' + libraries_URL = 'https://pypi.org/project/trezor/' minimum_firmware = (1, 5, 2) keystore_class = TrezorKeyStore - minimum_library = (0, 11, 5) - maximum_library = (0, 12) + minimum_library = (0, 12, 0) + maximum_library = (0, 13) SUPPORTED_XTYPES = ('standard', 'p2wpkh-p2sh', 'p2wpkh', 'p2wsh-p2sh', 'p2wsh') DEVICE_IDS = (TREZOR_PRODUCT_KEY,) From fb5382f75f2168a9cbadbddd2d53f8820de59bf0 Mon Sep 17 00:00:00 2001 From: SomberNight Date: Mon, 6 Apr 2020 19:49:56 +0200 Subject: [PATCH 2/2] follow-up prev (typo) --- electrum/plugins/trezor/clientbase.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/electrum/plugins/trezor/clientbase.py b/electrum/plugins/trezor/clientbase.py index 66e32ad15..430905b0a 100644 --- a/electrum/plugins/trezor/clientbase.py +++ b/electrum/plugins/trezor/clientbase.py @@ -271,7 +271,7 @@ class TrezorClientBase(HardwareClientBase, Logger): msg = _("Enter the passphrase to unlock this wallet:") self.handler.passphrase_on_device = available_on_device - passphrase = self.handler.trezor_get_passphrase(msg, self.creating_wallet) + passphrase = self.handler.get_passphrase(msg, self.creating_wallet) if passphrase is PASSPHRASE_ON_DEVICE: return passphrase if passphrase is None: