Trezor: add session timeout to preferences

Fixes #803
This commit is contained in:
Neil Booth 2016-01-03 17:25:47 +09:00
parent 87363c8301
commit 43fd684d97
2 changed files with 53 additions and 4 deletions

View File

@ -29,11 +29,18 @@ class TrezorCompatibleWallet(BIP44_Wallet):
# This is set when paired with a device, and used to re-pair # This is set when paired with a device, and used to re-pair
# a device that is disconnected and re-connected # a device that is disconnected and re-connected
self.device_id = None self.device_id = None
# After timeout seconds we clear the device session
self.session_timeout = storage.get('session_timeout', 180)
# Errors and other user interaction is done through the wallet's # Errors and other user interaction is done through the wallet's
# handler. The handler is per-window and preserved across # handler. The handler is per-window and preserved across
# device reconnects # device reconnects
self.handler = None self.handler = None
def set_session_timeout(self, seconds):
self.print_error("setting session timeout to %d seconds" % seconds)
self.session_timeout = seconds
self.storage.put('session_timeout', seconds)
def disconnected(self): def disconnected(self):
self.print_error("disconnected") self.print_error("disconnected")
self.handler.watching_only_changed() self.handler.watching_only_changed()
@ -46,9 +53,8 @@ class TrezorCompatibleWallet(BIP44_Wallet):
self.print_error("wiped") self.print_error("wiped")
self.handler.watching_only_changed() self.handler.watching_only_changed()
def initialized(self): def timeout(self):
self.print_error("initialized") self.print_error("timed out")
self.handler.watching_only_changed()
def get_action(self): def get_action(self):
pass pass
@ -155,6 +161,7 @@ class TrezorCompatiblePlugin(BasePlugin):
BasePlugin.__init__(self, parent, config, name) BasePlugin.__init__(self, parent, config, name)
self.device = self.wallet_class.device self.device = self.wallet_class.device
self.wallet_class.plugin = self self.wallet_class.plugin = self
self.prevent_timeout = time.time() + 3600 * 24 * 365
# A set of client instances to USB paths # A set of client instances to USB paths
self.clients = set() self.clients = set()
# The device wallets we have seen to inform on reconnection # The device wallets we have seen to inform on reconnection
@ -173,6 +180,13 @@ class TrezorCompatiblePlugin(BasePlugin):
if now > self.last_scan + 1: if now > self.last_scan + 1:
self.last_scan = now self.last_scan = now
self.scan_devices() self.scan_devices()
for wallet in self.paired_wallets:
if now > wallet.last_operation + wallet.session_timeout:
client = self.lookup_client(wallet)
if client:
wallet.last_operation = self.prevent_timeout
self.clear_session(client)
wallet.timeout()
def scan_devices(self): def scan_devices(self):
paths = self.HidTransport.enumerate() paths = self.HidTransport.enumerate()
@ -221,6 +235,9 @@ class TrezorCompatiblePlugin(BasePlugin):
client.clear_session() client.clear_session()
def initialize_device(self, wallet, wizard): def initialize_device(self, wallet, wizard):
# Prevent timeouts during initialization
wallet.last_operation = self.prevent_timeout
(strength, label, pin_protection, passphrase_protection) \ (strength, label, pin_protection, passphrase_protection) \
= wizard.request_trezor_reset_settings(self.device) = wizard.request_trezor_reset_settings(self.device)
@ -247,10 +264,16 @@ class TrezorCompatiblePlugin(BasePlugin):
if not client.is_initialized(): if not client.is_initialized():
self.initialize_device(wallet, wizard) self.initialize_device(wallet, wizard)
def operated_on(self, wallet):
self.print_error("set last_operation")
wallet.last_operation = time.time()
def pair_wallet(self, wallet, client): def pair_wallet(self, wallet, client):
self.print_error("pairing wallet %s to device %s" % (wallet, client)) self.print_error("pairing wallet %s to device %s" % (wallet, client))
self.operated_on(wallet)
self.paired_wallets.add(wallet) self.paired_wallets.add(wallet)
wallet.device_id = client.features.device_id wallet.device_id = client.features.device_id
wallet.last_operation = time.time()
client.wallet = wallet client.wallet = wallet
wallet.connected() wallet.connected()
@ -301,6 +324,7 @@ class TrezorCompatiblePlugin(BasePlugin):
assert isinstance(wallet, self.wallet_class) assert isinstance(wallet, self.wallet_class)
assert wallet.handler != None assert wallet.handler != None
self.operated_on(wallet)
if wallet.device_id is None: if wallet.device_id is None:
client = self.try_to_pair_wallet(wallet) client = self.try_to_pair_wallet(wallet)
else: else:

View File

@ -1,6 +1,7 @@
from functools import partial from functools import partial
import threading import threading
from PyQt4.Qt import Qt
from PyQt4.Qt import QGridLayout, QInputDialog, QPushButton from PyQt4.Qt import QGridLayout, QInputDialog, QPushButton
from PyQt4.Qt import QVBoxLayout, QLabel, SIGNAL from PyQt4.Qt import QVBoxLayout, QLabel, SIGNAL
from electrum_gui.qt.main_window import StatusBarButton from electrum_gui.qt.main_window import StatusBarButton
@ -217,12 +218,17 @@ def qt_plugin_class(base_plugin_class):
client().wipe_device() client().wipe_device()
refresh() refresh()
def slider_moved():
mins = timeout_slider.sliderPosition()
timeout_label.setText(_("%2d minutes") % mins)
wallet = window.wallet wallet = window.wallet
handler = wallet.handler handler = wallet.handler
device = self.device device = self.device
info_tab = QWidget() info_tab = QWidget()
info_layout = QGridLayout(info_tab) tab_layout = QVBoxLayout(info_tab)
info_layout = QGridLayout()
noyes = [_("No"), _("Yes")] noyes = [_("No"), _("Yes")]
bl_hash_label = QLabel() bl_hash_label = QLabel()
device_label = QLabel() device_label = QLabel()
@ -249,6 +255,22 @@ def qt_plugin_class(base_plugin_class):
(_("Firmware Version"), version_label), (_("Firmware Version"), version_label),
(_("Language"), language_label), (_("Language"), language_label),
]) ])
tab_layout.addLayout(info_layout)
timeout_layout = QHBoxLayout()
timeout_label = QLabel()
timeout_slider = QSlider(Qt.Horizontal)
timeout_slider.setRange(1, 60)
timeout_slider.setSingleStep(1)
timeout_slider.setSliderPosition(wallet.session_timeout // 60)
timeout_slider.setTickInterval(5)
timeout_slider.setTickPosition(QSlider.TicksBelow)
timeout_slider.setTracking(True)
timeout_slider.valueChanged.connect(slider_moved)
timeout_layout.addWidget(QLabel(_("Session Timeout")))
timeout_layout.addWidget(timeout_slider)
timeout_layout.addWidget(timeout_label)
tab_layout.addLayout(timeout_layout)
advanced_tab = QWidget() advanced_tab = QWidget()
advanced_layout = QGridLayout(advanced_tab) advanced_layout = QGridLayout(advanced_tab)
@ -267,8 +289,11 @@ def qt_plugin_class(base_plugin_class):
vbox.addStretch(1) vbox.addStretch(1)
vbox.addLayout(Buttons(CloseButton(dialog))) vbox.addLayout(Buttons(CloseButton(dialog)))
# Show values
slider_moved()
refresh() refresh()
dialog.setLayout(vbox) dialog.setLayout(vbox)
handler.exec_dialog(dialog) handler.exec_dialog(dialog)
wallet.set_session_timeout(timeout_slider.sliderPosition() * 60)
return QtPlugin return QtPlugin