1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2024-11-26 09:28:13 +00:00

core: update Python facing APIs

This commit is contained in:
matejcik 2020-02-26 19:25:22 +01:00
parent 9ab84d2455
commit 18ac4fc9ca
6 changed files with 118 additions and 109 deletions

View File

@ -1,6 +1,6 @@
import storage.sd_salt import storage.sd_salt
from storage.sd_salt import SD_CARD_HOT_SWAPPABLE from storage.sd_salt import SD_CARD_HOT_SWAPPABLE
from trezor import sdcard, ui, wire from trezor import fatfs, sdcard, ui, wire
from trezor.ui.text import Text from trezor.ui.text import Text
from apps.common.confirm import confirm, hold_to_confirm from apps.common.confirm import confirm, hold_to_confirm
@ -91,8 +91,8 @@ async def ensure_sdcard(
while True: while True:
try: try:
with sdcard.get_filesystem(mounted=False) as fs: with sdcard.filesystem(mounted=False):
fs.mount() fatfs.mount()
# Mount succeeded, filesystem is OK # Mount succeeded, filesystem is OK
return return
except OSError: except OSError:
@ -103,13 +103,18 @@ async def ensure_sdcard(
raise SdCardUnavailable("SD card not formatted.") raise SdCardUnavailable("SD card not formatted.")
try: try:
with sdcard.get_filesystem(mounted=False) as fs: with sdcard.filesystem(mounted=False):
fs.mkfs() fatfs.mkfs()
# mkfs succeeded. Re-run loop to retry mounting. fatfs.mount()
continue fatfs.setlabel("TREZOR")
# mkfs and mount succeeded
return
except OSError: except OSError:
if not await sd_problem_dialog(ctx): pass
raise SdCardUnavailable("Problem formatting SD card.")
# allow retry if we get as far as here
if not await sd_problem_dialog(ctx):
raise SdCardUnavailable("Problem formatting SD card.")
async def request_sd_salt( async def request_sd_salt(

View File

@ -145,8 +145,7 @@ if __debug__:
try: try:
io.sdcard.power_on() io.sdcard.power_on()
if msg.format: if msg.format:
fs = io.FatFS() io.fatfs.mkfs()
fs.mkfs()
else: else:
# trash first 1 MB of data to destroy the FAT filesystem # trash first 1 MB of data to destroy the FAT filesystem
assert io.sdcard.capacity() >= 1024 * 1024 assert io.sdcard.capacity() >= 1024 * 1024

View File

@ -1,13 +1,13 @@
from micropython import const from micropython import const
import storage.device import storage.device
from trezor import fatfs
from trezor.crypto import hmac from trezor.crypto import hmac
from trezor.crypto.hashlib import sha256 from trezor.crypto.hashlib import sha256
from trezor.sdcard import get_filesystem from trezor.sdcard import with_filesystem
from trezor.utils import consteq from trezor.utils import consteq
if False: if False:
from trezor import io
from typing import Optional, TypeVar, Callable from typing import Optional, TypeVar, Callable
T = TypeVar("T", bound=Callable) T = TypeVar("T", bound=Callable)
@ -38,10 +38,11 @@ def _get_salt_path(new: bool = False) -> str:
return "{}/salt{}".format(_get_device_dir(), ".new" if new else "") return "{}/salt{}".format(_get_device_dir(), ".new" if new else "")
def _load_salt(fs: io.FatFS, auth_key: bytes, path: str) -> Optional[bytearray]: @with_filesystem
def _load_salt(auth_key: bytes, path: str) -> Optional[bytearray]:
# Load the salt file if it exists. # Load the salt file if it exists.
try: try:
with fs.open(path, "r") as f: with fatfs.open(path, "r") as f:
salt = bytearray(SD_SALT_LEN_BYTES) salt = bytearray(SD_SALT_LEN_BYTES)
stored_tag = bytearray(SD_SALT_AUTH_TAG_LEN_BYTES) stored_tag = bytearray(SD_SALT_AUTH_TAG_LEN_BYTES)
f.read(salt) f.read(salt)
@ -57,6 +58,7 @@ def _load_salt(fs: io.FatFS, auth_key: bytes, path: str) -> Optional[bytearray]:
return salt return salt
@with_filesystem
def load_sd_salt() -> Optional[bytearray]: def load_sd_salt() -> Optional[bytearray]:
salt_auth_key = storage.device.get_sd_salt_auth_key() salt_auth_key = storage.device.get_sd_salt_auth_key()
if salt_auth_key is None: if salt_auth_key is None:
@ -65,55 +67,54 @@ def load_sd_salt() -> Optional[bytearray]:
salt_path = _get_salt_path() salt_path = _get_salt_path()
new_salt_path = _get_salt_path(new=True) new_salt_path = _get_salt_path(new=True)
with get_filesystem() as fs: salt = _load_salt(salt_auth_key, salt_path)
salt = _load_salt(fs, salt_auth_key, salt_path) if salt is not None:
if salt is not None:
return salt
# Check if there is a new salt.
salt = _load_salt(fs, salt_auth_key, new_salt_path)
if salt is None:
# No valid salt file on this SD card.
raise WrongSdCard
# Normal salt file does not exist, but new salt file exists. That means that
# SD salt regeneration was interrupted earlier. Bring into consistent state.
# TODO Possibly overwrite salt file with random data.
try:
fs.unlink(salt_path)
except OSError:
pass
# fs.rename can fail with a write error, which falls through as an OSError.
# This should be handled in calling code, by allowing the user to retry.
fs.rename(new_salt_path, salt_path)
return salt return salt
# Check if there is a new salt.
salt = _load_salt(salt_auth_key, new_salt_path)
if salt is None:
# No valid salt file on this SD card.
raise WrongSdCard
# Normal salt file does not exist, but new salt file exists. That means that
# SD salt regeneration was interrupted earlier. Bring into consistent state.
# TODO Possibly overwrite salt file with random data.
try:
fatfs.unlink(salt_path)
except OSError:
pass
# fatfs.rename can fail with a write error, which falls through as an OSError.
# This should be handled in calling code, by allowing the user to retry.
fatfs.rename(new_salt_path, salt_path)
return salt
@with_filesystem
def set_sd_salt(salt: bytes, salt_tag: bytes, stage: bool = False) -> None: def set_sd_salt(salt: bytes, salt_tag: bytes, stage: bool = False) -> None:
salt_path = _get_salt_path(stage) salt_path = _get_salt_path(stage)
with get_filesystem() as fs: fatfs.mkdir("/trezor", True)
fs.mkdir("/trezor", True) fatfs.mkdir(_get_device_dir(), True)
fs.mkdir(_get_device_dir(), True) with fatfs.open(salt_path, "w") as f:
with fs.open(salt_path, "w") as f: f.write(salt)
f.write(salt) f.write(salt_tag)
f.write(salt_tag)
@with_filesystem
def commit_sd_salt() -> None: def commit_sd_salt() -> None:
salt_path = _get_salt_path(new=False) salt_path = _get_salt_path(new=False)
new_salt_path = _get_salt_path(new=True) new_salt_path = _get_salt_path(new=True)
with get_filesystem() as fs: try:
try: fatfs.unlink(salt_path)
fs.unlink(salt_path) except OSError:
except OSError: pass
pass fatfs.rename(new_salt_path, salt_path)
fs.rename(new_salt_path, salt_path)
@with_filesystem
def remove_sd_salt() -> None: def remove_sd_salt() -> None:
salt_path = _get_salt_path() salt_path = _get_salt_path()
with get_filesystem() as fs: # TODO Possibly overwrite salt file with random data.
# TODO Possibly overwrite salt file with random data. fatfs.unlink(salt_path)
fs.unlink(salt_path)

View File

@ -1,2 +1,4 @@
import trezorconfig as config # noqa: F401 import trezorconfig as config # noqa: F401
import trezorio as io # noqa: F401 import trezorio as io # noqa: F401
fatfs = io.fatfs

View File

@ -1,14 +1,15 @@
from trezorio import FatFS, sdcard from trezorio import fatfs, sdcard
if False: if False:
from typing import Any, Optional from typing import Any, Callable, Optional, TypeVar
T = TypeVar("T", bound=Callable)
class FilesystemWrapper: class FilesystemWrapper:
_INSTANCE = None # type: Optional[FilesystemWrapper] _INSTANCE = None # type: Optional[FilesystemWrapper]
def __init__(self, mounted: bool) -> None: def __init__(self, mounted: bool) -> None:
self.fs = FatFS()
self.mounted = mounted self.mounted = mounted
self.counter = 0 self.counter = 0
@ -21,20 +22,18 @@ class FilesystemWrapper:
return cls._INSTANCE return cls._INSTANCE
def _deinit_instance(self) -> None: def _deinit_instance(self) -> None:
if self.mounted: fatfs.unmount()
self.fs.unmount()
sdcard.power_off() sdcard.power_off()
FilesystemWrapper._INSTANCE = None FilesystemWrapper._INSTANCE = None
def __enter__(self) -> "FatFS": def __enter__(self) -> None:
try: try:
if self.counter <= 0: if self.counter <= 0:
self.counter = 0 self.counter = 0
sdcard.power_on() sdcard.power_on()
if self.mounted: if self.mounted:
self.fs.mount() fatfs.mount()
self.counter += 1 self.counter += 1
return self.fs
except Exception: except Exception:
self._deinit_instance() self._deinit_instance()
raise raise
@ -46,8 +45,17 @@ class FilesystemWrapper:
self._deinit_instance() self._deinit_instance()
def get_filesystem(mounted: bool = True) -> FilesystemWrapper: def filesystem(mounted: bool = True) -> FilesystemWrapper:
return FilesystemWrapper.get_instance(mounted=mounted) return FilesystemWrapper.get_instance(mounted=mounted)
def with_filesystem(func: T) -> T:
def wrapped_func(*args, **kwargs) -> Any: # type: ignore
with filesystem():
return func(*args, **kwargs)
return wrapped_func # type: ignore
is_present = sdcard.is_present is_present = sdcard.is_present
capacity = sdcard.capacity

View File

@ -1,75 +1,68 @@
from common import * from common import *
from trezor import io, sdcard from trezor import io, fatfs, sdcard
class TestTrezorSdcard(unittest.TestCase): class TestTrezorSdcard(unittest.TestCase):
def test_power(self): def test_power(self):
# io.sdcard.capacity() will return 0 if the card is not powered, # sdcard.capacity() will return 0 if the card is not powered,
# non-zero value otherwise # non-zero value otherwise
self.assertEqual(io.sdcard.capacity(), 0) self.assertEqual(sdcard.capacity(), 0)
with sdcard.get_filesystem(mounted=False): with sdcard.filesystem(mounted=False):
self.assertTrue(io.sdcard.capacity() > 0) self.assertTrue(sdcard.capacity() > 0)
self.assertEqual(io.sdcard.capacity(), 0) self.assertEqual(sdcard.capacity(), 0)
def test_nomount(self): def test_nomount(self):
with sdcard.get_filesystem(mounted=False) as fs: with sdcard.filesystem(mounted=False):
with self.assertRaises(OSError): self.assertFalse(fatfs.is_mounted())
fs.listdir("/")
def test_mount(self): def test_mount(self):
# set up a filesystem first # set up a filesystem first
with sdcard.get_filesystem(mounted=False) as fs: with sdcard.filesystem(mounted=False):
fs.mkfs() fatfs.mkfs()
with sdcard.get_filesystem() as fs: with sdcard.filesystem():
# the following should succeed self.assertTrue(fatfs.is_mounted())
fs.listdir("/")
# filesystem should not be available self.assertFalse(fatfs.is_mounted())
with self.assertRaises(OSError):
fs.listdir("/")
def test_nesting(self): def test_nesting(self):
# set up a filesystem first # set up a filesystem first
with sdcard.get_filesystem(mounted=False) as fs: with sdcard.filesystem(mounted=False):
fs.mkfs() fatfs.mkfs()
self.assertEqual(io.sdcard.capacity(), 0) self.assertEqual(sdcard.capacity(), 0)
with sdcard.get_filesystem() as fs_a: with sdcard.filesystem():
self.assertTrue(io.sdcard.capacity() > 0) self.assertTrue(sdcard.capacity() > 0)
with sdcard.get_filesystem() as fs_b: self.assertTrue(fatfs.is_mounted())
self.assertTrue(io.sdcard.capacity() > 0) with sdcard.filesystem():
self.assertIs(fs_a, fs_b) self.assertTrue(sdcard.capacity() > 0)
fs_b.listdir("/") self.assertTrue(fatfs.is_mounted())
self.assertTrue(io.sdcard.capacity() > 0)
# filesystem should still be mounted
fs_a.listdir("/")
self.assertEqual(io.sdcard.capacity(), 0) self.assertTrue(sdcard.capacity() > 0)
# filesystem should not be available self.assertTrue(fatfs.is_mounted())
with self.assertRaises(OSError):
fs_a.listdir("/") self.assertEqual(sdcard.capacity(), 0)
self.assertFalse(fatfs.is_mounted())
def test_mount_nomount(self): def test_mount_nomount(self):
with self.assertRaises(RuntimeError): with self.assertRaises(RuntimeError):
with sdcard.get_filesystem(mounted=True): with sdcard.filesystem(mounted=True):
with sdcard.get_filesystem(mounted=False): with sdcard.filesystem(mounted=False):
pass pass
with self.assertRaises(RuntimeError): with self.assertRaises(RuntimeError):
with sdcard.get_filesystem(mounted=False): with sdcard.filesystem(mounted=False):
with sdcard.get_filesystem(mounted=True): with sdcard.filesystem(mounted=True):
pass pass
def test_failed_mount(self): def test_failed_mount(self):
# set up a filesystem first # set up a filesystem first
with sdcard.get_filesystem(mounted=False) as fs: with sdcard.filesystem(mounted=False):
fs.mkfs() fatfs.mkfs()
with sdcard.get_filesystem() as fs: with sdcard.filesystem():
# the following should succeed self.assertTrue(fatfs.is_mounted())
fs.listdir("/")
# trash filesystem # trash filesystem
io.sdcard.power_on() io.sdcard.power_on()
@ -78,17 +71,18 @@ class TestTrezorSdcard(unittest.TestCase):
# mounting should now fail # mounting should now fail
with self.assertRaises(OSError): with self.assertRaises(OSError):
with sdcard.get_filesystem() as fs: with sdcard.filesystem():
pass pass
self.assertFalse(fatfs.is_mounted())
# it should be possible to create an unmounted instance # it should be possible to create an unmounted instance
with sdcard.get_filesystem(mounted=False) as fs: with sdcard.filesystem(mounted=False):
fs.mkfs() fatfs.mkfs()
# mounting should now succeed # mounting should now succeed
with sdcard.get_filesystem() as fs: with sdcard.filesystem():
fs.listdir("/") self.assertTrue(fatfs.is_mounted())
if __name__ == "__main__": if __name__ == "__main__":