fix test_multisig.py; proper handling of buttons

This commit is contained in:
scgbckbone 2024-02-08 14:56:30 +01:00 committed by doc-hex
parent a51734237a
commit b3c3d2d21a
21 changed files with 566 additions and 499 deletions

View File

@ -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

View File

@ -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)

View File

@ -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"

View File

@ -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

View File

@ -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('')

View File

@ -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)

View File

@ -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

View File

@ -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)

View File

@ -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()

View File

@ -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

View File

@ -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

View File

@ -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")

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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()

View File

@ -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"))

View File

@ -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:
# <https://github.com/sparrowwallet/drongo/blob/master/src/test/java/com/sparrowwallet/drongo/crypto/ECKeyTest.java>
@ -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))

View File

@ -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 <https://github.com/bitcoin/bitcoin/blob/master/doc/psbt.md>
@ -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

View File

@ -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):

View File

@ -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)