rename files on SD card via List Files
This commit is contained in:
parent
4d2349fef4
commit
3353f3d4a4
@ -8,6 +8,7 @@ This lists the new changes that have not yet been published in a normal release.
|
||||
- Enhancement: Add warning for zero value outputs if not `OP_RETURN`
|
||||
- Enhancement: Show QR codes of output addresses in transaction output explorer. Explorer is
|
||||
now offered for transactions of all sizes, not just complex ones.
|
||||
Enhancement: Add ability to rename files on SD card via `Advanced/Tools -> File Management -> List Files`
|
||||
- Bugfix: If all change outputs have `nValue=0` they were not shown in UX.
|
||||
- Bugfix: Disallow negative input/output amounts in PSBT.
|
||||
- Bugfix: Fix filesystem initialization after Wife LFS or Destroy Seed.
|
||||
|
||||
@ -1683,30 +1683,39 @@ async def list_files(*A):
|
||||
from pincodes import pa
|
||||
|
||||
digest = chk.digest()
|
||||
basename = fn.rsplit('/', 1)[-1]
|
||||
msg_base = 'SHA256(%s)\n\n%s\n\nPress ' % (basename, B2A(digest))
|
||||
escape = "6"
|
||||
path, basename = fn.rsplit('/', 1)
|
||||
msg_base = 'SHA256(%s)\n\n' + B2A(digest) + '\n\nPress (1) to rename file, '
|
||||
escape = "61"
|
||||
if pa.has_secrets():
|
||||
msg_sign = '(4) to sign file digest and export detached signature, '
|
||||
msg_base += '(4) to sign file digest and export detached signature, '
|
||||
escape += "4"
|
||||
else:
|
||||
msg_sign = ""
|
||||
msg_delete = '(6) to delete.'
|
||||
msg = msg_base + msg_sign + msg_delete
|
||||
msg_base += '(6) to delete.'
|
||||
|
||||
while True:
|
||||
ch = await ux_show_story(msg, escape=escape)
|
||||
ch = await ux_show_story(msg_base % basename, escape=escape)
|
||||
if ch == "x": break
|
||||
if ch in '46':
|
||||
if ch in '461':
|
||||
with CardSlot() as card:
|
||||
if ch == '6':
|
||||
card.securely_blank_file(fn)
|
||||
break
|
||||
elif ch == '1':
|
||||
new_basename = await ux_input_text(basename, max_len=32, min_len=3)
|
||||
if new_basename:
|
||||
try:
|
||||
# prohibit both slashes and space in filenames
|
||||
for s in "\/ ":
|
||||
assert s not in new_basename, "illegal char"
|
||||
uos.rename(path + "/" + basename, path + "/" + new_basename)
|
||||
basename = new_basename
|
||||
except Exception as e:
|
||||
await ux_show_story("Failed to rename the file. " + str(e),
|
||||
title="Failure")
|
||||
else:
|
||||
from msgsign import write_sig_file
|
||||
|
||||
sig_nice = write_sig_file([(digest, fn)])
|
||||
await ux_show_story("Signature file %s written." % sig_nice)
|
||||
msg = msg_base + msg_delete
|
||||
return
|
||||
|
||||
async def file_picker(suffix=None, min_size=1, max_size=1000000, taster=None,
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
#
|
||||
import pytest, time, os, re, hashlib, shutil
|
||||
from helpers import xfp2str, prandom
|
||||
from charcodes import KEY_DOWN, KEY_QR, KEY_NFC, KEY_DELETE
|
||||
from charcodes import KEY_DOWN, KEY_QR, KEY_NFC, KEY_DELETE, KEY_CANCEL
|
||||
from constants import AF_CLASSIC, simulator_fixed_words, simulator_fixed_xfp
|
||||
from mnemonic import Mnemonic
|
||||
from bip32 import BIP32Node
|
||||
@ -818,7 +818,6 @@ def test_sign_file_from_list_files(f_len, goto_home, cap_story, pick_menu_item,
|
||||
verify_detached_signature_file([fname], signame, "sd", AF_CLASSIC)
|
||||
time.sleep(0.1)
|
||||
_, story = cap_story()
|
||||
assert "(4) to sign file digest and export detached signature" not in story
|
||||
|
||||
assert "(6) to delete" in story
|
||||
|
||||
@ -828,6 +827,68 @@ def test_sign_file_from_list_files(f_len, goto_home, cap_story, pick_menu_item,
|
||||
assert "List Files" in menu
|
||||
|
||||
|
||||
def test_rename_from_list_files(goto_home, cap_story, pick_menu_item, need_keypress, is_q1,
|
||||
microsd_path, press_select, cap_screen, enter_complex):
|
||||
def clear(fname):
|
||||
for i in range(len(fname)):
|
||||
if not is_q1 and not i:
|
||||
# Mk4 different menu entry UX
|
||||
continue
|
||||
need_keypress(KEY_DELETE if is_q1 else "x")
|
||||
time.sleep(0.01)
|
||||
|
||||
fname = "file_to_rename.pdf"
|
||||
fpath = microsd_path(fname)
|
||||
contents = os.urandom(64)
|
||||
digest = hashlib.sha256(contents).digest().hex()
|
||||
with open(fpath, "wb") as f:
|
||||
f.write(contents)
|
||||
|
||||
goto_home()
|
||||
pick_menu_item("Advanced/Tools")
|
||||
pick_menu_item('File Management')
|
||||
pick_menu_item('List Files')
|
||||
time.sleep(0.1)
|
||||
pick_menu_item(fname)
|
||||
time.sleep(0.1)
|
||||
_, story = cap_story()
|
||||
assert f"SHA256({fname})" in story
|
||||
assert digest in story
|
||||
assert "Press (1) to rename file" in story
|
||||
need_keypress("1")
|
||||
time.sleep(0.1)
|
||||
if is_q1:
|
||||
scr = cap_screen()
|
||||
assert fname in scr
|
||||
|
||||
clear(fname)
|
||||
|
||||
bad_fnames = ["renamed file.txt", "/sd/renamed_file.txt", "renamed\\file.txt"]
|
||||
for bad in bad_fnames:
|
||||
enter_complex(bad, b39pass=False)
|
||||
time.sleep(.1)
|
||||
title, story = cap_story()
|
||||
assert title == "Failure"
|
||||
assert "Failed to rename the file" in story
|
||||
assert "illegal char" in story
|
||||
press_select()
|
||||
time.sleep(.1)
|
||||
need_keypress("1") # rename again
|
||||
time.sleep(.1)
|
||||
clear(fname)
|
||||
if not is_q1:
|
||||
need_keypress("1") # toggle case back to upper (enter complex expect to start in that state)
|
||||
|
||||
new_fname = "renamed_file.txt"
|
||||
enter_complex(new_fname, b39pass=False)
|
||||
time.sleep(.1)
|
||||
_, story = cap_story()
|
||||
assert f"SHA256({new_fname})" in story
|
||||
assert digest in story
|
||||
assert not os.path.exists(fpath)
|
||||
assert os.path.exists(microsd_path(new_fname))
|
||||
|
||||
|
||||
def test_bip39_pw_signing_xfp_ux(pick_menu_item, press_select, cap_story, enter_complex,
|
||||
reset_seed_words, cap_menu, go_to_passphrase, microsd_wipe):
|
||||
microsd_wipe() # need to wipe all PSBT on SD card so we do not proceed to signing
|
||||
|
||||
Loading…
Reference in New Issue
Block a user