diff --git a/releases/ChangeLog.md b/releases/ChangeLog.md index 7c4ba0fd..cbd2aa09 100644 --- a/releases/ChangeLog.md +++ b/releases/ChangeLog.md @@ -1,5 +1,6 @@ ## 5.2.0 - 2023-09-21 +- Enhancement: Shortcut to `Batch Sign PSBT` via `Ready To Sign` -> `Press (9)` - Enhancement: Old plausible deniability feature on fresh COLDCARD removed. Only needed for Mk 2-3 where SPI flash was external chip, easily observed, but now that's different. New simpler and less storage diff --git a/shared/actions.py b/shared/actions.py index b90ca7e0..87c1c052 100644 --- a/shared/actions.py +++ b/shared/actions.py @@ -1578,7 +1578,8 @@ async def list_files(*A): return async def file_picker(msg, suffix=None, min_size=1, max_size=1000000, taster=None, - choices=None, escape=None, none_msg=None, title=None, force_vdisk=False): + choices=None, escape=None, none_msg=None, title=None, + force_vdisk=False, batch_sign=False): # present a menu w/ a list of files... to be read # - optionally, enforce a max size, and provide a "tasting" function # - if msg==None, don't prompt, just do the search and return list @@ -1659,10 +1660,17 @@ async def file_picker(msg, suffix=None, min_size=1, max_size=1000000, taster=Non # tell them they need to pick; can quit here too, but that's obvious. if len(choices) != 1: msg += '\n\nThere are %d files to pick from.' % len(choices) + if batch_sign: + msg += '\n\nPress (9) to select all files for potential signing.' + else: msg += '\n\nThere is only one file to pick from.' ch = await ux_show_story(msg, escape=escape, title=title) + if batch_sign and (ch == escape == "9"): + await _batch_sign(choices=choices) + return + if escape and ch in escape: return ch if ch == 'x': return @@ -1720,8 +1728,7 @@ def is_psbt(filename): return True return False -async def batch_sign(*a): - +async def _batch_sign(choices=None): force_vdisk = False prompt, escape = import_prompt_builder("PSBTs", no_nfc=True) if prompt: @@ -1730,9 +1737,10 @@ async def batch_sign(*a): if ch == "2": force_vdisk = True - choices = await file_picker(None, suffix='psbt', min_size=50, - force_vdisk=force_vdisk, - max_size=MAX_TXN_LEN, taster=is_psbt) + if not choices: + choices = await file_picker(None, suffix='psbt', min_size=50, + force_vdisk=force_vdisk, + max_size=MAX_TXN_LEN, taster=is_psbt) if not choices: await ux_show_story("No PSBTs found. Need to have '.psbt' suffix.") @@ -1748,6 +1756,9 @@ async def batch_sign(*a): await sleep_ms(100) await the_ux.top_of_stack().interact() +async def batch_sign(*a): + await _batch_sign() + async def ready2sign(*a): # Top menu choice of top menu! Signing! @@ -1792,7 +1803,8 @@ any signature is performed." input_psbt = path + '/' + fn else: input_psbt = await file_picker('Choose PSBT file to be signed.', - choices=choices, title=title) + choices=choices, title=title, + batch_sign=True, escape="9") if not input_psbt: return @@ -2237,7 +2249,7 @@ async def change_which_chain(*a): async def microsd_2fa(*a): # Feature: enforce special MicroSD being inserted at login time (a 2FA) from pwsave import MicroSD2FA - + if not settings.get('sd2fa'): ch = await ux_show_story('When enabled, this feature requires a specially prepared MicroSD card ' 'to be inserted during login process. After correct PIN is provided, ' diff --git a/shared/utils.py b/shared/utils.py index ff647d44..934c5b66 100644 --- a/shared/utils.py +++ b/shared/utils.py @@ -486,7 +486,7 @@ def parse_extended_key(ln, private=False): def import_prompt_builder(title, no_nfc=False): from glob import NFC, VD prompt, escape = None, None - if NFC or VD: + if (NFC and (not no_nfc)) or VD: prompt = "Press (1) to import %s from SD Card" % title escape = "1" if VD is not None: diff --git a/testing/test_sign.py b/testing/test_sign.py index eaae0deb..43dd443d 100644 --- a/testing/test_sign.py +++ b/testing/test_sign.py @@ -2318,9 +2318,11 @@ def test_invalid_output_tapproot_psbt(fake_txn, start_sign, cap_story, dev): @pytest.mark.parametrize("num_tx", [1, 2, 10]) +@pytest.mark.parametrize("ui_path", [True, False]) @pytest.mark.parametrize("action", ["sign", "skip", "refuse"]) -def test_batch_sign(num_tx, action, fake_txn, need_keypress, pick_menu_item, - cap_story, microsd_path, microsd_wipe, goto_home): +def test_batch_sign(num_tx, ui_path, action, fake_txn, need_keypress, + pick_menu_item, cap_story, microsd_path, + microsd_wipe, goto_home): goto_home() microsd_wipe() @@ -2330,9 +2332,22 @@ def test_batch_sign(num_tx, action, fake_txn, need_keypress, pick_menu_item, with open(microsd_path(f"{i}.psbt"), "wb") as f: f.write(psbt) - pick_menu_item("Advanced/Tools") - pick_menu_item("File Management") - pick_menu_item("Batch Sign PSBT") + if ui_path: + pick_menu_item("Advanced/Tools") + pick_menu_item("File Management") + pick_menu_item("Batch Sign PSBT") + else: + # shortcut via Ready To Sign + pick_menu_item("Ready To Sign") + time.sleep(.1) + if num_tx == 1: + need_keypress("x") + pytest.skip("classic sign") + + _, story = cap_story() + assert "Press (9) to use Batch Sign" in story + need_keypress("9") + time.sleep(.1) title, story = cap_story() if "Press (1)" in story: