mk4=Q rest fixed (sim tests)

This commit is contained in:
scgbckbone 2024-04-08 20:27:49 +02:00 committed by doc-hex
parent 964c8b77ab
commit a3f1f7f5de
14 changed files with 69 additions and 56 deletions

View File

@ -86,11 +86,11 @@ class LoginUX:
callgate.fast_wipe(False)
# NOT REACHED
if ch in KEY_DELETE+KEY_LEFT:
if has_qwerty and ch in KEY_DELETE+KEY_LEFT:
if self.pin:
self.pin = self.pin[:-1]
self.show_pin()
elif has_qwerty and self.pin_prefix:
elif self.pin_prefix:
# trying to delete past start of second half, take them
# to first part again. Q only
ux_show_phish_words(dis, None)
@ -277,7 +277,6 @@ suffix break point is correct.\n\n'''
if story:
# give them background
ch = await ux_show_story(story, title=title)
if ch == 'x': return None
# first first one

View File

@ -369,14 +369,14 @@ class PasswordContent(NoteContentBase):
# Edit, also used for add new
title = await ux_input_text(self.title, max_len=ONE_LINE, confirm_exit=False,
prompt='Title', placeholder='(required for menu)')
prompt='Title', placeholder='(required for menu)')
if not title:
return None
# blank is OK for all other values
user = await ux_input_text(self.user, max_len=ONE_LINE, scan_ok=True, confirm_exit=False,
prompt='Username', placeholder='(optional)')
prompt='Username', placeholder='(optional)')
if user is None:
user = self.user
@ -385,12 +385,12 @@ class PasswordContent(NoteContentBase):
self.password = await get_a_password(self.password)
site = await ux_input_text(self.site, max_len=ONE_LINE, scan_ok=True, confirm_exit=False,
prompt='Website', placeholder='(optional)')
prompt='Website', placeholder='(optional)')
if site is None:
site = self.site
misc = await ux_input_text(self.misc, max_len=None, scan_ok=True, confirm_exit=False,
prompt='More Notes', placeholder='(optional)')
prompt='More Notes', placeholder='(optional)')
if misc is None:
misc = self.misc
@ -459,13 +459,13 @@ class NoteContent(NoteContentBase):
# Edit, also used for add new
title = await ux_input_text(self.title, confirm_exit=False, max_len=CHARS_W-2,
prompt='Title', placeholder='(required for menu)')
prompt='Title', placeholder='(required for menu)')
if not title:
return
misc = await ux_input_text(self.misc, confirm_exit=False,
max_len=None, scan_ok=True,
prompt='Your Notes', placeholder='(freeform text)')
max_len=None, scan_ok=True,
prompt='Your Notes', placeholder='(freeform text)')
if misc is None:
misc = self.misc

View File

@ -349,12 +349,12 @@ async def add_dice_rolls(count, seed, judge_them, nwords=None, enforce=False):
# this is slow enough to see
md.update(ch)
elif ch == KEY_CANCEL:
elif ch in KEY_CANCEL+"x":
# Because the change (roll) has already been applied,
# only let them abort if it's early still
if count < 10 and judge_them:
return 0, seed
elif ch == KEY_ENTER:
elif ch in KEY_ENTER+"y":
if count < threshold and judge_them:
if not count:
return 0, seed
@ -1126,7 +1126,7 @@ OK to continue or press (2) to hide this message forever.
if version.has_qwerty and not PassphraseSaver.has_file():
# no need for any menus if Q and no card present
pp = await ux_input_text('', prompt="Your BIP-39 Passphrase",
b39_complete=True, scan_ok=True, max_len=100)
b39_complete=True, scan_ok=True, max_len=100)
if not pp: return
await apply_pass_value(pp)

View File

@ -88,7 +88,8 @@ async def import_tapsigner_backup_file(_1, _2, item):
while True:
backup_key = await ux_input_text("", confirm_exit=False, hex_only=True,
min_len=32, max_len=32, prompt='Backup Password (32 hex digits)')
min_len=32, max_len=32,
prompt='Backup Password (32 hex digits)')
if backup_key is None:
return

View File

@ -347,10 +347,10 @@ def _import_prompt_builder(title, no_qr, no_nfc, slot_b_only=False):
from version import has_qwerty, num_sd_slots, has_qr
from glob import NFC, VD
prompt, escape = None, KEY_CANCEL
prompt, escape = None, KEY_CANCEL+"x"
if (NFC or VD) or num_sd_slots>1:
if slot_b_only:
if slot_b_only and (num_sd_slots>1):
prompt = "Press (B) to import %s from lower slot SD Card" % title
escape += "b"
else:

View File

@ -287,7 +287,10 @@ async def ux_input_text(pw, confirm_exit=True, hex_only=False, max_len=100, min_
ch = await press.wait()
if ch == 'y':
if len(pw) < min_len:
# enforce a minimum length, better: say so.
ch = await ux_show_story('Need %d characters at least. Press OK '
'to continue X to exit.' % min_len, escape="xy",
strict_escape=True)
if ch == "x": return
continue
return str(pw, 'ascii')
elif ch == 'x':

View File

@ -135,7 +135,6 @@ async def xor_all_done(new_words):
num_parts = len(import_xor_parts)
enc_parts = [bip39.a2b_words(w) for w in import_xor_parts]
seed = xor(*enc_parts)
num_parts = len(import_xor_parts)
msg = "You've entered %d parts so far.\n\n" % num_parts
if num_parts >= 2:
@ -151,7 +150,6 @@ async def xor_all_done(new_words):
msg += "Press (1) to enter next list of words, or (2) if done with all words."
ch = await ux_show_story(msg, strict_escape=True, escape='12x'+KEY_CANCEL, sensitive=True)
if ch == 'x':
# give up
import_xor_parts.clear() # concern: we are contaminated w/ secrets
@ -164,7 +162,7 @@ async def xor_all_done(new_words):
await seed_word_entry("Part %s Words" % chr(65+len(import_xor_parts)),
target_words, done_cb=xor_all_done)
else:
nxt = XORWordNestMenu(num_words=target_words)
nxt = XORWordNestMenu(num_words=target_words, done_cb=xor_all_done)
the_ux.push(nxt)
elif ch == '2':

View File

@ -127,7 +127,7 @@ def sim_card_ejected(sim_exec, is_simulator):
return
# see unix/frozen-modules/pyb.py class SDCard
cmd = f'import pyb; pyb.SDCard.ejected={ejected}; RV.write("ok")'
cmd = f'import files; files.CardSlot.sd_detect = lambda: int({ejected}); RV.write("ok")'
assert sim_exec(cmd) == 'ok'
yield doit
@ -601,7 +601,7 @@ def cap_screen_qr(cap_image):
def get_pp_sofar(sim_exec):
# get entry value for bip39 passphrase
def doit():
resp = sim_exec('import seed; RV.write(seed.pp_sofar)')
resp = sim_exec('import seed; RV.write(seed.PassphraseMenu.pp_sofar)')
assert 'Error' not in resp
return resp
@ -675,7 +675,7 @@ def press_right(need_keypress, has_qwerty):
return doit
@pytest.fixture
def goto_home(cap_menu, press_cancel, press_select, pick_menu_item, has_qwerty, cap_screen):
def goto_home(cap_menu, press_cancel, press_select, pick_menu_item, cap_screen):
def doit():
# get to top, force a redraw
@ -685,18 +685,19 @@ def goto_home(cap_menu, press_cancel, press_select, pick_menu_item, has_qwerty,
m = cap_menu()
if 'CANCEL' in m:
# special case to get out of passphrase menu
pick_menu_item('CANCEL')
time.sleep(.01)
if "Are you SURE ?" in cap_screen():
press_select()
chk = cap_screen()
if m[0] not in chk:
# menu vs. screen wrong ... happens if looking at a story, not a menu
press_cancel()
continue
if 'CANCEL' in m:
# special case to get out of passphrase menu
pick_menu_item('CANCEL')
time.sleep(.01)
press_select()
if m[0] in { 'New Seed Words', 'Ready To Sign'}:
break
if len(m) > 1 and (m[1] == "Ready To Sign") and (m[0][0] == "["):

View File

@ -6,7 +6,7 @@ import stash, chains
from pincodes import pa
from glob import settings
import stash
from seed import set_seed_value
from seed import set_seed_value, PassphraseMenu
from utils import xfp2str
from actions import goto_top_menu
from nvstore import SettingsObject
@ -19,6 +19,7 @@ settings.current = sim_defaults
import main
pa.tmp_value = None
PassphraseMenu.pp_sofar = ''
SettingsObject.master_sv_data = {}
SettingsObject.master_nvram_key = None
set_seed_value(main.WORDS)

View File

@ -104,7 +104,7 @@ def my_enter_pin(cap_screen, need_keypress, is_q1, press_right, press_select):
scr = cap_screen().split('\n')
assert scr[-1] == 'Enter rest of PIN'
press_select()
press_select()
time.sleep(0.1)
return title, words
@ -115,7 +115,7 @@ def my_enter_pin(cap_screen, need_keypress, is_q1, press_right, press_select):
@pytest.fixture
def change_pin(cap_screen, cap_story, cap_menu, press_select, my_enter_pin, press_cancel):
def doit(old_pin, new_pin, hdr_text, expect_fail=None):
# use standard menus and UX to change a PIN
# use standard menus and UX to change a PIN
title, story = cap_story()
assert title == hdr_text
assert "changing the main PIN used to unlock your Coldcard" in story

View File

@ -608,7 +608,7 @@ def test_ephemeral_seed_import_tapsigner(way, testnet, pick_menu_item, cap_story
def test_ephemeral_seed_import_tapsigner_fail(pick_menu_item, cap_story, fail, cap_screen,
need_keypress, reset_seed_words, enter_hex,
tapsigner_encrypted_backup, goto_eph_seed_menu,
microsd_path, ephemeral_seed_disabled, is_q1,
microsd_path, ephemeral_seed_disabled,
settings_set, press_select, press_cancel):
@ -648,8 +648,8 @@ def test_ephemeral_seed_import_tapsigner_fail(pick_menu_item, cap_story, fail, c
enter_hex(backup_key_hex)
time.sleep(0.3)
if fail == "key_len" and is_q1:
assert "Need 32 char" in cap_screen()
if fail == "key_len":
assert "Need 32" in cap_screen()
press_cancel()
return
@ -1043,8 +1043,9 @@ def test_seed_vault_modifications(settings_set, reset_seed_words, pick_menu_item
# first entry again
press_select()
pick_menu_item("Rename")
for _ in range(11):
for _ in range(10 if is_q1 else 9):
press_delete()
if is_q1:
do_keypresses("AA")
else:
@ -1054,7 +1055,7 @@ def test_seed_vault_modifications(settings_set, reset_seed_words, pick_menu_item
# name changed to AA
press_select()
time.sleep(.1)
m = cap_menu()
assert m[0] == "AA"
assert "Rename" in m
@ -1083,7 +1084,7 @@ def test_seed_vault_modifications(settings_set, reset_seed_words, pick_menu_item
assert "Delete" in m
pick_menu_item("Rename")
for _ in range(11):
for _ in range(10 if is_q1 else 9):
press_delete()
if is_q1:

View File

@ -71,7 +71,7 @@ def compute_policy_hash(policy):
if type_ == Deriv:
rv = []
for orig in value or []:
rv.append(orig if orig in ["any", "p2sh"] else orig.replace('p', "'").replace('h', "'"))
rv.append(orig if orig in ["any", "p2sh"] else orig.replace('p', "h").replace("'", 'h'))
elif type_ == WhitelistOpts:
rv = OrderedDict()
rv["mode"] = value.get("mode", "BASIC")
@ -165,17 +165,17 @@ def hsm_reset(dev, sim_exec):
(DICT(boot_to_hsm='123123'), 'Boot to HSM enabled'),
# msg signing
(DICT(msg_paths=["m/1'/2p/3H"]), "m/1'/2'/3'"),
(DICT(msg_paths=["m/1'/2p/3H"]), "m/1h/2h/3h"),
(DICT(msg_paths=["m/1", "m/2"]), "m/1 OR m/2"),
(DICT(msg_paths=["any"]), "(any path)"),
# data sharing
(DICT(share_addrs=["m/1'/2p/3H"]), ['Address values values will be shared', "m/1'/2'/3'"]),
(DICT(share_addrs=["m/1'/2p/3H"]), ['Address values values will be shared', "m/1h/2h/3h"]),
(DICT(share_addrs=["m/1", "m/2"]), ['Address values values will be shared', "m/1 OR m/2"]),
(DICT(share_addrs=["any"]), ['Address values values will be shared', "(any path)"]),
(DICT(share_addrs=["p2sh", "any"]), ['Address values values will be shared', "(any P2SH)", "(any path"]),
(DICT(share_xpubs=["m/1'/2p/3H"]), ['XPUB values will be shared', "m/1'/2'/3'"]),
(DICT(share_xpubs=["m/1'/2p/3H"]), ['XPUB values will be shared', "m/1h/2h/3h"]),
(DICT(share_xpubs=["m/1", "m/2"]), ['XPUB values will be shared', "m/1 OR m/2"]),
(DICT(share_xpubs=["any"]), ['XPUB values will be shared', "(any path)"]),
@ -898,7 +898,7 @@ def test_multiple_signings_multisig(cc_first, M_N, dev, quick_start_hsm,
attempt_psbt(psbt)
def test_sign_msg_good(quick_start_hsm, change_hsm, attempt_msg_sign, addr_fmt=AF_CLASSIC):
def test_sign_msg_good(quick_start_hsm, change_hsm, attempt_msg_sign):
# message signing, but only at certain derivations
permit = ['m/73', "m/*'", 'm/1p/3h/4/5/6/7' ]
block = ['m', 'm/72', permit[-1][:-2]]
@ -907,15 +907,14 @@ def test_sign_msg_good(quick_start_hsm, change_hsm, attempt_msg_sign, addr_fmt=A
policy = DICT(msg_paths=permit)
quick_start_hsm(policy)
if 1:
for addr_fmt in [ AF_CLASSIC, AF_P2WPKH, AF_P2WPKH_P2SH]:
for addr_fmt in [ AF_CLASSIC, AF_P2WPKH, AF_P2WPKH_P2SH]:
for p in permit:
p = p.replace('*', '75333')
attempt_msg_sign(None, msg, p, addr_fmt=addr_fmt)
for p in permit:
p = p.replace('*', '75333')
attempt_msg_sign(None, msg, p, addr_fmt=addr_fmt)
for p in block:
attempt_msg_sign('not enabled for that path', msg, p, addr_fmt=addr_fmt)
for p in block:
attempt_msg_sign('not enabled for that path', msg, p, addr_fmt=addr_fmt)
policy = DICT(msg_paths=['any'])
change_hsm(policy)

View File

@ -589,7 +589,7 @@ def test_ux_duress_choices(with_wipe, subchoice, expect, xflags, xargs, words12,
words = seed_story_to_words(story)
else:
ln = story.split('\n')
assert ln[0] == 'Seed words (24):'
assert ln[0] == ('Seed words (12):' if words12 else 'Seed words (24):')
words = [i[4:] for i in ln[1:25]]
seed = Mnemonic.to_seed(' '.join(words), passphrase='')
@ -699,7 +699,7 @@ from test_change_pins import change_pin, goto_pin_options, my_enter_pin
def force_main_pin(change_pin, goto_pin_options, pick_menu_item, repl):
# make main-pin match needs
def doit(want_pin, expect_fail=None):
pin_b4 = repl.eval('pa.pin').decode('ascii')
pin_b4 = repl.eval('pa.pin').decode('ascii')
if pin_b4 == want_pin:
assert not expect_fail
return

View File

@ -16,7 +16,7 @@ def test_get_secrets(get_secrets, master_xpub):
assert v['xpub'] == master_xpub
def test_home_menu(cap_menu, cap_story, cap_screen, need_keypress, reset_seed_words,
press_select, press_cancel, is_q1):
press_select, press_cancel, press_down, is_q1):
reset_seed_words()
# get to top, force a redraw
press_cancel()
@ -41,7 +41,17 @@ def test_home_menu(cap_menu, cap_story, cap_screen, need_keypress, reset_seed_wo
# check 4 lines of menu are shown right
scr = cap_screen().rstrip()
chk = '\n'.join(m)
assert scr == chk
if is_q1:
assert scr == chk
else:
# does not fit to single screen on mk4
assert scr in chk
# go down to the bottom
for i in range(6):
press_down()
scr = cap_screen().rstrip()
assert scr in chk
# pick first item, expect a story
need_keypress('0')
@ -120,7 +130,8 @@ def word_menu_entry(cap_menu, pick_menu_item, is_q1, do_keypresses, cap_screen):
assert which, "cant find: " + word
pick_menu_item(which)
if '-' not in which: break
if '-' not in which:
break
return doit
@ -615,7 +626,6 @@ def test_bip39_complex(target, goto_home, pick_menu_item, cap_story,
enter_complex(target, apply=True)
press_select()
# import pdb;pdb.set_trace()
verify_ephemeral_secret_ui(xpub=expect.hwif(), is_b39pw=True)