remove ability to use Passphrase if passphrase already in use; remove ability to choose to which seed apply passphrase - always apply to tmp seed if active and possible
This commit is contained in:
parent
2411c7566d
commit
3eee677648
@ -1,5 +1,9 @@
|
||||
## 5.2.3 - 2024-XX-XX
|
||||
|
||||
- Change: `Passphrase` menu item is no longer offered if BIP39 passphrase
|
||||
already in use. Use `Restore Master` with ability to keep or purge current
|
||||
passphrase wallet settings.
|
||||
- Change: Removed ability to add passphrase to master seed if active temporary seed.
|
||||
- Bugfix: Saving passphrase on SD Card caused a freeze that required reboot
|
||||
- Bugfix: Properly handle and finalize framing error response
|
||||
- Bugfix: `Brick Me` option for `If Wrong` PIN caused yikes
|
||||
|
||||
@ -25,6 +25,10 @@
|
||||
|
||||
## 1.1.1Q - 2024-04-XX
|
||||
|
||||
- Change: `Passphrase` menu item is no longer offered if BIP39 passphrase
|
||||
already in use. Use `Restore Master` with ability to keep or purge current
|
||||
passphrase wallet settings.
|
||||
- Change: Removed ability to add passphrase to master seed if active temporary seed.
|
||||
- Bugfix: Handle ZeroSecretException for BIP39 passphrase calculation when on temporary
|
||||
seed without master secret.
|
||||
- Bugfix: Battery idle timeout also considers last progress bar update
|
||||
|
||||
@ -1207,35 +1207,27 @@ class NewPassphrase(UserAuthorizedAction):
|
||||
from pincodes import pa
|
||||
|
||||
title = "Passphrase"
|
||||
bypass_tmp = True
|
||||
escape = "x2" + KEY_CANCEL
|
||||
escape = "yx2" + KEY_CANCEL + KEY_ENTER
|
||||
while 1:
|
||||
msg = ('BIP-39 passphrase (%d chars long) has been provided over '
|
||||
'USB connection. Should we switch to that wallet now?\n\n')
|
||||
if pa.tmp_value and settings.get("words", True):
|
||||
escape += "1"
|
||||
msg += "Press (1) to add passphrase to currently active temporary seed. "
|
||||
'USB connection. Should we switch to that wallet now?\n\n'
|
||||
'Press OK to add passphrase ' % len(self._pw))
|
||||
if pa.tmp_value:
|
||||
msg += "to current active temporary seed. "
|
||||
else:
|
||||
msg += "to master seed. "
|
||||
|
||||
if not pa.is_secret_blank() and settings.master_get("words", True):
|
||||
escape += "y" + KEY_ENTER
|
||||
msg += "Press OK to add passphrase to master seed. "
|
||||
msg += 'Press (2) to view the provided passphrase. X to cancel.'
|
||||
|
||||
msg += ('Press (2) to view the provided passphrase.\n\n'
|
||||
'X to cancel.')
|
||||
|
||||
ch = await ux_show_story(msg=msg % len(self._pw), title=title,
|
||||
escape=escape, strict_escape=True)
|
||||
ch = await ux_show_story(msg=msg, title=title, escape=escape,
|
||||
strict_escape=True)
|
||||
if ch == '2':
|
||||
await ux_show_story('Provided:\n\n%s\n\n' % self._pw, title=title)
|
||||
continue
|
||||
else:
|
||||
if ch == '1':
|
||||
bypass_tmp = False
|
||||
|
||||
break
|
||||
else: break
|
||||
|
||||
try:
|
||||
if ch not in 'y1'+ KEY_ENTER:
|
||||
if ch not in ('y'+ KEY_ENTER):
|
||||
# they don't want to!
|
||||
self.refused = True
|
||||
await ux_dramatic_pause("Refused.", 1)
|
||||
@ -1243,9 +1235,7 @@ class NewPassphrase(UserAuthorizedAction):
|
||||
from seed import set_bip39_passphrase
|
||||
|
||||
# full screen message shown: "Working..."
|
||||
await set_bip39_passphrase(self._pw, bypass_tmp=bypass_tmp,
|
||||
summarize_ux=False)
|
||||
|
||||
await set_bip39_passphrase(self._pw, summarize_ux=False)
|
||||
self.result = settings.get('xpub')
|
||||
|
||||
except BaseException as exc:
|
||||
|
||||
@ -85,10 +85,8 @@ def se2_and_real_secret():
|
||||
from pincodes import pa
|
||||
return (not pa.is_secret_blank()) and (not pa.tmp_value)
|
||||
|
||||
def bip39_passphrase_active():
|
||||
import stash
|
||||
return settings.get('words', True) \
|
||||
or (settings.master_get('words', True) and stash.bip39_passphrase)
|
||||
def word_based_seed():
|
||||
return settings.get("words", True)
|
||||
|
||||
|
||||
HWTogglesMenu = [
|
||||
@ -243,7 +241,7 @@ DebugFunctionsMenu = [
|
||||
|
||||
SeedXORMenu = [
|
||||
# xxxxxxxxxxxxxxxx
|
||||
MenuItem("Split Existing", f=xor_split_start, predicate=lambda: settings.get('words', True)),
|
||||
MenuItem("Split Existing", f=xor_split_start, predicate=word_based_seed),
|
||||
MenuItem("Restore Seed XOR", f=xor_restore_start),
|
||||
]
|
||||
|
||||
@ -252,8 +250,7 @@ SeedFunctionsMenu = [
|
||||
MenuItem('Seed XOR', menu=SeedXORMenu),
|
||||
MenuItem("Destroy Seed", f=clear_seed, predicate=se2_and_real_secret),
|
||||
MenuItem('Lock Down Seed', f=convert_ephemeral_to_master),
|
||||
MenuItem('Export SeedQR', f=export_seedqr,
|
||||
predicate=lambda: settings.get('words', True)),
|
||||
MenuItem('Export SeedQR', f=export_seedqr, predicate=word_based_seed),
|
||||
]
|
||||
|
||||
DangerZoneMenu = [
|
||||
@ -382,7 +379,7 @@ EmptyWallet = [
|
||||
NormalSystem = [
|
||||
# xxxxxxxxxxxxxxxx
|
||||
MenuItem('Ready To Sign', f=ready2sign, shortcut='r'),
|
||||
MenuItem('Passphrase', f=start_b39_pw, predicate=bip39_passphrase_active, shortcut='p'),
|
||||
MenuItem('Passphrase', f=start_b39_pw, predicate=word_based_seed, shortcut='p'),
|
||||
MenuItem('Scan Any QR Code', predicate=lambda: version.has_qr,
|
||||
shortcut=KEY_QR, f=scan_any_qr, arg=(False, True)),
|
||||
MenuItem('Start HSM Mode', f=start_hsm_menu_item, predicate=hsm_policy_available),
|
||||
|
||||
@ -662,12 +662,7 @@ async def calc_bip39_passphrase(pw, bypass_tmp=False):
|
||||
|
||||
dis.fullscreen("Working...")
|
||||
|
||||
# get xfp of parent reliably - cannot go to settings for this if in ephemeral
|
||||
current_xfp = settings.get("xfp", 0) if not pa.tmp_value else 0
|
||||
if not current_xfp:
|
||||
with stash.SensitiveValues(bypass_tmp=bypass_tmp) as sv:
|
||||
assert sv.mode == 'words', sv.mode
|
||||
current_xfp = swab32(sv.node.my_fp())
|
||||
current_xfp = settings.get("xfp", 0)
|
||||
|
||||
with stash.SensitiveValues(bip39pw=pw, bypass_tmp=bypass_tmp) as sv:
|
||||
# can't do it without original seed words (late, but caller has checked)
|
||||
@ -1266,53 +1261,14 @@ class PassphraseMenu(MenuSystem):
|
||||
cls.pp_sofar = ''
|
||||
|
||||
async def apply_pass_value(new_pp):
|
||||
# Apply provided BIP-39 passphrase to master seed, and go to top menu.
|
||||
mdata = None
|
||||
tdata = None
|
||||
# Apply provided BIP-39 passphrase to master or current active tmp seed
|
||||
# and go to top menu.
|
||||
nv, xfp, parent_xfp = await calc_bip39_passphrase(new_pp)
|
||||
xfp_str = xfp2str(xfp)
|
||||
parent_xfp_str = xfp2str(parent_xfp)
|
||||
|
||||
try:
|
||||
m_nv, m_xfp, m_parent_xfp = await calc_bip39_passphrase(new_pp,
|
||||
bypass_tmp=True)
|
||||
m_parent_xfp_str = xfp2str(m_parent_xfp)
|
||||
m_xfp_str = xfp2str(m_xfp)
|
||||
mdata = (
|
||||
m_nv, m_xfp, m_xfp_str, m_parent_xfp_str,
|
||||
"master seed [%s]" % m_parent_xfp_str,
|
||||
"(1) master+pass:\n%s→%s\n\n" % (m_parent_xfp_str, m_xfp_str),
|
||||
)
|
||||
except (AssertionError, ZeroSecretException): pass
|
||||
|
||||
if pa.tmp_value and settings.get("words", True):
|
||||
# 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(new_pp,
|
||||
bypass_tmp=False)
|
||||
t_parent_xfp_str = xfp2str(t_parent_xfp)
|
||||
t_xfp_str = xfp2str(t_xfp)
|
||||
tdata = (
|
||||
t_nv, t_xfp, t_xfp_str, t_parent_xfp_str,
|
||||
"current active temporary seed [%s]" % t_parent_xfp_str,
|
||||
"(2) tmp+pass:\n%s→%s\n\n" % (t_parent_xfp_str, t_xfp_str),
|
||||
)
|
||||
|
||||
if tdata is None and mdata is None:
|
||||
# if master is not word based, temporary has to be, otherwise "Passphrase"
|
||||
# not offered in menu
|
||||
# should never be seen by user because flow.py::bip39_passphrase_active
|
||||
await ux_show_story(title="FAILED", msg="Need word based secret")
|
||||
return
|
||||
|
||||
tmp = False
|
||||
if tdata and mdata:
|
||||
ch = await ux_show_story(mdata[-1] + tdata[-1], escape='12x',
|
||||
strict_escape=True, scrollbar=False)
|
||||
if ch == "x": return # exit
|
||||
if ch == "2":
|
||||
tmp = True
|
||||
elif tdata:
|
||||
tmp = True
|
||||
|
||||
data = tdata if tmp else mdata
|
||||
nv, xfp, xfp_str, parent_xfp_str, msg, _ = data
|
||||
msg = "current active temporary seed [%s]" if pa.tmp_value else "master seed [%s]"
|
||||
msg = msg % parent_xfp_str
|
||||
|
||||
msg = ('Above is the master key fingerprint of the new wallet'
|
||||
' created by adding passphrase to %s.'
|
||||
|
||||
@ -552,11 +552,10 @@ class USBHandler:
|
||||
if cmd == 'pass':
|
||||
# bip39 passphrase provided, maybe use it if authorized
|
||||
assert self.encrypted_req, 'must encrypt'
|
||||
from flow import bip39_passphrase_active
|
||||
from auth import start_bip39_passphrase
|
||||
from glob import settings
|
||||
|
||||
assert bip39_passphrase_active(), 'no seed'
|
||||
assert settings.get("words", True), 'no seed'
|
||||
assert len(args) < 400, 'too long'
|
||||
pw = str(args, 'utf8')
|
||||
assert len(pw) < 100, 'too long'
|
||||
|
||||
@ -93,10 +93,11 @@ def set_bip39_pw(dev, need_keypress, reset_seed_words, cap_story,
|
||||
time.sleep(.1)
|
||||
title, body = cap_story()
|
||||
if on_tmp:
|
||||
assert "Press (1)" in body
|
||||
need_keypress("1")
|
||||
assert "to current active temporary seed" in body
|
||||
else:
|
||||
press_select()
|
||||
assert "to master seed" in body
|
||||
|
||||
press_select()
|
||||
|
||||
time.sleep(.3)
|
||||
title, story = cap_story()
|
||||
@ -232,12 +233,11 @@ def test_lockdown(stype, pick_menu_item, set_bip39_pw, goto_home, cap_story,
|
||||
|
||||
|
||||
@pytest.mark.parametrize("stype", ["words", "xprv"])
|
||||
@pytest.mark.parametrize("on_eph", [True, False])
|
||||
@pytest.mark.parametrize("seed_vault", [True, False])
|
||||
def test_bip39pass_on_ephemeral_seed(generate_ephemeral_words, import_ephemeral_xprv,
|
||||
need_keypress, pick_menu_item, goto_home,
|
||||
reset_seed_words, goto_eph_seed_menu, stype,
|
||||
enter_complex, cap_story, cap_menu, on_eph,
|
||||
enter_complex, cap_story, cap_menu,
|
||||
settings_set, seed_vault, press_select):
|
||||
passphrase = "@coinkite rulez!!"
|
||||
reset_seed_words()
|
||||
@ -246,8 +246,6 @@ 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)
|
||||
@ -268,38 +266,18 @@ def test_bip39pass_on_ephemeral_seed(generate_ephemeral_words, import_ephemeral_
|
||||
pick_menu_item("Passphrase")
|
||||
press_select()
|
||||
enter_complex(passphrase, apply=True)
|
||||
time.sleep(.1)
|
||||
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")
|
||||
else:
|
||||
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:
|
||||
assert tmp_fp == title_xfp
|
||||
assert f"current active temporary seed [{parent_fp}]" in story
|
||||
else:
|
||||
assert master_fp == title_xfp
|
||||
assert f"master seed [{sim_fp}]" in story
|
||||
assert tmp_fp == title_xfp
|
||||
assert f"current active temporary seed [{parent_fp}]" in story
|
||||
|
||||
press_select()
|
||||
|
||||
@ -333,10 +311,7 @@ def test_bip39pass_on_ephemeral_seed(generate_ephemeral_words, import_ephemeral_
|
||||
time.sleep(.1)
|
||||
_, story = cap_story()
|
||||
assert title_xfp in story
|
||||
if on_eph:
|
||||
assert ("BIP-39 Passphrase on [%s]" % parent_fp) in story
|
||||
else:
|
||||
assert "BIP-39 Passphrase on [0F056943]" in story
|
||||
assert ("BIP-39 Passphrase on [%s]" % parent_fp) in story
|
||||
|
||||
|
||||
@pytest.mark.parametrize("stype", ["words", "xprv", "b39pw"])
|
||||
@ -345,9 +320,9 @@ def test_bip39pass_on_ephemeral_seed_usb(generate_ephemeral_words, import_epheme
|
||||
reset_seed_words, goto_eph_seed_menu, stype,
|
||||
cap_story, cap_menu, set_bip39_pw,
|
||||
get_identity_story, settings_set):
|
||||
settings_set("seedvault", 0)
|
||||
passphrase = "@coinkite rulez!!"
|
||||
reset_seed_words()
|
||||
settings_set("seedvault", 0)
|
||||
|
||||
goto_eph_seed_menu()
|
||||
|
||||
@ -364,7 +339,7 @@ def test_bip39pass_on_ephemeral_seed_usb(generate_ephemeral_words, import_epheme
|
||||
import_ephemeral_xprv("sd", from_main=True, seed_vault=False)
|
||||
|
||||
goto_home()
|
||||
if stype == "xprv":
|
||||
if stype in ("xprv", "b39pw"):
|
||||
with pytest.raises(Exception) as e:
|
||||
set_bip39_pw(passphrase, reset=False)
|
||||
assert "no seed" in e.value.args[0]
|
||||
|
||||
@ -627,6 +627,8 @@ def test_bip39_complex(target, goto_home, pick_menu_item, cap_story,
|
||||
enter_complex(target, apply=True)
|
||||
press_select()
|
||||
verify_ephemeral_secret_ui(xpub=expect.hwif(), is_b39pw=True)
|
||||
pick_menu_item("Restore Master")
|
||||
press_select()
|
||||
|
||||
|
||||
@pytest.mark.qrcode
|
||||
|
||||
Loading…
Reference in New Issue
Block a user