Skip to content

Commit c32f75a

Browse files
committed
wizard: display seed type. restore 2fa if needed
1 parent 1fe1fc3 commit c32f75a

7 files changed

Lines changed: 88 additions & 33 deletions

File tree

gui/qt/installwizard.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -256,9 +256,9 @@ def seed_input(self, title, message, is_seed):
256256
vbox.addStretch(1)
257257
vbox.addWidget(QLabel(_('Options') + ':'))
258258
def f(b):
259-
slayout.is_seed = (lambda x: bool(x)) if b else is_valid
259+
slayout.is_seed = (lambda x: bool(x)) if b else is_seed
260260
slayout.on_edit()
261-
cb_bip39 = QCheckBox(_('BIP39/BIP44 seed'))
261+
cb_bip39 = QCheckBox(_('BIP39 seed'))
262262
cb_bip39.toggled.connect(f)
263263
vbox.addWidget(cb_bip39)
264264
self.set_main_layout(vbox, title, next_enabled=False)

gui/qt/seed_dialog.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,8 @@ class SeedInputLayout(SeedLayoutBase):
122122
def __init__(self, parent, title, is_seed):
123123
vbox = QVBoxLayout()
124124
vbox.addLayout(self._seed_layout(title=title))
125+
self.seed_type_label = QLabel('')
126+
vbox.addWidget(self.seed_type_label)
125127
self.layout_ = vbox
126128
self.parent = parent
127129
self.is_seed = is_seed
@@ -131,7 +133,13 @@ def get_seed(self):
131133
return clean_text(self.seed_edit())
132134

133135
def on_edit(self):
134-
self.parent.next_button.setEnabled(self.is_seed(self.get_seed()))
136+
from electrum.bitcoin import seed_type
137+
s = self.get_seed()
138+
b = self.is_seed(s)
139+
t = seed_type(s)
140+
label = _('Seed Type') + ': ' + t if t else ''
141+
self.seed_type_label.setText(label)
142+
self.parent.next_button.setEnabled(b)
135143

136144

137145

lib/base_wizard.py

Lines changed: 42 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
# SOFTWARE.
2525

2626
import os
27+
import bitcoin
2728
import keystore
2829
from wallet import Wallet, Imported_Wallet, Standard_Wallet, Multisig_Wallet, WalletStorage, wallet_types
2930
from i18n import _
@@ -85,16 +86,19 @@ def new(self):
8586
choices = [pair for pair in wallet_kinds if pair[0] in wallet_types]
8687
self.choice_dialog(title=title, message=message, choices=choices, run_next=self.on_wallet_type)
8788

89+
def load_2fa(self):
90+
self.storage.put('wallet_type', '2fa')
91+
self.storage.put('use_trustedcoin', True)
92+
self.plugin = self.plugins.load_plugin('trustedcoin')
93+
8894
def on_wallet_type(self, choice):
8995
self.wallet_type = choice
9096
if choice == 'standard':
9197
action = 'choose_keystore'
9298
elif choice == 'multisig':
9399
action = 'choose_multisig'
94100
elif choice == '2fa':
95-
self.storage.put('wallet_type', '2fa')
96-
self.storage.put('use_trustedcoin', True)
97-
self.plugin = self.plugins.load_plugin('trustedcoin')
101+
self.load_2fa()
98102
action = self.storage.get_action()
99103
elif choice == 'imported':
100104
action = 'import_addresses'
@@ -243,31 +247,46 @@ def on_hw_derivation(self, name, device_info, derivation):
243247
k = hardware_keystore(d)
244248
self.on_keystore(k)
245249

246-
def restore_from_seed(self):
247-
self.opt_bip39 = True
248-
self.restore_seed_dialog(run_next=self.on_restore_seed, test=keystore.is_seed)
250+
def passphrase_dialog(self, run_next):
251+
message = '\n'.join([
252+
_('Your seed may be extended with a passphrase.'),
253+
_('If that is the case, enter it here.'),
254+
])
255+
warning = '\n'.join([
256+
_('Note that this is NOT your encryption password.'),
257+
_('If you do not know what this is, leave this field empty.'),
258+
])
259+
self.line_dialog(title=_('Passphrase'), message=message, warning=warning, default='', test=lambda x:True, run_next=run_next)
249260

250-
def on_restore_seed(self, seed, is_bip39):
251-
if keystore.is_new_seed(seed) or is_bip39:
252-
message = '\n'.join([
253-
_('Your seed may be extended with a passphrase.'),
254-
_('If that is the case, enter it here.'),
255-
])
256-
warning = '\n'.join([
257-
_('Note that this is NOT your encryption password.'),
258-
_('If you do not know what this is, leave this field empty.'),
259-
])
260-
f = lambda x: self.on_restore_passphrase(seed, x, is_bip39)
261-
self.line_dialog(title=_('Passphrase'), message=message, warning=warning, default='', test=lambda x:True, run_next=f)
261+
def restore_from_seed(self):
262+
if self.wallet_type == 'standard':
263+
self.opt_bip39 = True
264+
test = bitcoin.is_seed
262265
else:
263-
self.on_restore_passphrase(seed, '', False)
266+
self.opt_bip39 = False
267+
test = bitcoin.is_new_seed
268+
self.restore_seed_dialog(run_next=self.on_restore_seed, test=test)
264269

265-
def on_restore_passphrase(self, seed, passphrase, is_bip39):
270+
def on_restore_seed(self, seed, is_bip39):
266271
if is_bip39:
267-
f = lambda x: self.run('on_bip44', seed, passphrase, int(x))
268-
self.account_id_dialog(f)
272+
f = lambda x: self.on_restore_bip39(seed, x)
273+
self.passphrase_dialog(run_next=f)
269274
else:
270-
self.run('create_keystore', seed, passphrase)
275+
seed_type = bitcoin.seed_type(seed)
276+
if seed_type == 'standard':
277+
f = lambda x: self.run('create_keystore', seed, x)
278+
self.passphrase_dialog(run_next=f)
279+
elif seed_type == 'old':
280+
self.run('create_keystore', seed, passphrase)
281+
elif seed_type == '2fa':
282+
self.load_2fa()
283+
self.run('on_restore_seed', seed)
284+
else:
285+
raise
286+
287+
def on_restore_bip39(self, seed, passphrase):
288+
f = lambda x: self.run('on_bip44', seed, passphrase, int(x))
289+
self.account_id_dialog(f)
271290

272291
def create_keystore(self, seed, passphrase):
273292
k = keystore.from_seed(seed, passphrase)

lib/bitcoin.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -173,16 +173,25 @@ def is_old_seed(seed):
173173
uses_electrum_words = True
174174
except Exception:
175175
uses_electrum_words = False
176-
177176
try:
178177
seed.decode('hex')
179178
is_hex = (len(seed) == 32 or len(seed) == 64)
180179
except Exception:
181180
is_hex = False
182-
183181
return is_hex or (uses_electrum_words and (len(words) == 12 or len(words) == 24))
184182

185183

184+
def seed_type(x):
185+
if is_old_seed(x):
186+
return 'old'
187+
elif is_new_seed(x):
188+
return 'standard'
189+
elif is_new_seed(x, version.SEED_PREFIX_2FA):
190+
return '2fa'
191+
return ''
192+
193+
is_seed = lambda x: bool(seed_type(x))
194+
186195
# pywallet openssl private key implementation
187196

188197
def i2o_ECPublicKey(pubkey, compressed=False):

lib/keystore.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
from bitcoin import public_key_from_private_key, public_key_to_bc_address
3434
from bitcoin import *
3535

36-
from bitcoin import is_old_seed, is_new_seed
36+
from bitcoin import is_old_seed, is_new_seed, is_seed
3737
from util import PrintError, InvalidPassword
3838
from mnemonic import Mnemonic
3939

@@ -665,7 +665,7 @@ def is_private_key_list(text):
665665
parts = text.split()
666666
return bool(parts) and all(bitcoin.is_private_key(x) for x in parts)
667667

668-
is_seed = lambda x: is_old_seed(x) or is_new_seed(x)
668+
669669
is_mpk = lambda x: is_old_mpk(x) or is_xpub(x)
670670
is_private = lambda x: is_seed(x) or is_xprv(x) or is_private_key_list(x)
671671
is_any_key = lambda x: is_old_mpk(x) or is_xprv(x) or is_xpub(x) or is_address_list(x) or is_private_key_list(x)

plugins/trustedcoin/qt.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,10 @@ def setup_google_auth(self, window, _id, otp_secret):
252252
vbox.addWidget(qrw, 1)
253253
msg = _('Then, enter your Google Authenticator code:')
254254
else:
255-
label = QLabel("This wallet is already registered, but it was never authenticated. To finalize your registration, please enter your Google Authenticator Code. If you do not have this code, delete the wallet file and start a new registration")
255+
label = QLabel(
256+
"This wallet is already registered with Trustedcoin. "
257+
"To finalize wallet creation, please enter your Google Authenticator Code. "
258+
"If you do not have this code, delete the wallet file and start a new registration")
256259
label.setWordWrap(1)
257260
vbox.addWidget(label)
258261
msg = _('Google Authenticator code:')

plugins/trustedcoin/trustedcoin.py

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -404,8 +404,24 @@ def restore_wallet(self, wizard):
404404
wizard.restore_seed_dialog(run_next=f, test=self.is_valid_seed)
405405

406406
def on_restore_seed(self, wizard, seed):
407-
f = lambda pw: wizard.run('on_restore_pw', seed, pw)
408-
wizard.request_password(run_next=f)
407+
wizard.set_icon(':icons/trustedcoin.png')
408+
wizard.stack = []
409+
title = _('Restore 2FA wallet')
410+
msg = ' '.join([
411+
'You are going to restore a wallet protected with two-factor authentication.',
412+
'Do you want to keep using two-factor authentication with this wallet,',
413+
'or do you want to disable it, and have two master private keys in your wallet?'
414+
])
415+
choices = [('keep', 'Keep'), ('disable', 'Disable')]
416+
f = lambda x: self.on_choice(wizard, seed, x)
417+
wizard.choice_dialog(choices=choices, message=msg, title=title, run_next=f)
418+
419+
def on_choice(self, wizard, seed, x):
420+
if x == 'disable':
421+
f = lambda pw: wizard.run('on_restore_pw', seed, pw)
422+
wizard.request_password(run_next=f)
423+
else:
424+
self.create_keystore(wizard, seed, '')
409425

410426
def on_restore_pw(self, wizard, seed, password):
411427
storage = wizard.storage

0 commit comments

Comments
 (0)