firmware/testing/devtest/backups.py
2020-11-18 14:19:14 -05:00

133 lines
4.0 KiB
Python

# (c) Copyright 2020 by Coinkite Inc. All rights reserved.
#
# Unit test for shared/backups.py
#
# this will run on the simulator only
# run manually with:
# execfile('../../testing/devtest/backups.py')
from ubinascii import hexlify as b2a_hex
from ubinascii import unhexlify as a2b_hex
import tcc, ustruct
from main import settings, sf
if 1:
# test file contents: completeness, syntax
from backups import render_backup_contents
comments = 0
blanks = 0
checklist = set('mnemonic chain xprv xpub raw_secret fw_date fw_version fw_timestamp serial '
'setting.terms_ok setting.idle_to setting.chain'.split(' '))
optional = set('setting.pms setting.axi setting.nick setting.lgto setting.usr hsm_policy setting.words long_secret multisig setting.multisig setting.fee_limit'.split(' '))
for ln in render_backup_contents().split('\n'):
ln = ln.strip()
if not ln:
blanks += 1
continue
if ln[0] == '#':
comments += 1
continue
assert '=' in ln, ln
k, v = ln.split(' = ', 1)
assert v and k
assert (k in checklist) or (k in optional), "Unknown key: "+k
checklist.discard(k)
assert not checklist, "Missing: %r" % checklist
assert comments >= 4
assert blanks >= 3
async def test_7z():
# test full 7z round-trip
# Altho cleartext mode is not for real, if the code is written, I must test it.
from backups import write_complete_backup, restore_complete_doit
from sffile import SFFile
import tcc, version, uos
from main import settings, sf, numpad, pa
if version.has_fatram:
import hsm
had_policy = hsm.hsm_policy_available()
else:
had_policy = False
today = tcc.random.uniform(1000000)
import machine
machine.reset = lambda: None
for chain in ['BTC', 'XTN']:
for words in ( [], ['abc', 'def'] ):
settings.set('check', today)
settings.set('chain', chain)
if version.has_608:
ls = b'%416d' % today
pa.ls_change(ls)
ll, sha = await write_complete_backup(words, None, True)
result = SFFile(0, ll).read()
if words:
#open('debug.7z', 'wb').write(result)
assert ll > 800
assert len(sha) == 32
assert result[0:6] == b"7z\xbc\xaf'\x1c"
assert tcc.sha256(result).digest() == sha
assert len(set(result)) >= 240 # encrypted
else:
sr = str(result, 'ascii')
print("Backup contents:\n" + sr)
assert sr[0] == '#', result
assert 'Coldcard' in sr
assert len(set(sr)) < 100 # cleartext, english
assert ('chain = "%s"' % chain) in result
# test restore
# - cant wipe flash, since the backup file is there
# - cant wipe all settings becuase PIN and stuff is simulated there
del settings.current['check']
if had_policy:
from hsm import POLICY_FNAME
uos.unlink(POLICY_FNAME)
assert not hsm.hsm_policy_available()
with SFFile(0, ll) as fd:
numpad.inject('y') # for 'success' message
await restore_complete_doit(fd, words)
assert settings.get('check') == today, \
(settings.get('check'), '!=', today)
assert settings.get('chain') == chain, \
(settings.get('chain'), '!=', chain)
if version.has_608:
assert pa.ls_fetch() == ls
if had_policy:
assert had_policy == hsm.hsm_policy_available()
today += 3
import ux
ux.restore_menu()
from main import loop
loop.run_until_complete(test_7z())
# test recovery/reset
sf.chip_erase()
settings.load()
# EOF