diff --git a/core/CHANGELOG.md b/core/CHANGELOG.md index 7276e63bc..8fd970356 100644 --- a/core/CHANGELOG.md +++ b/core/CHANGELOG.md @@ -25,6 +25,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ### Fixed - CRW addresses are properly generated. [#1139] +- Fix boot loop after uploading invalid homescreen. [#1118] ### Security @@ -265,6 +266,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). [#1089]: https://github.com/trezor/trezor-firmware/issues/1089 [#1098]: https://github.com/trezor/trezor-firmware/issues/1098 [#1115]: https://github.com/trezor/trezor-firmware/issues/1115 +[#1118]: https://github.com/trezor/trezor-firmware/issues/1118 [#1126]: https://github.com/trezor/trezor-firmware/issues/1126 [#1139]: https://github.com/trezor/trezor-firmware/issues/1139 [#1159]: https://github.com/trezor/trezor-firmware/issues/1159 diff --git a/core/embed/extmod/modtrezorui/display.c b/core/embed/extmod/modtrezorui/display.c index d1b5ca1cc..642f6061f 100644 --- a/core/embed/extmod/modtrezorui/display.c +++ b/core/embed/extmod/modtrezorui/display.c @@ -349,6 +349,37 @@ void display_icon(int x, int y, int w, int h, const void *data, } } +// see docs/misc/toif.md for defintion of the TOIF format +bool display_toif_info(const uint8_t *data, uint32_t len, uint16_t *out_w, + uint16_t *out_h, bool *out_grayscale) { + if (len < 12 || memcmp(data, "TOI", 3) != 0) { + return false; + } + bool grayscale = false; + if (data[3] == 'f') { + grayscale = false; + } else if (data[3] == 'g') { + grayscale = true; + } else { + return false; + } + + uint16_t w = *(uint16_t *)(data + 4); + uint16_t h = *(uint16_t *)(data + 6); + + uint32_t datalen = *(uint32_t *)(data + 8); + if (datalen != len - 12) { + return false; + } + + if (out_w != NULL && out_h != NULL && out_grayscale != NULL) { + *out_w = w; + *out_h = h; + *out_grayscale = grayscale; + } + return true; +} + #if TREZOR_MODEL == T #include "loader.h" #endif diff --git a/core/embed/extmod/modtrezorui/display.h b/core/embed/extmod/modtrezorui/display.h index 7aa7ec2fe..2d8585065 100644 --- a/core/embed/extmod/modtrezorui/display.h +++ b/core/embed/extmod/modtrezorui/display.h @@ -77,6 +77,8 @@ void display_bar(int x, int y, int w, int h, uint16_t c); void display_bar_radius(int x, int y, int w, int h, uint16_t c, uint16_t b, uint8_t r); +bool display_toif_info(const uint8_t *buf, uint32_t len, uint16_t *out_w, + uint16_t *out_h, bool *out_grayscale); void display_image(int x, int y, int w, int h, const void *data, uint32_t datalen); void display_avatar(int x, int y, const void *data, uint32_t datalen, diff --git a/core/embed/extmod/modtrezorui/modtrezorui-display.h b/core/embed/extmod/modtrezorui/modtrezorui-display.h index 2414e8254..1fbd2c7ae 100644 --- a/core/embed/extmod/modtrezorui/modtrezorui-display.h +++ b/core/embed/extmod/modtrezorui/modtrezorui-display.h @@ -118,6 +118,33 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorui_Display_bar_radius_obj, 8, 8, mod_trezorui_Display_bar_radius); +/// def toif_info(self, image: bytes) -> Tuple[int, int, bool]: +/// """ +/// Returns tuple containing TOIF image dimensions: width, height, and +/// whether it is grayscale. +/// Raises an exception for corrupted images. +/// """ +STATIC mp_obj_t mod_trezorui_Display_toif_info(mp_obj_t self, mp_obj_t image) { + mp_buffer_info_t buffer = {0}; + mp_get_buffer_raise(image, &buffer, MP_BUFFER_READ); + + uint16_t w = 0; + uint16_t h = 0; + bool grayscale = false; + bool valid = display_toif_info(buffer.buf, buffer.len, &w, &h, &grayscale); + + if (!valid) { + mp_raise_ValueError("Invalid image format"); + } + mp_obj_tuple_t *tuple = MP_OBJ_TO_PTR(mp_obj_new_tuple(3, NULL)); + tuple->items[0] = MP_OBJ_NEW_SMALL_INT(w); + tuple->items[1] = MP_OBJ_NEW_SMALL_INT(h); + tuple->items[2] = mp_obj_new_bool(grayscale); + return MP_OBJ_FROM_PTR(tuple); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorui_Display_toif_info_obj, + mod_trezorui_Display_toif_info); + /// def image(self, x: int, y: int, image: bytes) -> None: /// """ /// Renders an image at position (x,y). @@ -131,16 +158,15 @@ STATIC mp_obj_t mod_trezorui_Display_image(size_t n_args, mp_buffer_info_t image = {0}; mp_get_buffer_raise(args[3], &image, MP_BUFFER_READ); const uint8_t *data = image.buf; - if (image.len < 8 || memcmp(data, "TOIf", 4) != 0) { + + uint16_t w = 0; + uint16_t h = 0; + bool grayscale = false; + bool valid = display_toif_info(data, image.len, &w, &h, &grayscale); + if (!valid || grayscale) { mp_raise_ValueError("Invalid image format"); } - mp_int_t w = *(uint16_t *)(data + 4); - mp_int_t h = *(uint16_t *)(data + 6); - uint32_t datalen = *(uint32_t *)(data + 8); - if (datalen != image.len - 12) { - mp_raise_ValueError("Invalid size of data"); - } - display_image(x, y, w, h, data + 12, datalen); + display_image(x, y, w, h, data + 12, image.len - 12); return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorui_Display_image_obj, 4, 4, @@ -162,21 +188,20 @@ STATIC mp_obj_t mod_trezorui_Display_avatar(size_t n_args, mp_buffer_info_t image = {0}; mp_get_buffer_raise(args[3], &image, MP_BUFFER_READ); const uint8_t *data = image.buf; - if (image.len < 8 || memcmp(data, "TOIf", 4) != 0) { + + uint16_t w = 0; + uint16_t h = 0; + bool grayscale = false; + bool valid = display_toif_info(data, image.len, &w, &h, &grayscale); + if (!valid || grayscale) { mp_raise_ValueError("Invalid image format"); } - mp_int_t w = *(uint16_t *)(data + 4); - mp_int_t h = *(uint16_t *)(data + 6); if (w != AVATAR_IMAGE_SIZE || h != AVATAR_IMAGE_SIZE) { mp_raise_ValueError("Invalid image size"); } - uint32_t datalen = *(uint32_t *)(data + 8); - if (datalen != image.len - 12) { - mp_raise_ValueError("Invalid size of data"); - } mp_int_t fgcolor = mp_obj_get_int(args[4]); mp_int_t bgcolor = mp_obj_get_int(args[5]); - display_avatar(x, y, data + 12, datalen, fgcolor, bgcolor); + display_avatar(x, y, data + 12, image.len - 12, fgcolor, bgcolor); return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorui_Display_avatar_obj, 6, @@ -196,15 +221,14 @@ STATIC mp_obj_t mod_trezorui_Display_icon(size_t n_args, const mp_obj_t *args) { mp_buffer_info_t icon = {0}; mp_get_buffer_raise(args[3], &icon, MP_BUFFER_READ); const uint8_t *data = icon.buf; - if (icon.len < 8 || memcmp(data, "TOIg", 4) != 0) { + + uint16_t w = 0; + uint16_t h = 0; + bool grayscale = false; + bool valid = display_toif_info(data, icon.len, &w, &h, &grayscale); + if (!valid || !grayscale) { mp_raise_ValueError("Invalid image format"); } - mp_int_t w = *(uint16_t *)(data + 4); - mp_int_t h = *(uint16_t *)(data + 6); - uint32_t datalen = *(uint32_t *)(data + 8); - if (datalen != icon.len - 12) { - mp_raise_ValueError("Invalid size of data"); - } mp_int_t fgcolor = mp_obj_get_int(args[4]); mp_int_t bgcolor = mp_obj_get_int(args[5]); display_icon(x, y, w, h, data + 12, icon.len - 12, fgcolor, bgcolor); @@ -545,6 +569,8 @@ STATIC const mp_rom_map_elem_t mod_trezorui_Display_locals_dict_table[] = { {MP_ROM_QSTR(MP_QSTR_bar), MP_ROM_PTR(&mod_trezorui_Display_bar_obj)}, {MP_ROM_QSTR(MP_QSTR_bar_radius), MP_ROM_PTR(&mod_trezorui_Display_bar_radius_obj)}, + {MP_ROM_QSTR(MP_QSTR_toif_info), + MP_ROM_PTR(&mod_trezorui_Display_toif_info_obj)}, {MP_ROM_QSTR(MP_QSTR_image), MP_ROM_PTR(&mod_trezorui_Display_image_obj)}, {MP_ROM_QSTR(MP_QSTR_avatar), MP_ROM_PTR(&mod_trezorui_Display_avatar_obj)}, {MP_ROM_QSTR(MP_QSTR_icon), MP_ROM_PTR(&mod_trezorui_Display_icon_obj)}, diff --git a/core/mocks/generated/trezorui.pyi b/core/mocks/generated/trezorui.pyi index 36e154825..c122d5d96 100644 --- a/core/mocks/generated/trezorui.pyi +++ b/core/mocks/generated/trezorui.pyi @@ -50,6 +50,13 @@ class Display: are drawn with radius radius. """ + def toif_info(self, image: bytes) -> Tuple[int, int, bool]: + """ + Returns tuple containing TOIF image dimensions: width, height, and + whether it is grayscale. + Raises an exception for corrupted images. + """ + def image(self, x: int, y: int, image: bytes) -> None: """ Renders an image at position (x,y). diff --git a/core/src/apps/management/apply_settings.py b/core/src/apps/management/apply_settings.py index 4bb80d951..c40af29f0 100644 --- a/core/src/apps/management/apply_settings.py +++ b/core/src/apps/management/apply_settings.py @@ -12,6 +12,27 @@ if False: from trezor.messages.ApplySettings import ApplySettings, EnumTypeSafetyCheckLevel +def validate_homescreen(homescreen: bytes) -> None: + if homescreen == b"": + return + + if len(homescreen) > storage.device.HOMESCREEN_MAXSIZE: + raise wire.DataError( + "Homescreen is too large, maximum size is {} bytes".format( + storage.device.HOMESCREEN_MAXSIZE + ) + ) + + try: + w, h, grayscale = ui.display.toif_info(homescreen) + except ValueError: + raise wire.DataError("Invalid homescreen") + if w != 144 or h != 144: + raise wire.DataError("Homescreen must be 144x144 pixel large") + if grayscale: + raise wire.DataError("Homescreen must be full-color TOIF image") + + async def apply_settings(ctx: wire.Context, msg: ApplySettings): if not storage.device.is_initialized(): raise wire.NotInitialized("Device is not initialized") @@ -27,8 +48,7 @@ async def apply_settings(ctx: wire.Context, msg: ApplySettings): raise wire.ProcessError("No setting provided") if msg.homescreen is not None: - if len(msg.homescreen) > storage.device.HOMESCREEN_MAXSIZE: - raise wire.DataError("Homescreen is too complex") + validate_homescreen(msg.homescreen) await require_confirm_change_homescreen(ctx) try: storage.device.set_homescreen(msg.homescreen) diff --git a/core/src/storage/device.py b/core/src/storage/device.py index 5e222d8d9..05478d168 100644 --- a/core/src/storage/device.py +++ b/core/src/storage/device.py @@ -138,10 +138,7 @@ def get_homescreen() -> Optional[bytes]: def set_homescreen(homescreen: bytes) -> None: if len(homescreen) > HOMESCREEN_MAXSIZE: raise ValueError # homescreen too large - if homescreen[:8] == b"TOIf\x90\x00\x90\x00" or homescreen == b"": - common.set(_NAMESPACE, _HOMESCREEN, homescreen, public=True) - else: - raise ValueError # invalid homescreen + common.set(_NAMESPACE, _HOMESCREEN, homescreen, public=True) def store_mnemonic_secret( diff --git a/tests/device_tests/test_msg_applysettings.py b/tests/device_tests/test_msg_applysettings.py index e04ce3c41..c9951e3fa 100644 --- a/tests/device_tests/test_msg_applysettings.py +++ b/tests/device_tests/test_msg_applysettings.py @@ -115,6 +115,39 @@ class TestMsgApplysettings: assert client.features.passphrase_protection is True assert client.features.passphrase_always_on_device is False + @pytest.mark.skip_t1 + def test_apply_homescreen_toif(self, client): + img = b"TOIf\x90\x00\x90\x00~\x00\x00\x00\xed\xd2\xcb\r\x83@\x10D\xc1^.\xde#!\xac31\x99\x10\x8aC%\x14~\x16\x92Y9\x02WI3\x01<\xf5cI2d\x1es(\xe1[\xdbn\xba\xca\xe8s7\xa4\xd5\xd4\xb3\x13\xbdw\xf6:\xf3\xd1\xe7%\xc7]\xdd_\xb3\x9e\x9f\x9e\x9fN\xed\xaaE\xef\xdc\xcf$D\xa7\xa4X\r\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf0OV" + + with client: + _set_expected_responses(client) + device.apply_settings(client, homescreen=img) + + client.set_expected_responses(EXPECTED_RESPONSES_NOPIN) + device.apply_settings(client, homescreen=b"") + + @pytest.mark.parametrize( + "toif_data", + [ + # incomplete header + b"TOIf\x90\00\x90\x00~" + # wrong magic + b"XXXf\x90\x00\x90\x00~\x00\x00\x00\xed\xd2\xcb\r\x83@\x10D\xc1^.\xde#!\xac31\x99\x10\x8aC%\x14~\x16\x92Y9\x02WI3\x01<\xf5cI2d\x1es(\xe1[\xdbn\xba\xca\xe8s7\xa4\xd5\xd4\xb3\x13\xbdw\xf6:\xf3\xd1\xe7%\xc7]\xdd_\xb3\x9e\x9f\x9e\x9fN\xed\xaaE\xef\xdc\xcf$D\xa7\xa4X\r\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf0OV" + # wrong datasize in header + b"TOIf\x90\x00\x90\x00~\x00\x00\x00\xed\xd2\xcb\r\x83@\x10D\xc1^.\xde#!\xac31\x99\x10\x8aC%\x14~\x16\x92Y9\x02WI3\x01<\xf5cI2d\x1es(\xe1[\xdbn\xba\xca\xe8s7\xa4\xd5\xd4\xb3\x13\xbdw\xf6:\xf3\xd1\xe7%\xc7]\xdd_\xb3\x9e\x9f\x9e\x9fN\xed\xaaE\xef\xdc\xcf$D\xa7\xa4X\r\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", + # grayscale 144x144 + b"TOIg\x90\x00\x90\x00~\x00\x00\x00\xed\xd2\xcb\r\x83@\x10D\xc1^.\xde#!\xac31\x99\x10\x8aC%\x14~\x16\x92Y9\x02WI3\x01<\xf5cI2d\x1es(\xe1[\xdbn\xba\xca\xe8s7\xa4\xd5\xd4\xb3\x13\xbdw\xf6:\xf3\xd1\xe7%\xc7]\xdd_\xb3\x9e\x9f\x9e\x9fN\xed\xaaE\xef\xdc\xcf$D\xa7\xa4X\r\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf0OV", + # fullcolor 128x128 + b"TOIf\x80\x00\x80\x00~\x00\x00\x00\xed\xd2\xcb\r\x83@\x10D\xc1^.\xde#!\xac31\x99\x10\x8aC%\x14~\x16\x92Y9\x02WI3\x01<\xf5cI2d\x1es(\xe1[\xdbn\xba\xca\xe8s7\xa4\xd5\xd4\xb3\x13\xbdw\xf6:\xf3\xd1\xe7%\xc7]\xdd_\xb3\x9e\x9f\x9e\x9fN\xed\xaaE\xef\xdc\xcf$D\xa7\xa4X\r\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf0OV", + ], + ) + @pytest.mark.skip_ui + @pytest.mark.skip_t1 + def test_apply_homescreen_toif_fail(self, client, toif_data): + with pytest.raises(exceptions.TrezorFailure), client: + client.use_pin_sequence([PIN4]) + device.apply_settings(client, homescreen=toif_data) + @pytest.mark.skip_t2 def test_apply_homescreen(self, client): img = b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"\x00\x00\x00\x00\x04\x80\x00\x00\x00\x00\x00\x00\x00\x00\x04\x88\x02\x00\x00\x00\x02\x91\x00\x00\x00\x00\x00\x00\x80\x00\x00\x00\x00\x90@\x00\x11@\x00\x00\x00\x00\x00\x00\x08\x00\x10\x92\x12\x04\x00\x00\x05\x12D\x00\x00\x00\x00\x00 \x00\x00\x08\x00Q\x00\x00\x02\xc0\x00\x00\x00\x00\x00\x00\x00\x10\x02 \x01\x04J\x00)$\x00\x00\x00\x00\x80\x00\x00\x00\x00\x08\x10\xa1\x00\x00\x02\x81 \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x08\x00\x00\tP\x00\x00\x00\x00\x00\x00 \x00\x00\xa0\x00\xa0R \x12\x84\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\t\x08\x00\tP\x00\x00\x00\x00 \x00\x04 \x00\x80\x02\x00@\x02T\xc2 \x00\x00\x00\x00\x00\x00\x00\x10@\x00)\t@\n\xa0\x80\x00\x00\x00\x00\x00\x00\x00\x00\x10\x00\x80@\x14\xa9H\x04\x00\x00\x88@\x00\x00\x00\x00\x00\x02\x02$\x00\x15B@\x00\nP\x00\x00\x00\x00\x00\x80\x00\x00\x91\x01UP\x00\x00 \x02\x00\x00\x00\x00\x00\x00\x02\x08@ Z\xa5 \x00\x00\x80\x00\x00\x00\x00\x00\x00\x08\xa1%\x14*\xa0\x00\x00\x02\x08\x00\x00\x00\x00\x00\x00\x00\x00\x00@\xaa\x91 \x00\x05E\x80\x00\x00\x00\x00\x00\x02*T\x05-D\x00\x00\x05 @\x00\x00\x00\x00\x00%@\x80\x11V\xa0\x88\x00\x05@\xb0\x00\x00\x00\x00\x00\x818$\x04\xabD \x00\x06\xa1T\x00\x00\x00\x00\x02\x03\xb8\x01R\xd5\x01\x00\x00\x05AP\x00\x00\x00\x00\x08\xadT\x00\x05j\xa4@\x00\x87ah\x00\x00\x00\x00\x02\x8d\xb8\x08\x00.\x01\x00\x00\x02\xa5\xa8\x10\x00\x00\x00*\xc1\xec \n\xaa\x88 \x02@\xf6\xd0\x02\x00\x00\x00\x0bB\xb6\x14@U"\x80\x00\x01{`\x00\x00\x00\x00M\xa3\xf8 \x15*\x00\x00\x00\x10n\xc0\x04\x00\x00\x02\x06\xc2\xa8)\x00\x96\x84\x80\x00\x00\x1b\x00\x00\x80@\x10\x87\xa7\xf0\x84\x10\xaa\x10\x00\x00D\x00\x00\x02 \x00\x8a\x06\xfa\xe0P\n-\x02@\x00\x12\x00\x00\x00\x00\x10@\x83\xdf\xa0\x00\x08\xaa@\x00\x00\x01H\x00\x05H\x04\x12\x01\xf7\x81P\x02T\t\x00\x00\x00 \x00\x00\x84\x10\x00\x00z\x00@)* \x00\x00\x01\n\xa0\x02 \x05\n\x00\x00\x05\x10\x84\xa8\x84\x80\x00\x00@\x14\x00\x92\x10\x80\x00\x04\x11@\tT\x00\x00\x00\x00\n@\x00\x08\x84@$\x00H\x00\x12Q\x02\x00\x00\x00\x00\x90\x02A\x12\xa8\n\xaa\x92\x10\x04\xa8\x10@\x00\x00\x04\x04\x00\x04I\x00\x04\x14H\x80"R\x01\x00\x00\x00!@\x00\x00$\xa0EB\x80\x08\x95hH\x00\x00\x00\x84\x10 \x05Z\x00\x00(\x00\x02\x00\xa1\x01\x00\x00\x04\x00@\x82\x00\xadH*\x92P\x00\xaaP\x00\x00\x00\x00\x11\x02\x01*\xad\x01\x00\x01\x01"\x11D\x08\x00\x00\x10\x80 \x00\x81W\x80J\x94\x04\x08\xa5 !\x00\x00\x00\x02\x00B*\xae\xa1\x00\x80\x10\x01\x08\xa4\x00\x00\x00\x00\x00\x84\x00\t[@"HA\x04E\x00\x84\x00\x00\x00\x10\x00\x01J\xd5\x82\x90\x02\x00!\x02\xa2\x00\x00\x00\x00\x00\x00\x00\x05~\xa0\x00 \x10\n)\x00\x11\x00\x00\x00\x00\x00\x00!U\x80\xa8\x88\x82\x80\x01\x00\x00\x00\x00\x00\x00H@\x11\xaa\xc0\x82\x00 *\n\x00\x00\x00\x00\x00\x00\x00\x00\n\xabb@ \x04\x00! \x84\x00\x00\x00\x00\x02@\xa5\x15A$\x04\x81(\n\x00\x00\x00\x00\x00\x00 \x01\x10\x02\xe0\x91\x02\x00\x00\x04\x00\x00\x00\x00\x00\x00\x01 \xa9\tQH@\x91 P\x00\x00\x00\x00\x00\x00\x08\x00\x00\xa0T\xa5\x00@\x80\x08\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"\x00\x00\x00\x00\xa2\x00\x00\x00\x00\x00\x00\x00\x08\x00\x00 T\xa0\t\x00\x08\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00@\x02\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00*\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x10\x00\x00\x10\x02\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\t\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x08\x00\x00@\x04\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00@\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x08@\x10\x00\x00\x00\x00' diff --git a/tests/ui_tests/fixtures.json b/tests/ui_tests/fixtures.json index c75a464da..2f2a130f4 100644 --- a/tests/ui_tests/fixtures.json +++ b/tests/ui_tests/fixtures.json @@ -11,6 +11,7 @@ "test_basic.py-test_device_id_same": "5a80508a71a9ef64f94762b07636f90e464832f0f4a3102af8fa1a8c69e94586", "test_basic.py-test_features": "5a80508a71a9ef64f94762b07636f90e464832f0f4a3102af8fa1a8c69e94586", "test_basic.py-test_ping": "5a80508a71a9ef64f94762b07636f90e464832f0f4a3102af8fa1a8c69e94586", +"test_msg_applysettings.py-test_apply_homescreen_toif": "d129829fe8c6c30125151b134826b6a11eb96cca2158c1cad951290ac314a5cc", "test_msg_applysettings.py-test_apply_settings": "2cc8bf660f3be815d19a4bf1265936162a58386fbe632ca4be01541245b79134", "test_msg_applysettings.py-test_apply_settings_passphrase": "5c1ed9a0be3d14475102d447da0b5d51bbb6dfaaeceff5ea9179064609db7870", "test_msg_applysettings.py-test_apply_settings_passphrase_on_device": "3e6527e227bdde54f51bc9c417b176d0d87fdb6c40c4761368f50eb201b4beed",