wizard: it is better to use a separate screen for passphrase
This commit is contained in:
parent
19e62ba643
commit
ebab390b1a
|
@ -402,18 +402,18 @@ Builder.load_string('''
|
|||
SeedButton:
|
||||
text: root.seed_text
|
||||
|
||||
<PassphraseDialog>
|
||||
<LineDialog>
|
||||
|
||||
BigLabel:
|
||||
text: "SEED PASSPHRASE"
|
||||
text: root.title
|
||||
SeedLabel:
|
||||
text: root.passphrase_message
|
||||
text: root.message
|
||||
GridLayout:
|
||||
cols: 2
|
||||
size_hint: 1, None
|
||||
height: '27dp'
|
||||
BigLabel:
|
||||
text: _('Passphrase')
|
||||
text: ''
|
||||
TextInput:
|
||||
id: passphrase_input
|
||||
multiline: False
|
||||
|
@ -512,14 +512,9 @@ class WizardChoiceDialog(WizardDialog):
|
|||
|
||||
|
||||
|
||||
class PassphraseDialog(WizardDialog):
|
||||
passphrase = StringProperty('')
|
||||
passphrase_message = ' '.join([
|
||||
_("You may extend your seed with a derivation passphrase."),
|
||||
'\n\n',
|
||||
_("Note: This is NOT your encryption password."),
|
||||
_("Leave this field empty if you are not sure about what it is."),
|
||||
])
|
||||
class LineDialog(WizardDialog):
|
||||
title = StringProperty('')
|
||||
message = StringProperty('')
|
||||
|
||||
def __init__(self, wizard, **kwargs):
|
||||
WizardDialog.__init__(self, wizard, **kwargs)
|
||||
|
@ -538,7 +533,7 @@ class ShowSeedDialog(WizardDialog):
|
|||
self._back = _back = partial(self.ids.back.dispatch, 'on_release')
|
||||
|
||||
def get_params(self, b):
|
||||
return(self.seed_text, '')
|
||||
return (self.seed_text,)
|
||||
|
||||
|
||||
class WordButton(Button):
|
||||
|
@ -552,7 +547,7 @@ class RestoreSeedDialog(WizardDialog):
|
|||
|
||||
def __init__(self, wizard, **kwargs):
|
||||
super(RestoreSeedDialog, self).__init__(wizard, **kwargs)
|
||||
self._test = kwargs['is_seed']
|
||||
self._test = kwargs['test']
|
||||
from electrum.mnemonic import Mnemonic
|
||||
from electrum.old_mnemonic import words as old_wordlist
|
||||
self.words = set(Mnemonic('en').wordlist).union(set(old_wordlist))
|
||||
|
@ -614,9 +609,6 @@ class RestoreSeedDialog(WizardDialog):
|
|||
text = ' '.join(text.split())
|
||||
return text
|
||||
|
||||
def get_params(self, b):
|
||||
return (self.get_text(), '', False)
|
||||
|
||||
def update_text(self, c):
|
||||
c = c.lower()
|
||||
text = self.ids.text_input_seed.text
|
||||
|
@ -653,6 +645,14 @@ class RestoreSeedDialog(WizardDialog):
|
|||
tis._keyboard.unbind(on_key_down=self.on_key_down)
|
||||
tis.focus = False
|
||||
|
||||
def get_params(self, b):
|
||||
return (self.get_text(), False)
|
||||
|
||||
|
||||
class ConfirmSeedDialog(RestoreSeedDialog):
|
||||
def get_params(self, b):
|
||||
return (self.get_text(),)
|
||||
|
||||
|
||||
class ShowXpubDialog(WizardDialog):
|
||||
|
||||
|
@ -744,12 +744,12 @@ class InstallWizard(BaseWizard, Widget):
|
|||
def choice_dialog(self, **kwargs): WizardChoiceDialog(self, **kwargs).open()
|
||||
def multisig_dialog(self, **kwargs): WizardMultisigDialog(self, **kwargs).open()
|
||||
def show_seed_dialog(self, **kwargs): ShowSeedDialog(self, **kwargs).open()
|
||||
def passphrase_dialog(self, **kwargs): PassphraseDialog(self, **kwargs).open()
|
||||
def line_dialog(self, **kwargs): LineDialog(self, **kwargs).open()
|
||||
|
||||
def confirm_seed_dialog(self, **kwargs):
|
||||
kwargs['title'] = _('Confirm Seed')
|
||||
kwargs['message'] = _('Please retype your seed phrase, to confirm that you properly saved it')
|
||||
RestoreSeedDialog(self, **kwargs).open()
|
||||
ConfirmSeedDialog(self, **kwargs).open()
|
||||
|
||||
def restore_seed_dialog(self, **kwargs):
|
||||
RestoreSeedDialog(self, **kwargs).open()
|
||||
|
|
|
@ -249,24 +249,23 @@ class InstallWizard(QDialog, MessageBoxMixin, BaseWizard):
|
|||
self.set_main_layout(slayout.layout(), title, next_enabled=False)
|
||||
return slayout.get_text()
|
||||
|
||||
def seed_input(self, title, message, is_seed, is_passphrase):
|
||||
slayout = SeedInputLayout(self, message, is_seed, is_passphrase)
|
||||
def seed_input(self, title, message, is_seed):
|
||||
slayout = SeedInputLayout(self, message, is_seed)
|
||||
vbox = QVBoxLayout()
|
||||
vbox.addLayout(slayout.layout())
|
||||
if self.opt_bip39:
|
||||
vbox.addStretch(1)
|
||||
vbox.addWidget(QLabel(_('Options') + ':'))
|
||||
def f(b):
|
||||
slayout.is_valid = (lambda x: bool(x)) if b else is_valid
|
||||
slayout.set_enabled()
|
||||
slayout.is_seed = (lambda x: bool(x)) if b else is_valid
|
||||
slayout.on_edit()
|
||||
cb_bip39 = QCheckBox(_('BIP39/BIP44 seed'))
|
||||
cb_bip39.toggled.connect(f)
|
||||
vbox.addWidget(cb_bip39)
|
||||
self.set_main_layout(vbox, title, next_enabled=False)
|
||||
seed = slayout.get_seed()
|
||||
passphrase = slayout.get_passphrase()
|
||||
is_bip39 = cb_bip39.isChecked() if self.opt_bip39 else False
|
||||
return seed, passphrase, is_bip39
|
||||
return seed, is_bip39
|
||||
|
||||
@wizard_dialog
|
||||
def restore_keys_dialog(self, title, message, is_valid, run_next):
|
||||
|
@ -282,14 +281,13 @@ class InstallWizard(QDialog, MessageBoxMixin, BaseWizard):
|
|||
return self.text_input(title, message, is_valid)
|
||||
|
||||
@wizard_dialog
|
||||
def restore_seed_dialog(self, run_next, is_seed):
|
||||
def restore_seed_dialog(self, run_next, test):
|
||||
title = _('Enter Seed')
|
||||
message = _('Please enter your seed phrase in order to restore your wallet.')
|
||||
is_passphrase = lambda x: True
|
||||
return self.seed_input(title, message, is_seed, is_passphrase)
|
||||
return self.seed_input(title, message, test)
|
||||
|
||||
@wizard_dialog
|
||||
def confirm_seed_dialog(self, run_next, is_seed, is_passphrase):
|
||||
def confirm_seed_dialog(self, run_next, test):
|
||||
self.app.clipboard().clear()
|
||||
title = _('Confirm Seed')
|
||||
message = ' '.join([
|
||||
|
@ -297,13 +295,14 @@ class InstallWizard(QDialog, MessageBoxMixin, BaseWizard):
|
|||
_('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.')
|
||||
])
|
||||
return self.seed_input(title, message, is_seed, is_passphrase)
|
||||
seed, is_bip39 = self.seed_input(title, message, test)
|
||||
return seed
|
||||
|
||||
@wizard_dialog
|
||||
def show_seed_dialog(self, run_next, seed_text):
|
||||
slayout = CreateSeedLayout(seed_text)
|
||||
self.set_main_layout(slayout.layout())
|
||||
return seed_text, slayout.passphrase()
|
||||
return seed_text
|
||||
|
||||
def pw_layout(self, msg, kind):
|
||||
playout = PasswordLayout(None, msg, kind, self.next_button)
|
||||
|
@ -380,20 +379,17 @@ class InstallWizard(QDialog, MessageBoxMixin, BaseWizard):
|
|||
return clayout.selected_index()
|
||||
|
||||
@wizard_dialog
|
||||
def account_id_dialog(self, run_next):
|
||||
message = '\n'.join([
|
||||
_('Enter your account number here.'),
|
||||
_('If you are not sure what this is, leave this field to zero.')
|
||||
])
|
||||
default = '0'
|
||||
title = _('Account Number')
|
||||
def line_dialog(self, run_next, title, message, default, test):
|
||||
vbox = QVBoxLayout()
|
||||
vbox.addWidget(WWLabel(message))
|
||||
line = QLineEdit()
|
||||
line.setText(default)
|
||||
vbox = QVBoxLayout()
|
||||
vbox.addWidget(QLabel(message))
|
||||
def f(text):
|
||||
self.next_button.setEnabled(test(text))
|
||||
line.textEdited.connect(f)
|
||||
vbox.addWidget(line)
|
||||
self.set_main_layout(vbox, title)
|
||||
return int(line.text())
|
||||
self.set_main_layout(vbox, title, next_enabled=test(default))
|
||||
return ' '.join(unicode(line.text()).split())
|
||||
|
||||
@wizard_dialog
|
||||
def show_xpub_dialog(self, xpub, run_next):
|
||||
|
|
|
@ -47,12 +47,12 @@ def check_password_strength(password):
|
|||
return password_strength[min(3, int(score))]
|
||||
|
||||
|
||||
PW_NEW, PW_CHANGE = range(0, 2)
|
||||
PW_NEW, PW_CHANGE, PW_PASSPHRASE = range(0, 3)
|
||||
|
||||
|
||||
class PasswordLayout(object):
|
||||
|
||||
titles = [_("Enter Password"), _("Change Password")]
|
||||
titles = [_("Enter Password"), _("Change Password"), _("Enter Passphrase")]
|
||||
|
||||
def __init__(self, wallet, msg, kind, OK_button):
|
||||
self.wallet = wallet
|
||||
|
@ -60,8 +60,8 @@ class PasswordLayout(object):
|
|||
self.pw = QLineEdit()
|
||||
self.pw.setEchoMode(2)
|
||||
self.new_pw = QLineEdit()
|
||||
self.conf_pw = QLineEdit()
|
||||
self.new_pw.setEchoMode(2)
|
||||
self.conf_pw = QLineEdit()
|
||||
self.conf_pw.setEchoMode(2)
|
||||
self.kind = kind
|
||||
self.OK_button = OK_button
|
||||
|
@ -76,15 +76,22 @@ class PasswordLayout(object):
|
|||
grid.setColumnMinimumWidth(1, 100)
|
||||
grid.setColumnStretch(1,1)
|
||||
|
||||
if kind == PW_PASSPHRASE:
|
||||
vbox.addWidget(label)
|
||||
msgs = [_('Passphrase:'), _('Confirm Passphrase:')]
|
||||
else:
|
||||
logo_grid = QGridLayout()
|
||||
logo_grid.setSpacing(8)
|
||||
logo_grid.setColumnMinimumWidth(0, 70)
|
||||
logo_grid.setColumnStretch(1,1)
|
||||
|
||||
logo = QLabel()
|
||||
logo.setAlignment(Qt.AlignCenter)
|
||||
|
||||
logo_grid.addWidget(logo, 0, 0)
|
||||
logo_grid.addWidget(label, 0, 1, 1, 2)
|
||||
vbox.addLayout(logo_grid)
|
||||
|
||||
m1 = _('New Password:') if kind == PW_NEW else _('Password:')
|
||||
msgs = [m1, _('Confirm Password:')]
|
||||
if wallet and wallet.has_password():
|
||||
|
@ -103,6 +110,7 @@ class PasswordLayout(object):
|
|||
vbox.addLayout(grid)
|
||||
|
||||
# Password Strength Label
|
||||
if kind != PW_PASSPHRASE:
|
||||
self.pw_strength = QLabel()
|
||||
grid.addWidget(self.pw_strength, 3, 0, 1, 2)
|
||||
self.new_pw.textChanged.connect(self.pw_changed)
|
||||
|
@ -139,7 +147,8 @@ class PasswordLayout(object):
|
|||
|
||||
def new_password(self):
|
||||
pw = unicode(self.new_pw.text())
|
||||
if pw == "":
|
||||
# Empty passphrases are fine and returned empty.
|
||||
if pw == "" and self.kind != PW_PASSPHRASE:
|
||||
pw = None
|
||||
return pw
|
||||
|
||||
|
|
|
@ -95,29 +95,12 @@ class CreateSeedLayout(SeedLayoutBase):
|
|||
|
||||
def __init__(self, seed):
|
||||
title = _("Your wallet generation seed is:")
|
||||
tooltip = '\n'.join([
|
||||
_('You may extend your seed with a passphrase.'),
|
||||
_('Note tha this is NOT your encryption password.'),
|
||||
_('If you do not know what it is, leave it empty.'),
|
||||
])
|
||||
vbox = QVBoxLayout()
|
||||
vbox.addLayout(self._seed_layout(seed=seed, title=title))
|
||||
self.passphrase_e = QLineEdit()
|
||||
self.passphrase_e.setToolTip(tooltip)
|
||||
hbox = QHBoxLayout()
|
||||
hbox.addStretch()
|
||||
label = QLabel(_('Passphrase') + ':')
|
||||
label.setToolTip(tooltip)
|
||||
hbox.addWidget(label)
|
||||
hbox.addWidget(self.passphrase_e)
|
||||
vbox.addLayout(hbox)
|
||||
msg = seed_warning_msg(seed)
|
||||
vbox.addWidget(WWLabel(msg))
|
||||
self.layout_ = vbox
|
||||
|
||||
def passphrase(self):
|
||||
return unicode(self.passphrase_e.text()).strip()
|
||||
|
||||
|
||||
class TextInputLayout(SeedLayoutBase):
|
||||
|
||||
|
@ -136,30 +119,19 @@ class TextInputLayout(SeedLayoutBase):
|
|||
|
||||
class SeedInputLayout(SeedLayoutBase):
|
||||
|
||||
def __init__(self, parent, title, is_seed, is_passphrase):
|
||||
def __init__(self, parent, title, is_seed):
|
||||
vbox = QVBoxLayout()
|
||||
vbox.addLayout(self._seed_layout(title=title))
|
||||
self.passphrase_e = QLineEdit()
|
||||
hbox = QHBoxLayout()
|
||||
hbox.addStretch()
|
||||
hbox.addWidget(QLabel(_('Passphrase') + ':'))
|
||||
hbox.addWidget(self.passphrase_e)
|
||||
vbox.addLayout(hbox)
|
||||
self.layout_ = vbox
|
||||
self.parent = parent
|
||||
self.is_seed = is_seed
|
||||
self.is_passphrase = is_passphrase
|
||||
self.seed_e.textChanged.connect(self.on_edit)
|
||||
self.passphrase_e.textChanged.connect(self.on_edit)
|
||||
|
||||
def get_passphrase(self):
|
||||
return unicode(self.passphrase_e.text()).strip()
|
||||
|
||||
def get_seed(self):
|
||||
return clean_text(self.seed_edit())
|
||||
|
||||
def on_edit(self):
|
||||
self.parent.next_button.setEnabled(self.is_seed(self.get_seed()) and self.is_passphrase(self.get_passphrase()))
|
||||
self.parent.next_button.setEnabled(self.is_seed(self.get_seed()))
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -207,8 +207,21 @@ class BaseWizard(object):
|
|||
self.plugin = self.plugins.get_plugin(name)
|
||||
self.plugin.setup_device(device_info, self)
|
||||
print device_info
|
||||
f = lambda x: self.run('on_hardware_account_id', name, device_info, x)
|
||||
self.account_id_dialog(run_next=f)
|
||||
f = lambda x: self.run('on_hardware_account_id', name, device_info, int(x))
|
||||
self.account_id_dialog(f)
|
||||
|
||||
def account_id_dialog(self, f):
|
||||
message = '\n'.join([
|
||||
_('Enter your BIP44 account number here.'),
|
||||
_('If you are not sure what this is, leave this field to zero.')
|
||||
])
|
||||
def is_int(x):
|
||||
try:
|
||||
int(x)
|
||||
return True
|
||||
except:
|
||||
return False
|
||||
self.line_dialog(run_next=f, title=_('Account Number'), message=message, default='0', test=is_int)
|
||||
|
||||
def on_hardware_account_id(self, name, device_info, account_id):
|
||||
from keystore import hardware_keystore, bip44_derivation
|
||||
|
@ -230,21 +243,29 @@ class BaseWizard(object):
|
|||
def restore_from_seed(self):
|
||||
self.opt_bip39 = True
|
||||
self.opt_ext = True
|
||||
self.restore_seed_dialog(run_next=self.on_seed, is_seed=keystore.is_seed)
|
||||
self.restore_seed_dialog(run_next=self.on_restore_seed, test=keystore.is_seed)
|
||||
|
||||
def on_seed(self, seed, passphrase, is_bip39):
|
||||
self.is_bip39 = is_bip39
|
||||
if self.is_kivy:
|
||||
f = lambda x: self.run('create_keystore', seed, x)
|
||||
self.passphrase_dialog(run_next=f)
|
||||
def on_restore_seed(self, seed, is_bip39):
|
||||
if keystore.is_new_seed(seed) or is_bip39:
|
||||
message = '\n'.join([
|
||||
_('You may have extended your seed with a passphrase.'),
|
||||
_('If that is the case, enter it here.'),
|
||||
_('Note that this is NOT your encryption password.'),
|
||||
_('If you do not know what this is, leave this field empty.'),
|
||||
])
|
||||
f = lambda x: self.on_restore_passphrase(seed, x, is_bip39)
|
||||
self.line_dialog(title=_('Passphrase'), message=message, default='', test=lambda x:True, run_next=f)
|
||||
else:
|
||||
self.on_restore_passphrase(seed, '', False)
|
||||
|
||||
def on_restore_passphrase(self, seed, passphrase, is_bip39):
|
||||
if is_bip39:
|
||||
f = lambda x: self.run('on_bip44', seed, passphrase, int(x))
|
||||
self.account_id_dialog(f)
|
||||
else:
|
||||
self.run('create_keystore', seed, passphrase)
|
||||
|
||||
def create_keystore(self, seed, passphrase):
|
||||
if self.is_bip39:
|
||||
f = lambda account_id: self.run('on_bip44', seed, passphrase, account_id)
|
||||
self.account_id_dialog(run_next=f)
|
||||
else:
|
||||
k = keystore.from_seed(seed, passphrase)
|
||||
self.on_keystore(k)
|
||||
|
||||
|
@ -309,10 +330,33 @@ class BaseWizard(object):
|
|||
seed = Mnemonic('en').make_seed()
|
||||
self.opt_bip39 = False
|
||||
self.opt_ext = True
|
||||
self.show_seed_dialog(run_next=self.confirm_seed, seed_text=seed)
|
||||
self.show_seed_dialog(run_next=self.request_passphrase, seed_text=seed)
|
||||
|
||||
def request_passphrase(self, seed):
|
||||
title = _('Passphrase')
|
||||
message = '\n'.join([
|
||||
_('You may extend your seed with a passphrase.'),
|
||||
_('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, default='', test=lambda x:True)
|
||||
|
||||
def confirm_seed(self, seed, passphrase):
|
||||
self.confirm_seed_dialog(run_next=self.on_seed, is_seed = lambda x: x==seed, is_passphrase=lambda x: x==passphrase)
|
||||
f = lambda x: self.confirm_passphrase(seed, passphrase)
|
||||
self.confirm_seed_dialog(run_next=f, test=lambda x: x==seed)
|
||||
|
||||
def confirm_passphrase(self, seed, passphrase):
|
||||
if passphrase:
|
||||
title = _('Confirm Passphrase')
|
||||
message = '\n'.join([
|
||||
_('Your passphrase must be saved with your seed.'),
|
||||
_('Please type it here.'),
|
||||
])
|
||||
f = lambda x: self.create_keystore(seed, x)
|
||||
self.line_dialog(run_next=f, title=title, message=message, default='', test=lambda x: x==passphrase)
|
||||
else:
|
||||
self.create_keystore(seed, '')
|
||||
|
||||
def create_addresses(self):
|
||||
def task():
|
||||
|
|
Loading…
Reference in New Issue