hw wallets: introduce HardwareHandlerBase
previously, client.handler was sometimes - an InstallWizard - a QtHandlerBase where win was an ElectrumWindow - a QtHandlerBase where win was an InstallWizard - a CmdLineHandler That's just too much dynamic untyped undocumented polymorphism... Now it will never be an InstallWizard (replaced with QtHandlerBase where win is an InstallWizard), and now in all cases client.handler is an instance of HardwareHandlerBase, yay. related: #6063
This commit is contained in:
@@ -2,13 +2,15 @@ from electrum.plugin import hook
|
||||
from electrum.util import print_msg, raw_input, print_stderr
|
||||
from electrum.logging import get_logger
|
||||
|
||||
from ..hw_wallet.cmdline import CmdLineHandler
|
||||
|
||||
from .coldcard import ColdcardPlugin
|
||||
|
||||
|
||||
_logger = get_logger(__name__)
|
||||
|
||||
|
||||
class ColdcardCmdLineHandler:
|
||||
class ColdcardCmdLineHandler(CmdLineHandler):
|
||||
|
||||
def get_passphrase(self, msg, confirm):
|
||||
raise NotImplementedError
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
from .plugin import HW_PluginBase, HardwareClientBase
|
||||
from .plugin import HW_PluginBase, HardwareClientBase, HardwareHandlerBase
|
||||
from .cmdline import CmdLineHandler
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
from electrum.util import print_stderr, raw_input
|
||||
from electrum.logging import get_logger
|
||||
|
||||
from .plugin import HardwareHandlerBase
|
||||
|
||||
|
||||
_logger = get_logger(__name__)
|
||||
|
||||
|
||||
class CmdLineHandler:
|
||||
class CmdLineHandler(HardwareHandlerBase):
|
||||
|
||||
def get_passphrase(self, msg, confirm):
|
||||
import getpass
|
||||
|
||||
@@ -37,6 +37,7 @@ from electrum.keystore import Xpub, Hardware_KeyStore
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from electrum.wallet import Abstract_Wallet
|
||||
from electrum.base_wizard import BaseWizard
|
||||
|
||||
|
||||
class HW_PluginBase(BasePlugin):
|
||||
@@ -63,7 +64,7 @@ class HW_PluginBase(BasePlugin):
|
||||
if isinstance(keystore, self.keystore_class):
|
||||
self.device_manager().unpair_xpub(keystore.xpub)
|
||||
|
||||
def setup_device(self, device_info, wizard, purpose):
|
||||
def setup_device(self, device_info, wizard: 'BaseWizard', purpose):
|
||||
"""Called when creating a new wallet or when using the device to decrypt
|
||||
an existing wallet. Select the device to use. If the device is
|
||||
uninitialized, go through the initialization process.
|
||||
@@ -139,15 +140,23 @@ class HW_PluginBase(BasePlugin):
|
||||
def is_outdated_fw_ignored(self) -> bool:
|
||||
return self._ignore_outdated_fw
|
||||
|
||||
def create_client(self, device: 'Device', handler) -> Optional['HardwareClientBase']:
|
||||
def create_client(self, device: 'Device',
|
||||
handler: Optional['HardwareHandlerBase']) -> Optional['HardwareClientBase']:
|
||||
raise NotImplementedError()
|
||||
|
||||
def get_xpub(self, device_id, derivation: str, xtype, wizard) -> str:
|
||||
def get_xpub(self, device_id, derivation: str, xtype, wizard: 'BaseWizard') -> str:
|
||||
raise NotImplementedError()
|
||||
|
||||
def create_handler(self, window) -> 'HardwareHandlerBase':
|
||||
# note: in Qt GUI, 'window' is either an ElectrumWindow or an InstallWizard
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
class HardwareClientBase:
|
||||
|
||||
plugin: 'HW_PluginBase'
|
||||
handler: Optional['HardwareHandlerBase']
|
||||
|
||||
def is_pairable(self) -> bool:
|
||||
raise NotImplementedError()
|
||||
|
||||
@@ -191,6 +200,41 @@ class HardwareClientBase:
|
||||
return password
|
||||
|
||||
|
||||
class HardwareHandlerBase:
|
||||
"""An interface between the GUI and the device handling logic for handling I/O."""
|
||||
win = None
|
||||
device: str
|
||||
|
||||
def get_wallet(self) -> Optional['Abstract_Wallet']:
|
||||
if self.win is not None:
|
||||
if hasattr(self.win, 'wallet'):
|
||||
return self.win.wallet
|
||||
|
||||
def update_status(self, paired: bool) -> None:
|
||||
pass
|
||||
|
||||
def query_choice(self, msg: str, labels: Sequence[str]) -> Optional[int]:
|
||||
raise NotImplementedError()
|
||||
|
||||
def yes_no_question(self, msg: str) -> bool:
|
||||
raise NotImplementedError()
|
||||
|
||||
def show_message(self, msg: str, on_cancel=None) -> None:
|
||||
raise NotImplementedError()
|
||||
|
||||
def show_error(self, msg: str, blocking: bool = False) -> None:
|
||||
raise NotImplementedError()
|
||||
|
||||
def finished(self) -> None:
|
||||
pass
|
||||
|
||||
def get_word(self, msg: str) -> str:
|
||||
raise NotImplementedError()
|
||||
|
||||
def get_passphrase(self, msg: str, confirm: bool) -> Optional[str]:
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
def is_any_tx_output_on_change_branch(tx: PartialTransaction) -> bool:
|
||||
return any([txout.is_change for txout in tx.outputs()])
|
||||
|
||||
|
||||
@@ -35,13 +35,14 @@ from electrum.gui.qt.password_dialog import PasswordLayout, PW_PASSPHRASE
|
||||
from electrum.gui.qt.util import (read_QIcon, WWLabel, OkButton, WindowModalDialog,
|
||||
Buttons, CancelButton, TaskThread, char_width_in_lineedit)
|
||||
from electrum.gui.qt.main_window import StatusBarButton, ElectrumWindow
|
||||
from electrum.gui.qt.installwizard import InstallWizard
|
||||
|
||||
from electrum.i18n import _
|
||||
from electrum.logging import Logger
|
||||
from electrum.util import parse_URI, InvalidBitcoinURI, UserCancelled
|
||||
from electrum.plugin import hook, DeviceUnpairableError
|
||||
|
||||
from .plugin import OutdatedHwFirmwareException, HW_PluginBase
|
||||
from .plugin import OutdatedHwFirmwareException, HW_PluginBase, HardwareHandlerBase
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from electrum.wallet import Abstract_Wallet
|
||||
@@ -50,7 +51,7 @@ if TYPE_CHECKING:
|
||||
|
||||
# The trickiest thing about this handler was getting windows properly
|
||||
# parented on macOS.
|
||||
class QtHandlerBase(QObject, Logger):
|
||||
class QtHandlerBase(HardwareHandlerBase, QObject, Logger):
|
||||
'''An interface between the GUI (here, QT) and the device handling
|
||||
logic for handling I/O.'''
|
||||
|
||||
@@ -63,7 +64,7 @@ class QtHandlerBase(QObject, Logger):
|
||||
yes_no_signal = pyqtSignal(object)
|
||||
status_signal = pyqtSignal(object)
|
||||
|
||||
def __init__(self, win, device):
|
||||
def __init__(self, win: Union[ElectrumWindow, InstallWizard], device: str):
|
||||
QObject.__init__(self)
|
||||
Logger.__init__(self)
|
||||
self.clear_signal.connect(self.clear_dialog)
|
||||
@@ -267,5 +268,5 @@ class QtPluginBase(object):
|
||||
dev_name = f"{plugin.device} ({keystore.label})"
|
||||
receive_address_e.addButton("eye1.png", show_address, _("Show on {}").format(dev_name))
|
||||
|
||||
def create_handler(self, window: ElectrumWindow) -> 'QtHandlerBase':
|
||||
def create_handler(self, window: Union[ElectrumWindow, InstallWizard]) -> 'QtHandlerBase':
|
||||
raise NotImplementedError()
|
||||
|
||||
@@ -282,7 +282,6 @@ class KeepKeyPlugin(HW_PluginBase):
|
||||
if client is None:
|
||||
raise UserFacingException(_('Failed to create a client for this device.') + '\n' +
|
||||
_('Make sure it is in the correct state.'))
|
||||
# fixme: we should use: client.handler = wizard
|
||||
client.handler = self.create_handler(wizard)
|
||||
if not device_info.initialized:
|
||||
self.initialize_device(device_id, wizard, client.handler)
|
||||
@@ -294,7 +293,7 @@ class KeepKeyPlugin(HW_PluginBase):
|
||||
raise ScriptTypeNotSupported(_('This type of script is not supported with {}.').format(self.device))
|
||||
devmgr = self.device_manager()
|
||||
client = devmgr.client_by_id(device_id)
|
||||
client.handler = wizard
|
||||
client.handler = self.create_handler(wizard)
|
||||
xpub = client.get_xpub(derivation, xtype)
|
||||
client.used()
|
||||
return xpub
|
||||
|
||||
@@ -195,9 +195,6 @@ class QtPlugin(QtPluginBase):
|
||||
# icon_file
|
||||
# pin_matrix_widget_class
|
||||
|
||||
def create_handler(self, window):
|
||||
return QtHandler(window, self.pin_matrix_widget_class(), self.device)
|
||||
|
||||
@only_hook_if_libraries_available
|
||||
@hook
|
||||
def receive_menu(self, menu, addrs, wallet):
|
||||
@@ -302,6 +299,9 @@ class Plugin(KeepKeyPlugin, QtPlugin):
|
||||
icon_paired = "keepkey.png"
|
||||
icon_unpaired = "keepkey_unpaired.png"
|
||||
|
||||
def create_handler(self, window):
|
||||
return QtHandler(window, self.pin_matrix_widget_class(), self.device)
|
||||
|
||||
@classmethod
|
||||
def pin_matrix_widget_class(self):
|
||||
from keepkeylib.qt.pinmatrix import PinMatrixWidget
|
||||
|
||||
@@ -71,9 +71,6 @@ class QtPlugin(QtPluginBase):
|
||||
# icon_file
|
||||
# pin_matrix_widget_class
|
||||
|
||||
def create_handler(self, window):
|
||||
return QtHandler(window, self.pin_matrix_widget_class(), self.device)
|
||||
|
||||
@only_hook_if_libraries_available
|
||||
@hook
|
||||
def receive_menu(self, menu, addrs, wallet):
|
||||
@@ -176,6 +173,9 @@ class Plugin(SafeTPlugin, QtPlugin):
|
||||
icon_unpaired = "safe-t_unpaired.png"
|
||||
icon_paired = "safe-t.png"
|
||||
|
||||
def create_handler(self, window):
|
||||
return QtHandler(window, self.pin_matrix_widget_class(), self.device)
|
||||
|
||||
@classmethod
|
||||
def pin_matrix_widget_class(self):
|
||||
from safetlib.qt.pinmatrix import PinMatrixWidget
|
||||
|
||||
@@ -256,7 +256,6 @@ class SafeTPlugin(HW_PluginBase):
|
||||
if client is None:
|
||||
raise UserFacingException(_('Failed to create a client for this device.') + '\n' +
|
||||
_('Make sure it is in the correct state.'))
|
||||
# fixme: we should use: client.handler = wizard
|
||||
client.handler = self.create_handler(wizard)
|
||||
if not device_info.initialized:
|
||||
self.initialize_device(device_id, wizard, client.handler)
|
||||
@@ -268,7 +267,7 @@ class SafeTPlugin(HW_PluginBase):
|
||||
raise ScriptTypeNotSupported(_('This type of script is not supported with {}.').format(self.device))
|
||||
devmgr = self.device_manager()
|
||||
client = devmgr.client_by_id(device_id)
|
||||
client.handler = wizard
|
||||
client.handler = self.create_handler(wizard)
|
||||
xpub = client.get_xpub(derivation, xtype)
|
||||
client.used()
|
||||
return xpub
|
||||
|
||||
@@ -169,9 +169,6 @@ class QtPlugin(QtPluginBase):
|
||||
# icon_file
|
||||
# pin_matrix_widget_class
|
||||
|
||||
def create_handler(self, window):
|
||||
return QtHandler(window, self.pin_matrix_widget_class(), self.device)
|
||||
|
||||
@only_hook_if_libraries_available
|
||||
@hook
|
||||
def receive_menu(self, menu, addrs, wallet):
|
||||
@@ -377,6 +374,9 @@ class Plugin(TrezorPlugin, QtPlugin):
|
||||
icon_unpaired = "trezor_unpaired.png"
|
||||
icon_paired = "trezor.png"
|
||||
|
||||
def create_handler(self, window):
|
||||
return QtHandler(window, self.pin_matrix_widget_class(), self.device)
|
||||
|
||||
@classmethod
|
||||
def pin_matrix_widget_class(self):
|
||||
from trezorlib.qt.pinmatrix import PinMatrixWidget
|
||||
|
||||
@@ -282,7 +282,6 @@ class TrezorPlugin(HW_PluginBase):
|
||||
.format(self.device, client.label(), self.firmware_URL))
|
||||
raise OutdatedHwFirmwareException(msg)
|
||||
|
||||
# fixme: we should use: client.handler = wizard
|
||||
client.handler = self.create_handler(wizard)
|
||||
if not device_info.initialized:
|
||||
self.initialize_device(device_id, wizard, client.handler)
|
||||
@@ -295,7 +294,7 @@ class TrezorPlugin(HW_PluginBase):
|
||||
raise ScriptTypeNotSupported(_('This type of script is not supported with {}.').format(self.device))
|
||||
devmgr = self.device_manager()
|
||||
client = devmgr.client_by_id(device_id)
|
||||
client.handler = wizard
|
||||
client.handler = self.create_handler(wizard)
|
||||
xpub = client.get_xpub(derivation, xtype)
|
||||
client.used()
|
||||
return xpub
|
||||
|
||||
Reference in New Issue
Block a user