From fc2bfe26ae18f514bdeea9d635bff23f72b88e31 Mon Sep 17 00:00:00 2001 From: scgbckbone Date: Thu, 23 Oct 2025 03:52:02 +0200 Subject: [PATCH] show backup filename during backup password entry (Q only) --- releases/Next-ChangeLog.md | 2 +- shared/backups.py | 14 +++++++++++--- shared/ux_q1.py | 14 ++++++++++++-- testing/conftest.py | 13 +++++++++---- testing/test_backup.py | 28 ++++++++++++++++++++++++++++ 5 files changed, 61 insertions(+), 10 deletions(-) diff --git a/releases/Next-ChangeLog.md b/releases/Next-ChangeLog.md index 127573cb..eda7ca54 100644 --- a/releases/Next-ChangeLog.md +++ b/releases/Next-ChangeLog.md @@ -18,6 +18,6 @@ This lists the new changes that have not yet been published in a normal release. ## 1.3.5Q - 2025-10-xx -- +- Enhancement: Show backup filename at the top of the screen during backup password entry diff --git a/shared/backups.py b/shared/backups.py index ce4627f2..bcaeae54 100644 --- a/shared/backups.py +++ b/shared/backups.py @@ -570,9 +570,17 @@ async def restore_complete(fname_or_fd, temporary=False, words=True, usb=False): if words: if version.has_qwerty: - from ux_q1 import seed_word_entry - return await seed_word_entry('Enter Password:', num_pw_words, - done_cb=done, has_checksum=False) + from ux_q1 import seed_word_entry, CHARS_W + + basename = None + if isinstance(fname_or_fd, str): + basename = fname_or_fd.split('/')[-1] + if len(basename) > CHARS_W: + basename = basename[:16] + "⋯" + basename[-16:] + + return await seed_word_entry("Enter Password%s:" % (" for" if basename else ""), + num_pw_words, done_cb=done, has_checksum=False, + line2=basename) # give them a menu to pick from, and start picking if usb: diff --git a/shared/ux_q1.py b/shared/ux_q1.py index 239a8205..78c1a65d 100644 --- a/shared/ux_q1.py +++ b/shared/ux_q1.py @@ -594,7 +594,7 @@ def ux_draw_words(y, num_words, words): return rv -async def seed_word_entry(prompt, num_words, has_checksum=True, done_cb=None): +async def seed_word_entry(prompt, num_words, has_checksum=True, done_cb=None, line2=None): # Accept a seed phrase, only # - replaces WordNestMenu on Q1 # - max word length is 8, min is 3 @@ -604,13 +604,23 @@ async def seed_word_entry(prompt, num_words, has_checksum=True, done_cb=None): assert num_words and prompt + not24 = (num_words != 24) + def redraw_words(wrds=None): if not wrds: wrds = ['' for _ in range(num_words)] dis.clear() dis.text(None, 0, prompt, invert=1) - p = ux_draw_words(2 if num_words != 24 else 1, num_words, wrds) + + Y = 2 if not24 else 1 + if line2 and not24: + # add second line, if provided, but only if words length < 24 + # currently only used to show backup filename during backup pwd entry + dis.text(None, 1, line2, invert=1) + Y += 1 + + p = ux_draw_words(Y, num_words, wrds) return wrds, p words, pos = redraw_words() diff --git a/testing/conftest.py b/testing/conftest.py index d655a26d..f45a8fbd 100644 --- a/testing/conftest.py +++ b/testing/conftest.py @@ -2339,9 +2339,9 @@ def restore_backup_unpacked(unit_test, pick_menu_item, cap_story, cap_menu, return doit @pytest.fixture -def restore_backup_cs(unit_test, pick_menu_item, cap_story, cap_menu, - press_select, word_menu_entry, get_setting, is_q1, - need_keypress, scan_a_qr, cap_screen, enter_complex, restore_backup_unpacked): +def restore_backup_cs(unit_test, pick_menu_item, cap_story, cap_menu, press_select, word_menu_entry, + get_setting, is_q1, need_keypress, scan_a_qr, cap_screen, enter_complex, + restore_backup_unpacked): # restore backup with clear seed as first step def doit(fn, passphrase, avail_settings=None, pass_way=None, custom_bkpw=False): unit_test('devtest/clear_seed.py') @@ -2360,7 +2360,7 @@ def restore_backup_cs(unit_test, pick_menu_item, cap_story, cap_menu, pick_menu_item(fn) time.sleep(.1) - if is_q1 and pass_way and pass_way == "qr": + if is_q1 and pass_way and (pass_way == "qr"): need_keypress(KEY_QR) time.sleep(.1) qr = ' '.join(w[:4] for w in passphrase) @@ -2374,6 +2374,11 @@ def restore_backup_cs(unit_test, pick_menu_item, cap_story, cap_menu, elif custom_bkpw: enter_complex(passphrase, b39pass=False) else: + # looking at word entry right now + if is_q1: + scr = cap_screen() + assert fn in scr # backup fname shown at the top + assert "Enter Password for:" in scr word_menu_entry(passphrase, has_checksum=False) restore_backup_unpacked(avail_settings=avail_settings) diff --git a/testing/test_backup.py b/testing/test_backup.py index f35b7698..9a3a2ce3 100644 --- a/testing/test_backup.py +++ b/testing/test_backup.py @@ -744,4 +744,32 @@ def test_exit_dev_backup(tmp, unit_test, goto_home, pick_menu_item, need_keypres pick_menu_item("Restore Bkup") press_cancel() + +@pytest.mark.parametrize("fname", [ + '03edd162a5f57eece68d8eea3891e2a150383a225187179ecb1599efe00d16dd70-ccbk.7z', + ('W'*31) + ".7z", +]) +def test_backup_long_name_display(fname, goto_home, pick_menu_item, need_keypress, src_root_dir, + microsd_path, press_cancel, cap_screen): + fn = microsd_path(fname) + shutil.copy(f'{src_root_dir}/docs/backup.7z', fn) + + goto_home() + pick_menu_item('Advanced/Tools') + pick_menu_item('Temporary Seed') + need_keypress("4") + pick_menu_item('Coldcard Backup') + + time.sleep(.1) + pick_menu_item(fname) + time.sleep(.1) + scr = cap_screen() + if len(fname) > 34: # CHARS_W + assert fname[:16] in scr + assert fname[-16:] in scr + else: + assert fname in scr + + press_cancel() + # EOF