diff --git a/shared/address_explorer.py b/shared/address_explorer.py index 5b571459..9b60140a 100644 --- a/shared/address_explorer.py +++ b/shared/address_explorer.py @@ -311,7 +311,7 @@ Press (3) if you really understand and accept these risks. # export options k0 = 'to show change addresses' if allow_change and change == 0 else None - export_msg, escape = export_prompt_builder('address summary file', + export_msg, escape = export_prompt_builder('Address summary file', no_qr=bool(ms_wallet), key0=k0) escape += KEY_PAGE_UP+KEY_PAGE_DOWN+KEY_HOME+KEY_LEFT+KEY_RIGHT diff --git a/shared/auth.py b/shared/auth.py index aac4f504..8699264e 100644 --- a/shared/auth.py +++ b/shared/auth.py @@ -19,7 +19,7 @@ from utils import B2A, parse_addr_fmt_str from psbt import psbtObject, FatalPSBTIssue, FraudulentChangeOutput from exceptions import HSMDenied from version import MAX_TXN_LEN -from charcodes import KEY_QR, KEY_NFC +from charcodes import KEY_QR, KEY_NFC, KEY_ENTER, KEY_CANCEL # Where in SPI flash/PSRAM the two PSBT files are (in and out) TXN_INPUT_OFFSET = 0 @@ -1206,7 +1206,7 @@ class NewPassphrase(UserAuthorizedAction): title = "Passphrase" bypass_tmp = True - escape = "x2" + escape = "x2" + KEY_CANCEL while 1: msg = ('BIP-39 passphrase (%d chars long) has been provided over ' 'USB connection. Should we switch to that wallet now?\n\n') @@ -1215,7 +1215,7 @@ class NewPassphrase(UserAuthorizedAction): msg += "Press (1) to add passphrase to currently active temporary seed. " if settings.master_get("words", True): - escape += "y" + escape += "y" + KEY_ENTER msg += "Press OK to add passphrase to master seed. " msg += ('Press (2) to view the provided passphrase.\n\n' @@ -1233,7 +1233,7 @@ class NewPassphrase(UserAuthorizedAction): break try: - if ch not in 'y1': + if ch not in 'y1'+ KEY_ENTER: # they don't want to! self.refused = True await ux_dramatic_pause("Refused.", 1) diff --git a/shared/ux.py b/shared/ux.py index 930e362b..17df5864 100644 --- a/shared/ux.py +++ b/shared/ux.py @@ -368,7 +368,7 @@ def _import_prompt_builder(title, no_qr, no_nfc): escape += "2" if (NFC is not None) and not no_nfc: if has_qwerty: - prompt += ", press (NFC) to import via NFC" + prompt += ", press " + KEY_NFC + " to import via NFC" escape += KEY_NFC else: prompt += ", press (3) to import via NFC" diff --git a/testing/conftest.py b/testing/conftest.py index 28b0097d..41ad447e 100644 --- a/testing/conftest.py +++ b/testing/conftest.py @@ -157,13 +157,14 @@ def need_keypress(dev, request): return doit + @pytest.fixture(scope='module') -def enter_number(need_keypress, is_q1): +def enter_number(need_keypress, press_select): def doit(number): number = str(number) if not isinstance(number, str) else number for d in number: need_keypress(d) - need_keypress(KEY_ENTER if is_q1 else 'y') + press_select() return doit @@ -183,24 +184,21 @@ def enter_hex(need_keypress, enter_text, is_q1): return doit @pytest.fixture(scope='module') -def enter_pin(enter_number, need_keypress, cap_screen, is_q1): +def enter_pin(enter_number, press_select, cap_screen, is_q1): def doit(pin): assert '-' in pin a,b = pin.split('-') enter_number(a) - need_keypress(KEY_ENTER) scr = cap_screen().split('\n') if is_q1: words = [i.strip() for i in scr[7].split()] else: # capture words? hard to know in general what they should be tho words = scr[2:4] - - need_keypress('y') + press_select() enter_number(b) - need_keypress(KEY_ENTER) return words @@ -640,18 +638,54 @@ def get_secrets(sim_execfile): return doit -@pytest.fixture +@pytest.fixture(scope='module') def press_select(need_keypress, has_qwerty): def doit(): need_keypress(KEY_ENTER if has_qwerty else 'y') return doit -@pytest.fixture +@pytest.fixture(scope='module') def press_cancel(need_keypress, has_qwerty): def doit(): need_keypress(KEY_CANCEL if has_qwerty else 'x') return doit +@pytest.fixture(scope='module') +def press_delete(need_keypress, has_qwerty): + def doit(): + need_keypress(KEY_DELETE if has_qwerty else 'x') + return doit + +@pytest.fixture(scope='module') +def press_nfc(need_keypress, has_qwerty): + def doit(num=3): + need_keypress(KEY_NFC if has_qwerty else str(num)) + return doit + +@pytest.fixture(scope='module') +def press_up(need_keypress, has_qwerty): + def doit(): + need_keypress(KEY_UP if has_qwerty else "5") + return doit + +@pytest.fixture(scope='module') +def press_down(need_keypress, has_qwerty): + def doit(): + need_keypress(KEY_DOWN if has_qwerty else "8") + return doit + +@pytest.fixture(scope='module') +def press_left(need_keypress, has_qwerty): + def doit(): + need_keypress(KEY_LEFT if has_qwerty else "7") + return doit + +@pytest.fixture(scope='module') +def press_right(need_keypress, has_qwerty): + def doit(): + need_keypress(KEY_RIGHT if has_qwerty else "9") + return doit + @pytest.fixture def goto_home(cap_menu, press_cancel, press_select, pick_menu_item, has_qwerty, cap_screen): @@ -688,7 +722,7 @@ def goto_home(cap_menu, press_cancel, press_select, pick_menu_item, has_qwerty, return doit @pytest.fixture -def pick_menu_item(cap_menu, need_keypress, has_qwerty, cap_screen): +def pick_menu_item(cap_menu, need_keypress, has_qwerty, cap_screen, press_select, press_up, press_down): WRAP_IF_OVER = 16 # see ../shared/menu.py def doit(text): @@ -706,18 +740,18 @@ def pick_menu_item(cap_menu, need_keypress, has_qwerty, cap_screen): if len(m) > WRAP_IF_OVER and m_pos > (len(m)//2): # use wrap around, work up from bottom for n in range(len(m) - m_pos): - need_keypress(KEY_UP if has_qwerty else '5') + press_up() time.sleep(.01) # required - need_keypress(KEY_ENTER if has_qwerty else 'y') + press_select() time.sleep(.01) # required else: # go down for n in range(m_pos): - need_keypress(KEY_DOWN if has_qwerty else '8') + press_down() time.sleep(.01) # required - need_keypress(KEY_ENTER if has_qwerty else 'y') + press_select() time.sleep(.01) # required return doit @@ -1568,10 +1602,10 @@ def nfc_write(request, needs_nfc, is_q1): # WRITE data into NFC "chip" def doit_usb(ccfile): sim_exec = request.getfixturevalue('sim_exec') - need_keypress = request.getfixturevalue('need_keypress') + press_select = request.getfixturevalue('press_select') rv = sim_exec('list(glob.NFC.big_write(%r))' % ccfile) if 'Traceback' in rv: raise pytest.fail(rv) - need_keypress(KEY_ENTER if is_q1 else 'y') # to end the animation and have it check value immediately + press_select() # to end the animation and have it check value immediately try: raise NotImplementedError @@ -1753,14 +1787,14 @@ def load_export_and_verify_signature(microsd_path, virtdisk_path, verify_detache @pytest.fixture def load_export(need_keypress, cap_story, microsd_path, virtdisk_path, nfc_read_text, nfc_read_json, - load_export_and_verify_signature, is_q1): + load_export_and_verify_signature, is_q1, press_cancel, press_select): def doit(way, label, is_json, sig_check=True, addr_fmt=AF_CLASSIC, ret_sig_addr=False, tail_check=None, sd_key=None, vdisk_key=None, nfc_key=None, ret_fname=False, fpattern=None): key_map = { "sd": sd_key or "1", "vdisk": vdisk_key or "2", - "nfc": nfc_key or (KEY_NFC if is_q1 else "(3)"), + "nfc": nfc_key or (KEY_NFC if is_q1 else "3"), } time.sleep(0.2) title, story = cap_story() @@ -1769,7 +1803,7 @@ def load_export(need_keypress, cap_story, microsd_path, virtdisk_path, nfc_read_ need_keypress(key_map['sd']) elif way == "nfc": - if f"{key_map['nfc']} to share via NFC" not in story: + if f"{key_map['nfc'] if is_q1 else '(3)'} to share via NFC" not in story: pytest.skip("NFC disabled") else: need_keypress(key_map['nfc']) @@ -1779,7 +1813,7 @@ def load_export(need_keypress, cap_story, microsd_path, virtdisk_path, nfc_read_ else: nfc_export = nfc_read_text() time.sleep(0.3) - need_keypress(KEY_CANCEL if is_q1 else "x") # exit NFC animation + press_cancel() # exit NFC animation return nfc_export else: # virtual disk @@ -1815,7 +1849,7 @@ def load_export(need_keypress, cap_story, microsd_path, virtdisk_path, nfc_read_ if is_json: export = json.loads(export) - need_keypress(KEY_ENTER if is_q1 else "y") + press_select() if ret_sig_addr and sig_addr: return export, sig_addr diff --git a/testing/helpers.py b/testing/helpers.py index d9fdaceb..8ce79198 100644 --- a/testing/helpers.py +++ b/testing/helpers.py @@ -253,7 +253,10 @@ def sign_msg(key, msg, addr_fmt, b64 = False): return sig def detruncate_address(s): - _idx = s.index("↳") + try: + _idx = s.index("↳") + except ValueError: + _idx = -1 if _idx != -1: s = s[_idx+1:] start, end = s.strip().split('⋯') diff --git a/testing/test_addr.py b/testing/test_addr.py index 88a49e59..de946348 100644 --- a/testing/test_addr.py +++ b/testing/test_addr.py @@ -12,11 +12,11 @@ from constants import msg_sign_unmap_addr_fmt @pytest.mark.parametrize('path', [ 'm', "m/1/2", "m/1'/100'"]) @pytest.mark.parametrize('addr_fmt', [ AF_CLASSIC, AF_P2WPKH, AF_P2WPKH_P2SH ]) -def test_show_addr_usb(dev, need_keypress, addr_vs_path, path, addr_fmt, is_simulator): +def test_show_addr_usb(dev, press_select, addr_vs_path, path, addr_fmt, is_simulator): addr = dev.send_recv(CCProtocolPacker.show_address(path, addr_fmt), timeout=None) - need_keypress('y') + press_select() if "'" in path and not is_simulator(): raise pytest.skip('we cant confirm hardened-derived keypaths') @@ -28,7 +28,9 @@ def test_show_addr_usb(dev, need_keypress, addr_vs_path, path, addr_fmt, is_simu @pytest.mark.parametrize('path', [ 'm', "m/1/2", "m/1'/100'"]) @pytest.mark.parametrize('addr_fmt', [ AF_CLASSIC, AF_P2WPKH, AF_P2WPKH_P2SH ]) @pytest.mark.parametrize('show_qr', [ False, True ]) -def test_show_addr_displayed(dev, need_keypress, addr_vs_path, path, addr_fmt, cap_story, show_qr, cap_screen_qr, qr_quality_check): +def test_show_addr_displayed(dev, need_keypress, addr_vs_path, path, addr_fmt, + cap_story, show_qr, cap_screen_qr, qr_quality_check, + press_cancel): time.sleep(0.1) addr = dev.send_recv(CCProtocolPacker.show_address(path, addr_fmt), timeout=None) @@ -36,7 +38,7 @@ def test_show_addr_displayed(dev, need_keypress, addr_vs_path, path, addr_fmt, c time.sleep(0.1) title, story = cap_story() - #need_keypress('x') + #press_cancel() # check expected addr was used addr_vs_path(addr, path, addr_fmt) @@ -56,7 +58,7 @@ def test_show_addr_displayed(dev, need_keypress, addr_vs_path, path, addr_fmt, c assert qr == addr or qr == addr.upper() @pytest.mark.bitcoind -def test_addr_vs_bitcoind(use_regtest, need_keypress, dev, bitcoind_d_sim_sign): +def test_addr_vs_bitcoind(use_regtest, press_select, dev, bitcoind_d_sim_sign): # check our p2wpkh wrapped in p2sh is right use_regtest() for i in range(5): @@ -68,7 +70,7 @@ def test_addr_vs_bitcoind(use_regtest, need_keypress, dev, bitcoind_d_sim_sign): path = resp['hdkeypath'] addr = dev.send_recv(CCProtocolPacker.show_address(path, AF_P2WPKH_P2SH), timeout=None) - need_keypress('y') + press_select() assert addr == core_addr @pytest.mark.parametrize("body_err", [ @@ -91,8 +93,9 @@ def test_show_addr_nfc_invalid(body_err, goto_home, pick_menu_item, nfc_write_te @pytest.mark.parametrize("path", ["m/84'/0'/0'/300/0", "m/800'", "m/0/0/0/0/1/1/1"]) @pytest.mark.parametrize("str_addr_fmt", ["p2pkh", "", "p2wpkh", "p2wpkh-p2sh", "p2sh-p2wpkh"]) -def test_show_addr_nfc(path, str_addr_fmt, nfc_write_text, nfc_read_text, pick_menu_item, goto_home, cap_story, - need_keypress, addr_vs_path): +def test_show_addr_nfc(path, str_addr_fmt, nfc_write_text, nfc_read_text, pick_menu_item, + goto_home, cap_story, press_nfc, addr_vs_path, press_select, is_q1, + cap_screen): # import pdb;pdb.set_trace() for _ in range(5): # need to wait for ApproveMessageSign to be popped from ux stack @@ -115,17 +118,19 @@ def test_show_addr_nfc(path, str_addr_fmt, nfc_write_text, nfc_read_text, pick_m nfc_write_text(body) time.sleep(0.5) _, story = cap_story() + split_story = story.split("\n\n") story_addr = split_story[0] story_path = split_story[1][2:] # remove "= " - assert "Press (3) to share via NFC" in story + if not is_q1: + assert "Press (3) to share via NFC" in story assert story_path == path - need_keypress("3") # share over NFC + press_nfc() # share over NFC addr = nfc_read_text() if addr == body: # missed it - again addr = nfc_read_text() - need_keypress("y") # exit NFC animation + press_select() # exit NFC animation assert story_addr == addr addr_vs_path(addr, path, addr_fmt) diff --git a/testing/test_address_explorer.py b/testing/test_address_explorer.py index 554e0fe4..428bb1e8 100644 --- a/testing/test_address_explorer.py +++ b/testing/test_address_explorer.py @@ -6,7 +6,7 @@ from pycoin.key.BIP32Node import BIP32Node from pycoin.contrib.segwit_addr import encode as sw_encode from pycoin.encoding import a2b_hashed_base58, hash160 from helpers import detruncate_address -from charcodes import KEY_QR, KEY_NFC, KEY_LEFT, KEY_RIGHT, KEY_ENTER, KEY_CANCEL +from charcodes import KEY_QR, KEY_LEFT, KEY_RIGHT @pytest.fixture def mk_common_derivations(): @@ -51,7 +51,7 @@ def parse_display_screen(cap_story, is_mark3): lines = body.split('\n') if start == 0: # no header after first page - assert 'to save address summary file' in body + assert 'to save Address summary file' in body assert 'show QR code' in body assert lines[0] == 'Addresses %d..%d:' % (start, start + n - 1) @@ -85,8 +85,9 @@ def validate_address(): return doit @pytest.fixture -def generate_addresses_file(goto_address_explorer, need_keypress, cap_story, microsd_path, is_q1, - virtdisk_path, nfc_read_text, load_export_and_verify_signature): +def generate_addresses_file(goto_address_explorer, need_keypress, cap_story, microsd_path, + virtdisk_path, nfc_read_text, load_export_and_verify_signature, + press_select, press_nfc): # Generates the address file through the simulator, reads the file and # returns a list of tuples of the form (subpath, address) def doit(expected_qty=250, way="sd", change=False): @@ -97,18 +98,18 @@ def generate_addresses_file(goto_address_explorer, need_keypress, cap_story, mic if way == "sd": need_keypress('1') elif way == "vdisk": - if "save to Virtual Disk." not in story: + if "save to Virtual Disk" not in story: raise pytest.skip("Vdisk disabled") need_keypress("2") else: # NFC if "share via NFC" not in story: raise pytest.skip("NFC disabled") - need_keypress("3" if not is_q1 else KEY_NFC) + press_nfc() time.sleep(0.3) addresses = nfc_read_text() time.sleep(0.3) - need_keypress(KEY_ENTER if is_q1 else "y") + press_select() # nfc just returns 10 addresses assert len(addresses.split("\n")) == 10 raise pytest.xfail("PASSED - different export format for NFC") @@ -135,7 +136,7 @@ def generate_addresses_file(goto_address_explorer, need_keypress, cap_story, mic def test_stub_menu(sim_execfile, goto_address_explorer, need_keypress, cap_menu, mk_common_derivations, pick_menu_item, - parse_display_screen, validate_address, is_q1): + parse_display_screen, validate_address, press_cancel): # For a given wallet, ensure the explorer shows the correct stub addresses node_prv = BIP32Node.from_wallet_key( sim_execfile('devtest/dump_private.py').strip() @@ -167,7 +168,7 @@ def test_stub_menu(sim_execfile, goto_address_explorer, need_keypress, start, end = detruncate_address(m[_id]) assert expected_addr.startswith(start) assert expected_addr.endswith(end) - need_keypress(KEY_CANCEL if is_q1 else "x") + press_cancel() @pytest.mark.parametrize("chain", ["BTC", "XRT", "XTN"]) @pytest.mark.parametrize("change", [True, False]) @@ -219,7 +220,7 @@ def test_applications_samourai(chain, change, option, goto_address_explorer, cap ]) def test_address_display(goto_address_explorer, parse_display_screen, mk_common_derivations, need_keypress, sim_execfile, validate_address, press_seq, expected_n, - expected_start, pick_menu_item, cap_menu, is_q1): + expected_start, pick_menu_item, cap_menu, is_q1, press_cancel): # The proper addresses are displayed # given the sequence of keys pressed node_prv = BIP32Node.from_wallet_key( @@ -248,7 +249,7 @@ def test_address_display(goto_address_explorer, parse_display_screen, mk_common_ sk = node_prv.subkey_for_path(subpath[2:]) validate_address(given_addr, sk) - need_keypress(KEY_CANCEL if is_q1 else "x") # back + press_cancel() # back @pytest.mark.parametrize('click_idx', ["Classic P2PKH", "P2SH-Segwit", "Segwit P2WPKH"]) @pytest.mark.parametrize("change", [True, False]) @@ -274,7 +275,8 @@ def test_dump_addresses(way, change, generate_addresses_file, mk_common_derivati def test_account_menu(way, account_num, sim_execfile, pick_menu_item, goto_address_explorer, need_keypress, cap_menu, mk_common_derivations, parse_display_screen, - validate_address, generate_addresses_file, is_q1): + validate_address, generate_addresses_file, + press_cancel, press_select): # Try a few sub-accounts node_prv = BIP32Node.from_wallet_key( sim_execfile('devtest/dump_private.py').strip() @@ -295,7 +297,7 @@ def test_account_menu(way, account_num, sim_execfile, pick_menu_item, time.sleep(0.1) for d in str(account_num): need_keypress(d) - need_keypress(KEY_ENTER if is_q1 else 'y') + press_select() time.sleep(0.1) m = cap_menu() @@ -334,8 +336,8 @@ def test_account_menu(way, account_num, sim_execfile, pick_menu_item, sk = node_prv.subkey_for_path(subpath[2:]) validate_address(addr, sk) - need_keypress(KEY_CANCEL if is_q1 else 'x') - need_keypress(KEY_CANCEL if is_q1 else 'x') + press_cancel() + press_cancel() # NOTE: (2**31)-1 = 0x7fff_ffff = 2147483647 @@ -351,7 +353,7 @@ def test_account_menu(way, account_num, sim_execfile, pick_menu_item, def test_custom_path(path, which_fmt, addr_vs_path, pick_menu_item, goto_address_explorer, need_keypress, cap_menu, parse_display_screen, validate_address, cap_story, cap_screen_qr, qr_quality_check, is_mark4plus, nfc_read_text, get_setting, - press_select, is_q1): + press_select, press_cancel, is_q1, press_nfc): is_single = '{idx}' not in path @@ -449,13 +451,13 @@ def test_custom_path(path, which_fmt, addr_vs_path, pick_menu_item, goto_address if is_mark4plus and get_setting('nfc', 0): # this is actually testing NFC export in qr code menu - need_keypress(KEY_NFC if is_q1 else '3') + press_nfc() time.sleep(.1) assert nfc_read_text() == addr - need_keypress(KEY_CANCEL if is_q1 else "x") # leave NFC animation - need_keypress(KEY_CANCEL if is_q1 else "x") # leave QR code display + press_cancel() # leave NFC animation + press_cancel() # leave QR code display # test NFC export in address explorer - need_keypress(KEY_NFC if is_q1 else '3') + press_nfc() time.sleep(.1) assert nfc_read_text() == addr diff --git a/testing/test_attended.py b/testing/test_attended.py index 5a7db8e6..9e995afd 100644 --- a/testing/test_attended.py +++ b/testing/test_attended.py @@ -22,7 +22,7 @@ def bkpw(settings_set): @pytest.mark.parametrize("last_saved", [True, False]) -def test_backup_refuse(last_saved, dev, need_keypress, bkpw): +def test_backup_refuse(last_saved, dev, press_cancel, bkpw): time.sleep(0.050) if last_saved: @@ -34,8 +34,8 @@ def test_backup_refuse(last_saved, dev, need_keypress, bkpw): assert r is None if last_saved: - need_keypress("x") - need_keypress('x') + press_cancel() + press_cancel() with pytest.raises(CCUserRefused): done = None @@ -45,7 +45,7 @@ def test_backup_refuse(last_saved, dev, need_keypress, bkpw): @pytest.mark.parametrize("last_saved", [True, False]) -def test_backup_accept(last_saved, dev, need_keypress, bkpw): +def test_backup_accept(last_saved, dev, need_keypress, press_select, bkpw): time.sleep(0.050) if last_saved: bkpw() @@ -54,7 +54,7 @@ def test_backup_accept(last_saved, dev, need_keypress, bkpw): r = dev.send_recv(CCProtocolPacker.start_backup()) assert r is None - need_keypress('y') + press_select() if last_saved: time.sleep(1) # needed done = dev.send_recv(CCProtocolPacker.get_backup_file(), timeout=5000) diff --git a/testing/test_backup.py b/testing/test_backup.py index 9bdfc3ac..c516b32e 100644 --- a/testing/test_backup.py +++ b/testing/test_backup.py @@ -1,7 +1,6 @@ import pytest, time, json, os, shutil, re -from collections import OrderedDict from constants import simulator_fixed_words, simulator_fixed_tprv -from charcodes import KEY_QR, KEY_ENTER, KEY_CANCEL +from charcodes import KEY_QR from pycoin.key.BIP32Node import BIP32Node from mnemonic import Mnemonic @@ -30,7 +29,8 @@ def decode_backup(txt): @pytest.fixture def backup_system(settings_set, settings_remove, goto_home, pick_menu_item, cap_story, need_keypress, cap_screen_qr, pass_word_quiz, - get_setting, seed_story_to_words, is_q1): + get_setting, seed_story_to_words, press_cancel, is_q1, + press_select): def doit(reuse_pw=False, save_pw=False, st=None, ct=False): # st -> seed type # ct -> cleartext backup @@ -54,27 +54,27 @@ def backup_system(settings_set, settings_remove, goto_home, pick_menu_item, assert "A temporary seed is in effect" in body assert "so backup will be of that seed" in body - need_keypress(KEY_ENTER if is_q1 else "y") + press_select() time.sleep(.1) title, body = cap_story() if ct: # cleartext backup if ' 1: zoo' in body: - need_keypress(KEY_CANCEL if is_q1 else "x") + press_cancel() need_keypress("6") time.sleep(.1) _, story = cap_story() assert "Are you SURE ?!?" in story assert "**NOT** be encrypted" in story - need_keypress("y") + press_select() return # nothing more to be done if reuse_pw: assert ' 1: zoo' in body assert '12: zoo' in body - need_keypress('y') + press_select() words = ['zoo'] * 12 time.sleep(0.1) @@ -94,7 +94,7 @@ def backup_system(settings_set, settings_remove, goto_home, pick_menu_item, need_keypress(KEY_QR if is_q1 else '1') got_qr = cap_screen_qr().decode('ascii').lower().split() assert [w[0:4] for w in words] == got_qr - need_keypress('y') + press_select() # pass the quiz! count, title, body = pass_word_quiz(words) @@ -107,7 +107,7 @@ def backup_system(settings_set, settings_remove, goto_home, pick_menu_item, assert get_setting('bkpw') == ' '.join(words) else: - need_keypress('x') + press_cancel() time.sleep(.01) assert get_setting('bkpw', 'xxx') == 'xxx' @@ -128,7 +128,8 @@ def test_make_backup(multisig, goto_home, pick_menu_item, cap_story, need_keypre cap_screen_qr, reuse_pw, save_pw, settings_set, settings_remove, generate_ephemeral_words, set_bip39_pw, verify_backup_file, check_and_decrypt_backup, restore_backup_cs, clear_ms, seedvault, - restore_main_seed, import_ephemeral_xprv, backup_system): + restore_main_seed, import_ephemeral_xprv, backup_system, + press_cancel, press_select): # Make an encrypted 7z backup, verify it, and even restore it! clear_ms() reset_seed_words() @@ -138,7 +139,7 @@ def test_make_backup(multisig, goto_home, pick_menu_item, cap_story, need_keypre # need to make multisig in my main wallet if multisig and st != "eph": import_ms_wallet(15, 15) - need_keypress('y') + press_select() time.sleep(.1) assert len(get_setting('multisig')) == 1 @@ -151,7 +152,7 @@ def test_make_backup(multisig, goto_home, pick_menu_item, cap_story, need_keypre if multisig: # make multisig in ephemeral wallet import_ms_wallet(15, 15, dev_key=True, common="605'/0'/0'") - need_keypress('y') + press_select() time.sleep(.1) assert len(get_setting('multisig')) == 1 else: @@ -193,7 +194,7 @@ def test_make_backup(multisig, goto_home, pick_menu_item, cap_story, need_keypre assert bk_a == bk_b, "contents mismatch" - need_keypress('x') + press_cancel() time.sleep(.01) verify_backup_file(fn) @@ -209,7 +210,7 @@ def test_make_backup(multisig, goto_home, pick_menu_item, cap_story, need_keypre assert "seeds" not in decrypted for i in range(10): - need_keypress('x') + press_cancel() time.sleep(.01) # test verify on device (CRC check) @@ -220,11 +221,11 @@ def test_make_backup(multisig, goto_home, pick_menu_item, cap_story, need_keypre @pytest.mark.parametrize("stype", ["words12", "words24", "xprv"]) -def test_backup_ephemeral_wallet(stype, pick_menu_item, need_keypress, goto_home, +def test_backup_ephemeral_wallet(stype, pick_menu_item, press_select, goto_home, cap_story, pass_word_quiz, get_setting, verify_backup_file, microsd_path, check_and_decrypt_backup, sim_execfile, unit_test, word_menu_entry, cap_menu, - restore_backup_cs, generate_ephemeral_words, + restore_backup_cs, generate_ephemeral_words, press_cancel, import_ephemeral_xprv, reset_seed_words, seed_story_to_words): reset_seed_words() goto_home() @@ -243,11 +244,11 @@ def test_backup_ephemeral_wallet(stype, pick_menu_item, need_keypress, goto_home title, story = cap_story() assert "A temporary seed is in effect" in story assert "so backup will be of that seed" in story - need_keypress("y") + press_select() time.sleep(.1) title, story = cap_story() if "Use same backup file password as last time?" in story: - need_keypress("x") + press_cancel() time.sleep(.1) title, story = cap_story() assert title == 'NO-TITLE' @@ -262,7 +263,7 @@ def test_backup_ephemeral_wallet(stype, pick_menu_item, need_keypress, goto_home assert count >= 4 assert "same words next time" in body assert "Press (1) to save" in body - need_keypress('x') + press_cancel() time.sleep(.01) assert get_setting('bkpw', 'xxx') == 'xxx' title, story = cap_story() @@ -308,7 +309,7 @@ def test_backup_bip39_wallet(passphrase, set_bip39_pw, pick_menu_item, need_keyp verify_backup_file, microsd_path, check_and_decrypt_backup, sim_execfile, unit_test, word_menu_entry, cap_menu, restore_backup_cs, seedvault, settings_set, reset_seed_words, - seed_story_to_words): + seed_story_to_words, press_cancel): reset_seed_words() goto_home() settings_set("seedvault", int(seedvault)) @@ -328,7 +329,7 @@ def test_backup_bip39_wallet(passphrase, set_bip39_pw, pick_menu_item, need_keyp time.sleep(.1) title, story = cap_story() if "Use same backup file password as last time?" in story: - need_keypress("x") + press_cancel() time.sleep(.1) title, story = cap_story() assert title == 'NO-TITLE' @@ -341,7 +342,7 @@ def test_backup_bip39_wallet(passphrase, set_bip39_pw, pick_menu_item, need_keyp assert count >= 4 assert "same words next time" in body assert "Press (1) to save" in body - need_keypress('x') + press_cancel() time.sleep(.01) assert get_setting('bkpw', 'xxx') == 'xxx' title, story = cap_story() @@ -374,7 +375,8 @@ def test_backup_bip39_wallet(passphrase, set_bip39_pw, pick_menu_item, need_keyp def test_trick_backups(goto_trick_menu, clear_all_tricks, repl, unit_test, - new_trick_pin, new_pin_confirmed, pick_menu_item, need_keypress): + new_trick_pin, new_pin_confirmed, pick_menu_item, + press_select): from test_se2 import TC_REBOOT, TC_BLANK_WALLET @@ -390,7 +392,7 @@ def test_trick_backups(goto_trick_menu, clear_all_tricks, repl, unit_test, new_trick_pin(pin, 'Duress Wallet', None) item = 'BIP-85 Wallet #%d' % (n % 4) if (n % 4 != 0) else 'Legacy Wallet' pick_menu_item(item) - need_keypress('y') + press_select() new_pin_confirmed(pin, item, None, None) for pin, op_mode, expect, _, xflags in [ @@ -433,7 +435,7 @@ def test_trick_backups(goto_trick_menu, clear_all_tricks, repl, unit_test, def test_seed_vault_backup(settings_set, reset_seed_words, generate_ephemeral_words, import_ephemeral_xprv, restore_main_seed, settings_get, - repl, pick_menu_item, need_keypress, cap_story, get_setting, + repl, pick_menu_item, press_cancel, cap_story, get_setting, pass_word_quiz, verify_backup_file, check_and_decrypt_backup, restore_backup_cs, cap_menu, verify_ephemeral_secret_ui, seed_story_to_words): @@ -470,7 +472,7 @@ def test_seed_vault_backup(settings_set, reset_seed_words, generate_ephemeral_wo time.sleep(.1) title, story = cap_story() if "Use same backup file password as last time?" in story: - need_keypress("x") + press_cancel() time.sleep(.1) title, story = cap_story() assert title == 'NO-TITLE' @@ -483,7 +485,7 @@ def test_seed_vault_backup(settings_set, reset_seed_words, generate_ephemeral_wo assert count >= 4 assert "same words next time" in body assert "Press (1) to save" in body - need_keypress('x') + press_cancel() time.sleep(.01) assert get_setting('bkpw', 'xxx') == 'xxx' title, story = cap_story() diff --git a/testing/test_bbqr.py b/testing/test_bbqr.py index 3951d44e..b63f6135 100644 --- a/testing/test_bbqr.py +++ b/testing/test_bbqr.py @@ -3,9 +3,9 @@ # BBQr and secure notes. # -import pytest, os, time, random -from helpers import B2A, prandom -from binascii import b2a_hex, a2b_hex +import pytest, time, random +from helpers import prandom +from binascii import a2b_hex from bbqr import split_qrs, join_qrs from charcodes import KEY_QR @@ -17,7 +17,7 @@ def THIS_FILE_requires_q1(is_q1): raise pytest.skip('Q1 only') @pytest.fixture -def readback_bbqr_ll(need_keypress, cap_screen_qr, sim_exec): +def readback_bbqr_ll(cap_screen_qr, sim_exec): # low level version def doit(): num_parts = None @@ -130,7 +130,7 @@ def render_bbqr(need_keypress, cap_screen_qr, sim_exec, readback_bbqr_ll): return doit @pytest.mark.parametrize('size', [ 1, 20, 990, 2060*2, 5000, 65537] ) -def test_show_bbqr_sizes(size, need_keypress, cap_screen_qr, sim_exec, render_bbqr): +def test_show_bbqr_sizes(size, cap_screen_qr, sim_exec, render_bbqr): # test lengths data, parts = render_bbqr(str_expr=f"'a'*{size}", msg=f'Size {size}', file_type='U') @@ -144,7 +144,7 @@ def test_show_bbqr_sizes(size, need_keypress, cap_screen_qr, sim_exec, render_bb assert ft == 'U' @pytest.mark.parametrize('src', [ 'rng', 'gpu', 'bigger'] ) -def test_show_bbqr_contents(src, need_keypress, cap_screen_qr, sim_exec, render_bbqr, load_shared_mod): +def test_show_bbqr_contents(src, cap_screen_qr, sim_exec, render_bbqr, load_shared_mod): args = dict(msg=f'Test {src}', file_type='B') if src == 'rng': @@ -171,10 +171,10 @@ def test_show_bbqr_contents(src, need_keypress, cap_screen_qr, sim_exec, render_ @pytest.mark.parametrize('max_ver', [ 20 ] ) # 20 max due to 4k USB buffer limit @pytest.mark.parametrize('encoding', '2HZ' ) @pytest.mark.parametrize('partial', [False, True]) -def test_bbqr_psbt(size, encoding, max_ver, partial, - need_keypress, scan_a_qr, readback_bbqr, - cap_screen_qr, render_bbqr, goto_home, use_regtest, decode_psbt_with_bitcoind, - decode_with_bitcoind, fake_txn, dev, cap_story, start_sign, end_sign): +def test_bbqr_psbt(size, encoding, max_ver, partial, scan_a_qr, readback_bbqr, + cap_screen_qr, render_bbqr, goto_home, use_regtest, cap_story, + decode_psbt_with_bitcoind, decode_with_bitcoind, fake_txn, dev, + start_sign, end_sign, press_cancel, press_select, need_keypress): num_in = size num_out = size*10 @@ -210,7 +210,7 @@ def test_bbqr_psbt(size, encoding, max_ver, partial, raise pytest.fail('never saw it?') # approve it - need_keypress('y') + press_select() time.sleep(.2) @@ -232,6 +232,6 @@ def test_bbqr_psbt(size, encoding, max_ver, partial, assert len(decoded['vin']) == num_in assert len(decoded['vout']) == num_out - need_keypress('x') # back to menu + press_cancel() # back to menu # EOF diff --git a/testing/test_bip39pw.py b/testing/test_bip39pw.py index ba5b548c..f8b74150 100644 --- a/testing/test_bip39pw.py +++ b/testing/test_bip39pw.py @@ -13,14 +13,13 @@ import json from mnemonic import Mnemonic from constants import simulator_fixed_xfp, simulator_fixed_words, simulator_fixed_tprv from helpers import xfp2str -from charcodes import KEY_ENTER # add the BIP39 test vectors vectors = json.load(open('bip39-vectors.json'))['english'] @pytest.mark.parametrize('vector', vectors) -def test_b9p_vectors(dev, set_seed_words, need_keypress, vector, pw='RoZert'[::-1].upper()): +def test_b9p_vectors(dev, set_seed_words, press_select, vector, pw='RoZert'[::-1].upper()): # Test all BIP-39 vectors. Slow. _, words, cooked, xprv = vector @@ -31,7 +30,7 @@ def test_b9p_vectors(dev, set_seed_words, need_keypress, vector, pw='RoZert'[::- dev.send_recv(CCProtocolPacker.bip39_passphrase(pw), timeout=None) - need_keypress('y') + press_select() xpub = None while xpub == None: @@ -55,7 +54,7 @@ def test_b9p_basic(pw, set_bip39_pw): @pytest.fixture() def set_bip39_pw(dev, need_keypress, reset_seed_words, cap_story, - sim_execfile): + sim_execfile, press_select): def doit(pw, reset=True, seed_vault=False, on_tmp=False): # reset from previous runs @@ -89,7 +88,7 @@ def set_bip39_pw(dev, need_keypress, reset_seed_words, cap_story, time.sleep(0.050) title, body = cap_story() assert pw in body - need_keypress("y") # go back + press_select() # go back time.sleep(.1) title, body = cap_story() @@ -97,7 +96,7 @@ def set_bip39_pw(dev, need_keypress, reset_seed_words, cap_story, assert "Press (1)" in body need_keypress("1") else: - need_keypress("y") + press_select() time.sleep(.3) title, story = cap_story() @@ -108,15 +107,15 @@ def set_bip39_pw(dev, need_keypress, reset_seed_words, cap_story, title, story = cap_story() assert "Saved to Seed Vault" in story - need_keypress("y") + press_select() else: - need_keypress("y") # do not store + press_select() # do not store time.sleep(.2) title, story = cap_story() assert "Above is the master key fingerprint" in story - need_keypress("y") + press_select() done = None while done is None: @@ -149,12 +148,12 @@ def test_b39_fails(dev, pw): with pytest.raises(CCProtoError): dev.send_recv(CCProtocolPacker.bip39_passphrase(pw), timeout=None) -def test_b39p_refused(dev, need_keypress, pw='testing 123'): +def test_b39p_refused(dev, press_cancel, pw='testing 123'): # user can refuse the passphrase (cancel) dev.send_recv(CCProtocolPacker.bip39_passphrase(pw), timeout=None) - need_keypress('x') + press_cancel() with pytest.raises(CCUserRefused): done = None @@ -163,17 +162,17 @@ def test_b39p_refused(dev, need_keypress, pw='testing 123'): done = dev.send_recv(CCProtocolPacker.get_passphrase_done(), timeout=None) -def test_cancel_on_empty_added_numbers(pick_menu_item, goto_home, need_keypress, - cap_menu, is_q1): +def test_cancel_on_empty_added_numbers(pick_menu_item, goto_home, press_select, + cap_menu, is_q1, press_cancel): if is_q1: # there is no Enter Number dialog on Q1 pytest.skip("'Enter Number' not available on Q1") goto_home() pick_menu_item('Passphrase') - need_keypress("y") # intro story + press_select() # intro story pick_menu_item('Add Numbers') - need_keypress("x") # do not add any numbers and cancel with x + press_cancel() # do not add any numbers and cancel with x pick_menu_item('CANCEL') time.sleep(0.1) m = cap_menu() @@ -182,9 +181,9 @@ def test_cancel_on_empty_added_numbers(pick_menu_item, goto_home, need_keypress, @pytest.mark.parametrize('stype', ["bip39pw", "words", "xprv", None]) def test_lockdown(stype, pick_menu_item, set_bip39_pw, goto_home, cap_story, - need_keypress, sim_exec, get_settings, reset_seed_words, + press_cancel, sim_exec, get_settings, reset_seed_words, get_setting, generate_ephemeral_words, import_ephemeral_xprv, - is_q1): + press_select, is_q1): # test UX and operation of the 'seed lockdown' option if stype: if stype == "bip39pw": @@ -211,13 +210,13 @@ def test_lockdown(stype, pick_menu_item, set_bip39_pw, goto_home, cap_story, assert 'Are you SURE' in where else: assert 'do not have an active temporary seed' in story - need_keypress('x') + press_cancel() return # real code does reboot, which is poorly simulated; avoid that sim_exec('import callgate; callgate.show_logout = lambda x:0') # commit change - need_keypress(KEY_ENTER if is_q1 else 'y') + press_select() time.sleep(0.25) @@ -239,7 +238,7 @@ def test_bip39pass_on_ephemeral_seed(generate_ephemeral_words, import_ephemeral_ need_keypress, pick_menu_item, goto_home, reset_seed_words, goto_eph_seed_menu, stype, enter_complex, cap_story, cap_menu, on_eph, - settings_set, seed_vault, is_q1): + settings_set, seed_vault, press_select): passphrase = "@coinkite rulez!!" reset_seed_words() settings_set("seedvault", 1) @@ -267,7 +266,7 @@ def test_bip39pass_on_ephemeral_seed(generate_ephemeral_words, import_ephemeral_ return pick_menu_item("Passphrase") - need_keypress("y") + press_select() enter_complex(passphrase) pick_menu_item("APPLY") time.sleep(.1) @@ -303,7 +302,7 @@ def test_bip39pass_on_ephemeral_seed(generate_ephemeral_words, import_ephemeral_ assert master_fp == title_xfp assert f"master seed [{sim_fp}]" in story - need_keypress(KEY_ENTER if is_q1 else "y") + press_select() time.sleep(.3) title, story = cap_story() @@ -315,9 +314,9 @@ def test_bip39pass_on_ephemeral_seed(generate_ephemeral_words, import_ephemeral_ assert "Saved to Seed Vault" in story assert title_xfp in story - need_keypress(KEY_ENTER if is_q1 else "y") + press_select() else: - need_keypress(KEY_ENTER if is_q1 else "y") # do not store + press_select() # do not store if seed_vault: # check correct meta in seed vault @@ -331,7 +330,7 @@ def test_bip39pass_on_ephemeral_seed(generate_ephemeral_words, import_ephemeral_ pytest.fail("not in menu") # choose first info item in submenu - need_keypress(KEY_ENTER if is_q1 else "y") + press_select() time.sleep(.1) _, story = cap_story() assert title_xfp in story @@ -343,7 +342,7 @@ def test_bip39pass_on_ephemeral_seed(generate_ephemeral_words, import_ephemeral_ @pytest.mark.parametrize("stype", ["words", "xprv", "b39pw"]) def test_bip39pass_on_ephemeral_seed_usb(generate_ephemeral_words, import_ephemeral_xprv, - need_keypress, pick_menu_item, goto_home, + pick_menu_item, goto_home, reset_seed_words, goto_eph_seed_menu, stype, cap_story, cap_menu, set_bip39_pw, get_identity_story, settings_set): @@ -384,7 +383,7 @@ def test_bip39pass_on_ephemeral_seed_usb(generate_ephemeral_words, import_epheme def test_tmp_on_xprv_master(generate_ephemeral_words, goto_home, cap_menu, pick_menu_item, need_keypress, enter_complex, cap_story, unit_test, microsd_path, expect_ftux, - set_bip39_pw, usb): + set_bip39_pw, usb, press_select): passphrase = "jfkdsfdks" fname = "ek.txt" fpath = microsd_path("ek.txt") @@ -399,7 +398,7 @@ def test_tmp_on_xprv_master(generate_ephemeral_words, goto_home, cap_menu, if "Press (1)" in story: need_keypress("1") - need_keypress("y") # Select file containing... + press_select() # Select file containing... pick_menu_item(fname) time.sleep(.2) expect_ftux() @@ -421,7 +420,7 @@ def test_tmp_on_xprv_master(generate_ephemeral_words, goto_home, cap_menu, return pick_menu_item("Passphrase") - need_keypress("y") + press_select() enter_complex(passphrase) pick_menu_item("APPLY") time.sleep(.1) @@ -430,11 +429,11 @@ def test_tmp_on_xprv_master(generate_ephemeral_words, goto_home, cap_menu, assert parent_fp in title # no choice story assert "current active temporary seed" in story - need_keypress("y") + press_select() time.sleep(.2) title, story = cap_story() if "Press (1)" in story: - need_keypress("y") + press_select() m = cap_menu() assert "Passphrase" not in m diff --git a/testing/test_change_pins.py b/testing/test_change_pins.py index 483ad871..e4eb6747 100644 --- a/testing/test_change_pins.py +++ b/testing/test_change_pins.py @@ -53,7 +53,7 @@ def goto_pin_options(pick_menu_item, goto_home): return doit @pytest.fixture -def my_enter_pin(cap_screen, need_keypress, is_q1): +def my_enter_pin(cap_screen, need_keypress, is_q1, press_right, press_select): def doit(pin): time.sleep(.01) # required? scr = cap_screen().split('\n') @@ -67,7 +67,7 @@ def my_enter_pin(cap_screen, need_keypress, is_q1): time.sleep(.1) # move second part - need_keypress(KEY_RIGHT) + press_right() time.sleep(.1) scr = cap_screen().split('\n') @@ -79,7 +79,7 @@ def my_enter_pin(cap_screen, need_keypress, is_q1): need_keypress(n) time.sleep(.1) - need_keypress(KEY_ENTER) + press_select() else: assert scr[2] == 'Enter PIN Prefix' @@ -91,20 +91,20 @@ def my_enter_pin(cap_screen, need_keypress, is_q1): continue if ch == '-': - need_keypress('y') + press_select() time.sleep(.1) # required scr = cap_screen().split('\n') assert ('Recognize these?' in scr) or ('Write these down:' in scr) words = scr[2:4] - need_keypress('y') + press_select() time.sleep(.1) # required scr = cap_screen().split('\n') assert scr[-1] == 'Enter rest of PIN' - need_keypress('y') + press_select() time.sleep(0.1) return title, words @@ -113,7 +113,7 @@ def my_enter_pin(cap_screen, need_keypress, is_q1): @pytest.fixture -def change_pin(cap_screen, cap_story, cap_menu, need_keypress, my_enter_pin): +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 title, story = cap_story() @@ -121,7 +121,7 @@ def change_pin(cap_screen, cap_story, cap_menu, need_keypress, my_enter_pin): assert "changing the main PIN used to unlock your Coldcard" in story assert "ABSOLUTELY NO WAY TO RECOVER A FORGOTTEN PIN!" in story assert "Write it down" in story - need_keypress('y') + press_select() time.sleep(0.01) # required assert max(len(i) for i in new_pin.split('-')) <= 6 @@ -147,7 +147,7 @@ def change_pin(cap_screen, cap_story, cap_menu, need_keypress, my_enter_pin): title, story = cap_story() assert title == 'Try Again' assert expect_fail in story - need_keypress('x') + press_cancel() return # saving/verifying can take tens of seconds. @@ -168,7 +168,7 @@ def change_pin(cap_screen, cap_story, cap_menu, need_keypress, my_enter_pin): return doit @pytest.mark.parametrize('new_pin', ['77-77', '123456-654321', '79-654321', '123456-12']) -def test_main_pin(goto_pin_options, pick_menu_item, cap_story, cap_screen, need_keypress, +def test_main_pin(goto_pin_options, pick_menu_item, cap_story, cap_screen, change_pin, new_pin, verify_pin_set, under_duress): goto_pin_options() pick_menu_item("Change Main PIN") diff --git a/testing/test_decoders.py b/testing/test_decoders.py index a2923ff2..2dc976b6 100644 --- a/testing/test_decoders.py +++ b/testing/test_decoders.py @@ -7,7 +7,7 @@ import pytest from binascii import a2b_hex, b2a_hex from base64 import b64encode from urllib.parse import urlparse, parse_qs -from helpers import prandom + from mnemonic import Mnemonic wordlist = Mnemonic('english').wordlist @@ -142,6 +142,6 @@ def test_urldecode(url, sim_exec): result = sim_exec(cmd) assert result == unquote_plus(url) - + # EOF diff --git a/testing/test_drv_entro.py b/testing/test_drv_entro.py index 63c77070..99a318f8 100644 --- a/testing/test_drv_entro.py +++ b/testing/test_drv_entro.py @@ -17,8 +17,9 @@ EXAMPLE_XPRV = '011b67969d1ec69bdfeeae43213da8460ba34b92d0788c8f7bfcfa44906e8a58 @pytest.fixture -def derive_bip85_secret(goto_home, need_keypress, pick_menu_item, cap_story, enter_text, - set_encoded_secret, set_seed_words, settings_set, seed_story_to_words, is_q1): +def derive_bip85_secret(goto_home, press_select, pick_menu_item, cap_story, enter_text, + set_encoded_secret, set_seed_words, settings_set, is_q1, + seed_story_to_words): def doit(mode, index, expect=None, entropy=None, sim_sec=None, chain="BTC"): if sim_sec: if len(sim_sec.split(" ")) in (12,18,24): @@ -41,11 +42,11 @@ def derive_bip85_secret(goto_home, need_keypress, pick_menu_item, cap_story, ent assert 'seed value' in story assert 'other wallet systems' in story - need_keypress('y') + press_select() time.sleep(0.1) title, story = cap_story() if "You have a temporary seed active - deriving from temporary" in story: - need_keypress("y") + press_select() time.sleep(0.1) pick_menu_item(mode) @@ -183,7 +184,7 @@ def activate_bip85_ephemeral(need_keypress, cap_story, sim_exec, reset_seed_word ]) def test_bip_vectors(mode, index, entropy, expect, cap_story, need_keypress, load_export_and_verify_signature, derive_bip85_secret, - activate_bip85_ephemeral): + activate_bip85_ephemeral, press_select, press_cancel): do_import, story = derive_bip85_secret(mode, index, expect, entropy, sim_sec=EXAMPLE_XPRV) @@ -196,7 +197,7 @@ def test_bip_vectors(mode, index, entropy, expect, cap_story, need_keypress, title, story = cap_story() contents,_ = load_export_and_verify_signature(story, "sd", fpattern="drv", label=None) assert contents.strip() == msg.strip() - need_keypress("y") + press_select() time.sleep(0.1) title, story = cap_story() @@ -205,7 +206,7 @@ def test_bip_vectors(mode, index, entropy, expect, cap_story, need_keypress, else: assert 'show QR code' in story - need_keypress('x') + press_cancel() @pytest.mark.qrcode @@ -221,7 +222,7 @@ def test_bip_vectors(mode, index, entropy, expect, cap_story, need_keypress, ]) @pytest.mark.parametrize('index', [0, 1, 10, 100, 1000, 9999]) def test_path_index(mode, pattern, index, need_keypress, cap_screen_qr, seed_story_to_words, - derive_bip85_secret, reset_seed_words, is_q1): + derive_bip85_secret, reset_seed_words, is_q1, press_cancel): reset_seed_words() # Uses any key on Simulator; just checking for operation + entropy level _, story = derive_bip85_secret(mode, index) @@ -256,7 +257,7 @@ def test_path_index(mode, pattern, index, need_keypress, cap_screen_qr, seed_sto if index == 0: assert 'show QR code' in story - need_keypress('4' if not is_q1 else KEY_QR) + need_keypress(KEY_QR if is_q1 else '4') qr = cap_screen_qr().decode('ascii') @@ -275,19 +276,18 @@ def test_path_index(mode, pattern, index, need_keypress, cap_screen_qr, seed_sto elif 'WIF' in mode: assert qr == got - need_keypress("x") + press_cancel() -def test_type_passwords(dev, cap_menu, pick_menu_item, - goto_home, cap_story, need_keypress, cap_screen, enter_text -): +def test_type_passwords(dev, cap_menu, pick_menu_item, goto_home, + cap_story, press_select, cap_screen, enter_text): goto_home() pick_menu_item('Settings') pick_menu_item('Keyboard EMU') _, story = cap_story() story1 = "This mode adds a top-level menu item for typing deterministically-generated passwords (BIP-85), directly into an attached USB computer (as an emulated keyboard)." assert story1 == story - need_keypress("y") + press_select() pick_menu_item('Enable') time.sleep(0.3) goto_home() @@ -308,7 +308,7 @@ def test_type_passwords(dev, cap_menu, pick_menu_item, assert path == f"m/83696968'/707764'/21'/{index}'" assert len(pwd) == 21 assert "=" not in pwd - need_keypress("y") # does nothing on simulator + press_select() # does nothing on simulator time.sleep(0.2) # exit Enter Password menu diff --git a/testing/test_ephemeral.py b/testing/test_ephemeral.py index 1fe80624..e2a2b225 100644 --- a/testing/test_ephemeral.py +++ b/testing/test_ephemeral.py @@ -11,7 +11,7 @@ from txn import fake_txn from test_ux import word_menu_entry from pycoin.key.BIP32Node import BIP32Node from helpers import xfp2str, a2b_hex -from charcodes import KEY_CLEAR, KEY_NFC, KEY_ENTER, KEY_DOWN, KEY_DELETE, KEY_SHIFT, KEY_CANCEL +from charcodes import KEY_CLEAR, KEY_NFC WORDLISTS = { @@ -33,10 +33,10 @@ SEEDVAULT_TEST_DATA = [ ] @pytest.fixture -def seed_vault_enable(cap_story, pick_menu_item, need_keypress, goto_home, - settings_set, is_q1): +def seed_vault_enable(cap_story, pick_menu_item, press_select, goto_home, + settings_set): def doit(enable=True): - confirm = KEY_ENTER if is_q1 else "y" + goto_home() pick_menu_item("Advanced/Tools") pick_menu_item("Danger Zone") @@ -44,7 +44,7 @@ def seed_vault_enable(cap_story, pick_menu_item, need_keypress, goto_home, time.sleep(.1) _, story = cap_story() if "Enable Seed Vault?" in story: - need_keypress(confirm) + press_select() if enable: pick_menu_item("Enable") @@ -53,7 +53,7 @@ def seed_vault_enable(cap_story, pick_menu_item, need_keypress, goto_home, time.sleep(.2) _, story = cap_story() if "Please remove all seeds from the vault" in story: - need_keypress(confirm) + press_select() settings_set("seeds", []) pick_menu_item("Seed Vault") time.sleep(.1) @@ -90,9 +90,9 @@ def ephemeral_seed_disabled_ui(cap_menu): @pytest.fixture def get_seed_value_ux(goto_home, pick_menu_item, need_keypress, cap_story, - nfc_read_text, seed_story_to_words, is_q1): + nfc_read_text, seed_story_to_words, press_nfc, press_select): def doit(nfc=False): - confirm = KEY_ENTER if is_q1 else "y" + goto_home() pick_menu_item("Advanced/Tools") pick_menu_item("Danger Zone") @@ -102,18 +102,18 @@ def get_seed_value_ux(goto_home, pick_menu_item, need_keypress, cap_story, title, body = cap_story() assert ('Are you SURE' in body) or ('Are you SURE' in title) assert 'can control all funds' in body - need_keypress(confirm) # skip warning + press_select() # skip warning time.sleep(0.01) title, story = cap_story() if nfc: need_keypress("1") # show QR code time.sleep(.2) - need_keypress(KEY_NFC if is_q1 else "3") # any QR can be exported via NFC + press_nfc() # any QR can be exported via NFC time.sleep(.2) str_words = nfc_read_text() time.sleep(.5) - need_keypress(confirm) # exit NFC animation + press_select() # exit NFC animation return str_words.split(" ") # always truncated return seed_story_to_words(story) @@ -160,7 +160,7 @@ def goto_eph_seed_menu(goto_home, pick_menu_item, cap_story, need_keypress): @pytest.fixture def restore_main_seed(goto_home, pick_menu_item, cap_story, cap_menu, - need_keypress, settings_slots, is_q1): + need_keypress, settings_slots, press_select): def doit(preserve_settings=False, seed_vault=False): if seed_vault: @@ -174,7 +174,6 @@ def restore_main_seed(goto_home, pick_menu_item, cap_story, cap_menu, pick_menu_item("Restore Master") time.sleep(.1) title, story = cap_story() - ch = KEY_ENTER if is_q1 else "y" assert "Restore main wallet and its settings?" in story if seed_vault: @@ -184,10 +183,12 @@ def restore_main_seed(goto_home, pick_menu_item, cap_story, cap_menu, assert "Press OK to forget current temporary seed " in story assert "settings, or press (1) to save & keep " in story assert "those settings if same seed is later restored." in story - if preserve_settings: - ch = "1" - need_keypress(ch) + if preserve_settings and not seed_vault: + need_keypress("1") + else: + press_select() + time.sleep(.3) menu = cap_menu() @@ -204,9 +205,9 @@ def restore_main_seed(goto_home, pick_menu_item, cap_story, cap_menu, @pytest.fixture -def confirm_tmp_seed(need_keypress, cap_story, is_q1): +def confirm_tmp_seed(need_keypress, cap_story, press_select): def doit(seedvault=False, expect_xfp=None): - confirm = KEY_ENTER if is_q1 else "y" + time.sleep(0.3) title, story = cap_story() if "Press (1) to store temporary seed into Seed Vault" in story: @@ -218,9 +219,9 @@ def confirm_tmp_seed(need_keypress, cap_story, is_q1): if expect_xfp is not None: assert expect_xfp in story - need_keypress(confirm) + press_select() else: - need_keypress(confirm) # do not store + press_select() # do not store time.sleep(.2) title, story = cap_story() @@ -231,7 +232,7 @@ def confirm_tmp_seed(need_keypress, cap_story, is_q1): expect_xfp = title[1:-1] assert "New temporary master key is in effect now." in story - need_keypress(confirm) + press_select() return expect_xfp return doit @@ -239,7 +240,7 @@ def confirm_tmp_seed(need_keypress, cap_story, is_q1): @pytest.fixture def seed_vault_delete(pick_menu_item, need_keypress, cap_menu, cap_story, - goto_home, is_q1): + goto_home, press_select): def doit(xfp, wipe=True): # delete it from records goto_home() @@ -261,7 +262,7 @@ def seed_vault_delete(pick_menu_item, need_keypress, cap_menu, cap_story, assert xfp in title assert "press (1)" in story if wipe: - need_keypress(KEY_ENTER if is_q1 else "y") + press_select() else: # preserve settings - remove just from seed vaul need_keypress("1") @@ -277,9 +278,9 @@ def seed_vault_delete(pick_menu_item, need_keypress, cap_menu, cap_story, @pytest.fixture -def verify_ephemeral_secret_ui(cap_story, need_keypress, cap_menu, dev, fake_txn, +def verify_ephemeral_secret_ui(cap_story, press_select, cap_menu, dev, fake_txn, get_identity_story, try_sign, get_seed_value_ux, - pick_menu_item, goto_home, is_q1): + pick_menu_item, goto_home): def doit(mnemonic=None, xpub=None, expected_xfp=None, seed_vault=False, testnet=True): @@ -331,14 +332,14 @@ def verify_ephemeral_secret_ui(cap_story, need_keypress, cap_menu, dev, fake_txn assert e_master_xpub == xpub psbt = fake_txn(2, 2, master_xpub=e_master_xpub, segwit_in=True) try_sign(psbt, accept=True, finalize=True) # MUST NOT raise - need_keypress(KEY_ENTER if is_q1 else "y") + press_select() return in_effect_xfp return doit @pytest.fixture -def generate_ephemeral_words(goto_eph_seed_menu, pick_menu_item, is_q1, +def generate_ephemeral_words(goto_eph_seed_menu, pick_menu_item, press_select, need_keypress, cap_story, settings_set, seed_story_to_words, ephemeral_seed_disabled_ui, confirm_tmp_seed): def doit(num_words, dice=False, from_main=False, seed_vault=None, testnet=True): @@ -372,7 +373,7 @@ def generate_ephemeral_words(goto_eph_seed_menu, pick_menu_item, is_q1, assert len(e_seed_words) == num_words need_keypress("6") # skip quiz - need_keypress(KEY_ENTER if is_q1 else "y") # yes - I'm sure + press_select() # yes - I'm sure confirm_tmp_seed(seedvault=seed_vault) return e_seed_words @@ -384,7 +385,7 @@ def generate_ephemeral_words(goto_eph_seed_menu, pick_menu_item, is_q1, def import_ephemeral_xprv(microsd_path, virtdisk_path, goto_eph_seed_menu, pick_menu_item, need_keypress, cap_story, settings_set, nfc_write_text, ephemeral_seed_disabled_ui, confirm_tmp_seed, - is_q1): + press_nfc, press_select, is_q1): def doit(way, extended_key=None, testnet=True, seed_vault=False, from_main=False): from pycoin.key.BIP32Node import BIP32Node if testnet: @@ -427,10 +428,10 @@ def import_ephemeral_xprv(microsd_path, virtdisk_path, goto_eph_seed_menu, if "Press (1) to import extended private key file from SD Card" in story: need_keypress("1") elif way == "nfc": - if f"press ({'NFC' if is_q1 else '3'}) to import via NFC" not in story: + if f"press {KEY_NFC if is_q1 else '(3)'} to import via NFC" not in story: pytest.xfail("NFC disabled") else: - need_keypress(KEY_NFC if is_q1 else "3") + press_nfc() time.sleep(0.2) nfc_write_text(ek) time.sleep(0.3) @@ -445,7 +446,7 @@ def import_ephemeral_xprv(microsd_path, virtdisk_path, goto_eph_seed_menu, time.sleep(0.1) _, story = cap_story() assert "Select file containing the extended private key" in story - need_keypress(KEY_ENTER if is_q1 else "y") + press_select() pick_menu_item(fname) confirm_tmp_seed(expect_xfp=node.fingerprint().hex().upper(), @@ -543,8 +544,8 @@ def test_ephemeral_seed_import_tapsigner(way, testnet, pick_menu_item, cap_story nfc_write_text, tapsigner_encrypted_backup, seed_vault, preserve_settings, seed_vault_enable, settings_set, seed_vault_delete, restore_main_seed, confirm_tmp_seed, - is_q1): - confirm = KEY_ENTER if is_q1 else "y" + is_q1, press_select, press_nfc): + reset_seed_words() if testnet: netcode = "XTN" @@ -567,10 +568,10 @@ def test_ephemeral_seed_import_tapsigner(way, testnet, pick_menu_item, cap_story if "Press (1) to import TAPSIGNER encrypted backup file from SD Card" in story: need_keypress("1") elif way == "nfc": - if f"press ({'NFC' if is_q1 else '3'}) to import via NFC" not in story: + if f"press {KEY_NFC if is_q1 else '(3)'} to import via NFC" not in story: pytest.xfail("NFC disabled") else: - need_keypress(KEY_NFC if is_q1 else "3") + press_nfc() time.sleep(0.2) nfc_write_text(fname) time.sleep(0.3) @@ -585,14 +586,14 @@ def test_ephemeral_seed_import_tapsigner(way, testnet, pick_menu_item, cap_story time.sleep(0.1) _, story = cap_story() assert "Pick TAPSIGNER encrypted backup file" in story - need_keypress(confirm) + press_select() pick_menu_item(fname) time.sleep(0.1) _, story = cap_story() assert "your TAPSIGNER" in story assert "back of the card" in story - need_keypress(confirm) # yes I have backup key + press_select() # yes I have backup key enter_hex(backup_key_hex) confirm_tmp_seed(expect_xfp=node.fingerprint().hex().upper(), @@ -607,12 +608,13 @@ def test_ephemeral_seed_import_tapsigner(way, testnet, pick_menu_item, cap_story @pytest.mark.parametrize("fail", ["wrong_key", "key_len", "plaintext", "garbage"]) -def test_ephemeral_seed_import_tapsigner_fail(pick_menu_item, cap_story, fail, is_q1, cap_screen, +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, settings_set): - confirm = KEY_ENTER if is_q1 else "y" - cancel = KEY_CANCEL if is_q1 else "x" + microsd_path, ephemeral_seed_disabled, is_q1, + settings_set, press_select, press_cancel): + + reset_seed_words() settings_set("seedvault", None) fail_msg = "Decryption failed - wrong key?" @@ -636,13 +638,13 @@ def test_ephemeral_seed_import_tapsigner_fail(pick_menu_item, cap_story, fail, i time.sleep(0.1) _, story = cap_story() assert "Pick TAPSIGNER encrypted backup file" in story - need_keypress(confirm) + press_select() pick_menu_item(fname) time.sleep(0.1) _, story = cap_story() assert "Press OK to continue X to cancel." in story - need_keypress(confirm) # yes I have backup key + press_select() # yes I have backup key if fail == "wrong_key": backup_key_hex = os.urandom(16).hex() if fail == "key_len": @@ -654,14 +656,14 @@ def test_ephemeral_seed_import_tapsigner_fail(pick_menu_item, cap_story, fail, i if fail == "key_len" and is_q1: assert "Need 32 char" in cap_screen() - need_keypress(cancel) + press_cancel() return title, story = cap_story() assert title == "FAILURE" assert fail_msg in story - need_keypress(cancel) - need_keypress(cancel) + press_cancel() + press_cancel() @pytest.mark.parametrize("data", [ @@ -680,8 +682,8 @@ def test_ephemeral_seed_import_tapsigner_real(data, pick_menu_item, cap_story, m need_keypress, reset_seed_words, enter_hex, goto_eph_seed_menu, verify_ephemeral_secret_ui, ephemeral_seed_disabled, settings_set, - confirm_tmp_seed, restore_main_seed, is_q1): - confirm = KEY_ENTER if is_q1 else "y" + confirm_tmp_seed, restore_main_seed, press_select): + fname, backup_key_hex, pub = data fpath = microsd_path(fname) shutil.copy(f"data/{fname}", fpath) @@ -699,13 +701,13 @@ def test_ephemeral_seed_import_tapsigner_real(data, pick_menu_item, cap_story, m time.sleep(0.1) _, story = cap_story() assert "Pick TAPSIGNER encrypted backup file" in story - need_keypress(confirm) + press_select() pick_menu_item(fname) time.sleep(0.1) _, story = cap_story() assert "Press OK to continue X to cancel." in story - need_keypress(confirm) # yes I have backup key + press_select() # yes I have backup key enter_hex(backup_key_hex) confirm_tmp_seed(seedvault=False) verify_ephemeral_secret_ui(xpub=pub) @@ -739,7 +741,7 @@ def test_ephemeral_seed_import_xprv(way, testnet, reset_seed_words, @pytest.mark.parametrize("seed_vault", [True, False]) def test_activate_current_tmp_secret(reset_seed_words, goto_eph_seed_menu, ephemeral_seed_disabled, cap_story, - pick_menu_item, need_keypress, + pick_menu_item, press_select, word_menu_entry, settings_set, seed_vault, seed_vault_enable, confirm_tmp_seed, is_q1): @@ -769,17 +771,18 @@ def test_activate_current_tmp_secret(reset_seed_words, goto_eph_seed_menu, assert "Temporary master key already in use" in story assert title == "FAILED" assert in_effect_xfp == expected_xfp - need_keypress(KEY_ENTER if is_q1 else "y") + press_select() @pytest.mark.parametrize('data', SEEDVAULT_TEST_DATA) def test_seed_vault_menus(dev, data, settings_set, master_settings_get, pick_menu_item, need_keypress, cap_story, cap_menu, reset_seed_words, get_identity_story, get_seed_value_ux, fake_txn, try_sign, - sim_exec, goto_home, seed_vault_enable, is_q1, enter_text): + sim_exec, goto_home, seed_vault_enable, is_q1, enter_text, + press_select, press_cancel, press_delete): # Verify "seed vault" feature works as intended - confirm = KEY_ENTER if is_q1 else "y" - cancel = KEY_CANCEL if is_q1 else "x" + + reset_seed_words() xfp, entropy, mnemonic = data @@ -818,13 +821,13 @@ def test_seed_vault_menus(dev, data, settings_set, master_settings_get, pick_men assert ('%d words' % (6 * (vlen // 8))) in story else: assert 'xprv' in story - need_keypress(cancel) + press_cancel() # rename pick_menu_item("Rename") if not is_q1: for _ in range(len(xfp) + 1): # [xfp] - need_keypress(KEY_DELETE if is_q1 else "x") + press_delete() # below should yield AAAA need_keypress("1") @@ -832,7 +835,7 @@ def test_seed_vault_menus(dev, data, settings_set, master_settings_get, pick_men need_keypress("9") # next char need_keypress("1") # letters - need_keypress(confirm) + press_select() else: need_keypress(KEY_CLEAR) enter_text('AAAA') @@ -841,7 +844,7 @@ def test_seed_vault_menus(dev, data, settings_set, master_settings_get, pick_men assert m[0] == "AAAA" # check parent menu - must be updated too - need_keypress(cancel) + press_cancel() m = cap_menu() for item in m: if "AAAA" in item: @@ -850,13 +853,13 @@ def test_seed_vault_menus(dev, data, settings_set, master_settings_get, pick_men assert False # go back - need_keypress(confirm) + press_select() pick_menu_item("Use This Seed") time.sleep(.1) title, story = cap_story() assert xfp in title assert 'temporary master key is in effect now' in story - need_keypress(confirm) + press_select() active = get_seed_value_ux() if mnemonic: assert active == mnemonic.split() @@ -877,7 +880,7 @@ def test_seed_vault_menus(dev, data, settings_set, master_settings_get, pick_men assert e_master_xpub != simulator_fixed_tpub psbt = fake_txn(2, 2, master_xpub=e_master_xpub, segwit_in=True) try_sign(psbt, accept=True, finalize=True) # MUST NOT raise - need_keypress(confirm) + press_select() encoded = sim_exec('from pincodes import pa; RV.write(repr(pa.fetch()))') assert 'Error' not in encoded @@ -900,11 +903,11 @@ def test_seed_vault_menus(dev, data, settings_set, master_settings_get, pick_men def test_seed_vault_captures(request, dev, settings_set, settings_get, pick_menu_item, - need_keypress, cap_story, reset_seed_words, fake_txn, - generate_ephemeral_words, goto_home, get_secrets, master_settings_get, + cap_story, reset_seed_words, fake_txn, master_settings_get, + generate_ephemeral_words, goto_home, get_secrets, import_ephemeral_xprv, set_bip39_pw, restore_main_seed, restore_seed_xor, derive_bip85_secret, activate_bip85_ephemeral, - seed_vault_enable, is_q1): + seed_vault_enable, is_q1, press_select, press_down): # Capture seeds by all the different paths and verify correct values are captured. # - BIP-85 -> 12, 24 words # - BIP-85 -> xprv (BIP-32) @@ -913,7 +916,7 @@ def test_seed_vault_captures(request, dev, settings_set, settings_get, pick_menu # - Capture a BIP-39 passphrase into words # - Trick pin -> duress wallet * 4 options # Then, verify those can all co-exist and be recalled correctly. - confirm = KEY_ENTER if is_q1 else "y" + reset_seed_words() seed_vault_enable(True) @@ -976,8 +979,8 @@ def test_seed_vault_captures(request, dev, settings_set, settings_get, pick_menu xfp, encoded_sec, name, meta = obj pick_menu_item("Seed Vault") for _ in range(i): - need_keypress(KEY_DOWN if is_q1 else "8") # go down - need_keypress(confirm) + press_down() # go down + press_select() pick_menu_item('Use This Seed') time.sleep(0.1) @@ -985,7 +988,7 @@ def test_seed_vault_captures(request, dev, settings_set, settings_get, pick_menu assert 'New temporary master key' in story assert 'power down' not in story assert xfp in title - need_keypress(confirm) # confirm activation of ephemeral secret + press_select() # confirm activation of ephemeral secret assert xfp2str(settings_get('xfp')) == xfp @@ -1005,11 +1008,8 @@ def test_seed_vault_captures(request, dev, settings_set, settings_get, pick_menu def test_seed_vault_modifications(settings_set, reset_seed_words, pick_menu_item, generate_ephemeral_words, import_ephemeral_xprv, goto_home, cap_story, cap_menu, restore_main_seed, - need_keypress, seed_vault_enable, is_q1, do_keypresses): - cancel = KEY_CANCEL if is_q1 else "x" - confirm = KEY_ENTER if is_q1 else "y" - delete = KEY_DELETE if is_q1 else "x" - k_down = KEY_DOWN if is_q1 else "8" + need_keypress, seed_vault_enable, is_q1, do_keypresses, + press_select, press_cancel, press_down, press_delete): reset_seed_words() seed_vault_enable(True) settings_set("seeds", []) @@ -1036,7 +1036,7 @@ def test_seed_vault_modifications(settings_set, reset_seed_words, pick_menu_item # we are no longer in ephemral assert "Restore Master" not in m # first entry in menu - need_keypress(confirm) + press_select() m = cap_menu() assert "Rename" in m assert "Use This Seed" in m # we are in master - so this must be there @@ -1044,16 +1044,16 @@ def test_seed_vault_modifications(settings_set, reset_seed_words, pick_menu_item # delete entry 0 pick_menu_item("Delete") - need_keypress(confirm) + press_select() time.sleep(.1) m = cap_menu() assert len(m) == 3 # first entry again - need_keypress(confirm) + press_select() pick_menu_item("Rename") for _ in range(11): - need_keypress(delete) + press_delete() if is_q1: do_keypresses("AA") else: @@ -1062,7 +1062,7 @@ def test_seed_vault_modifications(settings_set, reset_seed_words, pick_menu_item need_keypress("1") # name changed to AA - need_keypress(confirm) + press_select() m = cap_menu() assert m[0] == "AA" @@ -1071,20 +1071,20 @@ def test_seed_vault_modifications(settings_set, reset_seed_words, pick_menu_item assert "Delete" in m # go back - need_keypress(KEY_CANCEL if is_q1 else "x") + press_cancel() # second item - need_keypress(k_down) - need_keypress(confirm) + press_down() + press_select() time.sleep(.1) pick_menu_item("Use This Seed") title, _ = cap_story() - need_keypress(confirm) # confirm new eph + press_select() # confirm new eph time.sleep(.1) m = cap_menu() assert m[0] == title pick_menu_item("Seed Vault") - need_keypress(k_down) - need_keypress(confirm) + press_down() + press_select() time.sleep(.1) m = cap_menu() assert "Rename" in m @@ -1093,7 +1093,7 @@ def test_seed_vault_modifications(settings_set, reset_seed_words, pick_menu_item pick_menu_item("Rename") for _ in range(11): - need_keypress(delete) + press_delete() if is_q1: do_keypresses("AAA") @@ -1104,13 +1104,13 @@ def test_seed_vault_modifications(settings_set, reset_seed_words, pick_menu_item need_keypress("9") need_keypress("1") # name changed to AAA - need_keypress(confirm) + press_select() time.sleep(.1) m = cap_menu() assert m[0] == "AAA" pick_menu_item("Delete") - need_keypress(confirm) + press_select() time.sleep(.1) m = cap_menu() # after we delete from seed vault together with its settings @@ -1121,17 +1121,17 @@ def test_seed_vault_modifications(settings_set, reset_seed_words, pick_menu_item m = cap_menu() assert len(m) == 2 - need_keypress(k_down) - need_keypress(confirm) + press_down() + press_select() pick_menu_item("Use This Seed") title, _ = cap_story() - need_keypress(confirm) # confirm new eph + press_select() # confirm new eph time.sleep(.1) m = cap_menu() assert m[0] == title pick_menu_item("Seed Vault") - need_keypress(k_down) - need_keypress(confirm) + press_down() + press_select() time.sleep(.1) m = cap_menu() assert "Rename" in m @@ -1144,7 +1144,7 @@ def test_seed_vault_modifications(settings_set, reset_seed_words, pick_menu_item m = cap_menu() assert len(m) == 3 assert "Add current tmp" in m - need_keypress(confirm) + press_select() # this is now different eph - modification not allowed time.sleep(.1) m = cap_menu() @@ -1159,8 +1159,8 @@ def test_seed_vault_modifications(settings_set, reset_seed_words, pick_menu_item def test_xfp_collision(reset_seed_words, settings_set, import_ephemeral_xprv, - cap_story, need_keypress, pick_menu_item, cap_menu, - seed_vault_enable, is_q1): + cap_story, press_cancel, pick_menu_item, cap_menu, + seed_vault_enable): node = BIP32Node.from_master_secret(os.urandom(32), netcode="XTN") xfp = node.fingerprint().hex().upper() @@ -1191,7 +1191,7 @@ def test_xfp_collision(reset_seed_words, settings_set, import_ephemeral_xprv, sm = cap_menu() assert "Seed In Use" in sm assert "Use This Seed" not in sm - need_keypress(KEY_CANCEL if is_q1 else "x") # go back + press_cancel() # go back pick_menu_item(m[0]) time.sleep(.1) sm = cap_menu() @@ -1202,8 +1202,8 @@ def test_xfp_collision(reset_seed_words, settings_set, import_ephemeral_xprv, @pytest.mark.parametrize("refuse", [False, True]) def test_add_current_active(reset_seed_words, settings_set, import_ephemeral_xprv, goto_home, pick_menu_item, cap_story, cap_menu, - need_keypress, verify_ephemeral_secret_ui, - seed_vault_enable, refuse, is_q1): + press_cancel, verify_ephemeral_secret_ui, + seed_vault_enable, refuse, press_select): ADD_MI = "Add current tmp" reset_seed_words() @@ -1233,14 +1233,14 @@ def test_add_current_active(reset_seed_words, settings_set, import_ephemeral_xpr assert xfp in title assert "Add to Seed Vault?" in story if refuse: - need_keypress(KEY_CANCEL if is_q1 else "x") + press_cancel() time.sleep(.1) m = cap_menu() assert ADD_MI in m for mi in m: assert xfp not in mi else: - need_keypress(KEY_ENTER if is_q1 else "y") + press_select() verify_ephemeral_secret_ui(xpub=node.hwif(), seed_vault=True) @@ -1248,13 +1248,13 @@ def test_add_current_active(reset_seed_words, settings_set, import_ephemeral_xpr @pytest.mark.parametrize('seedvault', [False, True]) @pytest.mark.parametrize('data', SEEDVAULT_TEST_DATA) def test_temporary_from_backup(multisig, backup_system, import_ms_wallet, get_setting, - data, need_keypress, cap_story, set_encoded_secret, - reset_seed_words, check_and_decrypt_backup, is_q1, + data, press_select, cap_story, set_encoded_secret, + reset_seed_words, check_and_decrypt_backup, goto_eph_seed_menu, pick_menu_item, word_menu_entry, verify_ephemeral_secret_ui, seedvault, settings_set, seed_vault_enable, confirm_tmp_seed, settings_path, seed_vault_delete, restore_main_seed, set_seed_words): - confirm = KEY_ENTER if is_q1 else "y" + xfp_str, encoded_str, mnemonic = data if mnemonic: set_seed_words(mnemonic) @@ -1266,7 +1266,7 @@ def test_temporary_from_backup(multisig, backup_system, import_ms_wallet, get_se if multisig: import_ms_wallet(15, 15, dev_key=True) - need_keypress(confirm) + press_select() time.sleep(.1) assert len(get_setting('multisig')) == 1 @@ -1288,7 +1288,7 @@ def test_temporary_from_backup(multisig, backup_system, import_ms_wallet, get_se time.sleep(.1) _, story = cap_story() if "Select file containing the backup" in story: - need_keypress(confirm) + press_select() time.sleep(.1) pick_menu_item(fname) @@ -1349,9 +1349,10 @@ def test_import_master_as_tmp(reset_seed_words, goto_eph_seed_menu, cap_story, ephemeral_seed_disabled, pick_menu_item, goto_home, need_keypress, word_menu_entry, settings_set, confirm_tmp_seed, cap_menu, microsd_path, - restore_main_seed, get_identity_story, is_q1): - cancel = KEY_CANCEL if is_q1 else "x" - confirm = KEY_ENTER if is_q1 else "y" + restore_main_seed, get_identity_story, press_select, + press_cancel): + + reset_seed_words() goto_eph_seed_menu() @@ -1369,7 +1370,7 @@ def test_import_master_as_tmp(reset_seed_words, goto_eph_seed_menu, cap_story, title, story = cap_story() assert "FAILED" == title assert 'Cannot use master seed as temporary.' in story - need_keypress(cancel) + press_cancel() # go to ephemeral seed and then try to create new ephemeral seed from master # when in different temporary seed whatsoever @@ -1379,7 +1380,7 @@ def test_import_master_as_tmp(reset_seed_words, goto_eph_seed_menu, cap_story, pick_menu_item("Generate Words") pick_menu_item(f"12 Words") need_keypress("6") # skip quiz - need_keypress(confirm) # yes - I'm sure + press_select() # yes - I'm sure confirm_tmp_seed(seedvault=False) goto_home() @@ -1397,7 +1398,7 @@ def test_import_master_as_tmp(reset_seed_words, goto_eph_seed_menu, cap_story, title, story = cap_story() assert "FAILED" == title assert 'Cannot use master seed as temporary.' in story - need_keypress(cancel) + press_cancel() # now import same seed but represented as master extended key # this works and does not delete master settings as encoded @@ -1412,7 +1413,7 @@ def test_import_master_as_tmp(reset_seed_words, goto_eph_seed_menu, cap_story, if "Press (1)" in story: need_keypress("1") - need_keypress(confirm) # Select file containing... + press_select() # Select file containing... pick_menu_item(fname) confirm_tmp_seed(seedvault=False) # allowed diff --git a/testing/test_export.py b/testing/test_export.py index 7a2785fc..7a9746fb 100644 --- a/testing/test_export.py +++ b/testing/test_export.py @@ -16,7 +16,7 @@ from helpers import xfp2str, slip132undo from conftest import simulator_fixed_xfp, simulator_fixed_tprv, simulator_fixed_words from ckcc_protocol.constants import AF_CLASSIC, AF_P2WPKH from pprint import pprint -from charcodes import KEY_ENTER, KEY_CANCEL, KEY_NFC +from charcodes import KEY_NFC @pytest.mark.bitcoind @@ -24,7 +24,7 @@ from charcodes import KEY_ENTER, KEY_CANCEL, KEY_NFC @pytest.mark.parametrize('way', ["sd", "vdisk", "nfc"]) def test_export_core(way, dev, use_regtest, acct_num, pick_menu_item, goto_home, cap_story, need_keypress, microsd_path, virtdisk_path, bitcoind_wallet, bitcoind_d_wallet, - enter_number, nfc_read_text, load_export, bitcoind, is_q1): + enter_number, nfc_read_text, load_export, bitcoind, press_select): # test UX and operation of the 'bitcoin core' wallet export from pycoin.contrib.segwit_addr import encode as sw_encode use_regtest() @@ -47,7 +47,7 @@ def test_export_core(way, dev, use_regtest, acct_num, pick_menu_item, goto_home, enter_number(acct_num) else: acct_num = '0' - need_keypress(KEY_ENTER if is_q1 else 'y') + press_select() export = load_export(way, label="Bitcoin Core", is_json=False, addr_fmt=AF_P2WPKH) fp = io.StringIO(export).readlines() @@ -162,8 +162,8 @@ def test_export_core(way, dev, use_regtest, acct_num, pick_menu_item, goto_home, @pytest.mark.parametrize('way', ["sd", "vdisk", "nfc"]) @pytest.mark.parametrize('testnet', [True, False]) -def test_export_wasabi(way, dev, pick_menu_item, goto_home, cap_story, need_keypress, microsd_path, - nfc_read_json, virtdisk_path, testnet, use_mainnet, load_export, is_q1): +def test_export_wasabi(way, dev, pick_menu_item, goto_home, cap_story, press_select, microsd_path, + nfc_read_json, virtdisk_path, testnet, use_mainnet, load_export): # test UX and operation of the 'wasabi wallet export' if not testnet: use_mainnet() @@ -178,7 +178,7 @@ def test_export_wasabi(way, dev, pick_menu_item, goto_home, cap_story, need_keyp title, story = cap_story() assert 'This saves a skeleton Wasabi' in story - need_keypress(KEY_ENTER if is_q1 else 'y') + press_select() obj = load_export(way, label="Wasabi wallet", is_json=True, addr_fmt=AF_P2WPKH) @@ -203,7 +203,7 @@ def test_export_wasabi(way, dev, pick_menu_item, goto_home, cap_story, need_keyp @pytest.mark.parametrize('testnet', [True, False]) def test_export_electrum(way, dev, mode, acct_num, pick_menu_item, goto_home, cap_story, need_keypress, microsd_path, nfc_read_json, virtdisk_path, use_mainnet, testnet, load_export, - is_q1): + press_select): # lightly test electrum wallet export if not testnet: use_mainnet() @@ -231,7 +231,7 @@ def test_export_electrum(way, dev, mode, acct_num, pick_menu_item, goto_home, ca for n in acct_num: need_keypress(n) - need_keypress(KEY_ENTER if is_q1 else 'y') + press_select() time.sleep(0.1) pick_menu_item(mode) @@ -275,7 +275,7 @@ def test_export_electrum(way, dev, mode, acct_num, pick_menu_item, goto_home, ca ]) def test_export_coldcard(way, dev, acct_num, app, pick_menu_item, goto_home, cap_story, need_keypress, microsd_path, nfc_read_json, virtdisk_path, addr_vs_path, enter_number, - load_export, testnet, use_mainnet, is_q1): + load_export, testnet, use_mainnet, press_select): if not testnet: use_mainnet() @@ -298,7 +298,7 @@ def test_export_coldcard(way, dev, acct_num, app, pick_menu_item, goto_home, cap enter_number(acct_num) else: acct_num = '0' - need_keypress(KEY_ENTER if is_q1 else 'y') + press_select() obj = load_export(way, label=app_f_name, is_json=True, addr_fmt=AF_CLASSIC) @@ -356,7 +356,7 @@ def test_export_coldcard(way, dev, acct_num, app, pick_menu_item, goto_home, cap @pytest.mark.parametrize('acct_num', [None, '0', '99', '123']) def test_export_unchained(way, dev, pick_menu_item, goto_home, cap_story, need_keypress, acct_num, microsd_path, nfc_read_json, virtdisk_path, testnet, enter_number, - load_export, settings_set, use_mainnet, is_q1): + load_export, settings_set, use_mainnet, press_select): # test UX and operation of the 'unchained export' if not testnet: use_mainnet() @@ -378,7 +378,7 @@ def test_export_unchained(way, dev, pick_menu_item, goto_home, cap_story, need_k enter_number(acct_num) else: acct_num = '0' - need_keypress(KEY_ENTER if is_q1 else 'y') + press_select() obj = load_export(way, label="Unchained", is_json=True, sig_check=False) @@ -405,9 +405,9 @@ def test_export_unchained(way, dev, pick_menu_item, goto_home, cap_story, need_k @pytest.mark.parametrize('way', ["sd", "vdisk", "nfc"]) @pytest.mark.parametrize('testnet', [True, False]) -def test_export_public_txt(way, dev, pick_menu_item, goto_home, need_keypress, microsd_path, +def test_export_public_txt(way, dev, pick_menu_item, goto_home, press_select, microsd_path, addr_vs_path, virtdisk_path, nfc_read_text, cap_story, use_mainnet, - load_export, testnet, is_q1): + load_export, testnet): # test UX and values produced. if not testnet: use_mainnet() @@ -421,7 +421,7 @@ def test_export_public_txt(way, dev, pick_menu_item, goto_home, need_keypress, m title, story = cap_story() assert 'Saves a text file' in story - need_keypress(KEY_ENTER if is_q1 else 'y') + press_select() contents = load_export(way, label="Summary", is_json=False, addr_fmt=AF_CLASSIC) fp = io.StringIO(contents).readlines() @@ -470,12 +470,9 @@ def test_export_public_txt(way, dev, pick_menu_item, goto_home, need_keypress, m @pytest.mark.parametrize('use_nfc', [False, True]) def test_export_xpub(use_nfc, acct_num, dev, cap_menu, pick_menu_item, goto_home, cap_story, need_keypress, enter_number, cap_screen_qr, - use_mainnet, nfc_read_text, is_q1): + use_mainnet, nfc_read_text, is_q1, press_select, press_cancel, + press_nfc): # XPUB's via QR - confirm = KEY_ENTER if is_q1 else "y" - cancel = KEY_CANCEL if is_q1 else "x" - k_nfc = KEY_NFC if is_q1 else "3" - use_mainnet() goto_home() @@ -502,9 +499,9 @@ def test_export_xpub(use_nfc, acct_num, dev, cap_menu, pick_menu_item, goto_home if is_xfp: got = cap_screen_qr().decode('ascii') if use_nfc: - need_keypress(k_nfc) + press_nfc() assert got == xfp2str(simulator_fixed_xfp).upper() - need_keypress(cancel) + press_cancel() continue time.sleep(0.3) @@ -525,16 +522,16 @@ def test_export_xpub(use_nfc, acct_num, dev, cap_menu, pick_menu_item, goto_home expect = expect.format(acct=0) if not use_nfc: - need_keypress(confirm) + press_select() got_pub = cap_screen_qr().decode('ascii') else: assert f'Press {KEY_NFC if is_q1 else "(3)"}' in story assert 'NFC' in story - need_keypress(k_nfc) + press_nfc() time.sleep(0.2) got_pub = nfc_read_text() time.sleep(0.1) - #need_keypress(confirm) + #press_select() if got_pub[0] not in 'xt': got_pub,*_ = slip132undo(got_pub) @@ -546,7 +543,7 @@ def test_export_xpub(use_nfc, acct_num, dev, cap_menu, pick_menu_item, goto_home wallet = wallet.subkey_for_path(expect[2:]) assert got.sec() == wallet.sec() - need_keypress(cancel) + press_cancel() @pytest.mark.parametrize("chain", ["BTC", "XTN", "XRT"]) @pytest.mark.parametrize("way", ["sd", "vdisk", "nfc"]) @@ -555,8 +552,8 @@ def test_export_xpub(use_nfc, acct_num, dev, cap_menu, pick_menu_item, goto_home @pytest.mark.parametrize("int_ext", [True, False]) def test_generic_descriptor_export(chain, addr_fmt, acct_num, goto_home, settings_set, need_keypress, pick_menu_item, way, cap_story, cap_menu, nfc_read_text, int_ext, - microsd_path, settings_get, virtdisk_path, load_export, is_q1): - confirm = KEY_ENTER if is_q1 else "y" + microsd_path, settings_get, virtdisk_path, load_export, press_select): + settings_set('chain', chain) chain_num = 1 if chain in ["XTN", "XRT"] else 0 @@ -576,16 +573,16 @@ def test_generic_descriptor_export(chain, addr_fmt, acct_num, goto_home, setting need_keypress("1") # chosse account number for ch in str(acct_num): need_keypress(ch) # input num - need_keypress(confirm) # confirm selection + press_select() # confirm selection else: - need_keypress(confirm) # confirm story + press_select() # confirm story time.sleep(.1) _, story = cap_story() assert "To export receiving and change descriptors in one descriptor (<0;1> notation) press OK" in story assert "press (1) to export receiving and change descriptors separately" in story if int_ext: - need_keypress(confirm) + press_select() else: need_keypress("1") @@ -632,10 +629,7 @@ def test_generic_descriptor_export(chain, addr_fmt, acct_num, goto_home, setting @pytest.mark.parametrize("account", ["Postmix", "Premix"]) def test_samourai_vs_generic(chain, account, settings_set, pick_menu_item, goto_home, need_keypress, cap_story, microsd_path, nfc_read_text, - load_export, is_q1): - confirm = KEY_ENTER if is_q1 else "y" - cancel = KEY_CANCEL if is_q1 else "x" - + load_export, press_select, press_cancel): if account == "Postmix": acct_num = 2147483646 in_story = "Samourai POST-MIX" @@ -652,12 +646,12 @@ def test_samourai_vs_generic(chain, account, settings_set, pick_menu_item, goto_ need_keypress("1") for ch in str(acct_num): need_keypress(ch) - need_keypress(confirm) - need_keypress(confirm) # int_ext <0;1> + press_select() + press_select() # int_ext <0;1> pick_menu_item("Segwit P2WPKH") # both postmix and premix are p2wpkh only file_desc_generic = load_export("sd", label="Descriptor", is_json=False, addr_fmt=AF_P2WPKH) - need_keypress(confirm) # written - need_keypress(cancel) # go back to advanced + press_select() # written + press_cancel() # go back to advanced pick_menu_item("Export Wallet") pick_menu_item(f"Samourai {account}") time.sleep(.1) @@ -668,7 +662,7 @@ def test_samourai_vs_generic(chain, account, settings_set, pick_menu_item, goto_ assert "Press 1 to enter a non-zero account number" not in story # NOT assert "sensitive--in terms of privacy" in story assert "not compromise your funds directly" in story - need_keypress(confirm) + press_select() file_desc = load_export("sd", label="Descriptor", is_json=False, addr_fmt=AF_P2WPKH) assert file_desc.strip() == file_desc_generic.strip() diff --git a/testing/test_hsm.py b/testing/test_hsm.py index 82b2188e..c273e91c 100644 --- a/testing/test_hsm.py +++ b/testing/test_hsm.py @@ -389,7 +389,7 @@ def quick_start_hsm(hsm_reset, start_hsm, hsm_status, change_hsm, sim_eval): return doit @pytest.fixture -def start_hsm(request, dev, hsm_reset, hsm_status, need_keypress): +def start_hsm(request, dev, hsm_reset, hsm_status, need_keypress, press_select): def doit(policy): try: @@ -415,7 +415,7 @@ def start_hsm(request, dev, hsm_reset, hsm_status, need_keypress): if cap_story: # approve it - need_keypress('y') + press_select() time.sleep(.1) title, body2 = cap_story() @@ -444,7 +444,7 @@ def start_hsm(request, dev, hsm_reset, hsm_status, need_keypress): else: # do keypresses blindly - need_keypress('y') + press_select() time.sleep(.1) for ch in '12346': need_keypress(ch, timeout=10000) @@ -857,8 +857,8 @@ def test_multiple_signings_multisig(cc_first, M_N, dev, quick_start_hsm, time.sleep(.2) if dev.is_simulator: - need_keypress = request.getfixturevalue('need_keypress') - need_keypress("y") + press_select = request.getfixturevalue('press_select') + press_select() else: import pdb;pdb.set_trace() # user interaction required on real CC @@ -1547,7 +1547,7 @@ def test_op_return_output_bitcoind(op_return_data, start_hsm, attempt_psbt, bitc start_hsm(policy) attempt_psbt(base64.b64decode(psbt), refuse="non-whitelisted address: 6a") # 6a --> OP_RETURN -def test_hsm_commands_disabled(dev, goto_home, pick_menu_item, need_keypress, hsm_reset, start_hsm, +def test_hsm_commands_disabled(dev, goto_home, pick_menu_item, hsm_reset, start_hsm, sim_exec, enable_hsm_commands): dev.send_recv(CCProtocolPacker.create_user(b"xxx", 3, 32 * b"y")) dev.send_recv(CCProtocolPacker.delete_user(b"xxx")) diff --git a/testing/test_msg.py b/testing/test_msg.py index 201fd33d..0ce4cf86 100644 --- a/testing/test_msg.py +++ b/testing/test_msg.py @@ -10,18 +10,17 @@ from base64 import b64encode, b64decode from ckcc_protocol.protocol import CCProtocolPacker, CCProtoError, CCUserRefused from ckcc_protocol.constants import * from constants import addr_fmt_names, msg_sign_unmap_addr_fmt -from charcodes import KEY_ENTER, KEY_CANCEL, KEY_NFC @pytest.mark.parametrize('msg', [ 'aZ', 'hello', 'abc def eght', "x"*140, 'a'*240]) @pytest.mark.parametrize('path', [ 'm', "m/1/2", "m/1'/100'", 'm/23H/22p']) @pytest.mark.parametrize('addr_fmt', [ AF_CLASSIC, AF_P2WPKH, AF_P2WPKH_P2SH ]) -def test_sign_msg_good(dev, need_keypress, msg, path, addr_fmt, addr_vs_path, is_q1): +def test_sign_msg_good(dev, press_select, msg, path, addr_fmt, addr_vs_path): msg = msg.encode('ascii') dev.send_recv(CCProtocolPacker.sign_message(msg, path, addr_fmt=addr_fmt), timeout=None) - need_keypress(KEY_ENTER if is_q1 else 'y') + press_select() done = None while done == None: @@ -40,14 +39,14 @@ def test_sign_msg_good(dev, need_keypress, msg, path, addr_fmt, addr_vs_path, is assert verify_message(addr, sig, msg.decode("ascii")) is True -def test_sign_msg_refused(dev, need_keypress, is_q1): +def test_sign_msg_refused(dev, press_cancel): # user can refuse to sign (cancel) msg = b'testing 123' path = 'm' dev.send_recv(CCProtocolPacker.sign_message(msg, path), timeout=None) - need_keypress(KEY_CANCEL if is_q1 else 'x') + press_cancel() with pytest.raises(CCUserRefused): done = None @@ -80,12 +79,11 @@ def test_bad_paths(dev, path, expect): @pytest.fixture def sign_on_microsd(open_microsd, cap_story, pick_menu_item, goto_home, - need_keypress, microsd_path, is_q1): + press_select, microsd_path): # sign a file on the microSD card def doit(msg, subpath=None, addr_fmt=None, expect_fail=False): - confirm = KEY_ENTER if is_q1 else "y" fname = 't-msgsign.txt' result_fname = 't-msgsign-signed.txt' @@ -108,7 +106,7 @@ def sign_on_microsd(open_microsd, cap_story, pick_menu_item, goto_home, time.sleep(.1) _, story = cap_story() assert 'Choose text file to be signed' in story - need_keypress(confirm) + press_select() time.sleep(.1) try: @@ -133,7 +131,7 @@ def sign_on_microsd(open_microsd, cap_story, pick_menu_item, goto_home, x_subpath = subpath.lower().replace('p', "'").replace('h', "'") assert ('%s =>' % x_subpath) in story - need_keypress(confirm) + press_select() # wait for it to finish for r in range(10): @@ -245,7 +243,7 @@ def test_sign_msg_fails(dev, sign_on_microsd, msg, concern, no_file, transport, ('Test1', 3, 'IEt/v9K95YVFuRtRtWaabPVwWOFv1FSA/e874I8ABgYMbRyVvHhSwLFz0RZuO87ukxDd4TOsRdofQwMEA90LCgI='), ]) def test_low_R_cases(msg, num_iter, expect, dev, set_seed_words, use_mainnet, - need_keypress, is_q1): + press_select): # Thanks to @craigraw of Sparrow for this test case, copied from: # @@ -260,7 +258,7 @@ def test_low_R_cases(msg, num_iter, expect, dev, set_seed_words, use_mainnet, msg = msg.encode('ascii') dev.send_recv(CCProtocolPacker.sign_message(msg, path, addr_fmt=addr_fmt), timeout=None) - need_keypress(KEY_ENTER if is_q1 else 'y') + press_select() done = None while done == None: @@ -308,10 +306,8 @@ def test_nfc_msg_signing_invalid(body, goto_home, pick_menu_item, nfc_write_text @pytest.mark.parametrize("path", ["", "m/84'/0'/0'/300/0", "m/800'", "m/0/0/0/0/1/1/1"]) @pytest.mark.parametrize("str_addr_fmt", ["p2pkh", "", "p2wpkh", "p2wpkh-p2sh", "p2sh-p2wpkh"]) def test_nfc_msg_signing(msg, path, str_addr_fmt, nfc_write_text, nfc_read_text, pick_menu_item, - goto_home, cap_story, need_keypress, addr_vs_path, is_q1): - confirm = KEY_ENTER if is_q1 else "y" - cancel = KEY_CANCEL if is_q1 else "x" - # import pdb;pdb.set_trace() + goto_home, cap_story, press_select, press_cancel, addr_vs_path): + for _ in range(5): # need to wait for ApproveMessageSign to be popped from ux stack try: @@ -336,12 +332,12 @@ def test_nfc_msg_signing(msg, path, str_addr_fmt, nfc_write_text, nfc_read_text, assert "Ok to sign this?" in story assert msg in story assert path in story - need_keypress(confirm) + press_select() signed_msg = nfc_read_text() if "BITCOIN SIGNED MESSAGE" not in signed_msg: # missed it? again signed_msg = nfc_read_text() - need_keypress(confirm) # exit NFC animation + press_select() # exit NFC animation pmsg, addr, sig = parse_signed_message(signed_msg) assert pmsg == msg addr_vs_path(addr, path, addr_fmt) @@ -349,15 +345,15 @@ def test_nfc_msg_signing(msg, path, str_addr_fmt, nfc_write_text, nfc_read_text, time.sleep(0.5) _, story = cap_story() assert "Press OK to share again" in story - need_keypress(confirm) + press_select() signed_msg_again = nfc_read_text() assert signed_msg == signed_msg_again - need_keypress(cancel) # exit NFC animation - need_keypress(cancel) # do not want to share again + press_cancel() # exit NFC animation + press_cancel() # do not want to share again @pytest.fixture -def verify_armored_signature(pick_menu_item, nfc_write_text, need_keypress, - cap_story, goto_home, is_q1): +def verify_armored_signature(pick_menu_item, nfc_write_text, press_select, + cap_story, goto_home): def doit(way, fname=None, signed_msg=None): goto_home() pick_menu_item('Advanced/Tools') @@ -372,7 +368,7 @@ def verify_armored_signature(pick_menu_item, nfc_write_text, need_keypress, else: _, story = cap_story() assert 'Choose signature file.' in story - need_keypress(KEY_ENTER if is_q1 else 'y') + press_select() time.sleep(.1) pick_menu_item(fname) @@ -473,9 +469,7 @@ def test_verify_signature_file_fail(way, addr_sig, microsd_path, cap_story, goto @pytest.mark.parametrize("binary", [True, False]) def test_verify_signature_file_digest_prob(binary, microsd_path, cap_story, pick_menu_item, - need_keypress, goto_home, is_q1): - confirm = KEY_ENTER if is_q1 else "y" - cancel = KEY_CANCEL if is_q1 else "x" + need_keypress, goto_home, press_select, press_cancel): fpattern = "to_sign" if binary: @@ -499,19 +493,19 @@ def test_verify_signature_file_digest_prob(binary, microsd_path, cap_story, pick pick_menu_item("Advanced/Tools") pick_menu_item("File Management") pick_menu_item("List Files") - need_keypress(confirm) + press_select() pick_menu_item(fname) need_keypress("4") # create detached sig - need_keypress(confirm) - need_keypress(cancel) + press_select() + press_cancel() pick_menu_item("Verify Sig File") - need_keypress(confirm) + press_select() pick_menu_item(sig_name) time.sleep(0.1) title, story = cap_story() assert title == "CORRECT" assert "Good signature" in story - need_keypress(confirm) # back in File Management + press_select() # back in File Management # modify contents of the file with open(fpath, mode) as f: @@ -520,7 +514,7 @@ def test_verify_signature_file_digest_prob(binary, microsd_path, cap_story, pick mod_digest = hashlib.sha256(mod_contents if binary else mod_contents.encode()).digest().hex() pick_menu_item("Verify Sig File") - need_keypress(confirm) + press_select() pick_menu_item(sig_name) time.sleep(0.1) title, story = cap_story() @@ -529,12 +523,12 @@ def test_verify_signature_file_digest_prob(binary, microsd_path, cap_story, pick assert ("'%s' has wrong contents" % fname) in story assert ("Got:\n%s" % orig_digest) in story assert ("Expected:\n%s" % mod_digest) in story - need_keypress(confirm) # back in File Management + press_select() # back in File Management # remove file os.remove(fpath) pick_menu_item("Verify Sig File") - need_keypress(confirm) + press_select() pick_menu_item(sig_name) time.sleep(0.1) title, story = cap_story() @@ -542,13 +536,12 @@ def test_verify_signature_file_digest_prob(binary, microsd_path, cap_story, pick assert "Good signature" in story # sig is still correct assert ("'%s' is not present" % fname) in story assert 'Contents verification not possible' in story - need_keypress(confirm) # back in File Management + press_select() # back in File Management @pytest.mark.parametrize("f_num", [2, 10, 20]) def test_verify_signature_file_digest_prob_multi(f_num, microsd_path, cap_story, pick_menu_item, - need_keypress, goto_home, is_q1): - confirm = KEY_ENTER if is_q1 else "y" + press_select, goto_home): files = [] msg = "" for i in range(f_num): @@ -580,13 +573,13 @@ def test_verify_signature_file_digest_prob_multi(f_num, microsd_path, cap_story, pick_menu_item("Advanced/Tools") pick_menu_item("File Management") pick_menu_item("Verify Sig File") - need_keypress(confirm) + press_select() pick_menu_item(sig_name) time.sleep(0.1) title, story = cap_story() assert title == "CORRECT" assert "Good signature" in story - need_keypress(confirm) # back in File Management + press_select() # back in File Management # change contents of 0th file fname, orig_digest, fpath, _, _ = files[0] @@ -596,7 +589,7 @@ def test_verify_signature_file_digest_prob_multi(f_num, microsd_path, cap_story, f.write(new_contetns) pick_menu_item("Verify Sig File") - need_keypress(confirm) + press_select() pick_menu_item(sig_name) time.sleep(0.1) title, story = cap_story() @@ -605,7 +598,7 @@ def test_verify_signature_file_digest_prob_multi(f_num, microsd_path, cap_story, assert ("'%s' has wrong contents" % fname) in story assert ("Got:\n%s" % orig_digest) in story assert ("Expected:\n%s" % mod_digest) in story - need_keypress(confirm) # back in File Management + press_select() # back in File Management # change contents of 1st file remove 0th file # both warnings must be visible @@ -618,7 +611,7 @@ def test_verify_signature_file_digest_prob_multi(f_num, microsd_path, cap_story, f.write(new_contetns) pick_menu_item("Verify Sig File") - need_keypress(confirm) + press_select() pick_menu_item(sig_name) time.sleep(0.1) title, story = cap_story() @@ -629,12 +622,12 @@ def test_verify_signature_file_digest_prob_multi(f_num, microsd_path, cap_story, assert ("Expected:\n%s" % mod_digest) in story assert ("'%s' is not present" % fname0) in story assert 'Contents verification not possible' in story - need_keypress(confirm) # back in File Management + press_select() # back in File Management # remove 1st file too os.remove(fpath) pick_menu_item("Verify Sig File") - need_keypress(confirm) + press_select() pick_menu_item(sig_name) time.sleep(0.1) title, story = cap_story() @@ -643,7 +636,7 @@ def test_verify_signature_file_digest_prob_multi(f_num, microsd_path, cap_story, warn_msg = "Files:\n" + "\n".join("> %s" % fname for fname in (fname0, fname1)) assert warn_msg in story assert 'Contents verification not possible' in story - need_keypress(confirm) # back in File Management + press_select() # back in File Management # reboult valid signed files for tup in files: @@ -652,13 +645,13 @@ def test_verify_signature_file_digest_prob_multi(f_num, microsd_path, cap_story, f.write(conts) pick_menu_item("Verify Sig File") - need_keypress(confirm) + press_select() pick_menu_item(sig_name) time.sleep(0.1) title, story = cap_story() assert title == "CORRECT" assert "Good signature" in story - need_keypress(confirm) # back in File Management + press_select() # back in File Management @pytest.mark.parametrize("way", ("sd", "nfc")) @pytest.mark.parametrize("truncation_len", (0, 1)) diff --git a/testing/test_multisig.py b/testing/test_multisig.py index 22d8303f..60ac713a 100644 --- a/testing/test_multisig.py +++ b/testing/test_multisig.py @@ -143,7 +143,7 @@ def make_multisig(dev, sim_execfile): return doit @pytest.fixture -def offer_ms_import(cap_story, dev, need_keypress): +def offer_ms_import(cap_story, dev): def doit(config): # upload the file, trigger import file_len, sha = dev.upload_file(config.encode('ascii')) @@ -161,7 +161,7 @@ def offer_ms_import(cap_story, dev, need_keypress): return doit @pytest.fixture -def import_ms_wallet(dev, make_multisig, offer_ms_import, need_keypress): +def import_ms_wallet(dev, make_multisig, offer_ms_import, press_select, is_q1): def doit(M, N, addr_fmt=None, name=None, unique=0, accept=False, common=None, keys=None, do_import=True, derivs=None, descriptor=False, @@ -223,7 +223,7 @@ def import_ms_wallet(dev, make_multisig, offer_ms_import, need_keypress): if accept: time.sleep(.1) - need_keypress('y') + press_select() # Test it worked. time.sleep(.1) # required @@ -238,9 +238,10 @@ def import_ms_wallet(dev, make_multisig, offer_ms_import, need_keypress): @pytest.mark.parametrize('N', [ 3, 15]) -def test_ms_import_variations(N, make_multisig, offer_ms_import, need_keypress): +def test_ms_import_variations(N, make_multisig, offer_ms_import, press_cancel, is_q1): # all the different ways... keys = make_multisig(N, N) + # bare, no fingerprints # - no xfps @@ -248,7 +249,7 @@ def test_ms_import_variations(N, make_multisig, offer_ms_import, need_keypress): config = '\n'.join(sk.hwif(as_private=False) for xfp,m,sk in keys) title, story = offer_ms_import(config) assert f'Policy: {N} of {N}\n' in story - need_keypress('x') + press_cancel() # exclude myself (expect fail) config = '\n'.join(sk.hwif(as_private=False) @@ -264,7 +265,7 @@ def test_ms_import_variations(N, make_multisig, offer_ms_import, need_keypress): config = f'name: {name}\n' config += '\n'.join(sk.hwif(as_private=False) for xfp,m,sk in keys) title, story = offer_ms_import(config) - need_keypress('x') + press_cancel() assert name in story # too long name @@ -284,14 +285,14 @@ def test_ms_import_variations(N, make_multisig, offer_ms_import, need_keypress): config.insert(i, '') title, story = offer_ms_import('\n'.join(config)) assert f'Policy: {N} of {N}\n' in story - need_keypress('x') + press_cancel() # the different addr formats for af in unmap_addr_fmt.keys(): config = f'format: {af}\n' config += '\n'.join(sk.hwif(as_private=False) for xfp,m,sk in keys) title, story = offer_ms_import(config) - need_keypress('x') + press_cancel() assert f'Policy: {N} of {N}\n' in story def make_redeem(M, keys, path_mapper=None, @@ -394,7 +395,8 @@ def make_ms_address(M, keys, idx=0, is_change=0, addr_fmt=AF_P2SH, testnet=1, ** @pytest.fixture -def test_ms_show_addr(dev, cap_story, need_keypress, addr_vs_path, bitcoind_p2sh, has_ms_checks): +def test_ms_show_addr(dev, cap_story, press_select, addr_vs_path, bitcoind_p2sh, + has_ms_checks, is_q1): def doit(M, keys, addr_fmt=AF_P2SH, bip45=True, **make_redeem_args): # test we are showing addresses correctly # - verifies against bitcoind as well @@ -424,7 +426,7 @@ def test_ms_show_addr(dev, cap_story, need_keypress, addr_vs_path, bitcoind_p2sh else: assert 'UNVERIFIED' in story - need_keypress('y') + press_select() # check expected addr was generated based on my math addr_vs_path(got_addr, addr_fmt=addr_fmt, script=scr) @@ -434,7 +436,6 @@ def test_ms_show_addr(dev, cap_story, need_keypress, addr_vs_path, bitcoind_p2sh assert B2A(scr) == core_scr assert core_addr == got_addr - return doit @@ -459,7 +460,8 @@ def test_import_ranges(m_of_n, use_regtest, addr_fmt, clear_ms, import_ms_wallet @pytest.mark.bitcoind @pytest.mark.ms_danger -def test_violate_bip67(clear_ms, use_regtest, import_ms_wallet, need_keypress, test_ms_show_addr, has_ms_checks): +def test_violate_bip67(clear_ms, use_regtest, import_ms_wallet, + test_ms_show_addr, has_ms_checks): # detect when pubkeys are not in order in the redeem script M, N = 1, 15 @@ -477,7 +479,8 @@ def test_violate_bip67(clear_ms, use_regtest, import_ms_wallet, need_keypress, t @pytest.mark.bitcoind @pytest.mark.parametrize('which_pubkey', [0, 1, 14]) -def test_bad_pubkey(has_ms_checks, use_regtest, clear_ms, import_ms_wallet, need_keypress, test_ms_show_addr, which_pubkey): +def test_bad_pubkey(has_ms_checks, use_regtest, clear_ms, import_ms_wallet, + test_ms_show_addr, which_pubkey): # give incorrect pubkey inside redeem script M, N = 1, 15 keys = import_ms_wallet(M, N, accept=1) @@ -498,7 +501,8 @@ def test_bad_pubkey(has_ms_checks, use_regtest, clear_ms, import_ms_wallet, need @pytest.mark.bitcoind @pytest.mark.parametrize('addr_fmt', ['p2sh-p2wsh', 'p2sh', 'p2wsh' ]) -def test_zero_depth(clear_ms, use_regtest, addr_fmt, import_ms_wallet, need_keypress, test_ms_show_addr, make_multisig): +def test_zero_depth(clear_ms, use_regtest, addr_fmt, import_ms_wallet + , test_ms_show_addr, make_multisig): # test having a co-signer with "m" only key ... ie. depth=0 M, N = 1, 2 @@ -524,7 +528,8 @@ def test_zero_depth(clear_ms, use_regtest, addr_fmt, import_ms_wallet, need_keyp @pytest.mark.parametrize('mode', ['wrong-xfp', 'long-path', 'short-path', 'zero-path']) @pytest.mark.ms_danger @pytest.mark.bitcoind -def test_bad_xfp(mode, clear_ms, use_regtest, import_ms_wallet, need_keypress, test_ms_show_addr, has_ms_checks, request): +def test_bad_xfp(mode, clear_ms, use_regtest, import_ms_wallet + , test_ms_show_addr, has_ms_checks, request): # give incorrect xfp+path args during show_address if has_ms_checks and (mode in {'zero-path', 'wrong-xfp'}): @@ -572,7 +577,8 @@ def test_bad_xfp(mode, clear_ms, use_regtest, import_ms_wallet, need_keypress, t "m/1/2/3/4/5/6/7/8/9/10/11/12/13", # assuming MAX_PATH_DEPTH==12 ]) @pytest.mark.bitcoind -def test_bad_common_prefix(cpp, use_regtest, clear_ms, import_ms_wallet, need_keypress, test_ms_show_addr): +def test_bad_common_prefix(cpp, use_regtest, clear_ms, import_ms_wallet, + test_ms_show_addr): # give some incorrect path values as the common prefix derivation M, N = 1, 15 @@ -581,9 +587,10 @@ def test_bad_common_prefix(cpp, use_regtest, clear_ms, import_ms_wallet, need_ke assert 'bad derivation line' in str(ee) -def test_import_detail(clear_ms, import_ms_wallet, need_keypress, cap_story): +def test_import_detail(clear_ms, import_ms_wallet, need_keypress, + cap_story, is_q1, press_cancel): # check all details are shown right - + M,N = 14, 15 keys = import_ms_wallet(M, N) @@ -600,17 +607,20 @@ def test_import_detail(clear_ms, import_ms_wallet, need_keypress, cap_story): for xp in xpubs: assert xp in story - need_keypress('x') + press_cancel() time.sleep(.1) - need_keypress('x') + press_cancel() @pytest.mark.parametrize("way", ["sd", "vdisk", "nfc"]) @pytest.mark.parametrize('acct_num', [0, 99, 123]) @pytest.mark.parametrize('testnet', [True, False]) -def test_export_airgap(acct_num, goto_home, cap_story, pick_menu_item, cap_menu, need_keypress, - microsd_path, load_export, use_mainnet, testnet, way): +def test_export_airgap(acct_num, goto_home, cap_story, pick_menu_item, cap_menu, + need_keypress, microsd_path, load_export, use_mainnet, + testnet, way, is_q1, press_select): + + if not testnet: use_mainnet() @@ -626,13 +636,13 @@ def test_export_airgap(acct_num, goto_home, cap_story, pick_menu_item, cap_menu, assert f"m/48'/{int(testnet)}'" in story assert "acct'" in story - need_keypress('y') + press_select() # enter account number every time time.sleep(.1) for n in str(acct_num): need_keypress(n) - need_keypress('y') + press_select() rv = load_export(way, is_json=True, label="Multisig XPUB", fpattern="ccxp-", sig_check=False) @@ -677,8 +687,9 @@ def test_export_airgap(acct_num, goto_home, cap_story, pick_menu_item, cap_menu, @pytest.mark.parametrize('N', [ 3, 15]) @pytest.mark.parametrize('vdisk', [True, False]) -def test_import_ux(N, vdisk, goto_home, cap_story, pick_menu_item, need_keypress, microsd_path, make_multisig, - virtdisk_path): +def test_import_ux(N, vdisk, goto_home, cap_story, pick_menu_item, + need_keypress, microsd_path, make_multisig, + virtdisk_path, is_q1, press_cancel, press_select): # test menu-based UX for importing wallet file from SD M = N-1 @@ -715,7 +726,7 @@ def test_import_ux(N, vdisk, goto_home, cap_story, pick_menu_item, need_keypress time.sleep(.1) _, story = cap_story() assert "Pick multisig wallet" in story - need_keypress('y') + press_select() time.sleep(.1) pick_menu_item(fname.rsplit('/', 1)[1]) @@ -728,7 +739,7 @@ def test_import_ux(N, vdisk, goto_home, cap_story, pick_menu_item, need_keypress assert f'Policy: {M} of {N}\n' in story # abort install - need_keypress('x') + press_cancel() finally: # cleanup @@ -738,8 +749,8 @@ def test_import_ux(N, vdisk, goto_home, cap_story, pick_menu_item, need_keypress @pytest.mark.parametrize("way", ["sd", "vdisk", "nfc"]) @pytest.mark.parametrize('addr_fmt', ['p2sh-p2wsh', 'p2sh', 'p2wsh' ]) @pytest.mark.parametrize('comm_prefix', ['m/1/2/3/4/5/6/7/8/9/10/11/12', None, "m/45'"]) -def test_export_single_ux(goto_home, comm_prefix, cap_story, pick_menu_item, cap_menu, need_keypress, - microsd_path, import_ms_wallet, addr_fmt, clear_ms, way, load_export): +def test_export_single_ux(goto_home, comm_prefix, cap_story, pick_menu_item, cap_menu, press_select, + microsd_path, import_ms_wallet, addr_fmt, clear_ms, way, load_export, is_q1): # create a wallet, export to SD card, check file created. # - checks some values for derivation path, assuming MAX_PATH_DEPTH==12 @@ -803,11 +814,12 @@ def test_export_single_ux(goto_home, comm_prefix, cap_story, pick_menu_item, cap pick_menu_item('Delete') time.sleep(.2) - _, story = cap_story() - assert 'you SURE' in story + title, story = cap_story() + where = title if is_q1 else story + assert 'you SURE' in where assert name in story - need_keypress('y') + press_select() time.sleep(.1) menu = cap_menu() assert not [i for i in menu if name in i] @@ -815,7 +827,8 @@ def test_export_single_ux(goto_home, comm_prefix, cap_story, pick_menu_item, cap @pytest.mark.parametrize('N', [ 3, 15]) -def test_overflow(N, import_ms_wallet, clear_ms, need_keypress, cap_story, mk_num): +def test_overflow(N, import_ms_wallet, clear_ms, press_select, cap_story, mk_num, is_q1): + clear_ms() M = N name = 'a'*20 # longest possible @@ -824,7 +837,7 @@ def test_overflow(N, import_ms_wallet, clear_ms, need_keypress, cap_story, mk_nu common="m/45'/0'/34'") time.sleep(.1) - need_keypress('y') + press_select() time.sleep(.2) title, story = cap_story() @@ -842,7 +855,7 @@ def test_overflow(N, import_ms_wallet, clear_ms, need_keypress, cap_story, mk_nu if N == 15: assert count == 2, "Expect fail at 2" - need_keypress('y') + press_select() clear_ms() @pytest.fixture @@ -869,8 +882,11 @@ def test_make_example_file(microsd_path, make_multisig): return doit @pytest.mark.parametrize('N', [ 5, 10]) -def test_import_dup_safe(N, clear_ms, make_multisig, offer_ms_import, need_keypress, cap_story, goto_home, pick_menu_item, cap_menu): +def test_import_dup_safe(N, clear_ms, make_multisig, offer_ms_import, + need_keypress, cap_story, goto_home, pick_menu_item, + cap_menu, is_q1, press_select): # import wallet, rename it, (check that indicated, works), attempt same w/ addr fmt different + M = N clear_ms() @@ -898,7 +914,7 @@ def test_import_dup_safe(N, clear_ms, make_multisig, offer_ms_import, need_keypr assert 'Create new multisig wallet' in story assert 'xxx-orig' in story assert 'P2SH' in story - need_keypress('y') + press_select() has_name('xxx-orig') # just simple rename @@ -906,7 +922,7 @@ def test_import_dup_safe(N, clear_ms, make_multisig, offer_ms_import, need_keypr assert 'update name only' in story.lower() assert 'xxx-new' in story - need_keypress('y') + press_select() has_name('xxx-new') assert N < 15, 'cant make more, no space' @@ -921,9 +937,10 @@ def test_import_dup_safe(N, clear_ms, make_multisig, offer_ms_import, need_keypr assert 'P2WSH' in story # should be 2 now, slightly different - need_keypress('y') + press_select() has_name('xxx-newer', 2) + # TODO # repeat last one, should still be two for keys in ['yn', 'n']: title, story = offer_ms_import(newer) @@ -939,7 +956,9 @@ def test_import_dup_safe(N, clear_ms, make_multisig, offer_ms_import, need_keypr clear_ms() @pytest.mark.parametrize('N', [ 5]) -def test_import_dup_diff_xpub(N, clear_ms, make_multisig, offer_ms_import, need_keypress, cap_story, goto_home, pick_menu_item, cap_menu): +def test_import_dup_diff_xpub(N, clear_ms, make_multisig, offer_ms_import, + press_select, cap_story, goto_home, + pick_menu_item, cap_menu, is_q1): # import wallet, tweak xpub only, check that change detected clear_ms() @@ -963,7 +982,7 @@ def test_import_dup_diff_xpub(N, clear_ms, make_multisig, offer_ms_import, need_ assert 'Create new multisig wallet' in story assert 'xxx-orig' in story assert 'P2SH' in story - need_keypress('y') + press_select() # change one key. title, story = offer_ms_import(make_named('xxx-new', tweaked=True)) @@ -977,7 +996,8 @@ def test_import_dup_diff_xpub(N, clear_ms, make_multisig, offer_ms_import, need_ @pytest.mark.bitcoind @pytest.mark.parametrize('m_of_n', [(2,2), (2,3), (15,15)]) @pytest.mark.parametrize('addr_fmt', ['p2sh-p2wsh', 'p2sh', 'p2wsh' ]) -def test_import_dup_xfp_fails(m_of_n, use_regtest, addr_fmt, clear_ms, make_multisig, import_ms_wallet, need_keypress, test_ms_show_addr): +def test_import_dup_xfp_fails(m_of_n, use_regtest, addr_fmt, clear_ms, + make_multisig, import_ms_wallet, test_ms_show_addr): M, N = m_of_n @@ -1047,11 +1067,12 @@ def test_ms_cli(dev, addr_fmt, clear_ms, import_ms_wallet, addr_vs_path, M=1, N= @pytest.fixture -def make_myself_wallet(dev, set_bip39_pw, offer_ms_import, need_keypress, clear_ms, - reset_seed_words): +def make_myself_wallet(dev, set_bip39_pw, offer_ms_import, press_select, clear_ms, + reset_seed_words, is_q1): # construct a wallet (M of 4) using different bip39 passwords, and default sim def doit(M, addr_fmt=None, do_import=True): + passwords = ['Me', 'Myself', 'And I', ''] if 0: @@ -1095,7 +1116,7 @@ def make_myself_wallet(dev, set_bip39_pw, offer_ms_import, need_keypress, clear_ # dont care if update or create; accept it. time.sleep(.1) - need_keypress('y') + press_select() def select_wallet(idx): # select to specific pw @@ -1103,7 +1124,7 @@ def make_myself_wallet(dev, set_bip39_pw, offer_ms_import, need_keypress, clear_ if do_import: offer_ms_import(config) time.sleep(.1) - need_keypress('y') + press_select() assert xfp == keys[idx][0] return (keys, select_wallet) @@ -1332,9 +1353,12 @@ def test_ms_sign_myself(M, use_regtest, make_myself_wallet, segwit, num_ins, dev @pytest.mark.parametrize('addr_fmt', ['p2wsh', 'p2sh-p2wsh']) @pytest.mark.parametrize('acct_num', [ 0, 99, 4321]) @pytest.mark.parametrize('N', [ 3, 14]) -def test_make_airgapped(addr_fmt, acct_num, N, goto_home, cap_story, pick_menu_item, need_keypress, - microsd_path, set_bip39_pw, clear_ms, get_settings, load_export): +def test_make_airgapped(addr_fmt, acct_num, N, goto_home, cap_story, pick_menu_item, + need_keypress, microsd_path, set_bip39_pw, clear_ms, + get_settings, load_export, is_q1, press_select, press_cancel): # test UX and math for bip45 export + + # cleanup from glob import glob @@ -1355,13 +1379,13 @@ def test_make_airgapped(addr_fmt, acct_num, N, goto_home, cap_story, pick_menu_i pick_menu_item('Multisig Wallets') pick_menu_item('Export XPUB') time.sleep(.05) - need_keypress('y') + press_select() # enter account number every time time.sleep(.05) for n in str(acct_num): need_keypress(n) - need_keypress('y') + press_select() need_keypress('1') @@ -1378,7 +1402,7 @@ def test_make_airgapped(addr_fmt, acct_num, N, goto_home, cap_story, pick_menu_i assert 'XPUB' in story if addr_fmt == 'p2wsh': - need_keypress('y') + press_select() elif addr_fmt == 'p2sh-p2wsh': need_keypress('1') elif addr_fmt == 'p2sh': @@ -1407,13 +1431,13 @@ def test_make_airgapped(addr_fmt, acct_num, N, goto_home, cap_story, pick_menu_i else: assert 0, N - need_keypress('y') + press_select() time.sleep(.1) title, story = cap_story() assert "Create new multisig" in story - need_keypress('y') + press_select() impf, fname = load_export("sd", label="Coldcard multisig setup", is_json=False, sig_check=False, tail_check="Import that file onto the other Coldcards involved with this multisig wallet", @@ -1428,8 +1452,8 @@ def test_make_airgapped(addr_fmt, acct_num, N, goto_home, cap_story, pick_menu_i el_fname = microsd_path(fname) assert f'{M}of{N}' in wal['wallet_type'] - need_keypress('y') - need_keypress('y') + press_select() + press_select() if N == 4 and acct_num == 0: @@ -1454,7 +1478,7 @@ def test_make_airgapped(addr_fmt, acct_num, N, goto_home, cap_story, pick_menu_i if "Press (1) to import multisig wallet file from SD Card" in story: need_keypress("1") time.sleep(.05) - need_keypress('y') + press_select() time.sleep(.05) pick_menu_item(cc_fname.rsplit('/', 1)[1]) @@ -1471,8 +1495,8 @@ def test_make_airgapped(addr_fmt, acct_num, N, goto_home, cap_story, pick_menu_i # test code ehre # abort import, good enough - need_keypress('x') - need_keypress('x') + press_cancel() + press_cancel() @pytest.mark.unfinalized @@ -1480,7 +1504,7 @@ def test_make_airgapped(addr_fmt, acct_num, N, goto_home, cap_story, pick_menu_i @pytest.mark.parametrize('addr_style', ["legacy", "p2sh-segwit", "bech32"]) @pytest.mark.parametrize('cc_sign_first', [True, False]) def test_bitcoind_cosigning(cc_sign_first, dev, bitcoind, import_ms_wallet, clear_ms, try_sign, - need_keypress, addr_style, use_regtest): + press_cancel, addr_style, use_regtest, is_q1): # Make a P2SH wallet with local bitcoind as a co-signer (and simulator) # - send an receive various # - following text of @@ -1551,7 +1575,7 @@ def test_bitcoind_cosigning(cc_sign_first, dev, bitcoind, import_ms_wallet, clea M, xfp_paths, scr, addr_fmt=addr_fmt), timeout=None) assert got_addr == ms_addr time.sleep(.1) - need_keypress('x') # clear screen / start over + press_cancel() # clear screen / start over print(f"Will be signing an input from {ms_addr}") @@ -1766,7 +1790,7 @@ def test_iss6743(repeat, set_seed_words, sim_execfile, try_sign): @pytest.mark.parametrize('N', [ 3, 15]) @pytest.mark.parametrize('xderiv', [ None, 'any', 'unknown', '*', '', 'none']) -def test_ms_import_nopath(N, xderiv, make_multisig, clear_ms, offer_ms_import, need_keypress): +def test_ms_import_nopath(N, xderiv, make_multisig, clear_ms, offer_ms_import): # try various synonyms for unknown/any derivation styles keys = make_multisig(N, N, deriv="m/48'/0'/0'/1'/0", unique=1) @@ -1785,11 +1809,12 @@ def test_ms_import_nopath(N, xderiv, make_multisig, clear_ms, offer_ms_import, n @pytest.mark.parametrize('N', [ 15]) @pytest.mark.parametrize('M', [ 1, 15]) @pytest.mark.parametrize('way', ["sd", "vdisk", "nfc"]) -def test_ms_import_many_derivs(M, N, way, make_multisig, clear_ms, offer_ms_import, need_keypress, +def test_ms_import_many_derivs(M, N, way, make_multisig, clear_ms, offer_ms_import, press_select, pick_menu_item, cap_story, microsd_path, virtdisk_path, nfc_read_text, - goto_home, load_export): + goto_home, load_export, is_q1): # try config file with different derivation paths given, including None # - also check we can convert those into Electrum wallets + actual = "m/48'/0'/0'/1'/0" derivs = [ actual, 'm', "m/45'/0'/99'", "m/45'/34/34'/34"] @@ -1814,7 +1839,7 @@ def test_ms_import_many_derivs(M, N, way, make_multisig, clear_ms, offer_ms_impo assert f'P2SH-P2WSH' in story assert 'Derivation:\n Varies' in story assert f' Varies ({len(set(derivs))})\n' in story - need_keypress('y') + press_select() goto_home() pick_menu_item('Settings') @@ -1834,7 +1859,7 @@ def test_ms_import_many_derivs(M, N, way, make_multisig, clear_ms, offer_ms_impo time.sleep(.25) title, story = cap_story() assert 'This saves a skeleton Electrum wallet file' in story - need_keypress('y') + press_select() el = load_export(way, label="Electrum multisig wallet", sig_check=False, is_json=True) @@ -1913,15 +1938,15 @@ def test_ms_addr_explorer(descriptor, change, M, N, addr_fmt, make_multisig, cle time.sleep(.5) title, story = cap_story() - assert "Press (6)" in story + assert "(0)" in story assert "change addresses." in story if change: - need_keypress("6") + need_keypress("0") time.sleep(0.2) title, story = cap_story() # once change is selected - do not offer this option again assert "change addresses." not in story - assert "Press (6)" not in story + assert "(0)" not in story # unwrap text a bit if change: story = story.replace("=>\n", "=> ").replace('1/0]\n =>', "1/0 =>") @@ -1954,8 +1979,11 @@ def test_ms_addr_explorer(descriptor, change, M, N, addr_fmt, make_multisig, cle assert expect.endswith(end) -def test_dup_ms_wallet_bug(goto_home, pick_menu_item, need_keypress, import_ms_wallet, clear_ms, M=2, N=3): - +def test_dup_ms_wallet_bug(goto_home, pick_menu_item, press_select, import_ms_wallet, + clear_ms, is_q1): + M = 2 + N = 3 + deriv = ["m/48'/1'/0'/69'/1"]*N fmts = [ 'p2wsh', 'p2sh-p2wsh'] @@ -1972,13 +2000,13 @@ def test_dup_ms_wallet_bug(goto_home, pick_menu_item, need_keypress, import_ms_w time.sleep(.1) pick_menu_item('2/3: name-1') pick_menu_item('Delete') - need_keypress('y') + press_select() # BUG: pre v4.0.3, would be showing a "Yikes" referencing multisig:419 at this point pick_menu_item('2/3: name-0') pick_menu_item('Delete') - need_keypress('y') + press_select() clear_ms() @@ -1987,8 +2015,8 @@ def test_dup_ms_wallet_bug(goto_home, pick_menu_item, need_keypress, import_ms_w @pytest.mark.parametrize('int_ext_desc', [True, False]) @pytest.mark.parametrize('way', ["sd", "vdisk", "nfc"]) def test_import_desciptor(M_N, addr_fmt, int_ext_desc, way, import_ms_wallet, goto_home, pick_menu_item, - need_keypress, clear_ms, cap_story, microsd_path, virtdisk_path, - nfc_read_text, load_export): + press_select, clear_ms, cap_story, microsd_path, virtdisk_path, + nfc_read_text, load_export, is_q1): clear_ms() M, N = M_N import_ms_wallet(M, N, addr_fmt=addr_fmt, accept=1, descriptor=True, int_ext_desc=int_ext_desc) @@ -1996,7 +2024,7 @@ def test_import_desciptor(M_N, addr_fmt, int_ext_desc, way, import_ms_wallet, go goto_home() pick_menu_item('Settings') pick_menu_item('Multisig Wallets') - need_keypress('y') # only one enrolled multisig - choose it + press_select() # only one enrolled multisig - choose it pick_menu_item('Descriptors') pick_menu_item('Export') contents = load_export(way, label="Descriptor multisig setup", is_json=False, sig_check=False) @@ -2023,7 +2051,8 @@ def test_import_desciptor(M_N, addr_fmt, int_ext_desc, way, import_ms_wallet, go @pytest.mark.parametrize('way', ["sd", "vdisk", "nfc"]) def test_bitcoind_ms_address(change, descriptor, M_N, addr_fmt, clear_ms, goto_home, need_keypress, pick_menu_item, cap_menu, cap_story, make_multisig, import_ms_wallet, - microsd_path, bitcoind_d_wallet_w_sk, use_regtest, load_export, way): + microsd_path, bitcoind_d_wallet_w_sk, use_regtest, load_export, way, + is_q1, press_select): use_regtest() clear_ms() bitcoind = bitcoind_d_wallet_w_sk @@ -2057,22 +2086,22 @@ def test_bitcoind_ms_address(change, descriptor, M_N, addr_fmt, clear_ms, goto_h time.sleep(0.2) title, story = cap_story() - assert "Press (6)" in story + assert "(0)" in story assert "change addresses." in story if change: - need_keypress("6") + need_keypress("0") time.sleep(0.2) title, story = cap_story() # once change is selected - do not offer this option again assert "change addresses." not in story - assert "Press (6)" not in story + assert "(0)" not in story contents = load_export(way, label="Address summary", is_json=False, sig_check=False, vdisk_key="4") addr_cont = contents.strip() goto_home() pick_menu_item('Settings') pick_menu_item('Multisig Wallets') - need_keypress('y') # only one enrolled multisig - choose it + press_select() # only one enrolled multisig - choose it pick_menu_item('Descriptors') pick_menu_item("Bitcoin Core") contents = load_export(way, label="Bitcoin Core multisig setup", is_json=False, sig_check=False) @@ -2111,7 +2140,9 @@ def test_bitcoind_ms_address(change, descriptor, M_N, addr_fmt, clear_ms, goto_h @pytest.mark.bitcoind def test_legacy_multisig_witness_utxo_in_psbt(bitcoind, use_regtest, clear_ms, microsd_wipe, goto_home, need_keypress, - pick_menu_item, cap_story, load_export, microsd_path, cap_menu, try_sign): + pick_menu_item, cap_story, load_export, microsd_path, cap_menu, try_sign, + is_q1, press_select): + use_regtest() clear_ms() microsd_wipe() @@ -2129,9 +2160,9 @@ def test_legacy_multisig_witness_utxo_in_psbt(bitcoind, use_regtest, clear_ms, m time.sleep(0.5) title, story = cap_story() assert "extended public keys (XPUB) you would need to join a multisig wallet" in story - need_keypress("y") + press_select() need_keypress("0") # account - need_keypress("y") + press_select() xpub_obj = load_export("sd", label="Multisig XPUB", is_json=True, sig_check=False) template = xpub_obj["p2sh_desc"] # get key from bitcoind cosigner @@ -2159,7 +2190,7 @@ def test_legacy_multisig_witness_utxo_in_psbt(bitcoind, use_regtest, clear_ms, m # in case Vdisk is enabled need_keypress("1") time.sleep(0.5) - need_keypress("y") + press_select() pick_menu_item(name) _, story = cap_story() assert "Create new multisig wallet?" in story @@ -2168,7 +2199,7 @@ def test_legacy_multisig_witness_utxo_in_psbt(bitcoind, use_regtest, clear_ms, m assert f"All {N} co-signers must approve spends" in story assert "P2SH" in story assert "Derivation:\n Varies (2)" in story - need_keypress("y") # approve multisig import + press_select() # approve multisig import goto_home() pick_menu_item('Settings') pick_menu_item('Multisig Wallets') @@ -2221,8 +2252,10 @@ def test_legacy_multisig_witness_utxo_in_psbt(bitcoind, use_regtest, clear_ms, m @pytest.mark.parametrize("psbt_v2", [True, False]) def test_bitcoind_MofN_tutorial(m_n, desc_type, clear_ms, goto_home, need_keypress, pick_menu_item, sighash, cap_menu, cap_story, microsd_path, use_regtest, bitcoind, - microsd_wipe, load_export, settings_set, psbt_v2, finalize_v2_v0_convert): + microsd_wipe, load_export, settings_set, psbt_v2, is_q1, + finalize_v2_v0_convert, press_select): # 2of2 case here is described in docs with tutorial + M, N = m_n settings_set("sighshchk", 1) # disable checks use_regtest() @@ -2251,9 +2284,9 @@ def test_bitcoind_MofN_tutorial(m_n, desc_type, clear_ms, goto_home, need_keypre time.sleep(0.5) title, story = cap_story() assert "extended public keys (XPUB) you would need to join a multisig wallet" in story - need_keypress("y") + press_select() need_keypress("0") # account - need_keypress("y") + press_select() xpub_obj = load_export("sd", label="Multisig XPUB", is_json=True, sig_check=False) template = xpub_obj[desc_type] # get keys from bitcoind signers @@ -2289,7 +2322,7 @@ def test_bitcoind_MofN_tutorial(m_n, desc_type, clear_ms, goto_home, need_keypre # in case Vdisk is enabled need_keypress("1") time.sleep(0.5) - need_keypress("y") + press_select() pick_menu_item(name) _, story = cap_story() assert "Create new multisig wallet?" in story @@ -2306,7 +2339,7 @@ def test_bitcoind_MofN_tutorial(m_n, desc_type, clear_ms, goto_home, need_keypre else: assert "P2SH-P2WSH" in story assert "Derivation:\n Varies (2)" in story - need_keypress("y") # approve multisig import + press_select() # approve multisig import goto_home() pick_menu_item('Settings') pick_menu_item('Multisig Wallets') @@ -2377,7 +2410,7 @@ def test_bitcoind_MofN_tutorial(m_n, desc_type, clear_ms, goto_home, need_keypre pick_menu_item(name) except: time.sleep(0.5) - need_keypress("y") + press_select() pick_menu_item(name) time.sleep(0.5) title, story = cap_story() @@ -2391,12 +2424,12 @@ def test_bitcoind_MofN_tutorial(m_n, desc_type, clear_ms, goto_home, need_keypre else: assert "Caution" in story assert "Some inputs have unusual SIGHASH values not used in typical cases." in story - need_keypress("y") # confirm signing + press_select() # confirm signing time.sleep(0.5) title, story = cap_story() assert "PSBT Signed" == title assert "Updated PSBT is:" in story - need_keypress("y") + press_select() os.remove(microsd_path(name)) fname = story.split("\n\n")[-1] @@ -2442,12 +2475,12 @@ def test_bitcoind_MofN_tutorial(m_n, desc_type, clear_ms, goto_home, need_keypre pick_menu_item(name) except: time.sleep(0.5) - need_keypress("y") + press_select() pick_menu_item(name) time.sleep(0.5) title, story = cap_story() assert title == "OK TO SEND?" - need_keypress("y") # confirm signing + press_select() # confirm signing time.sleep(0.5) title, story = cap_story() if "SINGLE" in sighash: @@ -2460,7 +2493,7 @@ def test_bitcoind_MofN_tutorial(m_n, desc_type, clear_ms, goto_home, need_keypre assert "PSBT Signed" == title assert "Updated PSBT is:" in story - need_keypress("y") + press_select() fname = story.split("\n\n")[-1] with open(microsd_path(fname), "r") as f: cc_signed_psbt = f.read().strip() @@ -2499,7 +2532,7 @@ def test_bitcoind_MofN_tutorial(m_n, desc_type, clear_ms, goto_home, need_keypre ("M must be <= N", "wsh(sortedmulti(3,[0f056943/48'/1'/0'/2']tpubDF2rnouQaaYrXF4noGTv6rQYmx87cQ4GrUdhpvXkhtChwQPbdGTi8GA88NUaSrwZBwNsTkC9bFkkC8vDyGBVVAQTZ2AS6gs68RQXtXcCvkP/0/*,[c463f778/44'/0'/0']tpubDD8pw7eZ9bUzYUR1LK5wpkA69iy3BpuLxPzsE6FFNdtTnJDySduc1VJdFEhEJQDKjYktznKdJgHwaQDRfQDQJpceDxH22c1ZKUMjrarVs7M/0/*))#uueddtsy"), ]) def test_exotic_descriptors(desc, clear_ms, goto_home, need_keypress, pick_menu_item, cap_menu, cap_story, make_multisig, - import_ms_wallet, microsd_path, bitcoind_d_wallet_w_sk, use_regtest): + import_ms_wallet, microsd_path, bitcoind_d_wallet_w_sk, use_regtest, is_q1, press_select): use_regtest() clear_ms() msg, desc = desc @@ -2518,7 +2551,7 @@ def test_exotic_descriptors(desc, clear_ms, goto_home, need_keypress, pick_menu_ assert "Press (1) to import multisig wallet file from SD Card" in story need_keypress("1") time.sleep(0.5) - need_keypress("y") + press_select() pick_menu_item(name) _, story = cap_story() assert "Failed to import" in story diff --git a/testing/test_nfc.py b/testing/test_nfc.py index 34e83171..7ea9325f 100644 --- a/testing/test_nfc.py +++ b/testing/test_nfc.py @@ -11,7 +11,8 @@ from struct import pack, unpack import ndef from hashlib import sha256 from txn import * -from charcodes import KEY_NFC, KEY_ENTER, KEY_CANCEL +from charcodes import KEY_NFC + @pytest.mark.parametrize('case', range(6)) def test_ndef(case, load_shared_mod): @@ -147,17 +148,15 @@ def test_ndef_ccfile(ccfile, load_shared_mod): @pytest.fixture def try_sign_nfc(cap_story, pick_menu_item, goto_home, need_keypress, - sim_exec, nfc_read, nfc_write, nfc_block4rf, is_q1): + sim_exec, nfc_read, nfc_write, nfc_block4rf, press_select, + press_cancel, press_nfc): # like "try_sign" but use NFC to send/receive PSBT/results - confirm = KEY_ENTER if is_q1 else "y" - cancel = KEY_CANCEL if is_q1 else "x" - k_nfc = KEY_NFC if is_q1 else "3" sim_exec('from pyb import SDCard; SDCard.ejected = True; import nfc; nfc.NFCHandler.startup()') - def doit(f_or_data, accept=True, expect_finalize=False, accept_ms_import=False, complete=False, encoding='binary', over_nfc=True): - + def doit(f_or_data, accept=True, expect_finalize=False, accept_ms_import=False, + complete=False, encoding='binary', over_nfc=True): if f_or_data[0:5] == b'psbt\xff': ip = f_or_data @@ -203,7 +202,7 @@ def try_sign_nfc(cap_story, pick_menu_item, goto_home, need_keypress, _, story = cap_story() assert 'NFC' in story - need_keypress(k_nfc) + press_nfc() time.sleep(.1) nfc_write(ccfile) @@ -211,14 +210,17 @@ def try_sign_nfc(cap_story, pick_menu_item, goto_home, need_keypress, if accept_ms_import: # would be better to do cap_story here - need_keypress(confirm) + press_select() time.sleep(0.050) title, story = cap_story() assert title == 'OK TO SEND?' if accept != None: - need_keypress(confirm if accept else cancel) + if accept: + press_select() + else: + press_cancel() if accept == False: time.sleep(0.050) @@ -240,14 +242,14 @@ def try_sign_nfc(cap_story, pick_menu_item, goto_home, need_keypress, if 'Final TXID:' in lines: txid = lines[-1] - need_keypress(k_nfc) + press_nfc() time.sleep(.1) contents = nfc_read() - need_keypress(confirm) + press_select() else: nfc_block4rf() contents = nfc_read() - need_keypress(confirm) + press_select() txid = None got_txid = None @@ -326,10 +328,7 @@ def try_sign_nfc(cap_story, pick_menu_item, goto_home, need_keypress, @pytest.mark.parametrize('num_outs', [ 1, 20, 250]) def test_nfc_after(num_outs, fake_txn, try_sign, nfc_read, need_keypress, - cap_story, is_q1): - k_nfc = KEY_NFC if is_q1 else "3" - # import pdb;pdb.set_trace() - + cap_story, is_q1, press_nfc, press_cancel): # Read signing result (transaction) over NFC, decode it. psbt = fake_txn(1, num_outs) orig, result = try_sign(psbt, accept=True, finalize=True) @@ -344,7 +343,7 @@ def test_nfc_after(num_outs, fake_txn, try_sign, nfc_read, need_keypress, assert 'TXID' in title, story txid = a2b_hex(story.split()[0]) assert f'Press {KEY_NFC if is_q1 else "(3)"}' in story - need_keypress(k_nfc) + press_nfc() if too_big: title, story = cap_story() @@ -352,7 +351,7 @@ def test_nfc_after(num_outs, fake_txn, try_sign, nfc_read, need_keypress, return contents = nfc_read() - need_keypress(KEY_CANCEL if is_q1 else 'x') + press_cancel() #print("contents = " + B2A(contents)) for got in ndef.message_decoder(contents): diff --git a/testing/test_se2.py b/testing/test_se2.py index 3fc386e5..d62ea910 100644 --- a/testing/test_se2.py +++ b/testing/test_se2.py @@ -241,7 +241,8 @@ def test_ux_trick_menus(goto_trick_menu, pick_menu_item, cap_menu, need_keypress @pytest.fixture(scope='function') -def new_trick_pin(goto_trick_menu, pick_menu_item, cap_menu, need_keypress, cap_story, enter_pin, se2_gate, is_simulator): +def new_trick_pin(goto_trick_menu, pick_menu_item, cap_menu, press_select, + cap_story, enter_pin, se2_gate, is_simulator): # using menus and UX, setup a new trick PIN def doit(new_pin, op_mode, expect=None): goto_trick_menu() @@ -258,7 +259,7 @@ def new_trick_pin(goto_trick_menu, pick_menu_item, cap_menu, need_keypress, cap_ if 'on this duress wallet' in story: # extra confirm step, seen only for trick pins which lead to duress wallet time.sleep(.1) - need_keypress('y') + press_select() time.sleep(.1) _,story = cap_story() @@ -266,7 +267,7 @@ def new_trick_pin(goto_trick_menu, pick_menu_item, cap_menu, need_keypress, cap_ assert new_pin in story time.sleep(.1) - need_keypress('y') + press_select() time.sleep(.1) m = cap_menu() @@ -295,7 +296,7 @@ def new_trick_pin(goto_trick_menu, pick_menu_item, cap_menu, need_keypress, cap_ _, story = cap_story() if expect: assert expect in story - need_keypress('y') + press_select() return doit @@ -480,13 +481,13 @@ def test_ux_countdown_choices(subchoice, expect, xflags, new_trick_pin, new_pin_ def test_ux_duress_choices(with_wipe, subchoice, expect, xflags, xargs, reset_seed_words, repl, clear_all_tricks, import_ms_wallet, get_setting, clear_ms, new_trick_pin, new_pin_confirmed, cap_menu, pick_menu_item, cap_story, need_keypress, - stop_after_activated=False, + press_select, press_cancel, stop_after_activated=False, ): # import multisig clear_ms() import_ms_wallet(2, 2) - need_keypress('y') + press_select() time.sleep(.1) assert len(get_setting('multisig')) == 1 @@ -500,7 +501,7 @@ def test_ux_duress_choices(with_wipe, subchoice, expect, xflags, xargs, pick_menu_item('Wipe -> Wallet') _, story = cap_story() assert 'Seed is silently wiped, and' in story - need_keypress('y') + press_select() else: new_trick_pin(new_pin, 'Duress Wallet', 'Goes directly to a specific duress wallet') xflags &= ~TC_WIPE @@ -508,7 +509,7 @@ def test_ux_duress_choices(with_wipe, subchoice, expect, xflags, xargs, pick_menu_item(subchoice) _, story = cap_story() assert expect in story - need_keypress('y') + press_select() op_mode = subchoice if with_wipe: @@ -546,14 +547,14 @@ def test_ux_duress_choices(with_wipe, subchoice, expect, xflags, xargs, seed = Mnemonic.to_seed(' '.join(words), passphrase='') wallet = BIP32Node.from_master_secret(seed, netcode='XTN') # dev might be BTC - need_keypress('x') + press_cancel() time.sleep(.1) pick_menu_item('Activate Wallet') time.sleep(.1) _, story = cap_story() assert 'This will temporarily load' in story - need_keypress('y') + press_select() time.sleep(.1) if stop_after_activated: return _, story = cap_story() @@ -818,12 +819,13 @@ def build_duress_wallets(request, seed_vault=False): # fixtures I need directly cap_story = request.getfixturevalue('cap_story') need_keypress = request.getfixturevalue('need_keypress') + press_select = request.getfixturevalue('press_select') restore_main_seed = request.getfixturevalue('restore_main_seed') # fixtures I need in test_ux_duress_choices args = {f: request.getfixturevalue(f) for f in ['reset_seed_words', 'repl', 'clear_all_tricks', 'new_trick_pin', 'clear_ms', - 'import_ms_wallet', 'get_setting', + 'import_ms_wallet', 'get_setting', 'press_select', 'press_cancel', 'new_pin_confirmed', 'cap_menu', 'pick_menu_item', 'cap_story', 'need_keypress']} for (subchoice, expect, xflags, xargs) in [ @@ -842,11 +844,11 @@ def build_duress_wallets(request, seed_vault=False): _, story = cap_story() assert 'Saved to Seed Vault' in story - need_keypress('y') + press_select() time.sleep(0.1) _, story = cap_story() assert 'temporary master key is in effect now' in story - need_keypress("y") + press_select() # re-login to reset to normal seed # .. because cant get into trick menu when non-master seed is set (says Unavailable)