bugfix: quiz after XOR split can be canceled; UI improvements

This commit is contained in:
scgbckbone 2024-09-10 11:06:17 +02:00 committed by doc-hex
parent 8de49876b4
commit b6381fdbb5
4 changed files with 21 additions and 14 deletions

View File

@ -53,7 +53,6 @@ This lists the changes in the most recent firmware, for each hardware platform.
- Bugfix: Exporting BIP-85 derived entropy via NFC was offered even when NFC disabled,
leading to a Yikes error.
- Bugfix: Properly clear LCD screen after simple QR code is shown
- Change in default brightness (on battery) from 80% to 95%.
# Release History

View File

@ -43,10 +43,12 @@ This lists the new changes that have not yet been published in a normal release.
- New Feature: Seed XOR can be imported by scanning SeedQR parts.
- New Feature: Input backup password from QR scan.
- New Feature: (BB)QR file share of arbitrary files.
- New Feature: `Create Airgapped` now works with BBQRs
- New Feature: `Create Airgapped` now works with BBQRs.
- Change: Default brightness (on battery) adjusted from 80% to 95%.
- Bugfix: Properly clear LCD screen after BBQR is shown.
- Bugfix: Writing to empty slot B caused broken card reader.
- Bugfix: During Seed XOR import, display correct letter B if own seed already added to the mix.
- Bugfix: Stop re-wording UX stories using a regular expression.
- Bugfix: Fixed "easy exit" from quiz after split Seed XOR.

View File

@ -656,9 +656,11 @@ async def seed_word_entry(prompt, num_words, has_checksum=True, done_cb=None):
try:
got = await QRScannerInteraction.scan('Scan seed from a QR code')
what, vals = decode_qr_result(got, expect_secret=True)
except QRDecodeExplained:
redraw_words(words)
except QRDecodeExplained as e:
err_msg = str(e)
redraw_words()
continue
if what != "words":
err_msg = "Must be seed words, not %s" % what
elif num_words != len(vals[0]):

View File

@ -13,7 +13,7 @@ from glob import settings
from menu import MenuSystem, MenuItem
from actions import goto_top_menu
from utils import encode_seed_qr, pad_raw_secret
from charcodes import KEY_CANCEL, KEY_QR
from charcodes import KEY_QR
def xor(*args):
@ -107,7 +107,7 @@ Otherwise, press {ok} to continue.'''.format(n=num_parts, ok=OK), escape='2')
while 1:
ch = await show_n_parts(word_parts, chk_word)
if ch == KEY_CANCEL:
if ch == "x":
if not use_rng: return
if await ux_confirm("Stop and forget those words?"):
return
@ -124,7 +124,7 @@ Otherwise, press {ok} to continue.'''.format(n=num_parts, ok=OK), escape='2')
for ws, part in enumerate(word_parts):
ch = await word_quiz(part, title='Word %s%%d is?' % chr(65+ws))
if ch == KEY_CANCEL: break
if ch == "x": break
else:
break
@ -166,14 +166,14 @@ async def xor_all_done(data):
"right now. You may have doubled a part or made some other mistake.\n\n"
msg += "Press (1) to enter next list of words."
escape = "1"+KEY_CANCEL+KEY_QR
escape = "1"+KEY_QR
if num_parts >= 2:
msg += " Or (2) if done with all words."
escape += "2"
while True:
ch = await ux_show_story(msg, escape=escape, sensitive=True)
if ch in 'x'+KEY_CANCEL:
if ch in 'x':
# give up - needs confirmation
if import_xor_parts:
if not await ux_confirm("Throw away those words and stop this process?"):
@ -196,6 +196,8 @@ async def xor_all_done(data):
elif ch == '2':
# done; import on temp basis, or be the main secret
from pincodes import pa
from glob import dis
enc = stash.SecretStash.encode(seed_phrase=seed)
if pa.is_secret_blank():
@ -204,6 +206,7 @@ async def xor_all_done(data):
# update menu contents now that wallet defined
goto_top_menu(first_time=True)
else:
dis.fullscreen("Applying...")
# set as ephemeral seed, maybe save it too
# below is super costly as we need to bip32 generate master secret from entropy bytes
# only need XFPs for UI
@ -231,14 +234,13 @@ class XORWordNestMenu(WordNestMenu):
async def show_n_parts(parts, chk_word):
num_parts = len(parts)
seed_len = len(parts[0])
msg = 'Record these %d lists of %d-words each: ' % (num_parts, seed_len)
msg = 'Record these %d lists of %d-words each:' % (num_parts, seed_len)
for n,words in enumerate(parts):
msg += 'Part %s:\n' % chr(65+n)
msg += '\n\nPart %s:\n' % chr(65+n)
msg += ux_render_words(words, leading_blanks=0)
msg += '\n\n'
msg += ('The correctly reconstructed seed phrase will have this final word,'
msg += ('\n\nThe correctly reconstructed seed phrase will have this final word,'
' which we recommend recording:\n\n%d: %s\n\n' % (seed_len, chk_word))
msg += 'Please check and double check your notes. There will be a test! '
@ -270,6 +272,7 @@ or press (2) for 18 words XOR.''' % OK, escape="12")
import_xor_parts.clear()
from pincodes import pa
from glob import dis
escape = ""
if not pa.is_secret_blank():
@ -284,7 +287,8 @@ or press (2) for 18 words XOR.''' % OK, escape="12")
ch = await ux_show_story(msg, escape=escape)
if ch == 'x': return
elif ch == '1':
if ch == '1':
dis.fullscreen("Wait...")
with stash.SensitiveValues() as sv:
if sv.mode == 'words':
# needs copy here [:] otherwise rewritten with zeros in __exit__