commit 8d5e666d30aef45dc9992e1e01d9335083cb54e8
parent 5a75ce74d775ec5ea789c546f879c7212027ba06
Author: ThomasV <thomasv@electrum.org>
Date: Fri, 18 May 2018 18:07:52 +0200
support TrustedCoin plugin in the kivy GUI
Diffstat:
10 files changed, 291 insertions(+), 92 deletions(-)
diff --git a/gui/kivy/main_window.py b/gui/kivy/main_window.py
@@ -505,7 +505,7 @@ class ElectrumWindow(App):
else:
Logger.debug('Electrum: Wallet not found. Launching install wizard')
storage = WalletStorage(path, manual_upgrades=True)
- wizard = Factory.InstallWizard(self.electrum_config, storage)
+ wizard = Factory.InstallWizard(self.electrum_config, self.plugins, storage)
wizard.bind(on_wizard_complete=self.on_wizard_complete)
action = wizard.storage.get_action()
wizard.run(action)
@@ -823,6 +823,7 @@ class ElectrumWindow(App):
except InvalidPassword:
Clock.schedule_once(lambda dt: on_failure(_("Invalid PIN")))
return
+ on_success = run_hook('tc_sign_wrapper', self.wallet, tx, on_success, on_failure) or on_success
Clock.schedule_once(lambda dt: on_success(tx))
def _broadcast_thread(self, tx, on_complete):
diff --git a/gui/kivy/uix/dialogs/installwizard.py b/gui/kivy/uix/dialogs/installwizard.py
@@ -15,6 +15,7 @@ from kivy.clock import Clock
from kivy.utils import platform
from electrum.base_wizard import BaseWizard
+from electrum.util import is_valid_email
from . import EventsDialog
@@ -24,6 +25,7 @@ from .password_dialog import PasswordDialog
# global Variables
is_test = (platform == "linux")
test_seed = "time taxi field recycle tiny license olive virus report rare steel portion achieve"
+test_seed = "grape impose jazz bind spatial mind jelly tourist tank today holiday stomach"
test_xpub = "xpub661MyMwAqRbcEbvVtRRSjqxVnaWVUMewVzMiURAKyYratih4TtBpMypzzefmv8zUNebmNVzB3PojdC5sV2P9bDgMoo9B3SARw1MXUUfU1GL"
Builder.load_string('''
@@ -171,6 +173,95 @@ Builder.load_string('''
spacing: '14dp'
size_hint: 1, None
+<WizardConfirmDialog>
+ message : ''
+ Widget:
+ size_hint: 1, 1
+ Label:
+ color: root.text_color
+ size_hint: 1, None
+ text_size: self.width, None
+ height: self.texture_size[1]
+ text: root.message
+ Widget
+ size_hint: 1, 1
+
+<WizardTOSDialog>
+ message : ''
+ ScrollView:
+ size_hint: 1, 1
+ Label:
+ color: root.text_color
+ size_hint: 1, None
+ text_size: self.width, None
+ height: self.texture_size[1]
+ text: root.message
+
+<WizardEmailDialog>
+ Label:
+ color: root.text_color
+ size_hint: 1, None
+ text_size: self.width, None
+ height: self.texture_size[1]
+ text: 'Please enter your email address'
+ WizardTextInput:
+ id: email
+ on_text: Clock.schedule_once(root.on_text)
+
+<WizardKnownOTPDialog>
+ message : ''
+ message2: ''
+ Widget:
+ size_hint: 1, 1
+ Label:
+ color: root.text_color
+ size_hint: 1, None
+ text_size: self.width, None
+ height: self.texture_size[1]
+ text: root.message
+ Widget
+ size_hint: 1, 1
+ WizardTextInput:
+ id: otp
+ on_text: Clock.schedule_once(root.on_text)
+ Widget
+ size_hint: 1, 1
+ Label:
+ color: root.text_color
+ size_hint: 1, None
+ text_size: self.width, None
+ height: self.texture_size[1]
+ text: root.message2
+ BoxLayout:
+ orientation: 'horizontal'
+ size_hint: 1, 0.2
+ Widget
+ CheckBox:
+ id:cb
+ on_state: Clock.schedule_once(root.on_cb)
+
+<WizardNewOTPDialog>
+ message : ''
+ message2 : ''
+ Label:
+ color: root.text_color
+ size_hint: 1, None
+ text_size: self.width, None
+ height: self.texture_size[1]
+ text: root.message
+ QRCodeWidget:
+ id: qr
+ size_hint: 1, 1
+ Label:
+ color: root.text_color
+ size_hint: 1, None
+ text_size: self.width, None
+ height: self.texture_size[1]
+ text: root.message2
+ WizardTextInput:
+ id: otp
+ on_text: Clock.schedule_once(root.on_text)
+
<MButton@Button>:
size_hint: 1, None
height: '33dp'
@@ -485,6 +576,87 @@ class WizardMultisigDialog(WizardDialog):
n = self.ids.n.value
return m, n
+class WizardKnownOTPDialog(WizardDialog):
+
+ def __init__(self, wizard, **kwargs):
+ WizardDialog.__init__(self, wizard, **kwargs)
+ self.message = _("This wallet is already registered with TrustedCoin. To finalize wallet creation, please enter your Google Authenticator Code.")
+ self.message2 =_("If you have lost your Google Authenticator account, check the box below to request a new secret. You will need to retype your seed.")
+
+ def get_otp(self):
+ otp = self.ids.otp.text
+ if len(otp) != 6:
+ return
+ try:
+ return int(otp)
+ except:
+ return
+
+ def get_params(self, button):
+ return (self.get_otp(), self.ids.cb.active)
+
+ def on_cb(self, dt):
+ self.ids.otp.text = ''
+ self.ids.next.disabled = not self.ids.cb.active
+
+ def on_text(self, dt):
+ self.ids.next.disabled = self.get_otp() is None
+
+class WizardNewOTPDialog(WizardDialog):
+
+ def __init__(self, wizard, **kwargs):
+ WizardDialog.__init__(self, wizard, **kwargs)
+ otp_secret = kwargs['otp_secret']
+ uri = "otpauth://totp/%s?secret=%s"%('trustedcoin.com', otp_secret)
+ self.message = "Please scan the following QR code in Google Authenticator. You may also use the secret key: %s"%otp_secret
+ self.message2 = _('Then, enter your Google Authenticator code:')
+ self.ids.qr.set_data(uri)
+
+ def get_otp(self):
+ otp = self.ids.otp.text
+ if len(otp) != 6:
+ return
+ try:
+ return int(otp)
+ except:
+ return
+
+ def on_text(self, dt):
+ self.ids.next.disabled = self.get_otp() is None
+
+ def get_params(self, button):
+ return (self.get_otp(), False)
+
+class WizardTOSDialog(WizardDialog):
+
+ def __init__(self, wizard, **kwargs):
+ WizardDialog.__init__(self, wizard, **kwargs)
+ self.ids.next.text = 'Accept'
+ self.ids.next.disabled = False
+ self.message = kwargs['tos']
+ self.message2 = _('Enter your email address:')
+
+class WizardEmailDialog(WizardDialog):
+ def get_params(self, button):
+ return (self.ids.email.text,)
+ def on_text(self, dt):
+ self.ids.next.disabled = not is_valid_email(self.ids.email.text)
+
+class WizardConfirmDialog(WizardDialog):
+
+ def __init__(self, wizard, **kwargs):
+ super(WizardConfirmDialog, self).__init__(wizard, **kwargs)
+ self.message = kwargs.get('message', '')
+ self.value = 'ok'
+
+ def on_parent(self, instance, value):
+ if value:
+ app = App.get_running_app()
+ self._back = _back = partial(app.dispatch, 'on_back')
+
+ def get_params(self, button):
+ return (True,)
+
class WizardChoiceDialog(WizardDialog):
def __init__(self, wizard, **kwargs):
@@ -789,6 +961,21 @@ class InstallWizard(BaseWizard, Widget):
def restore_seed_dialog(self, **kwargs):
RestoreSeedDialog(self, **kwargs).open()
+ def confirm_dialog(self, **kwargs):
+ WizardConfirmDialog(self, **kwargs).open()
+
+ def tos_dialog(self, **kwargs):
+ WizardTOSDialog(self, **kwargs).open()
+
+ def email_dialog(self, **kwargs):
+ WizardEmailDialog(self, **kwargs).open()
+
+ def otp_dialog(self, **kwargs):
+ if kwargs['otp_secret']:
+ WizardNewOTPDialog(self, **kwargs).open()
+ else:
+ WizardKnownOTPDialog(self, **kwargs).open()
+
def add_xpub_dialog(self, **kwargs):
kwargs['message'] += ' ' + _('Use the camera button to scan a QR code.')
AddXpubDialog(self, **kwargs).open()
@@ -800,6 +987,8 @@ class InstallWizard(BaseWizard, Widget):
def show_xpub_dialog(self, **kwargs): ShowXpubDialog(self, **kwargs).open()
+ def show_message(self, msg): self.show_error(msg)
+
def show_error(self, msg):
app = App.get_running_app()
Clock.schedule_once(lambda dt: app.show_error(msg))
diff --git a/gui/qt/installwizard.py b/gui/qt/installwizard.py
@@ -92,13 +92,12 @@ class InstallWizard(QDialog, MessageBoxMixin, BaseWizard):
synchronized_signal = pyqtSignal(str)
def __init__(self, config, app, plugins, storage):
- BaseWizard.__init__(self, config, storage)
+ BaseWizard.__init__(self, config, plugins, storage)
QDialog.__init__(self, None)
self.setWindowTitle('Electrum - ' + _('Install Wizard'))
self.app = app
self.config = config
# Set for base base class
- self.plugins = plugins
self.language_for_seed = config.get('language')
self.setMinimumSize(600, 400)
self.accept_signal.connect(self.accept)
diff --git a/gui/qt/main_window.py b/gui/qt/main_window.py
@@ -1577,20 +1577,19 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
'''Sign the transaction in a separate thread. When done, calls
the callback with a success code of True or False.
'''
-
- def on_signed(result):
+ def on_success(result):
callback(True)
- def on_failed(exc_info):
+ def on_failure(exc_info):
self.on_error(exc_info)
callback(False)
-
+ on_success = run_hook('tc_sign_wrapper', self.wallet, tx, on_success, on_failure) or on_success
if self.tx_external_keypairs:
# can sign directly
task = partial(Transaction.sign, tx, self.tx_external_keypairs)
else:
task = partial(self.wallet.sign_transaction, tx, password)
- WaitingDialog(self, _('Signing transaction...'), task,
- on_signed, on_failed)
+ msg = _('Signing transaction...')
+ WaitingDialog(self, msg, task, on_success, on_failure)
def broadcast_transaction(self, tx, tx_desc):
diff --git a/lib/base_wizard.py b/lib/base_wizard.py
@@ -48,9 +48,10 @@ class GoBack(Exception): pass
class BaseWizard(object):
- def __init__(self, config, storage):
+ def __init__(self, config, plugins, storage):
super(BaseWizard, self).__init__()
self.config = config
+ self.plugins = plugins
self.storage = storage
self.wallet = None
self.stack = []
@@ -59,6 +60,9 @@ class BaseWizard(object):
self.is_kivy = config.get('gui') == 'kivy'
self.seed_type = None
+ def set_icon(self, icon):
+ pass
+
def run(self, *args):
action = args[0]
args = args[1:]
@@ -369,12 +373,8 @@ class BaseWizard(object):
elif self.seed_type == 'old':
self.run('create_keystore', seed, '')
elif self.seed_type == '2fa':
- if self.is_kivy:
- self.show_error(_('2FA seeds are not supported in this version'))
- self.run('restore_from_seed')
- else:
- self.load_2fa()
- self.run('on_restore_seed', seed, is_ext)
+ self.load_2fa()
+ self.run('on_restore_seed', seed, is_ext)
else:
raise Exception('Unknown seed type', self.seed_type)
diff --git a/lib/util.py b/lib/util.py
@@ -446,6 +446,10 @@ def user_dir():
#raise Exception("No home directory found in environment variables.")
return
+def is_valid_email(s):
+ regexp = r"[^@]+@[^@]+\.[^@]+"
+ return re.match(regexp, s) is not None
+
def format_satoshis_plain(x, decimal_point = 8):
"""Display a satoshi amount scaled. Always uses a '.' as a decimal
diff --git a/lib/wallet.py b/lib/wallet.py
@@ -1513,6 +1513,7 @@ class Abstract_Wallet(PrintError):
k.sign_transaction(tx, password)
except UserCancelled:
continue
+ return tx
def get_unused_addresses(self):
# fixme: use slots from expired requests
diff --git a/plugins/trustedcoin/__init__.py b/plugins/trustedcoin/__init__.py
@@ -8,4 +8,4 @@ description = ''.join([
])
requires_wallet_type = ['2fa']
registers_wallet_type = '2fa'
-available_for = ['qt', 'cmdline']
+available_for = ['qt', 'cmdline', 'kivy']
diff --git a/plugins/trustedcoin/qt.py b/plugins/trustedcoin/qt.py
@@ -38,7 +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 electrum.util import PrintError, is_valid_email
from .trustedcoin import TrustedCoinPlugin, server
@@ -48,36 +48,28 @@ class TOS(QTextEdit):
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):
+ def prompt_user_for_otp(self, wallet, tx, on_success, on_failure):
+ if not isinstance(wallet, self.plugin.wallet_class):
+ return
+ if wallet.can_sign_without_server():
+ return
+ if not wallet.keystores['x3/'].get_tx_derivations(tx):
+ self.print_error("twofactor: xpub3 not needed")
+ return
+ window = self.window.top_level_window()
+ auth_code = self.plugin.auth_dialog(window)
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()
-
+ wallet.on_otp(tx, auth_code)
+ except:
+ on_failure(sys.exc_info())
+ return
+ on_success(tx)
class Plugin(TrustedCoinPlugin):
@@ -123,8 +115,8 @@ class Plugin(TrustedCoinPlugin):
return
return pw.get_amount()
- def prompt_user_for_otp(self, wallet, tx):
- wallet.handler_2fa.prompt_user_for_otp(wallet, tx)
+ def prompt_user_for_otp(self, wallet, tx, on_success, on_failure):
+ wallet.handler_2fa.prompt_user_for_otp(wallet, tx, on_success, on_failure)
def waiting_dialog(self, window, on_finished=None):
task = partial(self.request_billing_info, window.wallet)
@@ -145,7 +137,6 @@ class Plugin(TrustedCoinPlugin):
return True
return False
-
def settings_dialog(self, window):
self.waiting_dialog(window, partial(self.show_settings_dialog, window))
@@ -216,6 +207,20 @@ class Plugin(TrustedCoinPlugin):
window.message_e.setFrozen(True)
window.amount_e.setFrozen(True)
+ def go_online_dialog(self, wizard):
+ msg = [
+ _("Your wallet file is: {}.").format(os.path.abspath(wizard.storage.path)),
+ _("You need to be online in order to complete the creation of "
+ "your wallet. If you generated your seed on an offline "
+ 'computer, click on "{}" to close this window, move your '
+ "wallet file to an online computer, and reopen it with "
+ "Electrum.").format(_('Cancel')),
+ _('If you are online, click on "{}" to continue.').format(_('Next'))
+ ]
+ msg = '\n\n'.join(msg)
+ wizard.stack = []
+ wizard.confirm_dialog(title='', message=msg, run_next = lambda x: wizard.run('accept_terms_of_use'))
+
def accept_terms_of_use(self, window):
vbox = QVBoxLayout()
vbox.addWidget(QLabel(_("Terms of Service")))
@@ -256,24 +261,21 @@ class Plugin(TrustedCoinPlugin):
window.terminate()
def set_enabled():
- valid_email = re.match(regexp, email_e.text()) is not None
- next_button.setEnabled(tos_received and valid_email)
+ next_button.setEnabled(tos_received and is_valid_email(email_e.text()))
tos_e.tos_signal.connect(on_result)
tos_e.error_signal.connect(on_error)
t = Thread(target=request_TOS)
t.setDaemon(True)
t.start()
-
- regexp = r"[^@]+@[^@]+\.[^@]+"
email_e.textChanged.connect(set_enabled)
email_e.setFocus(True)
-
window.exec_layout(vbox, next_enabled=False)
next_button.setText(prior_button_text)
- return str(email_e.text())
+ email = str(email_e.text())
+ self.create_remote_key(email, window)
- def request_otp_dialog(self, window, _id, otp_secret):
+ def request_otp_dialog(self, window, short_id, otp_secret, xpub3):
vbox = QVBoxLayout()
if otp_secret is not None:
uri = "otpauth://totp/%s?secret=%s"%('trustedcoin.com', otp_secret)
@@ -291,7 +293,6 @@ class Plugin(TrustedCoinPlugin):
label.setWordWrap(1)
vbox.addWidget(label)
msg = _('Google Authenticator code:')
-
hbox = QHBoxLayout()
hbox.addWidget(WWLabel(msg))
pw = AmountEdit(None, is_int = True)
@@ -299,21 +300,14 @@ class Plugin(TrustedCoinPlugin):
pw.setMaximumWidth(50)
hbox.addWidget(pw)
vbox.addLayout(hbox)
-
cb_lost = QCheckBox(_("I have lost my Google Authenticator account"))
cb_lost.setToolTip(_("Check this box to request a new secret. You will need to retype your seed."))
vbox.addWidget(cb_lost)
cb_lost.setVisible(otp_secret is None)
-
def set_enabled():
b = True if cb_lost.isChecked() else len(pw.text()) == 6
window.next_button.setEnabled(b)
-
pw.textChanged.connect(set_enabled)
cb_lost.toggled.connect(set_enabled)
-
- window.exec_layout(vbox, next_enabled=False,
- raise_on_cancel=False)
- return pw.get_amount(), cb_lost.isChecked()
-
-
+ window.exec_layout(vbox, next_enabled=False, raise_on_cancel=False)
+ self.check_otp(window, short_id, otp_secret, xpub3, pw.get_amount(), cb_lost.isChecked())
diff --git a/plugins/trustedcoin/trustedcoin.py b/plugins/trustedcoin/trustedcoin.py
@@ -75,6 +75,18 @@ DISCLAIMER = [
"To be safe from malware, you may want to do this on an offline "
"computer, and move your wallet later to an online computer."),
]
+
+KIVY_DISCLAIMER = [
+ _("Two-factor authentication is a service provided by TrustedCoin. "
+ "To use it, you must have a separate device with Google Authenticator."),
+ _("This service uses a multi-signature wallet, where you own 2 of 3 keys. "
+ "The third key is stored on a remote server that signs transactions on "
+ "your behalf.A small fee will be charged on each transaction that uses the "
+ "remote server."),
+ _("Note that your coins are not locked in this service. You may withdraw "
+ "your funds at any time and at no cost, without the remote server, by "
+ "using the 'restore wallet' option with your wallet seed."),
+]
RESTORE_MSG = _("Enter the seed for your 2-factor wallet:")
class TrustedCoinException(Exception):
@@ -215,7 +227,6 @@ 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()
@@ -269,25 +280,22 @@ class Wallet_2fa(Multisig_Wallet):
tx = mk_tx(outputs)
return tx
- def sign_transaction(self, tx, password):
- 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:
+ def on_otp(self, tx, otp):
+ if not otp:
self.print_error("sign_transaction: no auth code")
return
+ otp = int(otp)
long_user_id, short_id = self.get_user_id()
tx_dict = tx.as_dict()
raw_tx = tx_dict["hex"]
- r = server.sign(short_id, raw_tx, self.auth_code)
+ r = server.sign(short_id, raw_tx, otp)
if r:
raw_tx = r.get('transaction')
tx.update(raw_tx)
self.print_error("twofactor: is complete", tx.is_complete())
# reset billing_info
self.billing_info = None
- self.auth_code = None
+
# Utility functions
@@ -316,6 +324,7 @@ def make_billing_address(wallet, num):
class TrustedCoinPlugin(BasePlugin):
wallet_class = Wallet_2fa
+ disclaimer_msg = DISCLAIMER
def __init__(self, parent, config, name):
BasePlugin.__init__(self, parent, config, name)
@@ -336,6 +345,21 @@ class TrustedCoinPlugin(BasePlugin):
return False
@hook
+ def tc_sign_wrapper(self, wallet, tx, on_success, on_failure):
+ if not isinstance(wallet, self.wallet_class):
+ return
+ if tx.is_complete():
+ return
+ if wallet.can_sign_without_server():
+ return
+ if not wallet.keystores['x3/'].get_tx_derivations(tx):
+ self.print_error("twofactor: xpub3 not needed")
+ return
+ def wrapper(tx):
+ self.prompt_user_for_otp(wallet, tx, on_success, on_failure)
+ return wrapper
+
+ @hook
def get_tx_extra_fee(self, wallet, tx):
if type(wallet) != Wallet_2fa:
return
@@ -391,7 +415,7 @@ class TrustedCoinPlugin(BasePlugin):
def show_disclaimer(self, wizard):
wizard.set_icon(':icons/trustedcoin-wizard.png')
wizard.stack = []
- wizard.confirm_dialog(title='Disclaimer', message='\n\n'.join(DISCLAIMER), run_next = lambda x: wizard.run('choose_seed'))
+ wizard.confirm_dialog(title='Disclaimer', message='\n\n'.join(self.disclaimer_msg), run_next = lambda x: wizard.run('choose_seed'))
def choose_seed(self, wizard):
title = _('Create or restore')
@@ -450,18 +474,7 @@ class TrustedCoinPlugin(BasePlugin):
wizard.storage.put('x1/', k1.dump())
wizard.storage.put('x2/', k2.dump())
wizard.storage.write()
- msg = [
- _("Your wallet file is: {}.").format(os.path.abspath(wizard.storage.path)),
- _("You need to be online in order to complete the creation of "
- "your wallet. If you generated your seed on an offline "
- 'computer, click on "{}" to close this window, move your '
- "wallet file to an online computer, and reopen it with "
- "Electrum.").format(_('Cancel')),
- _('If you are online, click on "{}" to continue.').format(_('Next'))
- ]
- msg = '\n\n'.join(msg)
- wizard.stack = []
- wizard.confirm_dialog(title='', message=msg, run_next = lambda x: wizard.run('create_remote_key'))
+ self.go_online_dialog(wizard)
def restore_wallet(self, wizard):
wizard.opt_bip39 = False
@@ -516,8 +529,8 @@ class TrustedCoinPlugin(BasePlugin):
wizard.wallet = Wallet_2fa(storage)
wizard.create_addresses()
- def create_remote_key(self, wizard):
- email = self.accept_terms_of_use(wizard)
+
+ def create_remote_key(self, email, wizard):
xpub1 = wizard.storage.get('x1/')['xpub']
xpub2 = wizard.storage.get('x2/')['xpub']
# Generate third key deterministically.
@@ -550,10 +563,9 @@ class TrustedCoinPlugin(BasePlugin):
except Exception as e:
wizard.show_message(str(e))
return
- self.check_otp(wizard, short_id, otp_secret, xpub3)
+ self.request_otp_dialog(wizard, short_id, otp_secret, xpub3)
- def check_otp(self, wizard, short_id, otp_secret, xpub3):
- otp, reset = self.request_otp_dialog(wizard, short_id, otp_secret)
+ def check_otp(self, wizard, short_id, otp_secret, xpub3, otp, reset):
if otp:
self.do_auth(wizard, short_id, otp, xpub3)
elif reset:
@@ -569,8 +581,8 @@ class TrustedCoinPlugin(BasePlugin):
def do_auth(self, wizard, short_id, otp, xpub3):
try:
server.auth(short_id, otp)
- except:
- wizard.show_message(_('Incorrect password'))
+ except Exception as e:
+ wizard.show_message(str(e))
return
k3 = keystore.from_xpub(xpub3)
wizard.storage.put('x3/', k3.dump())
@@ -603,7 +615,7 @@ class TrustedCoinPlugin(BasePlugin):
if not new_secret:
wizard.show_message(_('Request rejected by server'))
return
- self.check_otp(wizard, short_id, new_secret, xpub3)
+ self.request_otp_dialog(wizard, short_id, new_secret, xpub3)
@hook
def get_action(self, storage):
@@ -614,4 +626,4 @@ class TrustedCoinPlugin(BasePlugin):
if not storage.get('x2/'):
return self, 'show_disclaimer'
if not storage.get('x3/'):
- return self, 'create_remote_key'
+ return self, 'accept_terms_of_use'