Merge branch 'Q' of github.com:Coldcard/q1firmware into Q
This commit is contained in:
commit
f357bc3d8b
@ -107,11 +107,11 @@ Extended Master Key:
|
||||
msg += '\nShipping Bag:\n %s\n' % bn
|
||||
|
||||
if xpub:
|
||||
msg += '\nPress (3) to show QR code of xpub.'
|
||||
msg += '\nPress %s to show QR code of xpub.' % (KEY_QR if version.has_qwerty else "(3)")
|
||||
|
||||
ch = await ux_show_story(msg, escape=('3' if xpub else None))
|
||||
ch = await ux_show_story(msg, escape=('3'+KEY_QR if xpub else None))
|
||||
|
||||
if ch == '3':
|
||||
if ch in '3'+KEY_QR:
|
||||
# show the QR
|
||||
from ux import show_qr_code
|
||||
await show_qr_code(xpub, False)
|
||||
|
||||
@ -393,7 +393,7 @@ def is_ftux_screen(sim_exec):
|
||||
return doit
|
||||
|
||||
@pytest.fixture
|
||||
def expect_ftux(cap_menu, cap_story, need_keypress, is_ftux_screen):
|
||||
def expect_ftux(cap_menu, cap_story, press_select, is_ftux_screen):
|
||||
# seed was entered, FTUX happens, get to main menu
|
||||
def doit():
|
||||
# first time UX here
|
||||
@ -401,7 +401,7 @@ def expect_ftux(cap_menu, cap_story, need_keypress, is_ftux_screen):
|
||||
_, story = cap_story()
|
||||
if not story:
|
||||
break
|
||||
need_keypress('y')
|
||||
press_select()
|
||||
|
||||
m = cap_menu()
|
||||
assert m[0] == 'Ready To Sign'
|
||||
|
||||
@ -4,9 +4,9 @@
|
||||
#
|
||||
# - not working well on simulator right now, but that's not key
|
||||
#
|
||||
import pytest, time, struct
|
||||
import pytest, struct
|
||||
from pycoin.key.BIP32Node import BIP32Node
|
||||
from binascii import b2a_hex, a2b_hex
|
||||
from binascii import b2a_hex
|
||||
from ckcc_protocol.protocol import MAX_MSG_LEN, CCProtocolPacker, CCProtoError
|
||||
|
||||
@pytest.mark.skip
|
||||
@ -99,7 +99,7 @@ def test_xpub_invalid(dev, path):
|
||||
xpub = dev.send_recv(CCProtocolPacker.get_xpub(path), timeout=None)
|
||||
|
||||
|
||||
def test_version(dev):
|
||||
def test_version(dev, is_q1):
|
||||
# read the version, yawn.
|
||||
v = dev.send_recv(CCProtocolPacker.version())
|
||||
assert '\n' in v
|
||||
@ -107,7 +107,10 @@ def test_version(dev):
|
||||
assert '-' in date
|
||||
assert '.' in label
|
||||
assert '.' in bl
|
||||
assert 'mk' in hw_label
|
||||
if is_q1:
|
||||
assert "q1" in hw_label
|
||||
else:
|
||||
assert 'mk' in hw_label
|
||||
print("date=%s" % date)
|
||||
assert build_date.startswith(date[2:].replace('-', ''))
|
||||
assert not extras
|
||||
|
||||
@ -2,8 +2,8 @@
|
||||
#
|
||||
import pytest, time, os, re, hashlib
|
||||
from helpers import xfp2str, prandom
|
||||
from charcodes import KEY_DOWN, KEY_ENTER
|
||||
from constants import AF_CLASSIC, simulator_fixed_words
|
||||
from charcodes import KEY_DOWN, KEY_QR, KEY_NFC
|
||||
from constants import AF_CLASSIC, simulator_fixed_words, simulator_fixed_xfp
|
||||
from mnemonic import Mnemonic
|
||||
from pycoin.key.BIP32Node import BIP32Node
|
||||
|
||||
@ -14,19 +14,21 @@ def test_get_secrets(get_secrets, master_xpub):
|
||||
assert 'xpub' in v
|
||||
assert v['xpub'] == master_xpub
|
||||
|
||||
def test_home_menu(cap_menu, cap_story, cap_screen, need_keypress, reset_seed_words):
|
||||
def test_home_menu(cap_menu, cap_story, cap_screen, need_keypress, reset_seed_words,
|
||||
press_select, press_cancel, is_q1):
|
||||
reset_seed_words()
|
||||
# get to top, force a redraw
|
||||
need_keypress('x')
|
||||
need_keypress('x')
|
||||
need_keypress('x')
|
||||
need_keypress('x')
|
||||
press_cancel()
|
||||
press_cancel()
|
||||
press_cancel()
|
||||
press_cancel()
|
||||
need_keypress('0')
|
||||
|
||||
# check menu contents
|
||||
m = cap_menu()
|
||||
assert 'Ready To Sign' in m
|
||||
assert 'Secure Logout' in m
|
||||
if not is_q1:
|
||||
assert 'Secure Logout' in m
|
||||
assert 'Address Explorer' in m
|
||||
assert 'Advanced/Tools' in m
|
||||
assert 'Settings' in m
|
||||
@ -36,13 +38,13 @@ def test_home_menu(cap_menu, cap_story, cap_screen, need_keypress, reset_seed_wo
|
||||
assert len(m) == 6
|
||||
|
||||
# check 4 lines of menu are shown right
|
||||
scr = cap_screen()
|
||||
chk = '\n'.join(m[0:5])
|
||||
scr = cap_screen().rstrip()
|
||||
chk = '\n'.join(m)
|
||||
assert scr == chk
|
||||
|
||||
# pick first item, expect a story
|
||||
need_keypress('0')
|
||||
need_keypress('y')
|
||||
press_select()
|
||||
|
||||
time.sleep(.01) # required
|
||||
|
||||
@ -50,7 +52,7 @@ def test_home_menu(cap_menu, cap_story, cap_screen, need_keypress, reset_seed_wo
|
||||
assert title == 'NO-TITLE'
|
||||
assert 'transactions' in body or 'Choose PSBT' in body, body
|
||||
|
||||
need_keypress('x')
|
||||
press_cancel()
|
||||
|
||||
@pytest.fixture
|
||||
def word_menu_entry(cap_menu, pick_menu_item, is_q1, do_keypresses, cap_screen):
|
||||
@ -78,7 +80,17 @@ def word_menu_entry(cap_menu, pick_menu_item, is_q1, do_keypresses, cap_screen):
|
||||
else:
|
||||
raise RuntimeError('timeout')
|
||||
|
||||
cap_scr = cap_screen()
|
||||
if len(words) == 23:
|
||||
do_keypresses(KEY_DOWN)
|
||||
cap_scr = cap_screen()
|
||||
while 'Next key' in cap_scr:
|
||||
target = cap_scr.split("\n")[-1].replace("Next key: ", "")
|
||||
do_keypresses(target[0])
|
||||
time.sleep(.1)
|
||||
cap_scr = cap_screen()
|
||||
else:
|
||||
cap_scr = cap_screen()
|
||||
|
||||
if has_checksum:
|
||||
assert 'Valid words' in cap_scr
|
||||
else:
|
||||
@ -112,10 +124,11 @@ def word_menu_entry(cap_menu, pick_menu_item, is_q1, do_keypresses, cap_screen):
|
||||
return doit
|
||||
|
||||
@pytest.fixture
|
||||
def pass_word_quiz(need_keypress, cap_story):
|
||||
def pass_word_quiz(need_keypress, cap_story, press_select):
|
||||
def doit(words, prefix='', preload=None):
|
||||
if not preload:
|
||||
need_keypress('y'); time.sleep(.01)
|
||||
press_select()
|
||||
time.sleep(.01)
|
||||
|
||||
count = 0
|
||||
last_title = None
|
||||
@ -155,9 +168,11 @@ def pass_word_quiz(need_keypress, cap_story):
|
||||
( 'abandon ' * 11 + 'about', 0x0adac573),
|
||||
( 'abandon ' * 17 + 'agent', 0xc38a8be0),
|
||||
( 'abandon ' * 23 + 'art', 0x24d73654 ),
|
||||
( "wife shiver author away frog air rough vanish fantasy frozen noodle athlete pioneer citizen symptom firm much faith extend rare axis garment kiwi clarify", 0x4369050f),
|
||||
( simulator_fixed_words, simulator_fixed_xfp),
|
||||
])
|
||||
def test_import_seed(goto_home, pick_menu_item, cap_story, need_keypress, unit_test, cap_menu, word_menu_entry, seed_words, xfp, get_secrets, reset_seed_words, cap_screen_qr, qr_quality_check, expect_ftux):
|
||||
def test_import_seed(goto_home, pick_menu_item, cap_story, need_keypress, unit_test,
|
||||
cap_menu, word_menu_entry, seed_words, xfp, get_secrets, is_q1,
|
||||
reset_seed_words, cap_screen_qr, qr_quality_check, expect_ftux):
|
||||
|
||||
unit_test('devtest/clear_seed.py')
|
||||
|
||||
@ -181,23 +196,23 @@ def test_import_seed(goto_home, pick_menu_item, cap_story, need_keypress, unit_t
|
||||
|
||||
v = get_secrets()
|
||||
|
||||
assert 'Press (3) to show QR code' in body
|
||||
need_keypress('3')
|
||||
assert f'Press {KEY_QR if is_q1 else "(3)"} to show QR code' in body
|
||||
need_keypress(KEY_QR if is_q1 else '3')
|
||||
qr = cap_screen_qr().decode('ascii')
|
||||
assert qr == v['xpub']
|
||||
|
||||
assert v['mnemonic'] == seed_words
|
||||
reset_seed_words()
|
||||
|
||||
wordlist = None
|
||||
|
||||
@pytest.mark.veryslow # 40 minutes realtime, skp with "-m not\ veryslow" on cmd line
|
||||
@pytest.mark.parametrize('pos', range(0, 0x800, 23))
|
||||
def test_all_bip39_words(pos, goto_home, pick_menu_item, cap_story, need_keypress, unit_test, cap_menu, word_menu_entry, get_secrets, reset_seed_words, expect_ftux):
|
||||
global wordlist
|
||||
if not wordlist:
|
||||
from mnemonic import Mnemonic
|
||||
wordlist = Mnemonic('english').wordlist
|
||||
def test_all_bip39_words(pos, goto_home, pick_menu_item, cap_story, unit_test,
|
||||
cap_menu, word_menu_entry, get_secrets, reset_seed_words,
|
||||
expect_ftux, is_q1):
|
||||
from mnemonic import Mnemonic
|
||||
mnem = Mnemonic('english')
|
||||
wordlist = mnem.wordlist
|
||||
|
||||
# try every single word! In 23-word batches (89 of them)
|
||||
unit_test('devtest/clear_seed.py')
|
||||
@ -218,24 +233,32 @@ def test_all_bip39_words(pos, goto_home, pick_menu_item, cap_story, need_keypres
|
||||
pick_menu_item('24 Words')
|
||||
word_menu_entry(sw)
|
||||
|
||||
m = cap_menu()
|
||||
assert len(m) == 9, repr(m)
|
||||
sw.append(m[0])
|
||||
pick_menu_item(m[0])
|
||||
if not is_q1:
|
||||
m = cap_menu()
|
||||
assert len(m) == 9, repr(m)
|
||||
sw.append(m[0])
|
||||
pick_menu_item(m[0])
|
||||
|
||||
print("Words: %r" % sw)
|
||||
|
||||
expect_ftux()
|
||||
|
||||
v = get_secrets()
|
||||
assert v['mnemonic'] == ' '.join(sw)
|
||||
if is_q1:
|
||||
assert v["mnemonic"].split(" ")[:-1] == sw
|
||||
mnem.check(v["mnemonic"])
|
||||
else:
|
||||
assert v['mnemonic'] == ' '.join(sw)
|
||||
|
||||
reset_seed_words()
|
||||
|
||||
@pytest.mark.qrcode
|
||||
@pytest.mark.parametrize('count', [20, 40, 51, 99, 104])
|
||||
@pytest.mark.parametrize('nwords', [12, 24])
|
||||
def test_import_from_dice(count, nwords, goto_home, pick_menu_item, cap_story, need_keypress, unit_test, cap_menu, word_menu_entry, get_secrets, reset_seed_words, cap_screen, cap_screen_qr, qr_quality_check, expect_ftux):
|
||||
def test_import_from_dice(count, nwords, goto_home, pick_menu_item, cap_story, need_keypress,
|
||||
unit_test, cap_menu, word_menu_entry, get_secrets, reset_seed_words,
|
||||
cap_screen, cap_screen_qr, qr_quality_check, expect_ftux, press_select,
|
||||
press_cancel, is_q1, seed_story_to_words):
|
||||
import random
|
||||
from hashlib import sha256
|
||||
|
||||
@ -255,7 +278,7 @@ def test_import_from_dice(count, nwords, goto_home, pick_menu_item, cap_story, n
|
||||
gave += ch
|
||||
|
||||
time.sleep(0.1)
|
||||
need_keypress('y')
|
||||
press_select()
|
||||
|
||||
time.sleep(0.1)
|
||||
title, body = cap_story()
|
||||
@ -265,31 +288,37 @@ def test_import_from_dice(count, nwords, goto_home, pick_menu_item, cap_story, n
|
||||
assert str(len(gave)) in body
|
||||
|
||||
time.sleep(0.1)
|
||||
need_keypress('y') # add more dice rolls
|
||||
press_select() # add more dice rolls
|
||||
for i in range(threshold - count):
|
||||
ch = chr(0x31 + (i % 6))
|
||||
time.sleep(0.01)
|
||||
need_keypress(ch)
|
||||
gave += ch
|
||||
|
||||
need_keypress("y")
|
||||
press_select()
|
||||
time.sleep(0.1)
|
||||
title, body = cap_story()
|
||||
|
||||
assert f'Record these {nwords}' in body
|
||||
|
||||
assert '(1) to view as QR Code' in body
|
||||
words = [i[4:4+4].upper() for i in re.findall(r'[ 0-9][0-9]: \w*', body)]
|
||||
need_keypress('1')
|
||||
assert f'{KEY_QR if is_q1 else "(1)"} to view as QR Code' in body
|
||||
if is_q1:
|
||||
words = [i[:4].upper() for i in seed_story_to_words(body)]
|
||||
else:
|
||||
words = [i[4:4+4].upper() for i in re.findall(r'[ 0-9][0-9]: \w*', body)]
|
||||
|
||||
need_keypress(KEY_QR if is_q1 else '1')
|
||||
|
||||
qr = cap_screen_qr()
|
||||
assert qr.decode('ascii').split() == words
|
||||
need_keypress('x') # close QR
|
||||
press_cancel() # close QR
|
||||
|
||||
need_keypress('6')
|
||||
time.sleep(0.1)
|
||||
title, body = cap_story()
|
||||
assert 'Are you SURE' in body
|
||||
need_keypress('y')
|
||||
where = title if is_q1 else body
|
||||
assert 'Are you SURE' in where
|
||||
press_select()
|
||||
time.sleep(0.1)
|
||||
|
||||
v = get_secrets()
|
||||
@ -309,9 +338,9 @@ def test_import_from_dice(count, nwords, goto_home, pick_menu_item, cap_story, n
|
||||
|
||||
@pytest.mark.parametrize('multiple_runs', range(3))
|
||||
@pytest.mark.parametrize('nwords', [12, 24])
|
||||
def test_new_wallet(nwords, goto_home, pick_menu_item, cap_story, need_keypress,
|
||||
def test_new_wallet(nwords, goto_home, pick_menu_item, cap_story, expect_ftux,
|
||||
cap_menu, get_secrets, unit_test, pass_word_quiz, multiple_runs,
|
||||
reset_seed_words, expect_ftux):
|
||||
reset_seed_words, is_q1, seed_story_to_words):
|
||||
# generate a random wallet, and check seeds are what's shown to user, etc
|
||||
|
||||
unit_test('devtest/clear_seed.py')
|
||||
@ -323,8 +352,10 @@ def test_new_wallet(nwords, goto_home, pick_menu_item, cap_story, need_keypress,
|
||||
assert title == 'NO-TITLE'
|
||||
assert f'Record these {nwords} secret words!' in body
|
||||
|
||||
|
||||
words = [w[3:].strip() for w in body.split('\n') if w and w[2] == ':']
|
||||
if is_q1:
|
||||
words = seed_story_to_words(body)
|
||||
else:
|
||||
words = [w[3:].strip() for w in body.split('\n') if w and w[2] == ':']
|
||||
assert len(words) == nwords
|
||||
|
||||
print("Words: %r" % words)
|
||||
@ -347,7 +378,8 @@ def test_new_wallet(nwords, goto_home, pick_menu_item, cap_story, need_keypress,
|
||||
@pytest.mark.parametrize('testnet', [True, False])
|
||||
def test_import_prv(way, testnet, pick_menu_item, cap_story, need_keypress, unit_test, cap_menu,
|
||||
word_menu_entry, get_secrets, microsd_path, multiple_runs, reset_seed_words,
|
||||
nfc_write_text, settings_set, virtdisk_path, expect_ftux):
|
||||
nfc_write_text, settings_set, virtdisk_path, expect_ftux, press_select,
|
||||
press_nfc, is_q1):
|
||||
if testnet:
|
||||
netcode = "XTN"
|
||||
settings_set('chain', 'XTN')
|
||||
@ -383,16 +415,16 @@ def test_import_prv(way, testnet, pick_menu_item, cap_story, need_keypress, unit
|
||||
if "Press (1) to import extended private key file from SD Card" in story:
|
||||
need_keypress("1")
|
||||
elif way == "nfc":
|
||||
if "press (3) to import via NFC" not in story:
|
||||
if f"{KEY_NFC if is_q1 else '(3)'} to import via NFC" not in story:
|
||||
pytest.skip("NFC disabled")
|
||||
else:
|
||||
need_keypress("3")
|
||||
press_nfc()
|
||||
time.sleep(0.2)
|
||||
nfc_write_text(prv)
|
||||
time.sleep(0.3)
|
||||
else:
|
||||
# virtual disk
|
||||
if "press (2) to import from Virtual Disk" not in story:
|
||||
if "(2) to import from Virtual Disk" not in story:
|
||||
pytest.skip("Vdisk disabled")
|
||||
else:
|
||||
need_keypress("2")
|
||||
@ -401,7 +433,7 @@ def test_import_prv(way, testnet, pick_menu_item, cap_story, need_keypress, unit
|
||||
time.sleep(0.1)
|
||||
_, story = cap_story()
|
||||
assert "Select file containing the extended private key" in story
|
||||
need_keypress("y")
|
||||
press_select()
|
||||
pick_menu_item(fname)
|
||||
|
||||
expect_ftux()
|
||||
@ -419,7 +451,8 @@ def test_import_prv(way, testnet, pick_menu_item, cap_story, need_keypress, unit
|
||||
@pytest.mark.parametrize("testnet", [True, False])
|
||||
def test_seed_import_tapsigner(way, retry, testnet, cap_menu, pick_menu_item, goto_home, cap_story,
|
||||
need_keypress, reset_seed_words, dev, try_sign, enter_hex, unit_test,
|
||||
settings_set, get_secrets, tapsigner_encrypted_backup, nfc_write_text):
|
||||
settings_set, get_secrets, tapsigner_encrypted_backup, nfc_write_text,
|
||||
press_nfc, press_select, is_q1):
|
||||
|
||||
fname, backup_key_hex, node = tapsigner_encrypted_backup(way, testnet=testnet)
|
||||
if testnet:
|
||||
@ -438,16 +471,16 @@ def test_seed_import_tapsigner(way, retry, testnet, cap_menu, pick_menu_item, go
|
||||
if "Press (1) to import TAPSIGNER encrypted backup file from SD Card" in story:
|
||||
need_keypress("1")
|
||||
elif way == "nfc":
|
||||
if "press (3) to import via NFC" not in story:
|
||||
if f"{KEY_NFC if is_q1 else '(3)'} to import via NFC" not in story:
|
||||
pytest.skip("NFC disabled")
|
||||
else:
|
||||
need_keypress("3")
|
||||
press_nfc()
|
||||
time.sleep(0.2)
|
||||
nfc_write_text(fname)
|
||||
time.sleep(0.3)
|
||||
else:
|
||||
# virtual disk
|
||||
if "press (2) to import from Virtual Disk" not in story:
|
||||
if "(2) to import from Virtual Disk" not in story:
|
||||
pytest.skip("Vdisk disabled")
|
||||
else:
|
||||
need_keypress("2")
|
||||
@ -456,14 +489,14 @@ def test_seed_import_tapsigner(way, retry, testnet, cap_menu, pick_menu_item, go
|
||||
time.sleep(0.1)
|
||||
_, story = cap_story()
|
||||
assert "Pick TAPSIGNER encrypted backup file" in story
|
||||
need_keypress("y")
|
||||
press_select()
|
||||
pick_menu_item(fname)
|
||||
|
||||
time.sleep(0.1)
|
||||
_, story = cap_story()
|
||||
assert "your TAPSIGNER" in story
|
||||
assert "back of the card" in story
|
||||
need_keypress("y") # yes I have backup key
|
||||
press_select() # yes I have backup key
|
||||
enter_hex(backup_key_hex)
|
||||
unit_test('devtest/abort_ux.py')
|
||||
|
||||
@ -477,14 +510,17 @@ def test_seed_import_tapsigner(way, retry, testnet, cap_menu, pick_menu_item, go
|
||||
|
||||
@pytest.mark.parametrize('target', ['baby', 'struggle', 'youth'])
|
||||
@pytest.mark.parametrize('version', range(8))
|
||||
def test_bip39_pick_words(target, version, goto_home, pick_menu_item, cap_story, need_keypress,
|
||||
cap_menu, word_menu_entry, get_pp_sofar, reset_seed_words):
|
||||
def test_bip39_pick_words(target, version, goto_home, pick_menu_item, cap_story,
|
||||
cap_menu, word_menu_entry, get_pp_sofar, reset_seed_words,
|
||||
press_select, only_mk4):
|
||||
# Check we can pick words
|
||||
reset_seed_words()
|
||||
|
||||
goto_home()
|
||||
pick_menu_item('Passphrase')
|
||||
time.sleep(.01); need_keypress('y'); time.sleep(.01) # skip warning
|
||||
time.sleep(.01)
|
||||
press_select()
|
||||
time.sleep(.01) # skip warning
|
||||
pick_menu_item('Add Word')
|
||||
|
||||
word_menu_entry([target])
|
||||
@ -507,15 +543,16 @@ def test_bip39_pick_words(target, version, goto_home, pick_menu_item, cap_story,
|
||||
|
||||
@pytest.mark.parametrize('target', ['123', '1', '4'*32, '12'*8])
|
||||
@pytest.mark.parametrize('backspaces', [1, 0, 12])
|
||||
def test_bip39_add_nums(target, backspaces, goto_home, pick_menu_item, cap_story,
|
||||
cap_menu, word_menu_entry, get_pp_sofar, need_keypress):
|
||||
def test_bip39_add_nums(target, backspaces, goto_home, pick_menu_item, cap_story,
|
||||
cap_menu, word_menu_entry, get_pp_sofar, need_keypress,
|
||||
press_select, press_cancel, only_mk4):
|
||||
|
||||
# Check we can pick numbers (appended)
|
||||
# - also the "clear all" menu item
|
||||
|
||||
goto_home()
|
||||
pick_menu_item('Passphrase')
|
||||
time.sleep(.01); need_keypress('y'); time.sleep(.01) # skip warning
|
||||
time.sleep(.01); press_select(); time.sleep(.01) # skip warning
|
||||
pick_menu_item('Add Numbers')
|
||||
|
||||
for d in target:
|
||||
@ -525,7 +562,7 @@ def test_bip39_add_nums(target, backspaces, goto_home, pick_menu_item, cap_story
|
||||
if backspaces < len(target):
|
||||
for x in range(backspaces):
|
||||
time.sleep(.01) # required
|
||||
need_keypress('x')
|
||||
press_cancel()
|
||||
|
||||
if backspaces:
|
||||
for d in target[-backspaces:]:
|
||||
@ -533,7 +570,7 @@ def test_bip39_add_nums(target, backspaces, goto_home, pick_menu_item, cap_story
|
||||
need_keypress(d)
|
||||
|
||||
time.sleep(0.01) # required
|
||||
need_keypress('y')
|
||||
press_select()
|
||||
|
||||
time.sleep(0.01) # required
|
||||
chk = get_pp_sofar()
|
||||
@ -544,13 +581,14 @@ def test_bip39_add_nums(target, backspaces, goto_home, pick_menu_item, cap_story
|
||||
pick_menu_item('Clear All')
|
||||
time.sleep(0.01) # required
|
||||
|
||||
need_keypress('y')
|
||||
press_select()
|
||||
time.sleep(0.01) # required
|
||||
chk = get_pp_sofar()
|
||||
assert chk == ''
|
||||
|
||||
@pytest.fixture
|
||||
def enter_complex(get_pp_sofar, need_keypress, pick_menu_item, is_q1):
|
||||
def enter_complex(get_pp_sofar, need_keypress, pick_menu_item, is_q1,
|
||||
press_select):
|
||||
def doit(target):
|
||||
# full entry mode
|
||||
# - just left to right here
|
||||
@ -561,7 +599,7 @@ def enter_complex(get_pp_sofar, need_keypress, pick_menu_item, is_q1):
|
||||
for ch in target:
|
||||
need_keypress(ch)
|
||||
time.sleep(.1)
|
||||
need_keypress(KEY_ENTER)
|
||||
press_select()
|
||||
return
|
||||
|
||||
symbols = ' !"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~'
|
||||
@ -602,7 +640,7 @@ def enter_complex(get_pp_sofar, need_keypress, pick_menu_item, is_q1):
|
||||
need_keypress('9')
|
||||
|
||||
time.sleep(0.01) # required
|
||||
need_keypress('y')
|
||||
press_select()
|
||||
|
||||
return doit
|
||||
|
||||
@ -611,15 +649,18 @@ def enter_complex(get_pp_sofar, need_keypress, pick_menu_item, is_q1):
|
||||
'I be stacking sats!! Come at me bro....',
|
||||
'Aa'*50,
|
||||
])
|
||||
def test_bip39_complex(target, goto_home, pick_menu_item, cap_story,
|
||||
cap_menu, word_menu_entry, get_pp_sofar, need_keypress, enter_complex):
|
||||
def test_bip39_complex(target, goto_home, pick_menu_item, cap_story,
|
||||
cap_menu, word_menu_entry, get_pp_sofar, press_select,
|
||||
enter_complex):
|
||||
|
||||
# failed run recovery; gets out of edit screen
|
||||
#need_keypress('y')
|
||||
#need_keypress('x')
|
||||
#press_select()
|
||||
#press_cancel()
|
||||
goto_home()
|
||||
pick_menu_item('Passphrase')
|
||||
time.sleep(.01); need_keypress('y'); time.sleep(.01) # skip warning
|
||||
time.sleep(.01)
|
||||
press_select()
|
||||
time.sleep(.01) # skip warning
|
||||
|
||||
enter_complex(target)
|
||||
|
||||
@ -632,7 +673,8 @@ def test_bip39_complex(target, goto_home, pick_menu_item, cap_story,
|
||||
@pytest.mark.parametrize('b39_word', ['', 'AbcZz1203'])
|
||||
def test_show_seed(mode, b39_word, goto_home, pick_menu_item, cap_story, need_keypress,
|
||||
sim_exec, cap_menu, get_pp_sofar, get_secrets, cap_screen_qr,
|
||||
set_encoded_secret, qr_quality_check, reset_seed_words, set_bip39_pw):
|
||||
set_encoded_secret, qr_quality_check, reset_seed_words, set_bip39_pw,
|
||||
press_select, is_q1, seed_story_to_words):
|
||||
|
||||
reset_seed_words()
|
||||
if mode == 'words':
|
||||
@ -661,9 +703,10 @@ def test_show_seed(mode, b39_word, goto_home, pick_menu_item, cap_story, need_ke
|
||||
pick_menu_item('View Seed Words')
|
||||
time.sleep(.01)
|
||||
title, body = cap_story()
|
||||
assert 'Are you SURE' in body
|
||||
where = title if is_q1 else body
|
||||
assert 'Are you SURE' in where
|
||||
assert 'can control all funds' in body
|
||||
need_keypress('y') # skip warning
|
||||
press_select() # skip warning
|
||||
time.sleep(0.01)
|
||||
|
||||
title, body = cap_story()
|
||||
@ -673,13 +716,23 @@ def test_show_seed(mode, b39_word, goto_home, pick_menu_item, cap_story, need_ke
|
||||
assert '24' in body
|
||||
|
||||
lines = body.split('\n')
|
||||
assert lines[1:25] == ['%2d: %s' % (n+1, w) for n,w in enumerate(words)]
|
||||
if is_q1:
|
||||
assert seed_story_to_words(body) == words
|
||||
else:
|
||||
assert lines[1:25] == ['%2d: %s' % (n+1, w) for n,w in enumerate(words)]
|
||||
|
||||
if b39_word:
|
||||
assert lines[26] == 'BIP-39 Passphrase:'
|
||||
assert "*" in lines[27]
|
||||
assert "Seed+Passphrase" in lines[29]
|
||||
ek = lines[30]
|
||||
if is_q1:
|
||||
assert lines[11] == 'BIP-39 Passphrase:'
|
||||
assert "*" in lines[12]
|
||||
assert "Seed+Passphrase" in lines[14]
|
||||
ek = lines[15]
|
||||
else:
|
||||
assert lines[26] == 'BIP-39 Passphrase:'
|
||||
assert "*" in lines[27]
|
||||
assert "Seed+Passphrase" in lines[29]
|
||||
ek = lines[30]
|
||||
|
||||
seed = Mnemonic.to_seed(simulator_fixed_words, passphrase=b39_word)
|
||||
expect = BIP32Node.from_master_secret(seed, netcode="XTN")
|
||||
esk = expect.hwif(as_private=True)
|
||||
@ -693,12 +746,13 @@ def test_show_seed(mode, b39_word, goto_home, pick_menu_item, cap_story, need_ke
|
||||
assert expect in body
|
||||
qr_expect = expect
|
||||
|
||||
assert '(1) to view as QR Code' in body
|
||||
need_keypress('1')
|
||||
if not is_q1:
|
||||
assert '(1) to view as QR Code' in body
|
||||
need_keypress(KEY_QR if is_q1 else '1')
|
||||
qr = cap_screen_qr().decode('ascii')
|
||||
assert qr == qr_expect
|
||||
|
||||
need_keypress('y') # clear screen
|
||||
press_select() # clear screen
|
||||
|
||||
@pytest.mark.qrcode
|
||||
@pytest.mark.parametrize("data", [
|
||||
@ -712,9 +766,9 @@ def test_show_seed(mode, b39_word, goto_home, pick_menu_item, cap_story, need_ke
|
||||
("atom solve joy ugly ankle message setup typical bean era cactus various odor refuse element afraid meadow quick medal plate wisdom swap noble shallow", "011416550964188800731119157218870156061002561932122514430573003611011405110613292018175411971576"),
|
||||
("attack pizza motion avocado network gather crop fresh patrol unusual wild holiday candy pony ranch winter theme error hybrid van cereal salon goddess expire", "011513251154012711900771041507421289190620080870026613431420201617920614089619290300152408010643"),
|
||||
])
|
||||
def test_show_seed_qr(data, goto_home, pick_menu_item, cap_story, need_keypress,
|
||||
def test_show_seed_qr(data, goto_home, pick_menu_item, cap_story, press_select,
|
||||
sim_exec, cap_menu, get_pp_sofar, get_secrets, cap_screen_qr,
|
||||
set_encoded_secret, qr_quality_check, set_seed_words):
|
||||
set_encoded_secret, qr_quality_check, set_seed_words, is_q1):
|
||||
n = 4 # SeedQr 4 str chars for each index
|
||||
words, qr_expect = data
|
||||
if isinstance(qr_expect, str):
|
||||
@ -729,20 +783,20 @@ def test_show_seed_qr(data, goto_home, pick_menu_item, cap_story, need_keypress,
|
||||
|
||||
time.sleep(.01)
|
||||
title, body = cap_story()
|
||||
assert 'Are you SURE' in body
|
||||
where = title if is_q1 else body
|
||||
assert 'Are you SURE' in where
|
||||
assert 'can control all funds' in body
|
||||
need_keypress('y') # skip warning
|
||||
press_select() # skip warning
|
||||
time.sleep(0.01)
|
||||
|
||||
qr = cap_screen_qr().decode('ascii')
|
||||
qr = [int(qr[i:i+n]) for i in range(0, len(qr), n)]
|
||||
assert qr == qr_expect
|
||||
|
||||
need_keypress('y') # clear screen
|
||||
|
||||
def test_destroy_seed(goto_home, pick_menu_item, cap_story, need_keypress, sim_exec,
|
||||
cap_menu, get_secrets):
|
||||
press_select() # clear screen
|
||||
|
||||
def test_destroy_seed(goto_home, pick_menu_item, cap_story, press_select,
|
||||
sim_exec, cap_menu, get_secrets, is_q1):
|
||||
# Check UX of destroying seeds, rarely used?
|
||||
|
||||
#v = get_secrets()
|
||||
@ -753,63 +807,64 @@ def test_destroy_seed(goto_home, pick_menu_item, cap_story, need_keypress, sim_e
|
||||
pick_menu_item('Danger Zone')
|
||||
pick_menu_item('Seed Functions')
|
||||
pick_menu_item('Destroy Seed')
|
||||
time.sleep(.01);
|
||||
time.sleep(.01)
|
||||
title, body = cap_story()
|
||||
assert 'Are you SURE' in body
|
||||
where = title if is_q1 else body
|
||||
assert 'Are you SURE' in where
|
||||
assert 'All funds will be lost' in body
|
||||
need_keypress('y');
|
||||
press_select()
|
||||
time.sleep(0.01)
|
||||
|
||||
title, body = cap_story()
|
||||
assert 'Are you REALLY sure though' in body
|
||||
assert 'certainly cause' in body
|
||||
assert 'accept all consequences' in body
|
||||
need_keypress('y'); # wants 4
|
||||
press_select() # wants 4
|
||||
time.sleep(0.01)
|
||||
|
||||
|
||||
def test_menu_wrapping(goto_home, pick_menu_item, cap_story, need_keypress, cap_menu):
|
||||
UP = "5"
|
||||
DOWN = "8"
|
||||
|
||||
def test_menu_wrapping(goto_home, pick_menu_item, cap_story, cap_menu,
|
||||
press_select, press_up, press_down, press_cancel,
|
||||
is_q1):
|
||||
goto_home()
|
||||
# first try that infinite scroll is turned off
|
||||
# home
|
||||
for i in range(10): # settings on 5th in home (10 is way past that)
|
||||
need_keypress(DOWN)
|
||||
press_down()
|
||||
|
||||
# sitting at Logout
|
||||
# one up to get to settings
|
||||
need_keypress(UP)
|
||||
need_keypress("y")
|
||||
if not is_q1:
|
||||
press_up()
|
||||
press_select()
|
||||
menu = cap_menu()
|
||||
# assert we are in settings, meaning we found bottom of home menu
|
||||
assert "Login Settings" in menu
|
||||
|
||||
for i in range(10):
|
||||
need_keypress(UP)
|
||||
press_up()
|
||||
|
||||
need_keypress("y")
|
||||
press_select()
|
||||
menu = cap_menu()
|
||||
# assert we are in Login settings, meaning we found top of settings menu
|
||||
assert "Change Main PIN" in menu
|
||||
need_keypress("x") # back to settings
|
||||
press_cancel() # back to settings
|
||||
pick_menu_item("Menu Wrapping")
|
||||
need_keypress("y")
|
||||
press_select()
|
||||
pick_menu_item("Enable")
|
||||
# back in settings on InfiniteScroll
|
||||
# go 2 positions down and should be on top on Login settings
|
||||
time.sleep(1)
|
||||
for i in range(2):
|
||||
need_keypress(DOWN)
|
||||
need_keypress("y")
|
||||
press_down()
|
||||
press_select()
|
||||
menu = cap_menu()
|
||||
assert "Change Main PIN" in menu
|
||||
need_keypress("x") # back to settings - on login settings
|
||||
press_cancel() # back to settings - on login settings
|
||||
# now go over top and back to Login settings from bottom
|
||||
for i in range(9):
|
||||
need_keypress(UP)
|
||||
need_keypress("y")
|
||||
for i in range(11 if is_q1 else 9):
|
||||
press_up()
|
||||
press_select()
|
||||
menu = cap_menu()
|
||||
assert "Change Main PIN" in menu
|
||||
# disable infinite scroll
|
||||
@ -820,38 +875,39 @@ def test_menu_wrapping(goto_home, pick_menu_item, cap_story, need_keypress, cap_
|
||||
time.sleep(1)
|
||||
# cannot scroll over top now - will land in Login Settings
|
||||
for i in range(15):
|
||||
need_keypress(UP)
|
||||
need_keypress("y")
|
||||
press_up()
|
||||
press_select()
|
||||
menu = cap_menu()
|
||||
assert "Change Main PIN" in menu
|
||||
goto_home()
|
||||
|
||||
def test_chain_changes_settings_xpub(pick_menu_item, need_keypress, goto_home, cap_story):
|
||||
def test_chain_changes_settings_xpub(pick_menu_item, goto_home, cap_story,
|
||||
press_select, press_cancel):
|
||||
goto_home()
|
||||
pick_menu_item("Advanced/Tools")
|
||||
pick_menu_item("View Identity")
|
||||
_, story = cap_story()
|
||||
extended_key = story.split("\n\n")[5]
|
||||
assert extended_key.startswith("tpub")
|
||||
need_keypress("y")
|
||||
press_select()
|
||||
pick_menu_item("Danger Zone")
|
||||
pick_menu_item("Testnet Mode")
|
||||
pick_menu_item("Bitcoin")
|
||||
need_keypress("x") # go back to advanced
|
||||
press_cancel() # go back to advanced
|
||||
time.sleep(0.1)
|
||||
pick_menu_item("View Identity")
|
||||
_, story = cap_story()
|
||||
extended_key = story.split("\n\n")[5]
|
||||
assert extended_key.startswith("xpub")
|
||||
need_keypress("y")
|
||||
press_select()
|
||||
pick_menu_item("Danger Zone")
|
||||
pick_menu_item("Testnet Mode")
|
||||
time.sleep(0.1)
|
||||
_, story = cap_story()
|
||||
assert "Testnet must only be used by developers" in story
|
||||
need_keypress("y")
|
||||
press_select()
|
||||
pick_menu_item("Regtest")
|
||||
need_keypress("x") # go back to advanced
|
||||
press_cancel() # go back to advanced
|
||||
time.sleep(0.1)
|
||||
pick_menu_item("View Identity")
|
||||
_, story = cap_story()
|
||||
@ -860,7 +916,8 @@ def test_chain_changes_settings_xpub(pick_menu_item, need_keypress, goto_home, c
|
||||
|
||||
@pytest.mark.parametrize("f_len", [50, 500, 5000])
|
||||
def test_sign_file_from_list_files(f_len, goto_home, cap_story, pick_menu_item, need_keypress,
|
||||
microsd_path, cap_menu, verify_detached_signature_file):
|
||||
microsd_path, cap_menu, verify_detached_signature_file,
|
||||
press_select):
|
||||
fname = "test_sign_listed.pdf"
|
||||
signame = "test_sign_listed.sig"
|
||||
fpath = microsd_path(fname)
|
||||
@ -876,7 +933,7 @@ def test_sign_file_from_list_files(f_len, goto_home, cap_story, pick_menu_item,
|
||||
time.sleep(0.1)
|
||||
_, story = cap_story()
|
||||
assert 'Lists all files, select one and SHA256(file contents) will be shown' in story
|
||||
need_keypress("y")
|
||||
press_select()
|
||||
pick_menu_item(fname)
|
||||
time.sleep(0.1)
|
||||
_, story = cap_story()
|
||||
@ -888,7 +945,7 @@ def test_sign_file_from_list_files(f_len, goto_home, cap_story, pick_menu_item,
|
||||
time.sleep(0.1)
|
||||
_, story = cap_story()
|
||||
assert f"Signature file {signame} written" in story
|
||||
need_keypress("y")
|
||||
press_select()
|
||||
verify_detached_signature_file([fname], signame, "sd", AF_CLASSIC)
|
||||
_, story = cap_story()
|
||||
assert "(4) to sign file digest and export detached signature" not in story
|
||||
@ -898,18 +955,18 @@ def test_sign_file_from_list_files(f_len, goto_home, cap_story, pick_menu_item,
|
||||
assert "List Files" in menu
|
||||
|
||||
|
||||
def test_bip39_pw_signing_xfp_ux(goto_home, pick_menu_item, need_keypress, cap_story,
|
||||
def test_bip39_pw_signing_xfp_ux(goto_home, pick_menu_item, press_select, cap_story,
|
||||
enter_complex, reset_seed_words, cap_menu):
|
||||
goto_home()
|
||||
pick_menu_item("Passphrase")
|
||||
need_keypress("y")
|
||||
press_select()
|
||||
enter_complex("21coinkite21")
|
||||
pick_menu_item("APPLY")
|
||||
time.sleep(0.3)
|
||||
title, story = cap_story()
|
||||
assert title == "[0C9DC99D]"
|
||||
assert 'Above is the master key fingerprint of the new wallet' in story
|
||||
need_keypress("y") # confirm passphrase
|
||||
press_select() # confirm passphrase
|
||||
m = cap_menu()
|
||||
assert m[0] == "[0C9DC99D]"
|
||||
pick_menu_item("Ready To Sign")
|
||||
|
||||
Loading…
Reference in New Issue
Block a user