commit 4c234397ec6d6012a32e3247640f94ae2d76d158
parent c113232e8bcc814e4693cb9abfb379819aee156e
Author: ThomasV <thomasv@electrum.org>
Date: Fri, 18 May 2018 17:36:18 +0200
Merge pull request #4351 from SomberNight/2fa_sign_then_otp
trustedcoin: sign first, then prompt for OTP
Diffstat:
5 files changed, 42 insertions(+), 18 deletions(-)
diff --git a/gui/qt/main_window.py b/gui/qt/main_window.py
@@ -1588,8 +1588,6 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
# can sign directly
task = partial(Transaction.sign, tx, self.tx_external_keypairs)
else:
- # call hook to see if plugin needs gui interaction
- run_hook('sign_tx', self, tx)
task = partial(self.wallet.sign_transaction, tx, password)
WaitingDialog(self, _('Signing transaction...'), task,
on_signed, on_failed)
diff --git a/lib/commands.py b/lib/commands.py
@@ -426,7 +426,6 @@ class Commands:
if rbf:
tx.set_rbf(True)
if not unsigned:
- run_hook('sign_tx', self.wallet, tx)
self.wallet.sign_transaction(tx, password)
return tx
diff --git a/plugins/trustedcoin/cmdline.py b/plugins/trustedcoin/cmdline.py
@@ -27,10 +27,10 @@ from electrum.i18n import _
from electrum.plugins import hook
from .trustedcoin import TrustedCoinPlugin
+
class Plugin(TrustedCoinPlugin):
- @hook
- def sign_tx(self, wallet, tx):
+ def prompt_user_for_otp(self, wallet, tx):
if not isinstance(wallet, self.wallet_class):
return
if not wallet.can_sign_without_server():
diff --git a/plugins/trustedcoin/qt.py b/plugins/trustedcoin/qt.py
@@ -24,6 +24,7 @@
# SOFTWARE.
from functools import partial
+import threading
from threading import Thread
import re
from decimal import Decimal
@@ -37,6 +38,7 @@ from electrum_gui.qt.amountedit import AmountEdit
from electrum_gui.qt.main_window import StatusBarButton
from electrum.i18n import _
from electrum.plugins import hook
+from electrum.util import PrintError
from .trustedcoin import TrustedCoinPlugin, server
@@ -45,6 +47,38 @@ class TOS(QTextEdit):
error_signal = pyqtSignal(object)
+class HandlerTwoFactor(QObject, PrintError):
+ otp_start_signal = pyqtSignal(object, object)
+
+ def __init__(self, plugin, window):
+ super().__init__()
+ self.plugin = plugin
+ self.window = window
+ self.otp_start_signal.connect(self._prompt_user_for_otp)
+ self.otp_done = threading.Event()
+
+ def prompt_user_for_otp(self, wallet, tx):
+ self.otp_done.clear()
+ self.otp_start_signal.emit(wallet, tx)
+ self.otp_done.wait()
+
+ def _prompt_user_for_otp(self, wallet, tx):
+ try:
+ window = self.window.top_level_window()
+ if not isinstance(wallet, self.plugin.wallet_class):
+ return
+ if not wallet.can_sign_without_server():
+ self.print_error("twofactor:sign_tx")
+ auth_code = None
+ if wallet.keystores['x3/'].get_tx_derivations(tx):
+ auth_code = self.plugin.auth_dialog(window)
+ else:
+ self.print_error("twofactor: xpub3 not needed")
+ wallet.auth_code = auth_code
+ finally:
+ self.otp_done.set()
+
+
class Plugin(TrustedCoinPlugin):
def __init__(self, parent, config, name):
@@ -55,6 +89,7 @@ class Plugin(TrustedCoinPlugin):
wallet = window.wallet
if not isinstance(wallet, self.wallet_class):
return
+ wallet.handler_2fa = HandlerTwoFactor(self, window)
if wallet.can_sign_without_server():
msg = ' '.join([
_('This wallet was restored from seed, and it contains two master private keys.'),
@@ -88,19 +123,8 @@ class Plugin(TrustedCoinPlugin):
return
return pw.get_amount()
- @hook
- def sign_tx(self, window, tx):
- wallet = window.wallet
- if not isinstance(wallet, self.wallet_class):
- return
- if not wallet.can_sign_without_server():
- self.print_error("twofactor:sign_tx")
- auth_code = None
- if wallet.keystores['x3/'].get_tx_derivations(tx):
- auth_code = self.auth_dialog(window)
- else:
- self.print_error("twofactor: xpub3 not needed")
- window.wallet.auth_code = auth_code
+ def prompt_user_for_otp(self, wallet, tx):
+ wallet.handler_2fa.prompt_user_for_otp(wallet, tx)
def waiting_dialog(self, window, on_finished=None):
task = partial(self.request_billing_info, window.wallet)
diff --git a/plugins/trustedcoin/trustedcoin.py b/plugins/trustedcoin/trustedcoin.py
@@ -215,6 +215,7 @@ class Wallet_2fa(Multisig_Wallet):
Deterministic_Wallet.__init__(self, storage)
self.is_billing = False
self.billing_info = None
+ self.auth_code = None
def can_sign_without_server(self):
return not self.keystores['x2/'].is_watching_only()
@@ -272,6 +273,7 @@ class Wallet_2fa(Multisig_Wallet):
Multisig_Wallet.sign_transaction(self, tx, password)
if tx.is_complete():
return
+ self.plugin.prompt_user_for_otp(self, tx)
if not self.auth_code:
self.print_error("sign_transaction: no auth code")
return
@@ -285,6 +287,7 @@ class Wallet_2fa(Multisig_Wallet):
self.print_error("twofactor: is complete", tx.is_complete())
# reset billing_info
self.billing_info = None
+ self.auth_code = None
# Utility functions