Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

core: fix boot loop after uploading invalid homescreen #1205

Merged
merged 1 commit into from
Aug 21, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions core/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,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

Expand Down Expand Up @@ -264,6 +265,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
Expand Down
31 changes: 31 additions & 0 deletions core/embed/extmod/modtrezorui/display.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions core/embed/extmod/modtrezorui/display.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
72 changes: 49 additions & 23 deletions core/embed/extmod/modtrezorui/modtrezorui-display.h
Original file line number Diff line number Diff line change
Expand Up @@ -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).
Expand All @@ -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,
Expand All @@ -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,
Expand All @@ -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);
Expand Down Expand Up @@ -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)},
Expand Down
7 changes: 7 additions & 0 deletions core/mocks/generated/trezorui.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -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).
Expand Down
24 changes: 22 additions & 2 deletions core/src/apps/management/apply_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,27 @@
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")
Expand All @@ -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)
Expand Down
5 changes: 1 addition & 4 deletions core/src/storage/device.py
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
33 changes: 33 additions & 0 deletions tests/device_tests/test_msg_applysettings.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,39 @@ def test_apply_settings_passphrase_on_device(self, client):
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",
],
tsusanka marked this conversation as resolved.
Show resolved Hide resolved
)
@pytest.mark.skip_ui
tsusanka marked this conversation as resolved.
Show resolved Hide resolved
@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'
Expand Down
1 change: 1 addition & 0 deletions tests/ui_tests/fixtures.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down