Improve BIP39 Passphrase UX if temporary seed active and passphrase applicable

This commit is contained in:
scgbckbone 2023-11-30 18:04:18 +01:00 committed by doc-hex
parent 9824e59ef9
commit 4359a9735b
4 changed files with 69 additions and 41 deletions

View File

@ -17,6 +17,7 @@
- Enhancement: One instant retry on SE1 comm failures
- Enhancement: Allow passphrase via USB if passphrase already set - operates on master seed.
- Enhancement: Continuation of removal of obsolete Mk2/Mk3 code-paths from master branch.
- Enhancement: Improve BIP39 Passphrase UX when temporary seed is active and applicable.
- Bugfix: Handle any failures in slot reading when loading settings
- Bugfix: Add missing First Time UX for extended key import as master seed
- Bugfix: Hide `Upgrade Firmware` menu item if temporary seed is active

View File

@ -1194,30 +1194,41 @@ class PassphraseMenu(MenuSystem):
# empty string here - noop
return
nv, xfp, parent_xfp = await calc_bip39_passphrase(pp_sofar, bypass_tmp=True)
msg = ('Above is the master key fingerprint of the new wallet. '
'Press X to abort and keep editing passphrase, '
'OK to use the new wallet, (1) to use and save to MicroSD')
msg1 = ""
nv, xfp, parent_xfp = await calc_bip39_passphrase(pp_sofar,
bypass_tmp=True)
parent_xfp_str = xfp2str(parent_xfp)
xfp_str = xfp2str(xfp)
msg0 = "master seed [%s]" % parent_xfp_str
if pa.tmp_value and settings.get("words", True):
# we have ephemeral seed but can add passphrase to it as it is word based
msg1 = (", or press (2) to add passphrase to the current "
"active temporary seed instead of the main seed.")
# we have ephemeral seed - can add passphrase to it as it is word based
t_nv, t_xfp, t_parent_xfp = await calc_bip39_passphrase(pp_sofar,
bypass_tmp=False)
t_parent_xfp_str = xfp2str(t_parent_xfp)
t_xfp_str = xfp2str(t_xfp)
choice_msg = "(1) master+pass:\n%s%s\n\n" % (parent_xfp_str, xfp_str)
choice_msg += "(2) tmp+pass:\n%s%s\n\n" % (t_parent_xfp_str, t_xfp_str)
ch = await ux_show_story(choice_msg, escape='12x', strict_escape=True,
scrollbar=False)
if ch == "x": return # exit
if ch == "2":
parent_xfp_str = t_parent_xfp_str
xfp = t_xfp
xfp_str = t_xfp_str
msg0 = "current active temporary seed [%s]" % t_parent_xfp_str
nv = t_nv
ch = await ux_show_story(msg + msg1, title="[%s]" % xfp2str(xfp), escape='12')
msg = ('Above is the master key fingerprint of the new wallet'
' created by adding passphrase to %s.'
' Press X to abort and keep editing passphrase,'
' OK to use the new wallet, (1) to use'
' and save to MicroSD') % msg0
ch = await ux_show_story(msg, title="[%s]" % xfp_str, escape='1')
if ch == 'x':
return
if ch == "2":
stash.SensitiveValues.clear_cache()
nv, xfp, parent_xfp = await calc_bip39_passphrase(pp_sofar, bypass_tmp=False)
ch = await ux_show_story(msg, title="[%s]" % xfp2str(xfp), escape='1')
if ch == "x": return
await set_ephemeral_seed(nv, summarize_ux=False, bip39pw=pp_sofar,
meta="BIP-39 Passphrase on [%s]" % xfp2str(parent_xfp))
meta="BIP-39 Passphrase on [%s]" % parent_xfp_str)
if ch == '1':
await PassphraseSaver().append(xfp, pp_sofar)

View File

@ -173,7 +173,8 @@ class PressRelease:
# (using FontSmall)
CH_PER_W = const(17)
async def ux_show_story(msg, title=None, escape=None, sensitive=False, strict_escape=False):
async def ux_show_story(msg, title=None, escape=None, sensitive=False,
strict_escape=False, scrollbar=True):
# show a big long string, and wait for XY to continue
# - returns character used to get out (X or Y)
# - can accept other chars to 'escape' as well.
@ -239,7 +240,10 @@ async def ux_show_story(msg, title=None, escape=None, sensitive=False, strict_es
y += 13
dis.scroll_bar(top / len(lines))
if scrollbar:
# help in cases when last char in a row hidden by scroll bar
dis.scroll_bar(top / len(lines))
dis.show()
# wait to do something

View File

@ -12,6 +12,7 @@ from ckcc_protocol.constants import *
import json
from mnemonic import Mnemonic
from constants import simulator_fixed_xfp, simulator_fixed_words
from helpers import xfp2str
# add the BIP39 test vectors
vectors = json.load(open('bip39-vectors.json'))['english']
@ -109,6 +110,7 @@ def set_bip39_pw(dev, need_keypress, reset_seed_words, cap_story,
else:
need_keypress("y") # do not store
time.sleep(.2)
title, story = cap_story()
assert "Above is the master key fingerprint" in story
@ -236,6 +238,8 @@ def test_bip39pass_on_ephemeral_seed(generate_ephemeral_words, import_ephemeral_
goto_eph_seed_menu()
sim_fp = xfp2str(simulator_fixed_xfp)
if stype == "words":
# words
sec = generate_ephemeral_words(24, from_main=True, seed_vault=seed_vault)
@ -258,31 +262,39 @@ def test_bip39pass_on_ephemeral_seed(generate_ephemeral_words, import_ephemeral_
enter_complex(passphrase)
pick_menu_item("APPLY")
time.sleep(.1)
title, story = cap_story()
# title is xfp = simulator fixed words + pass (as first iteration is always from main seed)
xfp0 = title[1:-1]
seed0 = Mnemonic.to_seed(simulator_fixed_words, passphrase=passphrase)
expect0 = BIP32Node.from_master_secret(seed0)
assert expect0.fingerprint().hex().upper() == xfp0
assert "press (2) to add passphrase to the current active temporary seed" in story
title, choice_story = cap_story()
tmp_seed = Mnemonic.to_seed(" ".join(sec), passphrase=passphrase)
tmp_node = BIP32Node.from_master_secret(tmp_seed)
tmp_fp = tmp_node.fingerprint().hex().upper()
master_seed = Mnemonic.to_seed(simulator_fixed_words, passphrase=passphrase)
master_node = BIP32Node.from_master_secret(master_seed)
master_fp = master_node.fingerprint().hex().upper()
choice_msg = "(1) master+pass:\n%s%s\n\n" % (sim_fp, master_fp)
choice_msg += "(2) tmp+pass:\n%s%s\n\n" % (parent_fp, tmp_fp)
assert choice_story == choice_msg
if on_eph:
need_keypress("2")
time.sleep(.5)
title, story = cap_story()
xfp1 = title[1:-1]
seed1 = Mnemonic.to_seed(" ".join(sec), passphrase=passphrase)
expect1 = BIP32Node.from_master_secret(seed1)
assert expect1.fingerprint().hex().upper() == xfp1
assert "press (2)" not in story
need_keypress("y")
else:
need_keypress("y")
need_keypress("1")
time.sleep(.2)
title, story = cap_story()
title_xfp = title[1:-1]
assert "created by adding passphrase to" in story
if on_eph:
to_check = xfp1
assert tmp_fp == title_xfp
assert f"current active temporary seed [{parent_fp}]" in story
else:
to_check = xfp0
assert master_fp == title_xfp
assert f"master seed [{sim_fp}]" in story
need_keypress("y")
time.sleep(.3)
title, story = cap_story()
@ -292,7 +304,7 @@ def test_bip39pass_on_ephemeral_seed(generate_ephemeral_words, import_ephemeral_
time.sleep(.1)
title, story = cap_story()
assert "Saved to Seed Vault" in story
assert to_check in story
assert title_xfp in story
need_keypress("y")
else:
@ -303,7 +315,7 @@ def test_bip39pass_on_ephemeral_seed(generate_ephemeral_words, import_ephemeral_
pick_menu_item("Seed Vault")
m = cap_menu()
for i in m:
if to_check in i:
if title_xfp in i:
pick_menu_item(i)
break
else:
@ -313,7 +325,7 @@ def test_bip39pass_on_ephemeral_seed(generate_ephemeral_words, import_ephemeral_
need_keypress("y")
time.sleep(.1)
_, story = cap_story()
assert to_check in story
assert title_xfp in story
if on_eph:
assert ("BIP-39 Passphrase on [%s]" % parent_fp) in story
else: