Browse Source

Merge pull request #4351 from SomberNight/2fa_sign_then_otp

trustedcoin: sign first, then prompt for OTP
3.2.x
ThomasV 7 years ago
committed by GitHub
parent
commit
4c234397ec
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      gui/qt/main_window.py
  2. 1
      lib/commands.py
  3. 4
      plugins/trustedcoin/cmdline.py
  4. 50
      plugins/trustedcoin/qt.py
  5. 3
      plugins/trustedcoin/trustedcoin.py

2
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)

1
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

4
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():

50
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)

3
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

Loading…
Cancel
Save