You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
188 lines
6.9 KiB
188 lines
6.9 KiB
from common import *
|
|
|
|
from storage.sd_seed_backup import *
|
|
from trezor import io, sdcard
|
|
from trezor.enums import BackupType
|
|
|
|
EMPTY_BLOCK = bytes([0xFF] * io.sdcard.BLOCK_SIZE)
|
|
|
|
|
|
def erase_sdcard(portion: float = 1.0):
|
|
"""
|
|
Helper function to erase a portion of virtual SD card.
|
|
`portion` param is supplied in range [0.0; 1.0].
|
|
|
|
Assumption: virtual SD card is inserted.
|
|
"""
|
|
assert 0.0 <= portion and portion <= 1.0
|
|
assert io.sdcard.is_present()
|
|
with sdcard.filesystem(mounted=False):
|
|
try:
|
|
n_blocks = io.sdcard.capacity() // io.sdcard.BLOCK_SIZE
|
|
for i in range(int(portion * n_blocks)):
|
|
io.sdcard.write(i, EMPTY_BLOCK)
|
|
except Exception:
|
|
pass
|
|
|
|
# TODO: SLIP-39 tests
|
|
|
|
class TestStorageSdSeedBackup(unittest.TestCase):
|
|
def setUp(self):
|
|
self.mnemonic = (
|
|
b"crane mesh that gain predict open dice defy lottery toddler coin upgrade"
|
|
)
|
|
|
|
io.sdcard_inserter.insert(1, capacity_bytes=64 * 1024 * 1024)
|
|
io.sdcard.power_on()
|
|
io.fatfs.mkfs(True)
|
|
|
|
io.fatfs.mount()
|
|
io.fatfs.unmount()
|
|
|
|
def tearDown(self):
|
|
erase_sdcard()
|
|
io.sdcard.power_off()
|
|
io.sdcard_inserter.eject()
|
|
|
|
def test_backup_and_restore_basic(self):
|
|
store_seed_on_sdcard(self.mnemonic, BackupType.Bip39)
|
|
|
|
restored_mnemonic, restored_backup_type = recover_seed_from_sdcard()
|
|
self.assertEqual(restored_mnemonic, self.mnemonic)
|
|
self.assertEqual(restored_backup_type, BackupType.Bip39)
|
|
|
|
def test_backup_and_restore_from_party_wiped(self):
|
|
store_seed_on_sdcard(self.mnemonic, BackupType.Bip39)
|
|
|
|
# wipe half of the card, restore must succeed
|
|
erase_sdcard(portion=0.5)
|
|
restored_mnemonic, restored_backup_type = recover_seed_from_sdcard()
|
|
self.assertEqual(restored_mnemonic, self.mnemonic)
|
|
self.assertEqual(restored_backup_type, BackupType.Bip39)
|
|
|
|
# remove everything, restore fails
|
|
erase_sdcard(portion=1.0)
|
|
restored_mnemonic, restored_backup_type = recover_seed_from_sdcard()
|
|
self.assertEqual(restored_mnemonic, None)
|
|
self.assertEqual(restored_backup_type, None)
|
|
|
|
def test_is_backup_present_on_sdcard(self):
|
|
self.assertFalse(is_backup_present_on_sdcard())
|
|
|
|
store_seed_on_sdcard(self.mnemonic, BackupType.Bip39)
|
|
self.assertTrue(is_backup_present_on_sdcard())
|
|
|
|
erase_sdcard(portion=0.9)
|
|
self.assertTrue(is_backup_present_on_sdcard())
|
|
|
|
def test_check_health_of_backup_sdcard(self):
|
|
store_seed_on_sdcard(self.mnemonic, BackupType.Bip39)
|
|
|
|
# uncorrupted backup
|
|
health = check_health_of_backup_sdcard(self.mnemonic)
|
|
self.assertTrue(health.pt_is_mountable)
|
|
self.assertTrue(health.pt_has_correct_cap)
|
|
self.assertTrue(health.pt_readme_present)
|
|
self.assertTrue(health.pt_readme_content)
|
|
self.assertEqual(health.unalloc_seed_corrupt, 0)
|
|
|
|
# overwrite one seed backup
|
|
with sdcard.filesystem(mounted=False):
|
|
io.sdcard.write(SDBACKUP_BLOCK_START, EMPTY_BLOCK)
|
|
health = check_health_of_backup_sdcard(self.mnemonic)
|
|
self.assertTrue(health.pt_is_mountable)
|
|
self.assertTrue(health.pt_has_correct_cap)
|
|
self.assertTrue(health.pt_readme_present)
|
|
self.assertTrue(health.pt_readme_content)
|
|
self.assertEqual(health.unalloc_seed_corrupt, 1)
|
|
|
|
# change the informative file in FS
|
|
with sdcard.filesystem(mounted=True):
|
|
with fatfs.open(README_PATH, '+') as f:
|
|
f.write(b'abc')
|
|
health = check_health_of_backup_sdcard(self.mnemonic)
|
|
self.assertTrue(health.pt_is_mountable)
|
|
self.assertTrue(health.pt_has_correct_cap)
|
|
self.assertTrue(health.pt_readme_present)
|
|
self.assertFalse(health.pt_readme_content)
|
|
self.assertEqual(health.unalloc_seed_corrupt, 1)
|
|
|
|
|
|
# remove informative file from FS
|
|
with sdcard.filesystem(mounted=True):
|
|
fatfs.unlink(README_PATH)
|
|
health = check_health_of_backup_sdcard(self.mnemonic)
|
|
self.assertTrue(health.pt_is_mountable)
|
|
self.assertTrue(health.pt_has_correct_cap)
|
|
self.assertFalse(health.pt_readme_present)
|
|
self.assertFalse(health.pt_readme_content)
|
|
self.assertEqual(health.unalloc_seed_corrupt, 1)
|
|
|
|
# recreate FS over the whole card
|
|
with sdcard.filesystem(mounted=False):
|
|
fatfs.mkfs()
|
|
health = check_health_of_backup_sdcard(self.mnemonic)
|
|
self.assertTrue(health.pt_is_mountable)
|
|
self.assertFalse(health.pt_has_correct_cap)
|
|
self.assertFalse(health.pt_readme_present)
|
|
self.assertFalse(health.pt_readme_content)
|
|
self.assertEqual(health.unalloc_seed_corrupt, 1)
|
|
|
|
# erase a portion of the card to destory FS partition table
|
|
erase_sdcard(portion=0.1)
|
|
health = check_health_of_backup_sdcard(self.mnemonic)
|
|
self.assertFalse(health.pt_is_mountable)
|
|
self.assertFalse(health.pt_has_correct_cap)
|
|
self.assertFalse(health.pt_readme_present)
|
|
self.assertFalse(health.pt_readme_content)
|
|
self.assertEqual(health.unalloc_seed_corrupt, 1)
|
|
|
|
# erase the whole card
|
|
erase_sdcard(portion=1.0)
|
|
health = check_health_of_backup_sdcard(self.mnemonic)
|
|
self.assertFalse(health.pt_is_mountable)
|
|
self.assertFalse(health.pt_has_correct_cap)
|
|
self.assertFalse(health.pt_readme_present)
|
|
self.assertFalse(health.pt_readme_content)
|
|
self.assertEqual(health.unalloc_seed_corrupt, SDBACKUP_N_WRITINGS)
|
|
|
|
def test_refresh_backup_sdcard(self):
|
|
def assert_backup_health(flg: bool = True) -> None:
|
|
|
|
health = check_health_of_backup_sdcard(self.mnemonic)
|
|
self.assertEqual(flg, health.pt_is_mountable)
|
|
self.assertEqual(flg, health.pt_is_mountable)
|
|
self.assertEqual(flg, health.pt_has_correct_cap)
|
|
self.assertEqual(flg, health.pt_readme_present)
|
|
self.assertEqual(flg, health.pt_readme_content)
|
|
self.assertEqual(health.unalloc_seed_corrupt, 0)
|
|
|
|
store_seed_on_sdcard(self.mnemonic, BackupType.Bip39)
|
|
assert_backup_health()
|
|
|
|
# damage the backup
|
|
erase_sdcard(portion=0.5)
|
|
assert_backup_health(False)
|
|
|
|
# trying to refresh with a different seed must fail
|
|
mnemonic_faulty = (
|
|
b"all all all all all all all all all all all all"
|
|
)
|
|
self.assertFalse(refresh_backup_sdcard(mnemonic_faulty))
|
|
assert_backup_health(False)
|
|
|
|
refresh_backup_sdcard(self.mnemonic)
|
|
assert_backup_health()
|
|
|
|
|
|
def test_wipe_backup_sdcard(self):
|
|
store_seed_on_sdcard(self.mnemonic, BackupType.Bip39)
|
|
self.assertTrue(is_backup_present_on_sdcard())
|
|
|
|
wipe_backup_sdcard()
|
|
self.assertFalse(is_backup_present_on_sdcard())
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|