def test_cardano_sign_tx_failed(client: Client, parameters, result): client.init_device(new_session=True, derive_cardano=True) signing_mode = messages.CardanoTxSigningMode.__members__[ parameters["signing_mode"]] inputs = [cardano.parse_input(i) for i in parameters["inputs"]] outputs = [cardano.parse_output(o) for o in parameters["outputs"]] certificates = [ cardano.parse_certificate(c) for c in parameters["certificates"] ] withdrawals = [ cardano.parse_withdrawal(w) for w in parameters["withdrawals"] ] auxiliary_data = cardano.parse_auxiliary_data(parameters["auxiliary_data"]) mint = cardano.parse_mint(parameters["mint"]) script_data_hash = cardano.parse_script_data_hash( parameters["script_data_hash"]) collateral_inputs = [ cardano.parse_collateral_input(i) for i in parameters["collateral_inputs"] ] required_signers = [ cardano.parse_required_signer(s) for s in parameters["required_signers"] ] additional_witness_requests = [ cardano.parse_additional_witness_request(p) for p in parameters["additional_witness_requests"] ] if parameters.get("security_checks") == "prompt": device.apply_settings( client, safety_checks=messages.SafetyCheckLevel.PromptTemporarily) else: device.apply_settings(client, safety_checks=messages.SafetyCheckLevel.Strict) with client: with pytest.raises(TrezorFailure, match=result["error_message"]): cardano.sign_tx( client=client, signing_mode=signing_mode, inputs=inputs, outputs=outputs, fee=parameters["fee"], ttl=parameters.get("ttl"), validity_interval_start=parameters.get( "validity_interval_start"), certificates=certificates, withdrawals=withdrawals, protocol_magic=parameters["protocol_magic"], network_id=parameters["network_id"], auxiliary_data=auxiliary_data, mint=mint, script_data_hash=script_data_hash, collateral_inputs=collateral_inputs, required_signers=required_signers, additional_witness_requests=additional_witness_requests, include_network_id=parameters["include_network_id"], )
def test_change_invalid_current(client: Client): assert client.features.pin_protection is True # Check current PIN value _check_pin(client, PIN4) # Let's set new PIN def input_flow(): yield # do you want to change pin? client.debug.press_yes() yield # enter wrong current pin client.debug.input(PIN60) yield client.debug.press_no() with client, pytest.raises(TrezorFailure): client.set_expected_responses([messages.ButtonRequest] * 3 + [messages.Failure]) client.set_input_flow(input_flow) device.change_pin(client) # Check that there's still old PIN protection client.init_device() assert client.features.pin_protection is True _check_pin(client, PIN4)
def test_end_session(client: Client): # client instance starts out not initialized # XXX do we want to change this? assert client.session_id is not None # get_address will succeed with client: client.set_expected_responses([messages.Address]) get_test_address(client) client.end_session() assert client.session_id is None with pytest.raises(TrezorFailure) as exc: get_test_address(client) assert exc.value.code == messages.FailureType.InvalidSession assert exc.value.message.endswith("Invalid session") client.init_device() assert client.session_id is not None with client: client.set_expected_responses([messages.Address]) get_test_address(client) with client: # end_session should succeed on empty session too client.set_expected_responses([messages.Success] * 2) client.end_session() client.end_session()
def test_derivation_irrelevant_on_slip39(client: Client, derivation_type): client.init_device(new_session=True, derive_cardano=False) pubkey = get_public_key(client, ADDRESS_N, derivation_type=D.ICARUS) test_pubkey = get_public_key(client, ADDRESS_N, derivation_type=derivation_type) assert pubkey == test_pubkey
def test_set_failed(client: Client): assert client.features.pin_protection is False # Check that there's no PIN protection _check_no_pin(client) # Let's set new PIN def input_flow(): yield # do you want to set pin? client.debug.press_yes() yield # enter new pin client.debug.input(PIN4) yield # enter new pin again (but different) client.debug.input(PIN60) # failed retry yield # enter new pin client.cancel() with client, pytest.raises(Cancelled): client.set_expected_responses([messages.ButtonRequest] * 4 + [messages.Failure]) client.set_input_flow(input_flow) device.change_pin(client) # Check that there's still no PIN protection now client.init_device() assert client.features.pin_protection is False _check_no_pin(client)
def test_change_failed(client: Client): assert client.features.pin_protection is True # Check current PIN value _check_pin(client, PIN4) # Let's set new PIN def input_flow(): yield # do you want to change pin? client.debug.press_yes() yield # enter current pin client.debug.input(PIN4) yield # enter new pin client.debug.input("457891") yield # enter new pin again (but different) client.debug.input("381847") # failed retry yield # enter current pin again client.cancel() with client, pytest.raises(Cancelled): client.set_expected_responses([messages.ButtonRequest] * 5 + [messages.Failure]) client.set_input_flow(input_flow) device.change_pin(client) # Check that there's still old PIN protection client.init_device() assert client.features.pin_protection is True _check_pin(client, PIN4)
def test_skip_backup_msg(client: Client, backup_type, backup_flow): os_urandom = mock.Mock(return_value=EXTERNAL_ENTROPY) with mock.patch("os.urandom", os_urandom), client: device.reset( client, skip_backup=True, passphrase_protection=False, pin_protection=False, backup_type=backup_type, ) assert client.features.initialized is True assert client.features.needs_backup is True assert client.features.unfinished_backup is False assert client.features.no_backup is False assert client.features.backup_type is backup_type secret = backup_flow(client) client.init_device() assert client.features.initialized is True assert client.features.needs_backup is False assert client.features.unfinished_backup is False assert client.features.backup_type is backup_type assert secret is not None state = client.debug.state() assert state.mnemonic_type is backup_type assert state.mnemonic_secret == secret
def test_backup_bip39(client: Client): assert client.features.needs_backup is True mnemonic = None def input_flow(): nonlocal mnemonic yield # Confirm Backup client.debug.press_yes() # Mnemonic phrases mnemonic = yield from read_and_confirm_mnemonic(client.debug) yield # Confirm success client.debug.press_yes() yield # Backup is done client.debug.press_yes() with client: client.set_input_flow(input_flow) client.set_expected_responses([ messages.ButtonRequest(code=B.ResetDevice), messages.ButtonRequest(code=B.ResetDevice), messages.ButtonRequest(code=B.Success), messages.ButtonRequest(code=B.Success), messages.Success, messages.Features, ]) device.backup(client) assert mnemonic == MNEMONIC12 client.init_device() assert client.features.initialized is True assert client.features.needs_backup is False assert client.features.unfinished_backup is False assert client.features.no_backup is False assert client.features.backup_type is messages.BackupType.Bip39
def test_backup_slip39_basic(client: Client, click_info: bool): assert client.features.needs_backup is True mnemonics = [] def input_flow(): yield # Checklist client.debug.press_yes() if click_info: yield from click_info_button(client.debug) yield # Number of shares (5) client.debug.press_yes() yield # Checklist client.debug.press_yes() if click_info: yield from click_info_button(client.debug) yield # Threshold (3) client.debug.press_yes() yield # Checklist client.debug.press_yes() yield # Confirm show seeds client.debug.press_yes() # Mnemonic phrases for _ in range(5): # Phrase screen mnemonic = yield from read_and_confirm_mnemonic(client.debug) mnemonics.append(mnemonic) yield # Confirm continue to next client.debug.press_yes() yield # Confirm backup client.debug.press_yes() with client: client.set_input_flow(input_flow) client.set_expected_responses( [messages.ButtonRequest(code=B.ResetDevice)] * (8 if click_info else 6) # intro screens (and optional info) + [ messages.ButtonRequest(code=B.ResetDevice), messages.ButtonRequest(code=B.Success), ] * 5 # individual shares + [ messages.ButtonRequest(code=B.Success), messages.Success, messages.Features, ]) device.backup(client) client.init_device() assert client.features.initialized is True assert client.features.needs_backup is False assert client.features.unfinished_backup is False assert client.features.no_backup is False assert client.features.backup_type is messages.BackupType.Slip39_Basic expected_ms = shamir.combine_mnemonics(MNEMONIC_SLIP39_BASIC_20_3of6) actual_ms = shamir.combine_mnemonics(mnemonics[:3]) assert expected_ms == actual_ms
def test_pin_passphrase(client: Client): mnemonic = MNEMONIC12.split(" ") ret = client.call_raw( messages.RecoveryDevice( word_count=12, passphrase_protection=True, pin_protection=True, label="label", language="en-US", enforce_wordlist=True, ) ) # click through confirmation assert isinstance(ret, messages.ButtonRequest) client.debug.press_yes() ret = client.call_raw(messages.ButtonAck()) assert isinstance(ret, messages.PinMatrixRequest) # Enter PIN for first time pin_encoded = client.debug.encode_pin(PIN6) ret = client.call_raw(messages.PinMatrixAck(pin=pin_encoded)) assert isinstance(ret, messages.PinMatrixRequest) # Enter PIN for second time pin_encoded = client.debug.encode_pin(PIN6) ret = client.call_raw(messages.PinMatrixAck(pin=pin_encoded)) fakes = 0 for _ in range(int(12 * 2)): assert isinstance(ret, messages.WordRequest) (word, pos) = client.debug.read_recovery_word() if pos != 0: ret = client.call_raw(messages.WordAck(word=mnemonic[pos - 1])) mnemonic[pos - 1] = None else: ret = client.call_raw(messages.WordAck(word=word)) fakes += 1 # Workflow succesfully ended assert isinstance(ret, messages.Success) # 12 expected fake words and all words of mnemonic are used assert fakes == 12 assert mnemonic == [None] * 12 # Mnemonic is the same client.init_device() assert client.debug.state().mnemonic_secret == MNEMONIC12.encode() assert client.features.pin_protection is True assert client.features.passphrase_protection is True # Do passphrase-protected action, PassphraseRequest should be raised resp = client.call_raw(messages.GetAddress(address_n=parse_path("m/44'/0'/0'/0/0"))) assert isinstance(resp, messages.PassphraseRequest) client.call_raw(messages.Cancel())
def test_bad_session(client: Client): client.init_device(new_session=True) with pytest.raises(TrezorFailure, match="not enabled"): get_public_key(client, ADDRESS_N, derivation_type=D.ICARUS) client.init_device(new_session=True, derive_cardano=False) with pytest.raises(TrezorFailure, match="not enabled"): get_public_key(client, ADDRESS_N, derivation_type=D.ICARUS)
def test_device_id_same(client: Client): id1 = client.get_device_id() client.init_device() id2 = client.get_device_id() # ID must be at least 12 characters assert len(id1) >= 12 # Every resulf of UUID must be the same assert id1 == id2
def _check_wipe_code(client: Client, pin, wipe_code): client.init_device() assert client.features.wipe_code_protection is True # Try to change the PIN to the current wipe code value. The operation should fail. with client, pytest.raises(TrezorFailure): client.use_pin_sequence([pin, wipe_code, wipe_code]) client.set_expected_responses( [messages.ButtonRequest()] * 5 + [messages.Failure(code=messages.FailureType.PinInvalid)]) device.change_pin(client)
def test_cardano_get_public_key(client: Client, parameters, result): client.init_device(new_session=True, derive_cardano=True) derivation_type = CardanoDerivationType.__members__[ parameters.get("derivation_type", "ICARUS_TREZOR") ] key = get_public_key(client, parse_path(parameters["path"]), derivation_type) assert key.node.public_key.hex() == result["public_key"] assert key.node.chain_code.hex() == result["chain_code"] assert key.xpub == result["public_key"] + result["chain_code"]
def test_cardano_get_native_script_hash(client: Client, parameters, result): client.init_device(new_session=True, derive_cardano=True) native_script_hash = get_native_script_hash( client, native_script=parse_native_script(parameters["native_script"]), display_format=messages.CardanoNativeScriptHashDisplayFormat. __members__[parameters["display_format"]], ).script_hash assert native_script_hash.hex() == result["expected_hash"]
def test_set_wipe_code_to_pin(client: Client): _ensure_unlocked(client, PIN4) with client: client.set_expected_responses([messages.ButtonRequest()] * 6 + [messages.Success, messages.Features]) client.use_pin_sequence([PIN4, PIN4, WIPE_CODE4, WIPE_CODE4]) device.change_wipe_code(client) client.init_device() assert client.features.wipe_code_protection is True _check_wipe_code(client, PIN4, WIPE_CODE4)
def test_cannot_resume_ended_session(client: Client): session_id = client.session_id with client: client.set_expected_responses([messages.Features]) client.init_device(session_id=session_id) assert session_id == client.session_id client.end_session() with client: client.set_expected_responses([messages.Features]) client.init_device(session_id=session_id) assert session_id != client.session_id
def test_unlocked(client: Client): assert client.features.unlocked is False _assert_protection(client, passphrase=False) with client: client.use_pin_sequence([PIN4]) client.set_expected_responses([_pin_request(client), messages.Address]) get_test_address(client) client.init_device() assert client.features.unlocked is True with client: client.set_expected_responses([messages.Address]) get_test_address(client)
def test_set_pin(client: Client): assert client.features.pin_protection is False # Check that there's no PIN protection _check_no_pin(client) # Let's set new PIN with client: client.use_pin_sequence([PIN_MAX, PIN_MAX]) client.set_expected_responses([messages.ButtonRequest] * 4 + [messages.Success, messages.Features]) device.change_pin(client) client.init_device() assert client.features.pin_protection is True _check_pin(client, PIN_MAX)
def test_skip_backup_manual(client: Client, backup_type, backup_flow): def reset_skip_input_flow(): yield # Confirm Recovery client.debug.press_yes() yield # Skip Backup client.debug.press_no() yield # Confirm skip backup client.debug.press_no() os_urandom = mock.Mock(return_value=EXTERNAL_ENTROPY) with mock.patch("os.urandom", os_urandom), client: client.set_input_flow(reset_skip_input_flow) client.set_expected_responses([ messages.ButtonRequest(code=B.ResetDevice), messages.EntropyRequest(), messages.ButtonRequest(code=B.ResetDevice), messages.ButtonRequest(code=B.ResetDevice), messages.Success, messages.Features, ]) device.reset( client, pin_protection=False, passphrase_protection=False, backup_type=backup_type, ) assert client.features.initialized is True assert client.features.needs_backup is True assert client.features.unfinished_backup is False assert client.features.no_backup is False assert client.features.backup_type is backup_type secret = backup_flow(client) client.init_device() assert client.features.initialized is True assert client.features.needs_backup is False assert client.features.unfinished_backup is False assert client.features.backup_type is backup_type assert secret is not None state = client.debug.state() assert state.mnemonic_type is backup_type assert state.mnemonic_secret == secret
def screen_recording( client: Client, request: pytest.FixtureRequest) -> Generator[None, None, None]: test_ui = request.config.getoption("ui") test_name = get_test_name(request.node.nodeid) # Differentiating test names between T1 and TT # Making the model global for other functions global MODEL MODEL = f"T{client.features.model}" if os.getenv("UI2") == "1": MODEL += "ui2" test_name = f"{MODEL}_{test_name}" screens_test_path = SCREENS_DIR / test_name if test_ui == "record": screen_path = screens_test_path / "recorded" else: screen_path = screens_test_path / "actual" if not screens_test_path.exists(): screens_test_path.mkdir() # remove previous files shutil.rmtree(screen_path, ignore_errors=True) screen_path.mkdir() try: client.debug.start_recording(str(screen_path)) yield finally: # Wait for response to Initialize, which gives the emulator time to catch up # and redraw the homescreen. Otherwise there's a race condition between that # and stopping recording. client.init_device() client.debug.stop_recording() if test_ui: PROCESSED.add(test_name) if get_last_call_test_result(request) is False: FAILED_TESTS.add(test_name) if test_ui == "record": _process_recorded(screen_path, test_name) else: _process_tested(screens_test_path, test_name)
def test_remove_pin(client: Client): assert client.features.pin_protection is True # Check current PIN value _check_pin(client, PIN4) # Let's remove PIN with client: client.use_pin_sequence([PIN4]) client.set_expected_responses([messages.ButtonRequest] * 3 + [messages.Success, messages.Features]) device.change_pin(client, remove=True) # Check that there's no PIN protection now client.init_device() assert client.features.pin_protection is False _check_no_pin(client)
def test_abort(client: Client): debug = client.debug def input_flow(): yield # Confirm Recovery debug.press_yes() yield # Homescreen - abort process debug.press_no() yield # Homescreen - confirm abort debug.press_yes() with client: client.set_input_flow(input_flow) with pytest.raises(exceptions.Cancelled): device.recover(client, pin_protection=False, label="label") client.init_device() assert client.features.initialized is False
def test_noabort(client: Client): debug = client.debug def input_flow(): yield # Confirm Recovery debug.press_yes() yield # Homescreen - abort process debug.press_no() yield # Homescreen - go back to process debug.press_no() yield from recovery_enter_shares(debug, MNEMONIC_SLIP39_BASIC_20_3of6) with client: client.set_input_flow(input_flow) device.recover(client, pin_protection=False, label="label") client.init_device() assert client.features.initialized is True
def test_change_pin(client: Client): assert client.features.pin_protection is True # Check current PIN value _check_pin(client, PIN4) # Let's change PIN with client: client.use_pin_sequence([PIN4, PIN_MAX, PIN_MAX]) client.set_expected_responses([messages.ButtonRequest] * 5 + [messages.Success, messages.Features]) device.change_pin(client) # Check that there's still PIN protection now client.init_device() assert client.features.pin_protection is True # Check that the PIN is correct _check_pin(client, PIN_MAX)
def test_set_wipe_code_to_pin(client: Client): # Check that wipe code protection status is not revealed in locked state. assert client.features.wipe_code_protection is None # Let's try setting the wipe code to the curent PIN value. with client: client.use_pin_sequence([PIN4, PIN4]) client.set_expected_responses([ messages.ButtonRequest(), messages.PinMatrixRequest(type=PinType.Current), messages.PinMatrixRequest(type=PinType.WipeCodeFirst), messages.Failure(code=messages.FailureType.ProcessError), ]) with pytest.raises(exceptions.TrezorFailure): device.change_wipe_code(client) # Check that there is no wipe code protection. client.init_device() assert client.features.wipe_code_protection is False
def test_set_wipe_code_mismatch(client: Client): # Check that there is no wipe code protection. client.ensure_unlocked() assert client.features.wipe_code_protection is False # Let's set a new wipe code. with client: client.use_pin_sequence([WIPE_CODE4, WIPE_CODE6]) client.set_expected_responses([ messages.ButtonRequest(), messages.PinMatrixRequest(type=PinType.WipeCodeFirst), messages.PinMatrixRequest(type=PinType.WipeCodeSecond), messages.Failure(code=messages.FailureType.WipeCodeMismatch), ]) with pytest.raises(exceptions.TrezorFailure): device.change_wipe_code(client) # Check that there is no wipe code protection. client.init_device() assert client.features.wipe_code_protection is False
def test_change_mismatch(client: Client): assert client.features.pin_protection is True # Let's set new PIN with pytest.raises(TrezorFailure, match="PIN mismatch"), client: client.use_pin_sequence([PIN4, PIN6, PIN6 + "3"]) client.set_expected_responses([ messages.ButtonRequest( code=messages.ButtonRequestType.ProtectCall), messages.PinMatrixRequest, messages.PinMatrixRequest, messages.PinMatrixRequest, messages.Failure, ]) device.change_pin(client) # Check that there's still old PIN protection client.init_device() assert client.features.pin_protection is True _check_pin(client, PIN4)
def test_set_wipe_code_invalid(client: Client, invalid_wipe_code): # Let's set the wipe code ret = client.call_raw(messages.ChangeWipeCode()) assert isinstance(ret, messages.ButtonRequest) # Confirm client.debug.press_yes() ret = client.call_raw(messages.ButtonAck()) # Enter a wipe code containing an invalid digit assert isinstance(ret, messages.PinMatrixRequest) assert ret.type == PinType.WipeCodeFirst ret = client.call_raw(messages.PinMatrixAck(pin=invalid_wipe_code)) # Ensure the invalid wipe code is detected assert isinstance(ret, messages.Failure) # Check that there's still no wipe code protection. client.init_device() client.ensure_unlocked() assert client.features.wipe_code_protection is False
def test_set_pin_to_wipe_code(client: Client): # Set wipe code. _set_wipe_code(client, None, WIPE_CODE4) # Try to set the PIN to the current wipe code value. with client: client.use_pin_sequence([WIPE_CODE4, WIPE_CODE4]) client.set_expected_responses([ messages.ButtonRequest(), messages.PinMatrixRequest(type=PinType.NewFirst), messages.PinMatrixRequest(type=PinType.NewSecond), messages.Failure(code=messages.FailureType.ProcessError), ]) with pytest.raises(exceptions.TrezorFailure): device.change_pin(client) # Check that there is no PIN protection. client.init_device() assert client.features.pin_protection is False resp = client.call_raw(messages.GetAddress()) assert isinstance(resp, messages.Address)