mirror of
https://github.com/LBRYFoundation/LBRY-Vault.git
synced 2025-09-11 04:59:51 +00:00
Trezor: Add wipe device functionality
Also add a chicken box for PIN removal.
This commit is contained in:
parent
9aae66a9d2
commit
a7028176cd
6 changed files with 122 additions and 56 deletions
|
@ -55,7 +55,7 @@ class CosignWidget(QWidget):
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class InstallWizard(WindowModalDialog, MessageBoxMixin, WizardBase):
|
class InstallWizard(WindowModalDialog, WizardBase):
|
||||||
|
|
||||||
def __init__(self, config, app, plugins):
|
def __init__(self, config, app, plugins):
|
||||||
title = 'Electrum - ' + _('Install Wizard')
|
title = 'Electrum - ' + _('Install Wizard')
|
||||||
|
|
|
@ -8,7 +8,7 @@ import qrcode
|
||||||
import electrum
|
import electrum
|
||||||
from electrum import bmp
|
from electrum import bmp
|
||||||
from electrum.i18n import _
|
from electrum.i18n import _
|
||||||
from util import WindowModalDialog, MessageBoxMixin
|
from util import WindowModalDialog
|
||||||
|
|
||||||
|
|
||||||
class QRCodeWidget(QWidget):
|
class QRCodeWidget(QWidget):
|
||||||
|
@ -83,7 +83,7 @@ class QRCodeWidget(QWidget):
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class QRDialog(WindowModalDialog, MessageBoxMixin):
|
class QRDialog(WindowModalDialog):
|
||||||
|
|
||||||
def __init__(self, data, parent=None, title = "", show_text=False):
|
def __init__(self, data, parent=None, title = "", show_text=False):
|
||||||
WindowModalDialog.__init__(self, parent, title)
|
WindowModalDialog.__init__(self, parent, title)
|
||||||
|
|
|
@ -156,9 +156,10 @@ class CancelButton(QPushButton):
|
||||||
self.clicked.connect(dialog.reject)
|
self.clicked.connect(dialog.reject)
|
||||||
|
|
||||||
class MessageBoxMixin:
|
class MessageBoxMixin:
|
||||||
def question(self, msg, parent=None, title=None):
|
def question(self, msg, parent=None, title=None, icon=None):
|
||||||
Yes, No = QMessageBox.Yes, QMessageBox.No
|
Yes, No = QMessageBox.Yes, QMessageBox.No
|
||||||
return self.msg_box(QMessageBox.Question, parent or self, title or '',
|
return self.msg_box(icon or QMessageBox.Question,
|
||||||
|
parent or self, title or '',
|
||||||
msg, buttons=Yes|No, defaultButton=No) == Yes
|
msg, buttons=Yes|No, defaultButton=No) == Yes
|
||||||
|
|
||||||
def show_warning(self, msg, parent=None, title=None):
|
def show_warning(self, msg, parent=None, title=None):
|
||||||
|
@ -188,7 +189,7 @@ class MessageBoxMixin:
|
||||||
d.setDefaultButton(defaultButton)
|
d.setDefaultButton(defaultButton)
|
||||||
return d.exec_()
|
return d.exec_()
|
||||||
|
|
||||||
class WindowModalDialog(QDialog):
|
class WindowModalDialog(QDialog, MessageBoxMixin):
|
||||||
'''Handy wrapper; window modal dialogs are better for our multi-window
|
'''Handy wrapper; window modal dialogs are better for our multi-window
|
||||||
daemon model as other wallet windows can still be accessed.'''
|
daemon model as other wallet windows can still be accessed.'''
|
||||||
def __init__(self, parent, title=None):
|
def __init__(self, parent, title=None):
|
||||||
|
|
|
@ -154,7 +154,8 @@ def trezor_client_class(protocol_mixin, base_client, proto):
|
||||||
|
|
||||||
cls = TrezorClient
|
cls = TrezorClient
|
||||||
for method in ['apply_settings', 'change_pin', 'get_address',
|
for method in ['apply_settings', 'change_pin', 'get_address',
|
||||||
'get_public_node', 'sign_message', 'sign_tx']:
|
'get_public_node', 'sign_message', 'sign_tx',
|
||||||
|
'wipe_device']:
|
||||||
setattr(cls, method, wrapper(getattr(cls, method)))
|
setattr(cls, method, wrapper(getattr(cls, method)))
|
||||||
|
|
||||||
return cls
|
return cls
|
||||||
|
|
|
@ -42,6 +42,14 @@ class TrezorCompatibleWallet(BIP44_Wallet):
|
||||||
self.print_error("connected")
|
self.print_error("connected")
|
||||||
self.handler.watching_only_changed()
|
self.handler.watching_only_changed()
|
||||||
|
|
||||||
|
def wiped(self):
|
||||||
|
self.print_error("wiped")
|
||||||
|
self.handler.watching_only_changed()
|
||||||
|
|
||||||
|
def initialized(self):
|
||||||
|
self.print_error("initialized")
|
||||||
|
self.handler.watching_only_changed()
|
||||||
|
|
||||||
def get_action(self):
|
def get_action(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -316,6 +324,7 @@ class TrezorCompatiblePlugin(BasePlugin):
|
||||||
|
|
||||||
@hook
|
@hook
|
||||||
def close_wallet(self, wallet):
|
def close_wallet(self, wallet):
|
||||||
|
if isinstance(wallet, self.wallet_class):
|
||||||
# Don't retain references to a closed wallet
|
# Don't retain references to a closed wallet
|
||||||
self.paired_wallets.discard(wallet)
|
self.paired_wallets.discard(wallet)
|
||||||
client = self.lookup_client(wallet)
|
client = self.lookup_client(wallet)
|
||||||
|
|
|
@ -145,8 +145,36 @@ def qt_plugin_class(base_plugin_class):
|
||||||
lambda: self.show_address(wallet, addrs[0]))
|
lambda: self.show_address(wallet, addrs[0]))
|
||||||
|
|
||||||
def settings_dialog(self, window):
|
def settings_dialog(self, window):
|
||||||
handler = window.wallet.handler
|
|
||||||
client = self.client(window.wallet)
|
def client():
|
||||||
|
return self.client(wallet)
|
||||||
|
|
||||||
|
def add_rows_to_layout(layout, rows):
|
||||||
|
for row_num, items in enumerate(rows):
|
||||||
|
for col_num, txt in enumerate(items):
|
||||||
|
widget = txt if isinstance(txt, QWidget) else QLabel(txt)
|
||||||
|
layout.addWidget(widget, row_num, col_num)
|
||||||
|
|
||||||
|
def refresh():
|
||||||
|
features = client().features
|
||||||
|
bl_hash = features.bootloader_hash.encode('hex').upper()
|
||||||
|
bl_hash = "%s...%s" % (bl_hash[:10], bl_hash[-10:])
|
||||||
|
version = "%d.%d.%d" % (features.major_version,
|
||||||
|
features.minor_version,
|
||||||
|
features.patch_version)
|
||||||
|
|
||||||
|
bl_hash_label.setText(bl_hash)
|
||||||
|
device_label.setText(features.label)
|
||||||
|
device_id_label.setText(features.device_id)
|
||||||
|
initialized_label.setText(noyes[features.initialized])
|
||||||
|
version_label.setText(version)
|
||||||
|
pin_label.setText(noyes[features.pin_protection])
|
||||||
|
passphrase_label.setText(noyes[features.passphrase_protection])
|
||||||
|
language_label.setText(features.language)
|
||||||
|
|
||||||
|
pin_button.setText(_("Change") if features.pin_protection
|
||||||
|
else _("Set"))
|
||||||
|
clear_pin_button.setVisible(features.pin_protection)
|
||||||
|
|
||||||
def rename():
|
def rename():
|
||||||
title = _("Set Device Label")
|
title = _("Set Device Label")
|
||||||
|
@ -154,64 +182,91 @@ def qt_plugin_class(base_plugin_class):
|
||||||
response = QInputDialog().getText(dialog, title, msg)
|
response = QInputDialog().getText(dialog, title, msg)
|
||||||
if not response[1]:
|
if not response[1]:
|
||||||
return
|
return
|
||||||
new_label = str(response[0])
|
client().change_label(str(response[0]))
|
||||||
client.change_label(new_label)
|
refresh()
|
||||||
device_label.setText(new_label)
|
|
||||||
|
|
||||||
def update_pin_info():
|
def set_pin():
|
||||||
features = client.features
|
client().set_pin(remove=False)
|
||||||
pin_label.setText(noyes[features.pin_protection])
|
refresh()
|
||||||
pin_button.setText(_("Change") if features.pin_protection
|
|
||||||
else _("Set"))
|
|
||||||
clear_pin_button.setVisible(features.pin_protection)
|
|
||||||
|
|
||||||
def set_pin(remove):
|
def clear_pin():
|
||||||
client.set_pin(remove=remove)
|
title = _("Confirm Clear PIN")
|
||||||
update_pin_info()
|
msg = _("WARNING: if your clear your PIN, anyone with physical "
|
||||||
|
"access to your %s device can spend your bitcoins.\n\n"
|
||||||
|
"Are you certain you want to remove your PIN?") % device
|
||||||
|
if not dialog.question(msg, title=title):
|
||||||
|
return
|
||||||
|
client().set_pin(remove=True)
|
||||||
|
refresh()
|
||||||
|
|
||||||
|
def wipe_device():
|
||||||
|
title = _("Confirm Device Wipe")
|
||||||
|
msg = _("Are you sure you want to wipe the device? "
|
||||||
|
"You should make sure you have a copy of your recovery "
|
||||||
|
"seed and that your wallet holds no bitcoins.")
|
||||||
|
if not dialog.question(msg, title=title):
|
||||||
|
return
|
||||||
|
if sum(wallet.get_balance()):
|
||||||
|
title = _("Confirm Device Wipe")
|
||||||
|
msg = _("Are you SURE you want to wipe the device?\n"
|
||||||
|
"Your wallet still has bitcoins in it!")
|
||||||
|
if not dialog.question(msg, title=title,
|
||||||
|
icon=QMessageBox.Critical):
|
||||||
|
return
|
||||||
|
client().wipe_device()
|
||||||
|
refresh()
|
||||||
|
|
||||||
|
wallet = window.wallet
|
||||||
|
handler = wallet.handler
|
||||||
|
device = self.device
|
||||||
|
|
||||||
features = client.features
|
|
||||||
noyes = [_("No"), _("Yes")]
|
|
||||||
bl_hash = features.bootloader_hash.encode('hex').upper()
|
|
||||||
bl_hash = "%s...%s" % (bl_hash[:10], bl_hash[-10:])
|
|
||||||
info_tab = QWidget()
|
info_tab = QWidget()
|
||||||
layout = QGridLayout(info_tab)
|
info_layout = QGridLayout(info_tab)
|
||||||
device_label = QLabel(features.label)
|
noyes = [_("No"), _("Yes")]
|
||||||
|
bl_hash_label = QLabel()
|
||||||
|
device_label = QLabel()
|
||||||
|
passphrase_label = QLabel()
|
||||||
|
initialized_label = QLabel()
|
||||||
|
device_id_label = QLabel()
|
||||||
|
version_label = QLabel()
|
||||||
|
pin_label = QLabel()
|
||||||
|
language_label = QLabel()
|
||||||
rename_button = QPushButton(_("Rename"))
|
rename_button = QPushButton(_("Rename"))
|
||||||
rename_button.clicked.connect(rename)
|
rename_button.clicked.connect(rename)
|
||||||
pin_label = QLabel()
|
|
||||||
pin_button = QPushButton()
|
pin_button = QPushButton()
|
||||||
pin_button.clicked.connect(partial(set_pin, False))
|
pin_button.clicked.connect(set_pin)
|
||||||
clear_pin_button = QPushButton(_("Clear"))
|
clear_pin_button = QPushButton(_("Clear"))
|
||||||
clear_pin_button.clicked.connect(partial(set_pin, True))
|
clear_pin_button.clicked.connect(clear_pin)
|
||||||
update_pin_info()
|
|
||||||
|
|
||||||
version = "%d.%d.%d" % (features.major_version,
|
add_rows_to_layout(info_layout, [
|
||||||
features.minor_version,
|
|
||||||
features.patch_version)
|
|
||||||
rows = [
|
|
||||||
(_("Bootloader Hash"), bl_hash),
|
|
||||||
(_("Device ID"), features.device_id),
|
|
||||||
(_("Device Label"), device_label, rename_button),
|
(_("Device Label"), device_label, rename_button),
|
||||||
(_("Firmware Version"), version),
|
(_("Has Passphrase"), passphrase_label),
|
||||||
(_("Language"), features.language),
|
(_("Has PIN"), pin_label, pin_button, clear_pin_button),
|
||||||
(_("Has Passphrase"), noyes[features.passphrase_protection]),
|
(_("Initialized"), initialized_label),
|
||||||
(_("Has PIN"), pin_label, pin_button, clear_pin_button)
|
(_("Device ID"), device_id_label),
|
||||||
]
|
(_("Bootloader Hash"), bl_hash_label),
|
||||||
|
(_("Firmware Version"), version_label),
|
||||||
|
(_("Language"), language_label),
|
||||||
|
])
|
||||||
|
|
||||||
for row_num, items in enumerate(rows):
|
advanced_tab = QWidget()
|
||||||
for col_num, item in enumerate(items):
|
advanced_layout = QGridLayout(advanced_tab)
|
||||||
widget = item if isinstance(item, QWidget) else QLabel(item)
|
wipe_device_button = QPushButton(_("Wipe Device"))
|
||||||
layout.addWidget(widget, row_num, col_num)
|
wipe_device_button.clicked.connect(wipe_device)
|
||||||
|
add_rows_to_layout(advanced_layout, [
|
||||||
|
(wipe_device_button, ),
|
||||||
|
])
|
||||||
|
|
||||||
dialog = WindowModalDialog(window, _("%s Settings") % self.device)
|
dialog = WindowModalDialog(window, _("%s Settings") % device)
|
||||||
vbox = QVBoxLayout()
|
vbox = QVBoxLayout()
|
||||||
tabs = QTabWidget()
|
tabs = QTabWidget()
|
||||||
tabs.addTab(info_tab, _("Information"))
|
tabs.addTab(info_tab, _("Information"))
|
||||||
tabs.addTab(QWidget(), _("Advanced"))
|
tabs.addTab(advanced_tab, _("Advanced"))
|
||||||
vbox.addWidget(tabs)
|
vbox.addWidget(tabs)
|
||||||
vbox.addStretch(1)
|
vbox.addStretch(1)
|
||||||
vbox.addLayout(Buttons(CloseButton(dialog)))
|
vbox.addLayout(Buttons(CloseButton(dialog)))
|
||||||
|
|
||||||
|
refresh()
|
||||||
dialog.setLayout(vbox)
|
dialog.setLayout(vbox)
|
||||||
handler.exec_dialog(dialog)
|
handler.exec_dialog(dialog)
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue