refactor(core): convert apps.common to layouts

pull/1750/head
Martin Milata 3 years ago
parent 875cc0cb1a
commit 574dcbc8a3

@ -3,7 +3,6 @@ from trezor.ui.layouts import show_address
from apps.common import paths
from apps.common.keychain import Keychain, auto_keychain
from apps.common.layout import address_n_to_str
from .helpers import address_from_public_key
@ -18,7 +17,7 @@ async def get_address(ctx, msg: BinanceGetAddress, keychain: Keychain):
pubkey = node.public_key()
address = address_from_public_key(pubkey, HRP)
if msg.show_display:
title = address_n_to_str(msg.address_n)
title = paths.address_n_to_str(msg.address_n)
await show_address(ctx, address=address, address_qr=address, title=title)
return BinanceAddress(address=address)

@ -3,8 +3,7 @@ from trezor.enums import InputScriptType
from trezor.messages import Address
from trezor.ui.layouts import show_address
from apps.common.layout import address_n_to_str
from apps.common.paths import validate_path
from apps.common.paths import address_n_to_str, validate_path
from . import addresses
from .keychain import validate_path_against_script_type, with_keychain

@ -3,7 +3,6 @@ from trezor.messages import CardanoAddress
from trezor.ui.layouts import show_address
from apps.common import paths
from apps.common.layout import address_n_to_str
from . import seed
from .address import derive_human_readable_address, validate_address_parameters
@ -71,7 +70,7 @@ async def _display_address(
if not protocol_magics.is_mainnet(protocol_magic):
network_name = protocol_magics.to_ui_string(protocol_magic)
address_n = address_n_to_str(address_parameters.address_n)
address_n = paths.address_n_to_str(address_parameters.address_n)
await show_address(
ctx,
address=address,

@ -1,7 +1,6 @@
from micropython import const
from apps.common import HARDENED
from apps.common.paths import PathSchema
from apps.common.paths import HARDENED, PathSchema
SLIP44_ID = 1815

@ -8,7 +8,7 @@ from trezor.ui.layouts import (
confirm_properties,
)
from apps.common.layout import address_n_to_str
from apps.common.paths import address_n_to_str
from . import seed
from .address import (

@ -1,17 +0,0 @@
from micropython import const
from trezor import workflow
from trezor.enums import ButtonRequestType
from trezor.messages import ButtonAck, ButtonRequest
if False:
from trezor import wire
HARDENED = const(0x8000_0000)
async def button_request(
ctx: wire.GenericContext, code: ButtonRequestType = ButtonRequestType.Other
) -> None:
workflow.close_others()
await ctx.call(ButtonRequest(code=code), ButtonAck)

@ -7,8 +7,7 @@ from trezor.ui.components.tt.confirm import (
HoldToConfirm,
InfoConfirm,
)
from . import button_request
from trezor.ui.layouts.common import button_request
if __debug__:
from trezor.ui.components.tt.scroll import Paginated

@ -1,23 +0,0 @@
from trezor.utils import chunks
from apps.common import HARDENED
if False:
from typing import Iterable, Iterator
def split_address(address: str) -> Iterator[str]:
return chunks(address, 17)
def address_n_to_str(address_n: Iterable[int]) -> str:
def path_item(i: int) -> str:
if i & HARDENED:
return str(i ^ HARDENED) + "'"
else:
return str(i)
if not address_n:
return "m"
return "m/" + "/".join([path_item(i) for i in address_n])

@ -3,7 +3,7 @@ from trezor import ui, utils, workflow
from trezor.enums import BackupType
def get() -> tuple[bytes | None, int]:
def get() -> tuple[bytes | None, BackupType]:
return get_secret(), get_type()
@ -54,13 +54,12 @@ def get_seed(passphrase: str = "", progress_bar: bool = True) -> bytes:
def _start_progress() -> None:
from trezor.ui.components.tt.text import Text
from trezor.ui.layouts import draw_simple_text
# Because we are drawing to the screen manually, without a layout, we
# should make sure that no other layout is running.
workflow.close_others()
t = Text("Please wait", ui.ICON_CONFIG)
ui.draw_simple(t)
draw_simple_text("Please wait")
def _render_progress(progress: int, total: int) -> None:

@ -2,9 +2,6 @@ from micropython import const
import storage.device
from trezor import wire, workflow
from trezor.enums import ButtonRequestType
from . import button_request
_MAX_PASSPHRASE_LEN = const(50)
@ -23,7 +20,9 @@ async def get(ctx: wire.Context) -> str:
async def _request_from_user(ctx: wire.Context) -> str:
workflow.close_others() # request exclusive UI access
if storage.device.get_passphrase_always_on_device():
passphrase = await _request_on_device(ctx)
from trezor.ui.layouts import request_passphrase_on_device
passphrase = await request_passphrase_on_device(ctx, _MAX_PASSPHRASE_LEN)
else:
passphrase = await _request_on_host(ctx)
if len(passphrase.encode()) > _MAX_PASSPHRASE_LEN:
@ -36,19 +35,17 @@ async def _request_from_user(ctx: wire.Context) -> str:
async def _request_on_host(ctx: wire.Context) -> str:
from trezor.messages import PassphraseAck, PassphraseRequest
from trezor.ui import ICON_CONFIG
from trezor.ui.components.tt.text import Text
from .confirm import require_confirm
_entry_dialog()
request = PassphraseRequest()
ack = await ctx.call(request, PassphraseAck)
if ack.on_device:
from trezor.ui.layouts import request_passphrase_on_device
if ack.passphrase is not None:
raise wire.DataError("Passphrase provided when it should not be")
return await _request_on_device(ctx)
return await request_passphrase_on_device(ctx, _MAX_PASSPHRASE_LEN)
if ack.passphrase is None:
raise wire.DataError(
@ -57,41 +54,33 @@ async def _request_on_host(ctx: wire.Context) -> str:
# non-empty passphrase
if ack.passphrase:
text = Text("Hidden wallet", ICON_CONFIG)
text.normal("Access hidden wallet?")
text.br()
text.normal("Next screen will show")
text.normal("the passphrase!")
await require_confirm(ctx, text, ButtonRequestType.Other)
text = Text("Hidden wallet", ICON_CONFIG, break_words=True)
text.normal("Use this passphrase?")
text.br()
text.mono(ack.passphrase)
await require_confirm(ctx, text, ButtonRequestType.Other)
return ack.passphrase
async def _request_on_device(ctx: wire.Context) -> str:
from trezor.ui.components.tt.passphrase import CANCELLED, PassphraseKeyboard
await button_request(ctx, code=ButtonRequestType.PassphraseEntry)
keyboard = PassphraseKeyboard("Enter passphrase", _MAX_PASSPHRASE_LEN)
passphrase = await ctx.wait(keyboard)
if passphrase is CANCELLED:
raise wire.ActionCancelled("Passphrase entry cancelled")
from trezor import ui
from trezor.ui.layouts import confirm_action, confirm_blob
await confirm_action(
ctx,
"passphrase_host1",
title="Hidden wallet",
description="Access hidden wallet?\n\nNext screen will show\nthe passphrase!",
icon=ui.ICON_CONFIG,
)
assert isinstance(passphrase, str)
await confirm_blob(
ctx,
"passphrase_host2",
title="Hidden wallet",
description="Use this passphrase?\n",
data=ack.passphrase,
icon=ui.ICON_CONFIG,
icon_color=ui.ORANGE_ICON,
)
return passphrase
return ack.passphrase
def _entry_dialog() -> None:
from trezor.ui import ICON_CONFIG, draw_simple
from trezor.ui.components.tt.text import Text
from trezor.ui.layouts import draw_simple_text
text = Text("Passphrase entry", ICON_CONFIG)
text.normal("Please type your", "passphrase on the", "connected host.")
draw_simple(text)
draw_simple_text(
"Passphrase entry", "Please type your\npassphrase on the\nconnected host."
)

@ -1,4 +1,6 @@
from . import HARDENED
from micropython import const
HARDENED = const(0x8000_0000)
if False:
from typing import (
@ -325,7 +327,6 @@ async def validate_path(
async def show_path_warning(ctx: wire.Context, path: Bip32Path) -> None:
from trezor.ui.layouts import confirm_path_warning
from .layout import address_n_to_str
await confirm_path_warning(ctx, address_n_to_str(path))
@ -336,3 +337,16 @@ def is_hardened(i: int) -> bool:
def path_is_hardened(address_n: Bip32Path) -> bool:
return all(is_hardened(n) for n in address_n)
def address_n_to_str(address_n: Iterable[int]) -> str:
def path_item(i: int) -> str:
if i & HARDENED:
return str(i ^ HARDENED) + "'"
else:
return str(i)
if not address_n:
return "m"
return "m/" + "/".join(path_item(i) for i in address_n)

@ -2,11 +2,8 @@ import utime
import storage.cache
import storage.sd_salt
from trezor import config, ui, wire
from trezor.enums import ButtonRequestType
from trezor.ui.popup import Popup
from trezor import config, wire
from . import button_request
from .sdcard import SdCardUnavailable, request_sd_salt
if False:
@ -24,25 +21,9 @@ async def request_pin(
attempts_remaining: int | None = None,
allow_cancel: bool = True,
) -> str:
from trezor.ui.components.tt.pin import CANCELLED, PinDialog
from trezor.ui.layouts import request_pin_on_device
await button_request(ctx, code=ButtonRequestType.PinEntry)
if attempts_remaining is None:
subprompt = None
elif attempts_remaining == 1:
subprompt = "This is your last attempt"
else:
subprompt = "%s attempts remaining" % attempts_remaining
dialog = PinDialog(prompt, subprompt, allow_cancel)
while True:
pin = await ctx.wait(dialog)
if pin is CANCELLED:
raise wire.PinCancelled
assert isinstance(pin, str)
return pin
return await request_pin_on_device(ctx, prompt, attempts_remaining, allow_cancel)
async def request_pin_confirm(ctx: wire.Context, *args: Any, **kwargs: Any) -> str:
@ -55,14 +36,12 @@ async def request_pin_confirm(ctx: wire.Context, *args: Any, **kwargs: Any) -> s
async def pin_mismatch() -> None:
from trezor.ui.components.tt.text import Text
from trezor.ui.layouts import show_popup
text = Text("PIN mismatch", ui.ICON_WRONG, ui.RED)
text.normal("The PINs you entered", "do not match.")
text.normal("")
text.normal("Please try again.")
popup = Popup(text, 3000) # show for 3 seconds
await popup
await show_popup(
title="PIN mismatch",
description="The PINs you entered\ndo not match.\n\nPlease try again.",
)
async def request_pin_and_sd_salt(
@ -109,7 +88,11 @@ async def verify_user_pin(
return
if config.has_pin():
pin = await request_pin(ctx, prompt, config.get_pin_rem(), allow_cancel)
from trezor.ui.layouts import request_pin_on_device
pin = await request_pin_on_device(
ctx, prompt, config.get_pin_rem(), allow_cancel
)
config.ensure_not_wipe_code(pin)
else:
pin = ""
@ -125,7 +108,7 @@ async def verify_user_pin(
raise RuntimeError
while retry:
pin = await request_pin(
pin = await request_pin_on_device(
ctx, "Wrong PIN, enter again", config.get_pin_rem(), allow_cancel
)
if config.unlock(pin, salt):

@ -4,7 +4,6 @@ from trezor.messages import EthereumAddress
from trezor.ui.layouts import show_address
from apps.common import paths
from apps.common.layout import address_n_to_str
from . import networks
from .address import address_from_bytes
@ -27,7 +26,7 @@ async def get_address(ctx, msg, keychain):
address = address_from_bytes(address_bytes, network)
if msg.show_display:
title = address_n_to_str(msg.address_n)
title = paths.address_n_to_str(msg.address_n)
await show_address(ctx, address=address, address_qr=address, title=title)
return EthereumAddress(address=address)

@ -1,6 +1,6 @@
from trezor import wire
from apps.common import HARDENED, paths
from apps.common import paths
from apps.common.keychain import get_keychain
from . import CURVE, networks
@ -37,10 +37,10 @@ def _schemas_from_address_n(
if slip44_hardened not in networks.all_slip44_ids_hardened():
return ()
if not slip44_hardened & HARDENED:
if not slip44_hardened & paths.HARDENED:
return ()
slip44_id = slip44_hardened - HARDENED
slip44_id = slip44_hardened - paths.HARDENED
schemas = [paths.PathSchema.parse(pattern, slip44_id) for pattern in patterns]
return [s.copy() for s in schemas]

@ -3,7 +3,7 @@
from micropython import const
from apps.common import HARDENED
from apps.common.paths import HARDENED
SLIP44_WANCHAIN = const(5718350)
SLIP44_ETHEREUM = const(60)

@ -3,7 +3,7 @@
from micropython import const
from apps.common import HARDENED
from apps.common.paths import HARDENED
SLIP44_WANCHAIN = const(5718350)
SLIP44_ETHEREUM = const(60)

@ -3,7 +3,6 @@ from trezor.ui.layouts import show_address
from apps.common import paths
from apps.common.keychain import auto_keychain
from apps.common.layout import address_n_to_str
from .helpers import get_address_from_public_key
@ -18,7 +17,7 @@ async def get_address(ctx, msg, keychain):
address = get_address_from_public_key(pubkey)
if msg.show_display:
title = address_n_to_str(msg.address_n)
title = paths.address_n_to_str(msg.address_n)
await show_address(ctx, address=address, address_qr=address, title=title)
return LiskAddress(address=address)

@ -6,8 +6,8 @@ from trezor.ui.components.tt.scroll import Paginated
from trezor.ui.components.tt.text import Text
from trezor.ui.components.tt.word_select import WordSelector
from trezor.ui.layouts import confirm_action, show_success, show_warning
from trezor.ui.layouts.common import button_request
from apps.common import button_request
from apps.common.confirm import confirm, info_confirm, require_confirm
from .. import backup_types

@ -5,9 +5,8 @@ from trezor.crypto.hashlib import sha256
from trezor.messages import ECDHSessionKey
from trezor.ui.layouts import confirm_address
from apps.common import HARDENED
from apps.common.keychain import get_keychain
from apps.common.paths import AlwaysMatchingSchema
from apps.common.paths import HARDENED, AlwaysMatchingSchema
from .sign_identity import serialize_identity, serialize_identity_without_proto

@ -5,9 +5,9 @@ from trezor.crypto.hashlib import sha256
from trezor.messages import SignedIdentity
from trezor.ui.layouts import confirm_sign_identity
from apps.common import HARDENED, coininfo
from apps.common import coininfo
from apps.common.keychain import get_keychain
from apps.common.paths import AlwaysMatchingSchema
from apps.common.paths import HARDENED, AlwaysMatchingSchema
if False:
from trezor.messages import IdentityType, SignIdentity

@ -3,7 +3,6 @@ from trezor.ui.layouts import show_address
from apps.common import paths
from apps.common.keychain import auto_keychain
from apps.common.layout import address_n_to_str
from apps.monero import misc
from apps.monero.xmr import addresses, crypto, monero
from apps.monero.xmr.networks import net_version
@ -41,7 +40,7 @@ async def get_address(ctx, msg, keychain):
)
if msg.show_display:
title = address_n_to_str(msg.address_n)
title = paths.address_n_to_str(msg.address_n)
await show_address(
ctx,
address=addr.decode(),

@ -2,8 +2,7 @@ from trezor.messages import NEMAddress
from trezor.ui.layouts import show_address
from apps.common.keychain import with_slip44_keychain
from apps.common.layout import address_n_to_str
from apps.common.paths import validate_path
from apps.common.paths import address_n_to_str, validate_path
from . import CURVE, PATTERNS, SLIP44_ID
from .helpers import check_path, get_network_str

@ -1,6 +1,6 @@
from micropython import const
from apps.common import HARDENED, paths
from apps.common import paths
from . import SLIP44_ID
@ -45,7 +45,7 @@ def check_path(path: paths.Bip32Path, network: int) -> bool:
if len(path) < 2:
return False
coin_type = path[1] - HARDENED
coin_type = path[1] - paths.HARDENED
if network == NEM_NETWORK_TESTNET:
return coin_type == 1

@ -3,7 +3,6 @@ from trezor.ui.layouts import show_address
from apps.common import paths
from apps.common.keychain import auto_keychain
from apps.common.layout import address_n_to_str
from .helpers import address_from_public_key
@ -17,7 +16,7 @@ async def get_address(ctx, msg: RippleGetAddress, keychain):
address = address_from_public_key(pubkey)
if msg.show_display:
title = address_n_to_str(msg.address_n)
title = paths.address_n_to_str(msg.address_n)
await show_address(ctx, address=address, address_qr=address, title=title)
return RippleAddress(address=address)

@ -3,7 +3,6 @@ from trezor.ui.layouts import show_address
from apps.common import paths, seed
from apps.common.keychain import auto_keychain
from apps.common.layout import address_n_to_str
from . import helpers
@ -17,7 +16,7 @@ async def get_address(ctx, msg: StellarGetAddress, keychain):
address = helpers.address_from_public_key(pubkey)
if msg.show_display:
title = address_n_to_str(msg.address_n)
title = paths.address_n_to_str(msg.address_n)
await show_address(
ctx, address=address, address_qr=address.upper(), title=title
)

@ -4,7 +4,6 @@ from trezor.ui.layouts import show_address
from apps.common import paths, seed
from apps.common.keychain import with_slip44_keychain
from apps.common.layout import address_n_to_str
from . import CURVE, PATTERNS, SLIP44_ID, helpers
@ -22,7 +21,7 @@ async def get_address(ctx, msg, keychain):
)
if msg.show_display:
title = address_n_to_str(msg.address_n)
title = paths.address_n_to_str(msg.address_n)
await show_address(ctx, address=address, address_qr=address, title=title)
return TezosAddress(address=address)

@ -7,7 +7,8 @@ from trezor import log, utils
from trezor.crypto import bip32, chacha20poly1305, der, hashlib, hmac, random
from trezor.crypto.curve import ed25519, nist256p1
from apps.common import HARDENED, cbor, seed
from apps.common import cbor, seed
from apps.common.paths import HARDENED
from . import common

@ -14,17 +14,25 @@ if __debug__:
from ..components.tt.scroll import Paginated
async def button_request(
ctx: wire.GenericContext,
br_type: str,
code: ButtonRequestType = ButtonRequestType.Other,
) -> None:
log.debug(__name__, "ButtonRequest.type={}".format(br_type))
workflow.close_others()
await ctx.call(ButtonRequest(code=code), ButtonAck)
async def interact(
ctx: wire.GenericContext,
layout: LayoutType,
brtype: str,
brcode: ButtonRequestType = ButtonRequestType.Other,
br_type: str,
br_code: ButtonRequestType = ButtonRequestType.Other,
) -> Any:
log.debug(__name__, "ButtonRequest.type={}".format(brtype))
if layout.__class__.__name__ == "Paginated":
assert isinstance(layout, Paginated)
return await layout.interact(ctx, code=brcode)
return await layout.interact(ctx, code=br_code)
else:
workflow.close_others()
await ctx.call(ButtonRequest(code=brcode), ButtonAck)
await button_request(ctx, br_type, br_code)
return await ctx.wait(layout)

@ -12,6 +12,7 @@ from trezor.utils import chunks, chunks_intersperse
from ..components.common import break_path_to_lines
from ..components.common.confirm import is_confirmed, raise_if_cancelled
from ..components.common.webauthn import ConfirmInfo
from ..components.tt import passphrase, pin
from ..components.tt.button import ButtonCancel, ButtonDefault
from ..components.tt.confirm import Confirm, ConfirmPageable, HoldToConfirm, Pageable
from ..components.tt.scroll import (
@ -30,7 +31,7 @@ from ..constants.tt import (
QR_Y,
TEXT_MAX_LINES,
)
from .common import interact
from .common import button_request, interact
if False:
from typing import (
@ -78,6 +79,9 @@ __all__ = (
"show_popup",
"confirm_webauthn",
"confirm_webauthn_reset",
"draw_simple_text",
"request_passphrase_on_device",
"request_pin_on_device",
)
@ -1055,3 +1059,47 @@ async def confirm_webauthn_reset() -> bool:
text.normal("Do you really want to")
text.bold("erase all credentials?")
return is_confirmed(await Confirm(text))
def draw_simple_text(title: str, description: str = "") -> None:
text = Text(title, ui.ICON_CONFIG, new_lines=False)
text.normal(description)
ui.draw_simple(text)
async def request_passphrase_on_device(ctx: wire.GenericContext, max_len: int) -> str:
await button_request(
ctx, "passphrase_device", code=ButtonRequestType.PassphraseEntry
)
keyboard = passphrase.PassphraseKeyboard("Enter passphrase", max_len)
result = await ctx.wait(keyboard)
if result is passphrase.CANCELLED:
raise wire.ActionCancelled("Passphrase entry cancelled")
assert isinstance(result, str)
return result
async def request_pin_on_device(
ctx: wire.GenericContext,
prompt: str,
attempts_remaining: int,
allow_cancel: bool,
) -> str:
await button_request(ctx, "pin_device", code=ButtonRequestType.PinEntry)
if attempts_remaining is None:
subprompt = None
elif attempts_remaining == 1:
subprompt = "This is your last attempt"
else:
subprompt = "%s attempts remaining" % attempts_remaining
dialog = pin.PinDialog(prompt, subprompt, allow_cancel)
while True:
result = await ctx.wait(dialog)
if result is pin.CANCELLED:
raise wire.PinCancelled
assert isinstance(result, str)
return result

@ -7,7 +7,7 @@ from ubinascii import hexlify, unhexlify # noqa: F401
import unittest # noqa: F401
from trezor import utils # noqa: F401
from apps.common import HARDENED
from apps.common.paths import HARDENED
def H_(x: int) -> int:

@ -5,7 +5,8 @@ from trezor.enums import CardanoAddressType
from trezor.messages import CardanoAddressParametersType
from trezor.messages import CardanoBlockchainPointerType
from apps.common import HARDENED, seed
from apps.common import seed
from apps.common.paths import HARDENED
if not utils.BITCOIN_ONLY:
from apps.cardano.address import derive_human_readable_address, validate_address_parameters

@ -2,7 +2,8 @@ from common import *
from trezor import wire
from trezor.crypto import bip32, slip39
from apps.common import HARDENED, seed
from apps.common import seed
from apps.common.paths import HARDENED
if not utils.BITCOIN_ONLY:
from apps.cardano.seed import Keychain

@ -1,5 +1,5 @@
from common import *
from apps.common import HARDENED
from apps.common.paths import HARDENED
from trezor.messages import CardanoTxInputType
if not utils.BITCOIN_ONLY:

@ -2,7 +2,7 @@ from ubinascii import unhexlify
from common import *
from apps.common import HARDENED
from apps.common.paths import HARDENED
from trezor.crypto import bip32
from trezor.enums import CardanoAddressType
from trezor.messages import CardanoAddressParametersType

@ -1,6 +1,5 @@
from common import *
from trezor.utils import ensure
from apps.common.layout import address_n_to_str
from apps.common.paths import *

@ -1,5 +1,5 @@
from common import *
from apps.common import HARDENED
from apps.common.paths import HARDENED
if not utils.BITCOIN_ONLY:
from trezor.crypto import nem

@ -347,7 +347,7 @@
"test_msg_loaddevice.py-test_load_device_2": "dc13c8486d8a59c5062e19139d8b3cea4ece1a3bc93592be7dc226f83ba54477",
"test_msg_loaddevice.py-test_load_device_slip39_advanced": "1c6db0d592b1d22b3c9fce3ddab8a9fd138f11d83e5d4e64431a02bf4ffed605",
"test_msg_loaddevice.py-test_load_device_slip39_basic": "1c6db0d592b1d22b3c9fce3ddab8a9fd138f11d83e5d4e64431a02bf4ffed605",
"test_msg_loaddevice.py-test_load_device_utf": "ad7c162c76a13a161166aba78c461ad5525a9a5da846e8d99854248d521e6979",
"test_msg_loaddevice.py-test_load_device_utf": "b51beeb07c60e8c803b5bf81e4470db785dc46006374b15df21a7810d659b2b6",
"test_msg_monero_getaddress.py-test_monero_getaddress": "0ba9bba02378d62c8f9f76aac5181ab94b25dcbed0f58d006c1f7d4eb1ecd03e",
"test_msg_monero_getwatchkey.py-test_monero_getwatchkey": "d77fa4d4322e145c41f1ce07526ff59f8b58d8854aeffaa5266e14cd572350e7",
"test_msg_nem_getaddress.py-test_nem_getaddress": "d3ac0e389d139c79abeff96cd05b9c9f94c3372086096d5eb85759ab3a37b0b8",
@ -714,7 +714,7 @@
"test_session_id_and_passphrase.py::test_multiple_sessions": "5a80508a71a9ef64f94762b07636f90e464832f0f4a3102af8fa1a8c69e94586",
"test_session_id_and_passphrase.py::test_passphrase_ack_mismatch": "612dad8ab8762162a186ec9279d7de0bdfc589c52b4e4f4eba0545a00f21c3f0",
"test_session_id_and_passphrase.py::test_passphrase_always_on_device": "524d90c68c6f091c2145f571a884a8a168e8af101513966f5e0fbb3859035129",
"test_session_id_and_passphrase.py::test_passphrase_length": "a8858d89288f2160148860fee8938d261c4960732db3b2c874b9899395b9ddc6",
"test_session_id_and_passphrase.py::test_passphrase_length": "6c9063e65e113d7c67624392b1bedae600ae02d4576375a11b399b3c3dd15987",
"test_session_id_and_passphrase.py::test_passphrase_missing": "3a92115b6bfb2d53f2445a67c9c5df6b6b5ff97769de98e3fac9e1bf424c5669",
"test_session_id_and_passphrase.py::test_passphrase_on_device": "c9ca2c9cf6dd416dad4de311266690ec2266b551d74f9d3619301305b3dbe81e",
"test_session_id_and_passphrase.py::test_session_enable_passphrase": "b27321ed372b8ade7c4941a80f1f945851046b039a1b43c43a6953106bd1619e",

Loading…
Cancel
Save