mirror of
https://github.com/trezor/trezor-firmware.git
synced 2025-01-23 05:40:57 +00:00
feat(core): ability to not show passphrase coming from host
[no changelog]
This commit is contained in:
parent
afb5c55416
commit
20d280d7e0
@ -122,6 +122,7 @@ message Features {
|
||||
optional bool experimental_features = 40; // are experimental message types enabled?
|
||||
optional bool busy = 41; // is the device busy, showing "Do not disconnect"?
|
||||
optional HomescreenFormat homescreen_format = 42; // format of the homescreen, 1 = TOIf 144x144, 2 = jpg 240x240
|
||||
optional bool hide_passphrase_from_host = 43; // should we hide the passphrase when it comes from host?
|
||||
}
|
||||
|
||||
/**
|
||||
@ -168,6 +169,7 @@ message ApplySettings {
|
||||
optional bool passphrase_always_on_device = 8; // do not prompt for passphrase, enforce device entry
|
||||
optional SafetyCheckLevel safety_checks = 9; // Safety check level, set to Prompt to limit path namespace enforcement
|
||||
optional bool experimental_features = 10; // enable experimental message types
|
||||
optional bool hide_passphrase_from_host = 11; // do not show passphrase coming from host
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -128,6 +128,7 @@ def get_features() -> Features:
|
||||
f.auto_lock_delay_ms = storage_device.get_autolock_delay_ms()
|
||||
f.display_rotation = storage_device.get_rotation()
|
||||
f.experimental_features = storage_device.get_experimental_features()
|
||||
f.hide_passphrase_from_host = storage_device.get_hide_passphrase_from_host()
|
||||
|
||||
return f
|
||||
|
||||
|
@ -59,19 +59,29 @@ async def _request_on_host(ctx: Context) -> str:
|
||||
if passphrase:
|
||||
from trezor.ui.layouts import confirm_action, confirm_blob
|
||||
|
||||
await confirm_action(
|
||||
ctx,
|
||||
"passphrase_host1",
|
||||
"Hidden wallet",
|
||||
description="Access hidden wallet?\n\nNext screen will show the passphrase!",
|
||||
)
|
||||
# We want to hide the passphrase, or show it, according to settings.
|
||||
if storage_device.get_hide_passphrase_from_host():
|
||||
explanation = "Passphrase provided by host will be used but will not be displayed due to the device settings."
|
||||
await confirm_action(
|
||||
ctx,
|
||||
"passphrase_host1_hidden",
|
||||
"Hidden wallet",
|
||||
description=f"Access hidden wallet?\n\n{explanation}",
|
||||
)
|
||||
else:
|
||||
await confirm_action(
|
||||
ctx,
|
||||
"passphrase_host1",
|
||||
"Hidden wallet",
|
||||
description="Access hidden wallet?\n\nNext screen will show the passphrase!",
|
||||
)
|
||||
|
||||
await confirm_blob(
|
||||
ctx,
|
||||
"passphrase_host2",
|
||||
"Hidden wallet",
|
||||
passphrase,
|
||||
"Use this passphrase?\n",
|
||||
)
|
||||
await confirm_blob(
|
||||
ctx,
|
||||
"passphrase_host2",
|
||||
"Hidden wallet",
|
||||
passphrase,
|
||||
"Use this passphrase?\n",
|
||||
)
|
||||
|
||||
return passphrase
|
||||
|
@ -58,6 +58,7 @@ async def apply_settings(ctx: Context, msg: ApplySettings) -> Success:
|
||||
display_rotation = msg.display_rotation # local_cache_attribute
|
||||
msg_safety_checks = msg.safety_checks # local_cache_attribute
|
||||
experimental_features = msg.experimental_features # local_cache_attribute
|
||||
hide_passphrase_from_host = msg.hide_passphrase_from_host # local_cache_attribute
|
||||
|
||||
if (
|
||||
homescreen is None
|
||||
@ -68,6 +69,7 @@ async def apply_settings(ctx: Context, msg: ApplySettings) -> Success:
|
||||
and auto_lock_delay_ms is None
|
||||
and msg_safety_checks is None
|
||||
and experimental_features is None
|
||||
and hide_passphrase_from_host is None
|
||||
):
|
||||
raise ProcessError("No setting provided")
|
||||
|
||||
@ -117,6 +119,12 @@ async def apply_settings(ctx: Context, msg: ApplySettings) -> Success:
|
||||
await _require_confirm_experimental_features(ctx, experimental_features)
|
||||
storage_device.set_experimental_features(experimental_features)
|
||||
|
||||
if hide_passphrase_from_host is not None:
|
||||
if safety_checks.is_strict():
|
||||
raise ProcessError("Safety checks are strict")
|
||||
await _require_confirm_hide_passphrase_from_host(ctx, hide_passphrase_from_host)
|
||||
storage_device.set_hide_passphrase_from_host(hide_passphrase_from_host)
|
||||
|
||||
reload_settings_from_storage()
|
||||
|
||||
return Success(message="Settings applied")
|
||||
@ -269,3 +277,16 @@ async def _require_confirm_experimental_features(
|
||||
reverse=True,
|
||||
br_code=BRT_PROTECT_CALL,
|
||||
)
|
||||
|
||||
|
||||
async def _require_confirm_hide_passphrase_from_host(
|
||||
ctx: GenericContext, enable: bool
|
||||
) -> None:
|
||||
if enable:
|
||||
await confirm_action(
|
||||
ctx,
|
||||
"set_hide_passphrase_from_host",
|
||||
"Hide passphrase",
|
||||
description="Hide passphrase coming from host?",
|
||||
br_code=BRT_PROTECT_CALL,
|
||||
)
|
||||
|
@ -34,6 +34,7 @@ _SD_SALT_AUTH_KEY = const(0x12) # bytes
|
||||
INITIALIZED = const(0x13) # bool (0x01 or empty)
|
||||
_SAFETY_CHECK_LEVEL = const(0x14) # int
|
||||
_EXPERIMENTAL_FEATURES = const(0x15) # bool (0x01 or empty)
|
||||
_HIDE_PASSPHRASE_FROM_HOST = const(0x16) # bool (0x01 or empty)
|
||||
|
||||
SAFETY_CHECK_LEVEL_STRICT : Literal[0] = const(0)
|
||||
SAFETY_CHECK_LEVEL_PROMPT : Literal[1] = const(1)
|
||||
@ -334,3 +335,17 @@ def set_experimental_features(enabled: bool) -> None:
|
||||
cached_bytes = b"\x01" if enabled else b""
|
||||
storage_cache.set(storage_cache.STORAGE_DEVICE_EXPERIMENTAL_FEATURES, cached_bytes)
|
||||
common.set_true_or_delete(_NAMESPACE, _EXPERIMENTAL_FEATURES, enabled)
|
||||
|
||||
|
||||
def set_hide_passphrase_from_host(hide: bool) -> None:
|
||||
"""
|
||||
Whether we should hide the passphrase from the host.
|
||||
"""
|
||||
common.set_bool(_NAMESPACE, _HIDE_PASSPHRASE_FROM_HOST, hide)
|
||||
|
||||
|
||||
def get_hide_passphrase_from_host() -> bool:
|
||||
"""
|
||||
Whether we should hide the passphrase from the host.
|
||||
"""
|
||||
return common.get_bool(_NAMESPACE, _HIDE_PASSPHRASE_FROM_HOST)
|
||||
|
@ -2104,6 +2104,7 @@ if TYPE_CHECKING:
|
||||
experimental_features: "bool | None"
|
||||
busy: "bool | None"
|
||||
homescreen_format: "HomescreenFormat | None"
|
||||
hide_passphrase_from_host: "bool | None"
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
@ -2147,6 +2148,7 @@ if TYPE_CHECKING:
|
||||
experimental_features: "bool | None" = None,
|
||||
busy: "bool | None" = None,
|
||||
homescreen_format: "HomescreenFormat | None" = None,
|
||||
hide_passphrase_from_host: "bool | None" = None,
|
||||
) -> None:
|
||||
pass
|
||||
|
||||
@ -2190,6 +2192,7 @@ if TYPE_CHECKING:
|
||||
passphrase_always_on_device: "bool | None"
|
||||
safety_checks: "SafetyCheckLevel | None"
|
||||
experimental_features: "bool | None"
|
||||
hide_passphrase_from_host: "bool | None"
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
@ -2203,6 +2206,7 @@ if TYPE_CHECKING:
|
||||
passphrase_always_on_device: "bool | None" = None,
|
||||
safety_checks: "SafetyCheckLevel | None" = None,
|
||||
experimental_features: "bool | None" = None,
|
||||
hide_passphrase_from_host: "bool | None" = None,
|
||||
) -> None:
|
||||
pass
|
||||
|
||||
|
@ -18,9 +18,10 @@ import random
|
||||
|
||||
import pytest
|
||||
|
||||
from trezorlib import exceptions, messages
|
||||
from trezorlib import device, exceptions, messages
|
||||
from trezorlib.debuglink import TrezorClientDebugLink as Client
|
||||
from trezorlib.messages import FailureType
|
||||
from trezorlib.exceptions import TrezorFailure
|
||||
from trezorlib.messages import FailureType, SafetyCheckLevel
|
||||
from trezorlib.tools import parse_path
|
||||
|
||||
XPUB_PASSPHRASES = {
|
||||
@ -375,6 +376,83 @@ def test_passphrase_length(client: Client):
|
||||
call(passphrase="A" * 49 + "š", expected_result=False)
|
||||
|
||||
|
||||
@pytest.mark.skip_t1
|
||||
@pytest.mark.setup_client(passphrase=True)
|
||||
def test_hide_passphrase_from_host(client: Client):
|
||||
# Without safety checks, turning it on fails
|
||||
with pytest.raises(TrezorFailure, match="Safety checks are strict"), client:
|
||||
device.apply_settings(client, hide_passphrase_from_host=True)
|
||||
|
||||
device.apply_settings(client, safety_checks=SafetyCheckLevel.PromptTemporarily)
|
||||
|
||||
# Turning it on
|
||||
device.apply_settings(client, hide_passphrase_from_host=True)
|
||||
|
||||
passphrase = "abc"
|
||||
|
||||
with client:
|
||||
|
||||
def input_flow():
|
||||
yield
|
||||
layout = client.debug.wait_layout()
|
||||
assert (
|
||||
"Passphrase provided by host will be used but will not be displayed due to the device settings."
|
||||
in layout.get_content()
|
||||
)
|
||||
client.debug.press_yes()
|
||||
|
||||
client.watch_layout()
|
||||
client.set_input_flow(input_flow)
|
||||
client.set_expected_responses(
|
||||
[
|
||||
messages.PassphraseRequest,
|
||||
messages.ButtonRequest,
|
||||
messages.PublicKey,
|
||||
]
|
||||
)
|
||||
client.use_passphrase(passphrase)
|
||||
result = client.call(XPUB_REQUEST)
|
||||
assert isinstance(result, messages.PublicKey)
|
||||
xpub_hidden_passphrase = result.xpub
|
||||
|
||||
# Turning it off
|
||||
device.apply_settings(client, hide_passphrase_from_host=False)
|
||||
|
||||
# Starting new session, otherwise the passphrase would be cached
|
||||
_init_session(client)
|
||||
|
||||
with client:
|
||||
|
||||
def input_flow():
|
||||
yield
|
||||
layout = client.debug.wait_layout()
|
||||
assert "Next screen will show the passphrase!" in layout.get_content()
|
||||
client.debug.press_yes()
|
||||
|
||||
yield
|
||||
layout = client.debug.wait_layout()
|
||||
assert "Use this passphrase?" in layout.get_content()
|
||||
assert passphrase in layout.get_content()
|
||||
client.debug.press_yes()
|
||||
|
||||
client.watch_layout()
|
||||
client.set_input_flow(input_flow)
|
||||
client.set_expected_responses(
|
||||
[
|
||||
messages.PassphraseRequest,
|
||||
messages.ButtonRequest,
|
||||
messages.ButtonRequest,
|
||||
messages.PublicKey,
|
||||
]
|
||||
)
|
||||
client.use_passphrase(passphrase)
|
||||
result = client.call(XPUB_REQUEST)
|
||||
assert isinstance(result, messages.PublicKey)
|
||||
xpub_shown_passphrase = result.xpub
|
||||
|
||||
assert xpub_hidden_passphrase == xpub_shown_passphrase
|
||||
|
||||
|
||||
def _get_xpub_cardano(client: Client, passphrase):
|
||||
msg = messages.CardanoGetPublicKey(
|
||||
address_n=parse_path("m/44h/1815h/0h/0/0"),
|
||||
|
@ -1705,6 +1705,7 @@
|
||||
"TT_test_session.py::test_end_session_only_current": "bd83a31d0fc4c23953dfd0d138e4441984e34698ace96aad5308a4ae51b712ae",
|
||||
"TT_test_session.py::test_session_recycling": "07f265234a3269c8c99172e2f67abf626e17a542e6f4c00b45c5b685d0e4c240",
|
||||
"TT_test_session_id_and_passphrase.py::test_cardano_passphrase": "26e3b8bc6b1ba85fc89d5b237096685309a95f73350d2fca646720fb750d0e8f",
|
||||
"TT_test_session_id_and_passphrase.py::test_hide_passphrase_from_host": "ccdb34cba3b759d91500b3c2b2ee5d427167d21b6aefa709b659aed298760605",
|
||||
"TT_test_session_id_and_passphrase.py::test_max_sessions_with_passphrases": "5c85cb246fe4bb07076ed88f426e6133368f3417472cf2dfbef2daac32a088aa",
|
||||
"TT_test_session_id_and_passphrase.py::test_multiple_passphrases": "12231bae2ea96b600c96ade946e5dda29d6625d128906cf14728869c1e697987",
|
||||
"TT_test_session_id_and_passphrase.py::test_multiple_sessions": "bd83a31d0fc4c23953dfd0d138e4441984e34698ace96aad5308a4ae51b712ae",
|
||||
|
Loading…
Reference in New Issue
Block a user