diff --git a/shared/actions.py b/shared/actions.py index 6e3a1c0c..00605893 100644 --- a/shared/actions.py +++ b/shared/actions.py @@ -1797,7 +1797,6 @@ async def ready2sign(*a): # - check if any signable in SD card, if so do it # - if no card, check virtual disk for PSBT # - if still nothing, then talk about USB connection - import stash from pincodes import pa from glob import NFC diff --git a/shared/files.py b/shared/files.py index 908e399d..d401c909 100644 --- a/shared/files.py +++ b/shared/files.py @@ -240,7 +240,8 @@ class CardSlot: def __enter__(self): # Mk4: maybe use our virtual disk in preference to SD Card - if glob.VD and (self.force_vdisk or not self.is_inserted()): + inserted = pyb.SDCard().present() if ckcc.is_simulator() else self.is_inserted() + if glob.VD and (self.force_vdisk or not inserted): self.mountpt = glob.VD.mount(self.readonly) return self diff --git a/shared/ux.py b/shared/ux.py index b25a82d8..4c3141bb 100644 --- a/shared/ux.py +++ b/shared/ux.py @@ -391,7 +391,7 @@ def export_prompt_builder(what_it_is, no_qr=False, no_nfc=False, key0=None): prompt, escape = None, KEY_CANCEL - if (NFC or VD) or num_sd_slots>1 or key5: + if (NFC or VD) or num_sd_slots>1 or key0: # no need to spam with another prompt, only option is SD card prompt = "Press (1) to save %s to SD Card" % what_it_is diff --git a/testing/conftest.py b/testing/conftest.py index 83e6c3ef..748e9825 100644 --- a/testing/conftest.py +++ b/testing/conftest.py @@ -1793,6 +1793,11 @@ def load_export(need_keypress, cap_story, microsd_path, virtdisk_path, nfc_read_ 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): + + s_label = None + if label == "Address summary": + s_label = "address summary" + key_map = { "sd": sd_key or "1", "vdisk": vdisk_key or "2", @@ -1801,7 +1806,7 @@ def load_export(need_keypress, cap_story, microsd_path, virtdisk_path, nfc_read_ time.sleep(0.2) title, story = cap_story() if way == "sd": - if f"({key_map['sd']}) to save {label} file to SD Card" in story: + if f"({key_map['sd']}) to save {s_label if s_label else label} file to SD Card" in story: need_keypress(key_map['sd']) elif way == "nfc": diff --git a/testing/devtest/clear_seed.py b/testing/devtest/clear_seed.py index 72ee3ede..9cb85a3d 100644 --- a/testing/devtest/clear_seed.py +++ b/testing/devtest/clear_seed.py @@ -22,7 +22,6 @@ if not pa.is_secret_blank(): pa.login() assert pa.is_secret_blank() - settings.blank() settings.master_sv_data = {} settings.master_nvram_key = None diff --git a/testing/devtest/nvram_mk4.py b/testing/devtest/nvram_mk4.py index 7f09c5f4..64039e00 100644 --- a/testing/devtest/nvram_mk4.py +++ b/testing/devtest/nvram_mk4.py @@ -6,8 +6,6 @@ # run manually with: # execfile('../../testing/devtest/nvram_mk4.py') import os -from ubinascii import hexlify as b2a_hex -from ubinascii import unhexlify as a2b_hex import ustruct from glob import settings diff --git a/testing/test_address_explorer.py b/testing/test_address_explorer.py index 428bb1e8..2823c009 100644 --- a/testing/test_address_explorer.py +++ b/testing/test_address_explorer.py @@ -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) @@ -202,7 +202,7 @@ def test_applications_samourai(chain, change, option, goto_address_explorer, cap need_keypress("0") # change (internal) time.sleep(.1) screen_addrs = parse_display_screen(0, 10) - file_addr_gen = generate_addresses_file(None) + file_addr_gen = generate_addresses_file(change=change) for subpath, addr in screen_addrs.items(): f_subpath, f_addr = next(file_addr_gen) assert f_subpath == subpath diff --git a/testing/test_backup.py b/testing/test_backup.py index c516b32e..33479fa8 100644 --- a/testing/test_backup.py +++ b/testing/test_backup.py @@ -1,31 +1,10 @@ -import pytest, time, json, os, shutil, re +import pytest, time, json, os, shutil from constants import simulator_fixed_words, simulator_fixed_tprv from charcodes import KEY_QR from pycoin.key.BIP32Node import BIP32Node from mnemonic import Mnemonic -def decode_backup(txt): - import json - vals = dict() - trimmed = dict() - for ln in txt.split('\n'): - if not ln: continue - if ln[0] == '#': continue - - k, v = ln.split(' = ', 1) - - v = json.loads(v) - - if k.startswith('duress_') or k.startswith('fw_'): - # no space in USB xfer for thesE! - trimmed[k] = v - else: - vals[k] = v - - return vals, trimmed - - @pytest.fixture def backup_system(settings_set, settings_remove, goto_home, pick_menu_item, cap_story, need_keypress, cap_screen_qr, pass_word_quiz, @@ -374,65 +353,6 @@ def test_backup_bip39_wallet(passphrase, set_bip39_pw, pick_menu_item, need_keyp restore_backup_cs(fn, words) -def test_trick_backups(goto_trick_menu, clear_all_tricks, repl, unit_test, - new_trick_pin, new_pin_confirmed, pick_menu_item, - press_select): - - from test_se2 import TC_REBOOT, TC_BLANK_WALLET - - clear_all_tricks() - - # - make wallets of all duress types (x2 each) - # - plus a few simple ones - # - perform a backup and check result - - for n in range(8): - goto_trick_menu() - pin = '123-%04d' % n - 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) - press_select() - new_pin_confirmed(pin, item, None, None) - - for pin, op_mode, expect, _, xflags in [ - ('11-33', 'Just Reboot', 'Reboot when this PIN', False, TC_REBOOT), - ('11-55', 'Look Blank', 'Look and act like a freshly', False, TC_BLANK_WALLET), - ]: - new_trick_pin(pin, op_mode, expect) - new_pin_confirmed(pin, op_mode, xflags) - - # works, but not the best test - # unit_test('devtest/backups.py') - - bk = repl.exec('import backups; RV.write(backups.render_backup_contents())', raw=1) - - assert 'Coldcard backup file' in bk - - # decode it - vals, trimmed = decode_backup(bk) - - assert 'duress_xprv' in trimmed - assert 'duress_1001_words' in trimmed - assert 'duress_1002_words' in trimmed - assert 'duress_1003_words' in trimmed - - unit_test('devtest/clear_seed.py') - - repl.exec(f'import backups; backups.restore_from_dict_ll({vals!r})') - - # recover from recovery - repl.exec(f'import backups; pa.setup(pa.pin); pa.login(); from actions import goto_top_menu; goto_top_menu()') - - bk2 = repl.exec('import backups; RV.write(backups.render_backup_contents())', raw=1) - assert 'Traceback' not in bk2 - - vals2, tr2 = decode_backup(bk2) - - assert vals == vals2 - assert trimmed == tr2 - - 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, press_cancel, cap_story, get_setting, diff --git a/testing/test_multisig.py b/testing/test_multisig.py index 60ac713a..89817143 100644 --- a/testing/test_multisig.py +++ b/testing/test_multisig.py @@ -2096,7 +2096,7 @@ def test_bitcoind_ms_address(change, descriptor, M_N, addr_fmt, clear_ms, goto_h assert "change addresses." not in story assert "(0)" not in story - contents = load_export(way, label="Address summary", is_json=False, sig_check=False, vdisk_key="4") + contents = load_export(way, label="Address summary", is_json=False, sig_check=False) addr_cont = contents.strip() goto_home() pick_menu_item('Settings') diff --git a/testing/test_se2.py b/testing/test_se2.py index 4ec69f02..0a59cd8c 100644 --- a/testing/test_se2.py +++ b/testing/test_se2.py @@ -761,6 +761,25 @@ def test_ux_changing_pins(true_pin, repl, force_main_pin, goto_trick_menu, def test_trick_backups(goto_trick_menu, clear_all_tricks, repl, unit_test, new_trick_pin, new_pin_confirmed, pick_menu_item, press_select): + def decode_backup(txt): + import json + vals = dict() + trimmed = dict() + for ln in txt.split('\n'): + if not ln: continue + if ln[0] == '#': continue + + k, v = ln.split(' = ', 1) + + v = json.loads(v) + + if k.startswith('duress_') or k.startswith('fw_'): + # no space in USB xfer for thesE! + trimmed[k] = v + else: + vals[k] = v + + return vals, trimmed clear_all_tricks() @@ -791,26 +810,6 @@ def test_trick_backups(goto_trick_menu, clear_all_tricks, repl, unit_test, assert 'Coldcard backup file' in bk - def decode_backup(txt): - import json - vals = dict() - trimmed = dict() - for ln in txt.split('\n'): - if not ln: continue - if ln[0] == '#': continue - - k,v = ln.split(' = ', 1) - - v = json.loads(v) - - if k.startswith('duress_') or k.startswith('fw_'): - # no space in USB xfer for thesE! - trimmed[k] = v - else: - vals[k] = v - - return vals, trimmed - # decode it vals, trimmed = decode_backup(bk) diff --git a/testing/test_unit.py b/testing/test_unit.py index 2ff92272..eef0ce4e 100644 --- a/testing/test_unit.py +++ b/testing/test_unit.py @@ -91,7 +91,7 @@ def test_nvram(unit_test, only_mk3): # exercise nvram simulation: not mk4 unit_test('devtest/nvram.py') -def test_nvram_mk4(unit_test, only_mk4): +def test_nvram_mk4(unit_test, only_mk4plus): # exercise nvram simulation: only mk4 unit_test('devtest/nvram_mk4.py') diff --git a/testing/test_vdisk.py b/testing/test_vdisk.py index f62a1a35..921247ee 100644 --- a/testing/test_vdisk.py +++ b/testing/test_vdisk.py @@ -2,7 +2,7 @@ # # Mk4 Virtual Disk related tests. # -import pytest, glob, re, time, random +import pytest, glob, re, time from binascii import b2a_hex, a2b_hex import ndef from hashlib import sha256 @@ -28,7 +28,7 @@ def test_vd_basics(dev, virtdisk_path, is_simulator): assert os.path.isfile(virtdisk_path(f'ident/ckcc-{sn}.txt')) @pytest.fixture -def try_sign_virtdisk(need_keypress, virtdisk_path, cap_story, virtdisk_wipe): +def try_sign_virtdisk(press_select, virtdisk_path, cap_story, virtdisk_wipe, press_cancel): # like "try_sign" but use Virtual Disk to send/receive PSBT/results # - on real dev, need user to manually say yes ... alot @@ -66,13 +66,16 @@ def try_sign_virtdisk(need_keypress, virtdisk_path, cap_story, virtdisk_wipe): xfn = virtdisk_path('testcase.psbt') open(xfn, 'wb').write(ip) - need_keypress('y') # ready to sign (hopefully) + press_select() # ready to sign (hopefully) # CC scans drive, reads PSBT, verifies... time.sleep(1) # approve siging txn - need_keypress('y' if accept else 'x') + if accept: + press_select() + else: + press_cancel() if accept == False: time.sleep(0.050) @@ -83,7 +86,7 @@ def try_sign_virtdisk(need_keypress, virtdisk_path, cap_story, virtdisk_wipe): # wait for it to finish signing title, story = cap_story() if "OK TO SEND" in title or "PSBT Signed" in title: - need_keypress('y') + press_select() result_fn = xfn.replace('.psbt', '-*.psbt') result_txn = xfn.replace('.psbt', '.txn') @@ -251,8 +254,10 @@ def test_macos_detection(): @pytest.mark.parametrize('multiple_runs', range(3)) @pytest.mark.parametrize('testnet', [True, False]) -def test_import_prv_virtdisk(testnet, pick_menu_item, cap_story, need_keypress, unit_test, cap_menu, get_secrets, - multiple_runs, reset_seed_words, virtdisk_path, virtdisk_wipe, settings_set): +def test_import_prv_virtdisk(testnet, pick_menu_item, cap_story, need_keypress, + unit_test, cap_menu, get_secrets, multiple_runs, + reset_seed_words, virtdisk_path, virtdisk_wipe, + settings_set, press_select): # copied from test_ux as we need vdisk enabled and card ejected if testnet: netcode = "XTN" @@ -260,6 +265,7 @@ def test_import_prv_virtdisk(testnet, pick_menu_item, cap_story, need_keypress, else: netcode = "BTC" settings_set('chain', 'XTN') + unit_test('devtest/clear_seed.py') fname = 'test-%d.txt' % os.getpid() @@ -286,7 +292,7 @@ def test_import_prv_virtdisk(testnet, pick_menu_item, cap_story, need_keypress, time.sleep(0.2) title, body = cap_story() assert 'Select file' in body - need_keypress('y') + press_select() time.sleep(.01) pick_menu_item(fname)