Skip to content

Commit

Permalink
trezor: bump lib version, implement new passphrase-on-device UI
Browse files Browse the repository at this point in the history
  • Loading branch information
matejcik authored and EchterAgo committed Aug 7, 2020
1 parent c2d8588 commit 8ac98c6
Show file tree
Hide file tree
Showing 6 changed files with 121 additions and 20 deletions.
2 changes: 1 addition & 1 deletion contrib/requirements/requirements-hw.txt
@@ -1,5 +1,5 @@
Cython>=0.27
trezor[hidapi]>=0.11.0
trezor[hidapi]>=0.12.0
keepkey>=6.1
btchip-python
hidapi
Expand Down
8 changes: 4 additions & 4 deletions plugins/trezor/__init__.py
@@ -1,8 +1,8 @@
from electroncash.i18n import _

fullname = _('TREZOR Wallet')
description = _('Provides support for TREZOR hardware wallet')
requires = [('trezorlib','github.com/trezor/python-trezor')]
registers_keystore = ('hardware', 'trezor', _("TREZOR wallet"))
fullname = 'Trezor Wallet'
description = _('Provides support for Trezor hardware wallet')
requires = [('trezorlib','pypi.org/project/trezor/')]
registers_keystore = ('hardware', 'trezor', _("Trezor wallet"))
available_for = ['qt', 'cmdline']

36 changes: 25 additions & 11 deletions plugins/trezor/clientbase.py
Expand Up @@ -6,21 +6,31 @@
from electroncash.keystore import bip39_normalize_passphrase
from electroncash.bitcoin import serialize_xpub

from trezorlib.client import TrezorClient
from trezorlib.client import TrezorClient, PASSPHRASE_ON_DEVICE
from trezorlib.exceptions import TrezorFailure, Cancelled, OutdatedFirmwareError, TrezorException
from trezorlib.messages import WordRequestType, FailureType, RecoveryDeviceType
from trezorlib.messages import WordRequestType, FailureType, RecoveryDeviceType, ButtonRequestType
import trezorlib.btc
import trezorlib.device

MESSAGES = {
3: _("Confirm the transaction output on your {} device"),
4: _("Confirm internal entropy on your {} device to begin"),
5: _("Write down the seed word shown on your {}"),
6: _("Confirm on your {} that you want to wipe it clean"),
7: _("Confirm the operation on on your {} device"),
8: _("Confirm the total amount spent and the transaction fee on your {} device"),
10: _("Confirm wallet address on your {} device"),
14: _("Choose on your {} device where to enter your passphrase"),
ButtonRequestType.ConfirmOutput:
_("Confirm the transaction output on your {} device"),
ButtonRequestType.ResetDevice:
_("Complete the initialization process on your {} device"),
ButtonRequestType.ConfirmWord:
_("Write down the seed word shown on your {}"),
ButtonRequestType.WipeDevice:
_("Confirm on your {} that you want to wipe it clean"),
ButtonRequestType.ProtectCall:
_("Confirm on your {} device the message to sign"),
ButtonRequestType.SignTx:
_("Confirm the total amount spent and the transaction fee on your {} device"),
ButtonRequestType.Address:
_("Confirm wallet address on your {} device"),
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"),
}

Expand Down Expand Up @@ -284,15 +294,19 @@ def get_pin(self, code=None):
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 "
"passphrase. If you forget the passphrase you cannot "
"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)
Expand Down
17 changes: 16 additions & 1 deletion plugins/trezor/cmdline.py
@@ -1,7 +1,22 @@
from electroncash.plugins import hook
from .trezor import TrezorPlugin
from electroncash.i18n import _
from electroncash.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
Expand Down
70 changes: 69 additions & 1 deletion plugins/trezor/qt.py
Expand Up @@ -15,7 +15,8 @@

from ..hw_wallet.qt import QtHandlerBase, QtPluginBase
from .trezor import (TrezorPlugin, TIM_NEW, TIM_RECOVER,
RECOVERY_TYPE_SCRAMBLED_WORDS, RECOVERY_TYPE_MATRIX)
RECOVERY_TYPE_SCRAMBLED_WORDS, RECOVERY_TYPE_MATRIX,
PASSPHRASE_ON_DEVICE)


PASSPHRASE_HELP_SHORT =_(
Expand Down Expand Up @@ -114,6 +115,7 @@ def __init__(self, win, pin_matrix_widget_class, device):
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()
Expand Down Expand Up @@ -158,6 +160,72 @@ def matrix_recovery_dialog(self, msg):
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:
Expand Down
8 changes: 6 additions & 2 deletions plugins/trezor/trezor.py
Expand Up @@ -30,6 +30,8 @@
RECOVERY_TYPE_SCRAMBLED_WORDS = RecoveryDeviceType.ScrambledWords
RECOVERY_TYPE_MATRIX = RecoveryDeviceType.Matrix

from trezorlib.client import PASSPHRASE_ON_DEVICE

TREZORLIB = True
except Exception as e:
import traceback
Expand All @@ -38,6 +40,8 @@

RECOVERY_TYPE_SCRAMBLED_WORDS, RECOVERY_TYPE_MATRIX = range(2)

PASSPHRASE_ON_DEVICE = object()


# TREZOR initialization methods
TIM_NEW, TIM_RECOVER = range(2)
Expand Down Expand Up @@ -104,10 +108,10 @@ 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, 0)
minimum_library = (0, 12, 0)
maximum_library = (0, 13)

DEVICE_IDS = (TREZOR_PRODUCT_KEY,)
Expand Down

0 comments on commit 8ac98c6

Please sign in to comment.