From d7b95823867d064b879573e4829f33ea5d68a065 Mon Sep 17 00:00:00 2001 From: matejcik Date: Fri, 21 Feb 2020 15:53:53 +0100 Subject: [PATCH] core/sdcard: add ensure_filesystem option (fixes #868) It is possible to call `ensure_sdcard` in a way that requires only SD card be inserted, but not necessarily formatted. This is useful for SD-protect and possibly other use-cases where the SD card is read-only, and "not formatted" is identical to "not containing the right files". --- core/src/apps/common/sdcard.py | 20 +++++++-- tests/device_tests/test_sdcard.py | 67 +++++++++++++++++++++++++++++++ tests/ui_tests/fixtures.json | 1 + 3 files changed, 85 insertions(+), 3 deletions(-) diff --git a/core/src/apps/common/sdcard.py b/core/src/apps/common/sdcard.py index 34c9a667d..56a0dd2d4 100644 --- a/core/src/apps/common/sdcard.py +++ b/core/src/apps/common/sdcard.py @@ -70,11 +70,25 @@ async def sd_problem_dialog(ctx: wire.GenericContext) -> bool: return await confirm(ctx, text, confirm="Retry", cancel="Abort") -async def ensure_sdcard(ctx: wire.GenericContext) -> None: +async def ensure_sdcard( + ctx: wire.GenericContext, ensure_filesystem: bool = True +) -> None: + """Ensure a SD card is ready for use. + + This function runs the UI flow needed to ask the user to insert a SD card if there + isn't one. + + If `ensure_filesystem` is True (the default), it also tries to mount the SD card + filesystem, and allows the user to format the card if a filesystem cannot be + mounted. + """ while not sdcard.is_present(): if not await insert_card_dialog(ctx): raise SdCardUnavailable("SD card required.") + if not ensure_filesystem: + return + while True: try: with sdcard.get_filesystem(mounted=False) as fs: @@ -105,7 +119,7 @@ async def request_sd_salt( return None while True: - await ensure_sdcard(ctx) + await ensure_sdcard(ctx, ensure_filesystem=False) try: return storage.sd_salt.load_sd_salt() except storage.sd_salt.WrongSdCard: @@ -117,4 +131,4 @@ async def request_sd_salt( # In either case, there is no good way to recover. If the user clicks Retry, # we will try again. if not await sd_problem_dialog(ctx): - raise + raise SdCardUnavailable("Error accessing SD card.") diff --git a/tests/device_tests/test_sdcard.py b/tests/device_tests/test_sdcard.py index 36bd019be..7f9b36519 100644 --- a/tests/device_tests/test_sdcard.py +++ b/tests/device_tests/test_sdcard.py @@ -43,3 +43,70 @@ def test_sd_no_format(client): device.sd_protect(client, Op.ENABLE) assert e.value.failure.code == messages.FailureType.ProcessError + + +@pytest.mark.sd_card +@pytest.mark.setup_client(pin="1234") +def test_sd_protect_unlock(client): + def input_flow_enable_sd_protect(): + yield # do you really want to enable SD protection + assert "SD card protection" in client.debug.wait_layout().text + client.debug.press_yes() + + yield # enter current PIN + assert "PinDialog" == client.debug.wait_layout().text + client.debug.input("1234") + + yield # you have successfully enabled SD protection + assert "Success" in client.debug.wait_layout().text + client.debug.press_yes() + + with client: + client.set_input_flow(input_flow_enable_sd_protect) + device.sd_protect(client, Op.ENABLE) + + def input_flow_change_pin(): + yield # do you really want to change PIN? + assert "Change PIN" in client.debug.wait_layout().text + client.debug.press_yes() + + yield # enter current PIN + assert "PinDialog" == client.debug.wait_layout().text + client.debug.input("1234") + + yield # enter new PIN + assert "PinDialog" == client.debug.wait_layout().text + client.debug.input("1234") + + yield # enter new PIN again + assert "PinDialog" == client.debug.wait_layout().text + client.debug.input("1234") + + yield # Pin change successful + assert "Success" in client.debug.wait_layout().text + client.debug.press_yes() + + with client: + client.set_input_flow(input_flow_change_pin) + device.change_pin(client) + + client.debug.erase_sd_card(format=False) + + def input_flow_change_pin_format(): + yield # do you really want to change PIN? + assert "Change PIN" in client.debug.wait_layout().text + client.debug.press_yes() + + yield # SD card problem + assert "SD card problem" in client.debug.wait_layout().text + client.debug.press_yes() # retry + + yield # still SD card problem + assert "SD card problem" in client.debug.wait_layout().text + client.debug.press_no() # do not retry + + with client, pytest.raises(TrezorFailure) as e: + client.set_input_flow(input_flow_change_pin_format) + device.change_pin(client) + + assert e.value.failure.code == messages.FailureType.ProcessError diff --git a/tests/ui_tests/fixtures.json b/tests/ui_tests/fixtures.json index e5e373a40..c51b3244e 100644 --- a/tests/ui_tests/fixtures.json +++ b/tests/ui_tests/fixtures.json @@ -388,6 +388,7 @@ "test_reset_backup.py::test_skip_backup_msg[2-backup_flow_slip39_advanced]": "df213fe327a775563fd8c442ed1ed2dfe5053d56d50307059292d5a5fe091b4c", "test_sdcard.py::test_sd_format": "e0da54c8a26386bff4eb310e9c7ebaa56a02fed3870f976d1dd3b230750a28fe", "test_sdcard.py::test_sd_no_format": "f47e897caee95cf98c1b4506732825f853c4b8afcdc2713e38e3b4055973c9ac", +"test_sdcard.py::test_sd_protect_unlock": "0b6cb625b59256552505575bce75fb0895b935d574f2a07ac4a5246d608252af", "test_u2f_counter.py::test_u2f_counter": "7d96a4d262b9d8a2c1158ac1e5f0f7b2c3ed5f2ba9d6235a014320313f9488fe", "test_zerosig.py-test_one_zero_signature": "401aeaf7b2f565e2064a3c1a57a8ee3afe1e9bf251fba0874390685e7e0f178f", "test_zerosig.py-test_two_zero_signature": "7a01a057fb5dd3e6e38e7986875c5d07f0700bd80b519660e0b42973a9afd664"