trezor: bump lib version, implement new passphrase-on-device UI

This commit is contained in:
matejcik 2020-03-31 12:22:59 +02:00
parent 3b7299bfde
commit 4cd50dd75a
6 changed files with 103 additions and 11 deletions

View file

@ -8,7 +8,7 @@
# see https://github.com/spesmilo/electrum/issues/5859 # see https://github.com/spesmilo/electrum/issues/5859
Cython>=0.27 Cython>=0.27
trezor[hidapi]>=0.11.5 trezor[hidapi]>=0.12.0
safet>=0.1.5 safet>=0.1.5
keepkey>=6.3.1 keepkey>=6.3.1
btchip-python>=0.1.26 btchip-python>=0.1.26

View file

@ -2,7 +2,7 @@ from electrum.i18n import _
fullname = 'Trezor Wallet' fullname = 'Trezor Wallet'
description = _('Provides support for Trezor hardware 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")) registers_keystore = ('hardware', 'trezor', _("Trezor wallet"))
available_for = ['qt', 'cmdline'] available_for = ['qt', 'cmdline']

View file

@ -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.logging import Logger
from electrum.plugins.hw_wallet.plugin import OutdatedHwFirmwareException, HardwareClientBase 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.exceptions import TrezorFailure, Cancelled, OutdatedFirmwareError
from trezorlib.messages import WordRequestType, FailureType, RecoveryDeviceType, ButtonRequestType from trezorlib.messages import WordRequestType, FailureType, RecoveryDeviceType, ButtonRequestType
import trezorlib.btc import trezorlib.btc
@ -30,8 +30,10 @@ MESSAGES = {
_("Confirm the total amount spent and the transaction fee on your {} device"), _("Confirm the total amount spent and the transaction fee on your {} device"),
ButtonRequestType.Address: ButtonRequestType.Address:
_("Confirm wallet address on your {} device"), _("Confirm wallet address on your {} device"),
ButtonRequestType.PassphraseType: ButtonRequestType._Deprecated_ButtonRequest_PassphraseType:
_("Choose on your {} device where to enter your passphrase"), _("Choose on your {} device where to enter your passphrase"),
ButtonRequestType.PassphraseEntry:
_("Please enter your passphrase on the {} device"),
'default': _("Check your {} device to continue"), 'default': _("Check your {} device to continue"),
} }
@ -259,7 +261,7 @@ class TrezorClientBase(HardwareClientBase, Logger):
raise Cancelled raise Cancelled
return pin return pin
def get_passphrase(self): def get_passphrase(self, available_on_device):
if self.creating_wallet: if self.creating_wallet:
msg = _("Enter a passphrase to generate this wallet. Each time " msg = _("Enter a passphrase to generate this wallet. Each time "
"you use this wallet your {} will prompt you for the " "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) "access the bitcoins in the wallet.").format(self.device)
else: else:
msg = _("Enter the passphrase to unlock this wallet:") 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: if passphrase is None:
raise Cancelled raise Cancelled
passphrase = bip39_normalize_passphrase(passphrase) passphrase = bip39_normalize_passphrase(passphrase)

View file

@ -1,7 +1,22 @@
from electrum.plugin import hook 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 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): class Plugin(TrezorPlugin):
handler = CmdLineHandler() handler = CmdLineHandler()
@hook @hook

View file

@ -16,7 +16,7 @@ from electrum.util import bh2u
from ..hw_wallet.qt import QtHandlerBase, QtPluginBase from ..hw_wallet.qt import QtHandlerBase, QtPluginBase
from ..hw_wallet.plugin import only_hook_if_libraries_available from ..hw_wallet.plugin import only_hook_if_libraries_available
from .trezor import (TrezorPlugin, TIM_NEW, TIM_RECOVER, TrezorInitSettings, from .trezor import (TrezorPlugin, TIM_NEW, TIM_RECOVER, TrezorInitSettings,
Capability, BackupType, RecoveryDeviceType) PASSPHRASE_ON_DEVICE, Capability, BackupType, RecoveryDeviceType)
PASSPHRASE_HELP_SHORT =_( PASSPHRASE_HELP_SHORT =_(
@ -119,6 +119,7 @@ class QtHandler(QtHandlerBase):
self.close_matrix_dialog_signal.connect(self._close_matrix_dialog) self.close_matrix_dialog_signal.connect(self._close_matrix_dialog)
self.pin_matrix_widget_class = pin_matrix_widget_class self.pin_matrix_widget_class = pin_matrix_widget_class
self.matrix_dialog = None self.matrix_dialog = None
self.passphrase_on_device = False
def get_pin(self, msg): def get_pin(self, msg):
self.done.clear() self.done.clear()
@ -163,6 +164,72 @@ class QtHandler(QtHandlerBase):
self.matrix_dialog.get_matrix(msg) self.matrix_dialog.get_matrix(msg)
self.done.set() 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): class QtPlugin(QtPluginBase):
# Derived classes must provide the following class-static variables: # Derived classes must provide the following class-static variables:

View file

@ -32,6 +32,8 @@ try:
InputScriptType, OutputScriptType, MultisigRedeemScriptType, InputScriptType, OutputScriptType, MultisigRedeemScriptType,
TxInputType, TxOutputType, TxOutputBinType, TransactionType, SignTx) TxInputType, TxOutputType, TxOutputBinType, TransactionType, SignTx)
from trezorlib.client import PASSPHRASE_ON_DEVICE
TREZORLIB = True TREZORLIB = True
except Exception as e: except Exception as e:
_logger.exception('error importing trezorlib') _logger.exception('error importing trezorlib')
@ -52,6 +54,8 @@ except Exception as e:
BackupType = _EnumMissing() BackupType = _EnumMissing()
RecoveryDeviceType = _EnumMissing() RecoveryDeviceType = _EnumMissing()
PASSPHRASE_ON_DEVICE = object()
# Trezor initialization methods # Trezor initialization methods
TIM_NEW, TIM_RECOVER = range(2) TIM_NEW, TIM_RECOVER = range(2)
@ -109,11 +113,11 @@ class TrezorPlugin(HW_PluginBase):
# wallet_class, types # wallet_class, types
firmware_URL = 'https://wallet.trezor.io' 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) minimum_firmware = (1, 5, 2)
keystore_class = TrezorKeyStore keystore_class = TrezorKeyStore
minimum_library = (0, 11, 5) minimum_library = (0, 12, 0)
maximum_library = (0, 12) maximum_library = (0, 13)
SUPPORTED_XTYPES = ('standard', 'p2wpkh-p2sh', 'p2wpkh', 'p2wsh-p2sh', 'p2wsh') SUPPORTED_XTYPES = ('standard', 'p2wpkh-p2sh', 'p2wpkh', 'p2wsh-p2sh', 'p2wsh')
DEVICE_IDS = (TREZOR_PRODUCT_KEY,) DEVICE_IDS = (TREZOR_PRODUCT_KEY,)