tMerge pull request #6064 from matejcik/trezor-0.12-passphrase - electrum - Electrum Bitcoin wallet HTML git clone https://git.parazyd.org/electrum DIR Log DIR Files DIR Refs DIR Submodules --- DIR commit 4d980cd4bdf3db7bbe0711b92f820d2525917322 DIR parent d2a58a2ec3682daea6a1f248eb7a543e2bad47fa HTML Author: ghost43 <somber.night@protonmail.com> Date: Mon, 6 Apr 2020 17:53:59 +0000 Merge pull request #6064 from matejcik/trezor-0.12-passphrase ttrezor: bump lib version, implement new passphrase-on-device UI Diffstat: M contrib/requirements/requirements-… | 2 +- M electrum/plugins/trezor/__init__.py | 2 +- M electrum/plugins/trezor/clientbase… | 12 +++++++++--- M electrum/plugins/trezor/cmdline.py | 17 ++++++++++++++++- M electrum/plugins/trezor/qt.py | 69 ++++++++++++++++++++++++++++++- M electrum/plugins/trezor/trezor.py | 10 +++++++--- 6 files changed, 102 insertions(+), 10 deletions(-) --- DIR diff --git a/contrib/requirements/requirements-hw.txt b/contrib/requirements/requirements-hw.txt t@@ -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 DIR diff --git a/electrum/plugins/trezor/__init__.py b/electrum/plugins/trezor/__init__.py t@@ -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'] DIR diff --git a/electrum/plugins/trezor/clientbase.py b/electrum/plugins/trezor/clientbase.py t@@ -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 t@@ -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"), } t@@ -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 " t@@ -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:") + + self.handler.passphrase_on_device = available_on_device passphrase = self.handler.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) DIR diff --git a/electrum/plugins/trezor/cmdline.py b/electrum/plugins/trezor/cmdline.py t@@ -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 DIR diff --git a/electrum/plugins/trezor/qt.py b/electrum/plugins/trezor/qt.py t@@ -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 =_( t@@ -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() t@@ -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: DIR diff --git a/electrum/plugins/trezor/trezor.py b/electrum/plugins/trezor/trezor.py t@@ -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') t@@ -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) t@@ -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,)