Files
pallectrum/electrum/plugins/trustedcoin/qml.py
Sander van Grieken eb29b7c95c qml: simplify QEConfig and QEDaemon use.
force QEDaemon singleton, and refer to QEDaemon.instance where possible
In cases where we would run into circular dependencies, pass the instance

also refer to singleton QEConfig instead of passing instance in qeapp.py
2025-04-09 13:44:26 +02:00

130 lines
4.6 KiB
Python

from typing import TYPE_CHECKING
from electrum.i18n import _
from electrum.plugin import hook
from electrum.util import UserFacingException
from electrum.gui.qml.qewallet import QEWallet
from electrum.gui.qml.qedaemon import QEDaemon
from .common_qt import TrustedcoinPluginQObject
from .trustedcoin import TrustedCoinPlugin, TrustedCoinException
if TYPE_CHECKING:
from electrum.gui.qml import ElectrumQmlApplication
from electrum.wallet import Abstract_Wallet
from electrum.wizard import NewWalletWizard
class Plugin(TrustedCoinPlugin):
def __init__(self, *args):
super().__init__(*args)
self._app = None
self.so = None
self.on_success = None
self.on_failure = None
self.tx = None
@hook
def load_wallet(self, wallet: 'Abstract_Wallet'):
if not isinstance(wallet, self.wallet_class):
return
self.logger.debug(f'plugin enabled for wallet "{str(wallet)}"')
if wallet.can_sign_without_server():
self.so._canSignWithoutServer = True
self.so.canSignWithoutServerChanged.emit()
msg = ' '.join([
_('This wallet was restored from seed, and it contains two master private keys.'),
_('Therefore, two-factor authentication is disabled.')
])
self.logger.info(msg)
self.start_request_thread(wallet)
@hook
def init_qml(self, app: 'ElectrumQmlApplication'):
self.logger.debug(f'init_qml hook called, gui={str(type(app))}')
self._app = app
wizard = QEDaemon.instance.newWalletWizard
# important: TrustedcoinPluginQObject needs to be parented, as keeping a ref
# in the plugin is not enough to avoid gc
# Note: storing the trustedcoin qt helper in the plugin is different from the desktop client,
# which stores the helper in the wizard object. As the mobile client only shows a single wizard
# at a time, this is ok for now.
self.so = TrustedcoinPluginQObject(self, wizard, self._app)
# extend wizard
self.extend_wizard(wizard)
# wizard support functions
def extend_wizard(self, wizard: 'NewWalletWizard'):
super().extend_wizard(wizard)
views = {
'trustedcoin_start': {
'gui': '../../../../plugins/trustedcoin/qml/Disclaimer',
},
'trustedcoin_choose_seed': {
'gui': '../../../../plugins/trustedcoin/qml/ChooseSeed',
},
'trustedcoin_create_seed': {
'gui': 'WCCreateSeed',
},
'trustedcoin_confirm_seed': {
'gui': 'WCConfirmSeed',
},
'trustedcoin_have_seed': {
'gui': 'WCHaveSeed',
},
'trustedcoin_keep_disable': {
'gui': '../../../../plugins/trustedcoin/qml/KeepDisable',
},
'trustedcoin_tos': {
'gui': '../../../../plugins/trustedcoin/qml/Terms',
},
'trustedcoin_keystore_unlock': {
# TODO when QML can import external wallet files
},
'trustedcoin_show_confirm_otp': {
'gui': '../../../../plugins/trustedcoin/qml/ShowConfirmOTP',
}
}
wizard.navmap_merge(views)
# running wallet functions
def prompt_user_for_otp(self, wallet, tx, on_success, on_failure):
self.logger.debug('prompt_user_for_otp')
self.on_success = on_success
self.on_failure = on_failure if on_failure else lambda x: self.logger.error(x)
self.wallet = wallet
self.tx = tx
qewallet = QEWallet.getInstanceFor(wallet)
qewallet.request_otp(self.on_otp)
def on_otp(self, otp):
if not otp:
self.on_failure(_('No auth code'))
return
self.logger.debug(f'on_otp {otp} for tx {repr(self.tx)}')
try:
self.wallet.on_otp(self.tx, otp)
except UserFacingException as e:
self.on_failure(_('Invalid one-time password.'))
except TrustedCoinException as e:
if e.status_code == 400: # invalid OTP
self.on_failure(_('Invalid one-time password.'))
else:
self.on_failure(_('Service Error') + ':\n' + str(e))
except Exception as e:
self.on_failure(_('Error') + ':\n' + str(e))
else:
self.on_success(self.tx)
def billing_info_retrieved(self, wallet):
self.logger.info('billing_info_retrieved')
qewallet = QEWallet.getInstanceFor(wallet)
qewallet.billingInfoChanged.emit()
self.so.updateBillingInfo(wallet)