USB send keystrokes for all BIP-85 secret types
This commit is contained in:
parent
440421731e
commit
01c27fe568
@ -7,6 +7,7 @@ This lists the new changes that have not yet been published in a normal release.
|
||||
- New Feature: Export [BIP-380](https://github.com/bitcoin/bips/blob/master/bip-0380.mediawiki) extended key expression.
|
||||
Navigate to `Advanced/Tools -> Export Wallet -> Key Expression`
|
||||
- New Feature: Support for v3 transactions
|
||||
- New Feature: Send keystrokes with all derived BIP-85 secrets
|
||||
|
||||
# Mk4 Specific Changes
|
||||
|
||||
|
||||
@ -548,8 +548,9 @@ class ApproveTransaction(UserAuthorizedAction):
|
||||
dis.fullscreen('Co-Signing...')
|
||||
gc.collect()
|
||||
CCCFeature.sign_psbt(self.psbt)
|
||||
else:
|
||||
# maybe capture new min-height for velocity limit
|
||||
|
||||
if SSSPFeature.is_enabled():
|
||||
# capture new min-height for velocity limit
|
||||
SSSPFeature.update_last_signed(self.psbt)
|
||||
|
||||
except FraudulentChangeOutput as exc:
|
||||
@ -883,7 +884,8 @@ async def done_signing(psbt, tx_req, input_method=None, filename=None,
|
||||
# In that case this would just return dict and keep producing signed
|
||||
# files on SD infinitely (would never actually prompt).
|
||||
ch = await import_export_prompt(noun, intro="\n\n".join(intro), offer_kt=offer_kt,
|
||||
txid=txid, title=title, force_prompt=not first_time,
|
||||
key6="for QR Code of TXID", title=title,
|
||||
force_prompt=not first_time,
|
||||
no_qr=not version.has_qwerty or not allow_qr)
|
||||
if ch == KEY_CANCEL:
|
||||
UserAuthorizedAction.cleanup()
|
||||
@ -964,7 +966,7 @@ async def _save_to_disk(psbt, txid, save_options, is_complete, data_len, output_
|
||||
|
||||
del_after = settings.get('del', 0)
|
||||
|
||||
def _chunk_write(file_d, ofs, chunk=2048):
|
||||
def _chunk_write(file_d, ofs, chunk=4096):
|
||||
written = 0
|
||||
while written < data_len:
|
||||
if (written + chunk) > data_len:
|
||||
|
||||
@ -205,14 +205,12 @@ async def drv_entro_step2(_1, picked, _2, just_pick=False):
|
||||
if new_secret:
|
||||
msg += '\n\nRaw Entropy:\n' + str(b2a_hex(new_secret), 'ascii')
|
||||
|
||||
# Add the standard export prompt at the end, with extra (5) option sometimes.
|
||||
|
||||
key6 = 'to type %s over USB' % s_mode
|
||||
key0 = None
|
||||
if encoded is not None:
|
||||
key0 = 'to switch to derived secret'
|
||||
elif s_mode == 'pw':
|
||||
key0 = 'to type password over USB'
|
||||
prompt, escape = export_prompt_builder('data', key0=key0,
|
||||
|
||||
prompt, escape = export_prompt_builder('data', key0=key0, key6=key6,
|
||||
no_qr=(not qr), force_prompt=True)
|
||||
title = None
|
||||
if node:
|
||||
@ -224,7 +222,9 @@ async def drv_entro_step2(_1, picked, _2, just_pick=False):
|
||||
ch = await ux_show_story(msg+'\n\n'+prompt, title=title, escape=escape,
|
||||
strict_escape=True, sensitive=True)
|
||||
choice = import_export_prompt_decode(ch)
|
||||
if isinstance(choice, dict):
|
||||
if choice == KEY_CANCEL:
|
||||
break
|
||||
elif isinstance(choice, dict):
|
||||
# write to SD card or Virtual Disk: simple text file
|
||||
dis.fullscreen("Saving...")
|
||||
try:
|
||||
@ -247,27 +247,27 @@ async def drv_entro_step2(_1, picked, _2, just_pick=False):
|
||||
story = "Filename is:\n\n%s" % out_fn
|
||||
story += "\n\nSignature filename is:\n\n%s" % sig_nice
|
||||
await ux_show_story(story, title='Saved')
|
||||
elif choice == KEY_CANCEL:
|
||||
break
|
||||
|
||||
elif choice == KEY_QR:
|
||||
from ux import show_qr_code
|
||||
await show_qr_code(qr, qr_alnum, is_secret=True)
|
||||
elif choice == '0':
|
||||
if s_mode == 'pw':
|
||||
# gets confirmation then types it
|
||||
await single_send_keystrokes(qr, path)
|
||||
elif encoded is not None:
|
||||
# switch over to new secret!
|
||||
dis.fullscreen("Applying...")
|
||||
from actions import goto_top_menu
|
||||
from glob import settings
|
||||
xfp_str = xfp2str(settings.get("xfp", 0))
|
||||
await seed.set_ephemeral_seed(
|
||||
encoded,
|
||||
origin='BIP85 Derived from [%s], index=%d' % (xfp_str, index)
|
||||
)
|
||||
goto_top_menu()
|
||||
break
|
||||
|
||||
elif (choice == '0') and (encoded is not None):
|
||||
# switch over to new secret!
|
||||
dis.fullscreen("Applying...")
|
||||
from actions import goto_top_menu
|
||||
from glob import settings
|
||||
xfp_str = xfp2str(settings.get("xfp", 0))
|
||||
await seed.set_ephemeral_seed(
|
||||
encoded,
|
||||
origin='BIP85 Derived from [%s], index=%d' % (xfp_str, index)
|
||||
)
|
||||
goto_top_menu()
|
||||
break
|
||||
|
||||
elif choice == "6":
|
||||
# gets confirmation then types it
|
||||
await single_send_keystrokes(qr, path)
|
||||
|
||||
elif NFC and choice == KEY_NFC:
|
||||
# Share any of these over NFC
|
||||
|
||||
16
shared/ux.py
16
shared/ux.py
@ -394,14 +394,14 @@ def _import_prompt_builder(title, no_qr, no_nfc, slot_b_only=False):
|
||||
|
||||
|
||||
def export_prompt_builder(what_it_is, no_qr=False, no_nfc=False, key0=None, offer_kt=False,
|
||||
force_prompt=False, txid=None):
|
||||
force_prompt=False, key6=None):
|
||||
# Build the prompt for export
|
||||
# - key0 can be for special stuff
|
||||
from glob import NFC, VD
|
||||
|
||||
prompt, escape = None, KEY_CANCEL+"x"
|
||||
|
||||
if (NFC or VD) or (num_sd_slots>1) or key0 or force_prompt or offer_kt or txid or (not no_qr):
|
||||
if (NFC or VD) or (num_sd_slots>1) or key0 or force_prompt or offer_kt or key6 or (not no_qr):
|
||||
# no need to spam with another prompt, only option is SD card
|
||||
|
||||
prompt = "Press (1) to save %s to SD Card" % what_it_is
|
||||
@ -431,10 +431,6 @@ def export_prompt_builder(what_it_is, no_qr=False, no_nfc=False, key0=None, offe
|
||||
prompt += ", (4) to show QR code"
|
||||
escape += '4'
|
||||
|
||||
if txid:
|
||||
prompt += ", (6) for QR Code of TXID"
|
||||
escape += "6"
|
||||
|
||||
if offer_kt:
|
||||
prompt += ", (T) to " + offer_kt
|
||||
escape += 't'
|
||||
@ -443,6 +439,10 @@ def export_prompt_builder(what_it_is, no_qr=False, no_nfc=False, key0=None, offe
|
||||
prompt += ', (0) ' + key0
|
||||
escape += '0'
|
||||
|
||||
if key6:
|
||||
prompt += ", (6) " + key6
|
||||
escape += "6"
|
||||
|
||||
prompt += "."
|
||||
|
||||
return prompt, escape
|
||||
@ -481,7 +481,7 @@ def import_export_prompt_decode(ch):
|
||||
async def import_export_prompt(what_it_is, is_import=False, no_qr=False,
|
||||
no_nfc=False, title=None, intro='', footnotes='',
|
||||
offer_kt=False, slot_b_only=False, force_prompt=False,
|
||||
txid=None):
|
||||
key0=None, key6=None):
|
||||
|
||||
# Show story allowing user to select source for importing/exporting
|
||||
# - return either str(mode) OR dict(file_args)
|
||||
@ -494,7 +494,7 @@ async def import_export_prompt(what_it_is, is_import=False, no_qr=False,
|
||||
if is_import:
|
||||
prompt, escape = _import_prompt_builder(what_it_is, no_qr, no_nfc, slot_b_only)
|
||||
else:
|
||||
prompt, escape = export_prompt_builder(what_it_is, no_qr, no_nfc, txid=txid,
|
||||
prompt, escape = export_prompt_builder(what_it_is, no_qr, no_nfc, key6=key6, key0=key0,
|
||||
force_prompt=force_prompt, offer_kt=offer_kt)
|
||||
|
||||
# TODO: detect if we're only asking A or B, when just one card is inserted
|
||||
|
||||
@ -77,6 +77,7 @@ def derive_bip85_secret(goto_home, press_select, pick_menu_item, cap_story, ente
|
||||
seed = Mnemonic.to_seed(' '.join(got))
|
||||
node = BIP32Node.from_master_secret(seed)
|
||||
assert node.fingerprint().hex().upper() in title
|
||||
assert "(6) to type words over USB" in story
|
||||
|
||||
elif 'XPRV' in mode:
|
||||
assert 'Derived XPRV:' in story
|
||||
@ -87,12 +88,14 @@ def derive_bip85_secret(goto_home, press_select, pick_menu_item, cap_story, ente
|
||||
|
||||
node = BIP32Node.from_hwif(story.split("\n\n")[0].split("\n")[-1])
|
||||
assert node.fingerprint().hex().upper() in title
|
||||
assert "(6) to type xprv over USB" in story
|
||||
|
||||
elif 'WIF' in mode:
|
||||
assert 'WIF (privkey)' in story
|
||||
assert f"m/83696968h/2h/{index}h" in story
|
||||
if expect:
|
||||
assert expect in story
|
||||
assert "(6) to type wif over USB" in story
|
||||
|
||||
elif 'bytes hex' in mode:
|
||||
width = int(mode.split('-')[0])
|
||||
@ -101,13 +104,14 @@ def derive_bip85_secret(goto_home, press_select, pick_menu_item, cap_story, ente
|
||||
assert f"m/83696968h/128169h/{width}h/{index}h" in story
|
||||
if expect:
|
||||
assert expect in story
|
||||
assert "(6) to type hex over USB" in story
|
||||
|
||||
elif 'Passwords' == mode:
|
||||
assert "Password:" in story
|
||||
assert f"m/83696968h/707764h/21h/{index}h" in story
|
||||
if expect:
|
||||
assert expect in story
|
||||
assert "(0) to type password over USB" in story
|
||||
assert "(6) to type pw over USB" in story
|
||||
|
||||
else:
|
||||
raise ValueError(mode)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user