mirror of
https://github.com/LBRYFoundation/LBRY-Vault.git
synced 2025-08-23 17:47:31 +00:00
wizard: add checkbox for passphrases. allow passphrases with 2fa seeds
This commit is contained in:
parent
0fd813f229
commit
121ac07b01
5 changed files with 60 additions and 48 deletions
|
@ -530,7 +530,7 @@ class ShowSeedDialog(WizardDialog):
|
||||||
self._back = _back = partial(self.ids.back.dispatch, 'on_release')
|
self._back = _back = partial(self.ids.back.dispatch, 'on_release')
|
||||||
|
|
||||||
def get_params(self, b):
|
def get_params(self, b):
|
||||||
return (self.seed_text,)
|
return (True,)
|
||||||
|
|
||||||
|
|
||||||
class WordButton(Button):
|
class WordButton(Button):
|
||||||
|
@ -643,7 +643,7 @@ class RestoreSeedDialog(WizardDialog):
|
||||||
tis.focus = False
|
tis.focus = False
|
||||||
|
|
||||||
def get_params(self, b):
|
def get_params(self, b):
|
||||||
return (self.get_text(), False)
|
return (self.get_text(), False, True)
|
||||||
|
|
||||||
|
|
||||||
class ConfirmSeedDialog(RestoreSeedDialog):
|
class ConfirmSeedDialog(RestoreSeedDialog):
|
||||||
|
|
|
@ -252,9 +252,13 @@ class InstallWizard(QDialog, MessageBoxMixin, BaseWizard):
|
||||||
slayout = SeedInputLayout(self, message, is_seed)
|
slayout = SeedInputLayout(self, message, is_seed)
|
||||||
vbox = QVBoxLayout()
|
vbox = QVBoxLayout()
|
||||||
vbox.addLayout(slayout.layout())
|
vbox.addLayout(slayout.layout())
|
||||||
if self.opt_bip39:
|
if self.opt_ext or self.opt_bip39:
|
||||||
vbox.addStretch(1)
|
vbox.addStretch(1)
|
||||||
vbox.addWidget(QLabel(_('Options') + ':'))
|
vbox.addWidget(QLabel(_('Options') + ':'))
|
||||||
|
if self.opt_ext:
|
||||||
|
cb_pass = QCheckBox(_('Add a passphrase to this seed'))
|
||||||
|
vbox.addWidget(cb_pass)
|
||||||
|
if self.opt_bip39:
|
||||||
def f(b):
|
def f(b):
|
||||||
if b:
|
if b:
|
||||||
msg = ' '.join([
|
msg = ' '.join([
|
||||||
|
@ -278,7 +282,8 @@ class InstallWizard(QDialog, MessageBoxMixin, BaseWizard):
|
||||||
self.set_main_layout(vbox, title, next_enabled=False)
|
self.set_main_layout(vbox, title, next_enabled=False)
|
||||||
seed = slayout.get_seed()
|
seed = slayout.get_seed()
|
||||||
is_bip39 = cb_bip39.isChecked() if self.opt_bip39 else False
|
is_bip39 = cb_bip39.isChecked() if self.opt_bip39 else False
|
||||||
return seed, is_bip39
|
is_ext = cb_pass.isChecked() if self.opt_ext else False
|
||||||
|
return seed, is_bip39, is_ext
|
||||||
|
|
||||||
@wizard_dialog
|
@wizard_dialog
|
||||||
def add_xpub_dialog(self, title, message, is_valid, run_next):
|
def add_xpub_dialog(self, title, message, is_valid, run_next):
|
||||||
|
@ -308,14 +313,20 @@ class InstallWizard(QDialog, MessageBoxMixin, BaseWizard):
|
||||||
_('If you lose your seed, your money will be permanently lost.'),
|
_('If you lose your seed, your money will be permanently lost.'),
|
||||||
_('To make sure that you have properly saved your seed, please retype it here.')
|
_('To make sure that you have properly saved your seed, please retype it here.')
|
||||||
])
|
])
|
||||||
seed, is_bip39 = self.seed_input(title, message, test)
|
seed, is_bip39, is_pass = self.seed_input(title, message, test)
|
||||||
return seed
|
return seed
|
||||||
|
|
||||||
@wizard_dialog
|
@wizard_dialog
|
||||||
def show_seed_dialog(self, run_next, seed_text):
|
def show_seed_dialog(self, run_next, seed_text):
|
||||||
|
vbox = QVBoxLayout()
|
||||||
slayout = CreateSeedLayout(seed_text)
|
slayout = CreateSeedLayout(seed_text)
|
||||||
self.set_main_layout(slayout.layout())
|
vbox.addLayout(slayout.layout())
|
||||||
return seed_text
|
vbox.addStretch(1)
|
||||||
|
vbox.addWidget(QLabel('<b>'+_('Option') + '</b>:'))
|
||||||
|
cb_pass = QCheckBox(_('Add a passphrase to this seed'))
|
||||||
|
vbox.addWidget(cb_pass)
|
||||||
|
self.set_main_layout(vbox)
|
||||||
|
return cb_pass.isChecked()
|
||||||
|
|
||||||
def pw_layout(self, msg, kind):
|
def pw_layout(self, msg, kind):
|
||||||
playout = PasswordLayout(None, msg, kind, self.next_button)
|
playout = PasswordLayout(None, msg, kind, self.next_button)
|
||||||
|
|
|
@ -249,9 +249,10 @@ class BaseWizard(object):
|
||||||
self.on_keystore(k)
|
self.on_keystore(k)
|
||||||
|
|
||||||
def passphrase_dialog(self, run_next):
|
def passphrase_dialog(self, run_next):
|
||||||
|
title = _('Passphrase')
|
||||||
message = '\n'.join([
|
message = '\n'.join([
|
||||||
_('Your seed may be extended with a passphrase.'),
|
_('You may extend your seed with a passphrase.'),
|
||||||
_('If that is the case, enter it here.'),
|
_('The passphrase must be saved together with your seed.'),
|
||||||
])
|
])
|
||||||
warning = '\n'.join([
|
warning = '\n'.join([
|
||||||
_('Note that this is NOT your encryption password.'),
|
_('Note that this is NOT your encryption password.'),
|
||||||
|
@ -261,18 +262,19 @@ class BaseWizard(object):
|
||||||
|
|
||||||
def restore_from_seed(self):
|
def restore_from_seed(self):
|
||||||
self.opt_bip39 = True
|
self.opt_bip39 = True
|
||||||
|
self.opt_ext = True
|
||||||
test = bitcoin.is_seed if self.wallet_type == 'standard' else bitcoin.is_new_seed
|
test = bitcoin.is_seed if self.wallet_type == 'standard' else bitcoin.is_new_seed
|
||||||
self.restore_seed_dialog(run_next=self.on_restore_seed, test=test)
|
self.restore_seed_dialog(run_next=self.on_restore_seed, test=test)
|
||||||
|
|
||||||
def on_restore_seed(self, seed, is_bip39):
|
def on_restore_seed(self, seed, is_bip39, is_ext):
|
||||||
if is_bip39:
|
if is_bip39:
|
||||||
f = lambda x: self.on_restore_bip39(seed, x)
|
f = lambda passphrase: self.on_restore_bip39(seed, passphrase)
|
||||||
self.passphrase_dialog(run_next=f)
|
self.passphrase_dialog(run_next=f) if is_ext else f('')
|
||||||
else:
|
else:
|
||||||
seed_type = bitcoin.seed_type(seed)
|
seed_type = bitcoin.seed_type(seed)
|
||||||
if seed_type == 'standard':
|
if seed_type == 'standard':
|
||||||
f = lambda x: self.run('create_keystore', seed, x)
|
f = lambda passphrase: self.run('create_keystore', seed, passphrase)
|
||||||
self.passphrase_dialog(run_next=f)
|
self.passphrase_dialog(run_next=f) if is_ext else f('')
|
||||||
elif seed_type == 'old':
|
elif seed_type == 'old':
|
||||||
self.run('create_keystore', seed, passphrase)
|
self.run('create_keystore', seed, passphrase)
|
||||||
elif seed_type == '2fa':
|
elif seed_type == '2fa':
|
||||||
|
@ -281,7 +283,7 @@ class BaseWizard(object):
|
||||||
self.run('restore_from_seed')
|
self.run('restore_from_seed')
|
||||||
else:
|
else:
|
||||||
self.load_2fa()
|
self.load_2fa()
|
||||||
self.run('on_restore_seed', seed)
|
self.run('on_restore_seed', seed, is_ext)
|
||||||
else:
|
else:
|
||||||
raise
|
raise
|
||||||
|
|
||||||
|
@ -355,20 +357,15 @@ class BaseWizard(object):
|
||||||
from electrum.mnemonic import Mnemonic
|
from electrum.mnemonic import Mnemonic
|
||||||
seed = Mnemonic('en').make_seed()
|
seed = Mnemonic('en').make_seed()
|
||||||
self.opt_bip39 = False
|
self.opt_bip39 = False
|
||||||
self.show_seed_dialog(run_next=self.request_passphrase, seed_text=seed)
|
f = lambda x: self.request_passphrase(seed, x)
|
||||||
|
self.show_seed_dialog(run_next=f, seed_text=seed)
|
||||||
|
|
||||||
def request_passphrase(self, seed):
|
def request_passphrase(self, seed, opt_passphrase):
|
||||||
title = _('Passphrase')
|
if opt_passphrase:
|
||||||
message = '\n'.join([
|
f = lambda x: self.confirm_seed(seed, x)
|
||||||
_('You may extend your seed with a passphrase.'),
|
self.passphrase_dialog(run_next=f)
|
||||||
_('The passphrase must be saved together with your seed.'),
|
else:
|
||||||
])
|
self.run('confirm_seed', seed, '')
|
||||||
warning = '\n'.join([
|
|
||||||
_('Note that this is NOT your encryption password.'),
|
|
||||||
_('If you do not know what this is, leave this field empty.'),
|
|
||||||
])
|
|
||||||
f = lambda x: self.confirm_seed(seed, x)
|
|
||||||
self.line_dialog(run_next=f, title=title, message=message, warning=warning, default='', test=lambda x:True)
|
|
||||||
|
|
||||||
def confirm_seed(self, seed, passphrase):
|
def confirm_seed(self, seed, passphrase):
|
||||||
f = lambda x: self.confirm_passphrase(seed, passphrase)
|
f = lambda x: self.confirm_passphrase(seed, passphrase)
|
||||||
|
|
|
@ -825,8 +825,8 @@ def bip32_private_key(sequence, k, chain):
|
||||||
return SecretToASecret(k, True)
|
return SecretToASecret(k, True)
|
||||||
|
|
||||||
|
|
||||||
def xkeys_from_seed(seed, derivation):
|
def xkeys_from_seed(seed, passphrase, derivation):
|
||||||
from mnemonic import Mnemonic
|
from mnemonic import Mnemonic
|
||||||
xprv, xpub = bip32_root(Mnemonic.mnemonic_to_seed(seed, ''))
|
xprv, xpub = bip32_root(Mnemonic.mnemonic_to_seed(seed, passphrase))
|
||||||
xprv, xpub = bip32_private_derivation(xprv, "m/", derivation)
|
xprv, xpub = bip32_private_derivation(xprv, "m/", derivation)
|
||||||
return xprv, xpub
|
return xprv, xpub
|
||||||
|
|
|
@ -348,33 +348,31 @@ class TrustedCoinPlugin(BasePlugin):
|
||||||
('create_seed', _('Create a new seed')),
|
('create_seed', _('Create a new seed')),
|
||||||
('restore_wallet', _('I already have a seed')),
|
('restore_wallet', _('I already have a seed')),
|
||||||
]
|
]
|
||||||
wizard.opt_bip39 = False
|
|
||||||
wizard.opt_ext = False
|
|
||||||
wizard.choice_dialog(title=title, message=message, choices=choices, run_next=wizard.run)
|
wizard.choice_dialog(title=title, message=message, choices=choices, run_next=wizard.run)
|
||||||
|
|
||||||
def create_seed(self, wizard):
|
def create_seed(self, wizard):
|
||||||
seed = self.make_seed()
|
seed = self.make_seed()
|
||||||
f = lambda x: wizard.confirm_seed(seed, '')
|
f = lambda x: wizard.request_passphrase(seed, x)
|
||||||
wizard.show_seed_dialog(run_next=f, seed_text=seed)
|
wizard.show_seed_dialog(run_next=f, seed_text=seed)
|
||||||
|
|
||||||
def xkeys_from_seed(self, seed):
|
def xkeys_from_seed(self, seed, passphrase):
|
||||||
words = seed.split()
|
words = seed.split()
|
||||||
n = len(words)
|
n = len(words)
|
||||||
# old version use long seed phrases
|
# old version use long seed phrases
|
||||||
if n >= 24:
|
if n >= 24:
|
||||||
xprv1, xpub1 = keystore.xkeys_from_seed(' '.join(words[0:12]), "m/")
|
assert passphrase == ''
|
||||||
xprv2, xpub2 = keystore.xkeys_from_seed(' '.join(words[12:]), "m/")
|
xprv1, xpub1 = keystore.xkeys_from_seed(' '.join(words[0:12]), '', "m/")
|
||||||
|
xprv2, xpub2 = keystore.xkeys_from_seed(' '.join(words[12:]), '', "m/")
|
||||||
elif n==12:
|
elif n==12:
|
||||||
xprv1, xpub1 = keystore.xkeys_from_seed(seed, "m/0'/")
|
xprv1, xpub1 = keystore.xkeys_from_seed(seed, passphrase, "m/0'/")
|
||||||
xprv2, xpub2 = keystore.xkeys_from_seed(seed, "m/1'/")
|
xprv2, xpub2 = keystore.xkeys_from_seed(seed, passphrase, "m/1'/")
|
||||||
else:
|
else:
|
||||||
raise BaseException('unrecognized seed length')
|
raise BaseException('unrecognized seed length')
|
||||||
return xprv1, xpub1, xprv2, xpub2
|
return xprv1, xpub1, xprv2, xpub2
|
||||||
|
|
||||||
def create_keystore(self, wizard, seed, passphrase):
|
def create_keystore(self, wizard, seed, passphrase):
|
||||||
assert passphrase == ''
|
|
||||||
# this overloads the wizard's method
|
# this overloads the wizard's method
|
||||||
xprv1, xpub1, xprv2, xpub2 = self.xkeys_from_seed(seed)
|
xprv1, xpub1, xprv2, xpub2 = self.xkeys_from_seed(seed, passphrase)
|
||||||
k1 = keystore.from_xprv(xprv1)
|
k1 = keystore.from_xprv(xprv1)
|
||||||
k2 = keystore.from_xpub(xpub2)
|
k2 = keystore.from_xpub(xpub2)
|
||||||
wizard.request_password(run_next=lambda pw: self.on_password(wizard, pw, k1, k2))
|
wizard.request_password(run_next=lambda pw: self.on_password(wizard, pw, k1, k2))
|
||||||
|
@ -399,11 +397,17 @@ class TrustedCoinPlugin(BasePlugin):
|
||||||
wizard.confirm_dialog(title='', message=msg, run_next = lambda x: wizard.run('create_remote_key'))
|
wizard.confirm_dialog(title='', message=msg, run_next = lambda x: wizard.run('create_remote_key'))
|
||||||
|
|
||||||
def restore_wallet(self, wizard):
|
def restore_wallet(self, wizard):
|
||||||
|
wizard.opt_bip39 = False
|
||||||
|
wizard.opt_ext = True
|
||||||
title = _("Restore two-factor Wallet")
|
title = _("Restore two-factor Wallet")
|
||||||
f = lambda x, y: wizard.run('on_restore_seed', x)
|
f = lambda seed, is_bip39, is_ext: wizard.run('on_restore_seed', seed, is_ext)
|
||||||
wizard.restore_seed_dialog(run_next=f, test=self.is_valid_seed)
|
wizard.restore_seed_dialog(run_next=f, test=self.is_valid_seed)
|
||||||
|
|
||||||
def on_restore_seed(self, wizard, seed):
|
def on_restore_seed(self, wizard, seed, is_ext):
|
||||||
|
f = lambda x: self.restore_choice(wizard, seed, x)
|
||||||
|
wizard.passphrase_dialog(run_next=f) if is_ext else f('')
|
||||||
|
|
||||||
|
def restore_choice(self, wizard, seed, passphrase):
|
||||||
wizard.set_icon(':icons/trustedcoin.png')
|
wizard.set_icon(':icons/trustedcoin.png')
|
||||||
wizard.stack = []
|
wizard.stack = []
|
||||||
title = _('Restore 2FA wallet')
|
title = _('Restore 2FA wallet')
|
||||||
|
@ -413,19 +417,19 @@ class TrustedCoinPlugin(BasePlugin):
|
||||||
'or do you want to disable it, and have two master private keys in your wallet?'
|
'or do you want to disable it, and have two master private keys in your wallet?'
|
||||||
])
|
])
|
||||||
choices = [('keep', 'Keep'), ('disable', 'Disable')]
|
choices = [('keep', 'Keep'), ('disable', 'Disable')]
|
||||||
f = lambda x: self.on_choice(wizard, seed, x)
|
f = lambda x: self.on_choice(wizard, seed, passphrase, x)
|
||||||
wizard.choice_dialog(choices=choices, message=msg, title=title, run_next=f)
|
wizard.choice_dialog(choices=choices, message=msg, title=title, run_next=f)
|
||||||
|
|
||||||
def on_choice(self, wizard, seed, x):
|
def on_choice(self, wizard, seed, passphrase, x):
|
||||||
if x == 'disable':
|
if x == 'disable':
|
||||||
f = lambda pw: wizard.run('on_restore_pw', seed, pw)
|
f = lambda pw: wizard.run('on_restore_pw', seed, passphrase, pw)
|
||||||
wizard.request_password(run_next=f)
|
wizard.request_password(run_next=f)
|
||||||
else:
|
else:
|
||||||
self.create_keystore(wizard, seed, '')
|
self.create_keystore(wizard, seed, passphrase)
|
||||||
|
|
||||||
def on_restore_pw(self, wizard, seed, password):
|
def on_restore_pw(self, wizard, seed, passphrase, password):
|
||||||
storage = wizard.storage
|
storage = wizard.storage
|
||||||
xprv1, xpub1, xprv2, xpub2 = self.xkeys_from_seed(seed)
|
xprv1, xpub1, xprv2, xpub2 = self.xkeys_from_seed(seed, passphrase)
|
||||||
k1 = keystore.from_xprv(xprv1)
|
k1 = keystore.from_xprv(xprv1)
|
||||||
k2 = keystore.from_xprv(xprv2)
|
k2 = keystore.from_xprv(xprv2)
|
||||||
k1.add_seed(seed)
|
k1.add_seed(seed)
|
||||||
|
|
Loading…
Add table
Reference in a new issue