def test_clear_session(client): if client.features.model == "1": init_responses = [ messages.PinMatrixRequest(), messages.PassphraseRequest() ] else: init_responses = [messages.PassphraseRequest()] cached_responses = [messages.PublicKey()] with client: client.set_expected_responses(init_responses + cached_responses) assert get_public_node(client, ADDRESS_N).xpub == XPUB with client: # pin and passphrase are cached client.set_expected_responses(cached_responses) assert get_public_node(client, ADDRESS_N).xpub == XPUB client.clear_session() # session cache is cleared with client: client.set_expected_responses(init_responses + cached_responses) assert get_public_node(client, ADDRESS_N).xpub == XPUB with client: # pin and passphrase are cached client.set_expected_responses(cached_responses) assert get_public_node(client, ADDRESS_N).xpub == XPUB
def test_passphrase_works(emulator): """Check that passphrase handling in trezorlib works correctly in all versions.""" if emulator.client.features.model == "T" and emulator.client.version < ( 2, 3, 0): expected_responses = [ messages.PassphraseRequest(), messages.Deprecated_PassphraseStateRequest(), messages.Address(), ] elif (emulator.client.features.model == "T" and emulator.client.version < (2, 3, 3)) or (emulator.client.features.model == "1" and emulator.client.version < (1, 9, 3)): expected_responses = [ messages.PassphraseRequest(), messages.Address(), ] else: expected_responses = [ messages.PassphraseRequest(), messages.ButtonRequest(), messages.ButtonRequest(), messages.Address(), ] with emulator.client: emulator.client.use_passphrase("TREZOR") emulator.client.set_expected_responses(expected_responses) btc.get_address(emulator.client, "Testnet", parse_path("44h/1h/0h/0/0"))
def test_init_device(emulator): """Check that passphrase caching and session_id retaining works correctly across supported versions. """ if emulator.client.features.model == "T" and emulator.client.version < ( 2, 3, 0): expected_responses = [ messages.PassphraseRequest(), messages.Deprecated_PassphraseStateRequest(), messages.Address(), messages.Features(), messages.Address(), ] else: expected_responses = [ messages.PassphraseRequest(), messages.Address(), messages.Features(), messages.Address(), ] with emulator.client: emulator.client.use_passphrase("TREZOR") emulator.client.set_expected_responses(expected_responses) btc.get_address(emulator.client, "Testnet", parse_path("44h/1h/0h/0/0")) # in TT < 2.3.0 session_id will only be available after PassphraseStateRequest session_id = emulator.client.session_id emulator.client.init_device() btc.get_address(emulator.client, "Testnet", parse_path("44h/1h/0h/0/0")) assert session_id == emulator.client.session_id
def test_clearsession(self): self.setup_mnemonic_pin_passphrase() with self.client: self.client.set_expected_responses([ proto.ButtonRequest(code=proto.ButtonRequestType.ProtectCall), proto.PinMatrixRequest(), proto.PassphraseRequest(), proto.Success() ]) res = self.client.ping('random data', button_protection=True, pin_protection=True, passphrase_protection=True) assert res == 'random data' with self.client: # pin and passphrase are cached self.client.set_expected_responses([ proto.ButtonRequest(code=proto.ButtonRequestType.ProtectCall), proto.Success() ]) res = self.client.ping('random data', button_protection=True, pin_protection=True, passphrase_protection=True) assert res == 'random data' self.client.clear_session() # session cache is cleared with self.client: self.client.set_expected_responses([ proto.ButtonRequest(code=proto.ButtonRequestType.ProtectCall), proto.PinMatrixRequest(), proto.PassphraseRequest(), proto.Success() ]) res = self.client.ping('random data', button_protection=True, pin_protection=True, passphrase_protection=True) assert res == 'random data' with self.client: # pin and passphrase are cached self.client.set_expected_responses([ proto.ButtonRequest(code=proto.ButtonRequestType.ProtectCall), proto.Success() ]) res = self.client.ping('random data', button_protection=True, pin_protection=True, passphrase_protection=True) assert res == 'random data'
def test_session_recycling(client): session_id_orig = client.session_id with client: client.set_expected_responses([ messages.PassphraseRequest(), messages.ButtonRequest(), messages.ButtonRequest(), messages.Address(), ]) client.use_passphrase("TREZOR") address = get_test_address(client) # create and close 100 sessions - more than the session limit for _ in range(100): client.init_device(new_session=True) client.end_session() # it should still be possible to resume the original session with client: # passphrase should still be cached client.set_expected_responses( [messages.Features(), messages.Address()]) client.use_passphrase("TREZOR") client.init_device(session_id=session_id_orig) assert address == get_test_address(client)
def test_ping_caching(self): self.setup_mnemonic_pin_passphrase() with self.client: self.client.set_expected_responses([ proto.ButtonRequest(code=proto.ButtonRequestType.ProtectCall), proto.PinMatrixRequest(), proto.PassphraseRequest(), proto.Success(), ]) res = self.client.ping( "random data", button_protection=True, pin_protection=True, passphrase_protection=True, ) assert res == "random data" with self.client: # pin and passphrase are cached self.client.set_expected_responses([ proto.ButtonRequest(code=proto.ButtonRequestType.ProtectCall), proto.Success(), ]) res = self.client.ping( "random data", button_protection=True, pin_protection=True, passphrase_protection=True, ) assert res == "random data"
def test_get_address(self, client): with client: client.use_pin_sequence([PIN4]) client.set_expected_responses( [proto.PinMatrixRequest(), proto.PassphraseRequest(), proto.Address()] ) btc.get_address(client, "Bitcoin", [])
def test_get_public_key(self, client): with client: client.use_pin_sequence([PIN4]) client.set_expected_responses( [proto.PinMatrixRequest(), proto.PassphraseRequest(), proto.PublicKey()] ) btc.get_public_node(client, [])
def test_clear_session(client): is_trezor1 = client.features.model == "1" init_responses = [ messages.PinMatrixRequest() if is_trezor1 else messages.ButtonRequest(), messages.PassphraseRequest(), ] cached_responses = [messages.PublicKey()] with client: client.use_pin_sequence([PIN4]) client.set_expected_responses(init_responses + cached_responses) assert get_public_node(client, ADDRESS_N).xpub == XPUB with client: # pin and passphrase are cached client.set_expected_responses(cached_responses) assert get_public_node(client, ADDRESS_N).xpub == XPUB client.clear_session() # session cache is cleared with client: client.use_pin_sequence([PIN4]) client.set_expected_responses(init_responses + cached_responses) assert get_public_node(client, ADDRESS_N).xpub == XPUB with client: # pin and passphrase are cached client.set_expected_responses(cached_responses) assert get_public_node(client, ADDRESS_N).xpub == XPUB
def test_cardano_sign_tx_failed(client, parameters, result): inputs = [cardano.create_input(i) for i in parameters["inputs"]] outputs = [cardano.create_output(o) for o in parameters["outputs"]] certificates = [ cardano.create_certificate(c) for c in parameters["certificates"] ] withdrawals = [ cardano.create_withdrawal(w) for w in parameters["withdrawals"] ] expected_responses = [messages.PassphraseRequest(), messages.Failure()] with client: client.set_expected_responses(expected_responses) with pytest.raises(TrezorFailure, match=result["error_message"]): cardano.sign_tx( client=client, inputs=inputs, outputs=outputs, fee=parameters["fee"], ttl=parameters["ttl"], certificates=certificates, withdrawals=withdrawals, metadata=bytes.fromhex(parameters["metadata"]), protocol_magic=parameters["protocol_magic"], network_id=parameters["network_id"], )
def test_ping(self, client): with client: client.set_expected_responses([proto.Success()]) res = client.ping("random data") assert res == "random data" with client: client.set_expected_responses( [ proto.ButtonRequest(code=proto.ButtonRequestType.ProtectCall), proto.Success(), ] ) res = client.ping("random data", button_protection=True) assert res == "random data" with client: client.set_expected_responses([proto.PinMatrixRequest(), proto.Success()]) res = client.ping("random data", pin_protection=True) assert res == "random data" with client: client.set_expected_responses([proto.PassphraseRequest(), proto.Success()]) res = client.ping("random data", passphrase_protection=True) assert res == "random data"
def test_signtx(self, client): inp1 = proto.TxInputType( address_n=[0], # 14LmW5k4ssUrtbAB4255zdqv3b4w1TuX9e prev_hash=TXHASH_d5f65e, prev_index=0, ) out1 = proto.TxOutputType( address="1MJ2tj2ThBE62zXbBYA5ZaN3fdve5CPAz1", amount=390000 - 10000, script_type=proto.OutputScriptType.PAYTOADDRESS, ) with client: client.set_expected_responses([ proto.PinMatrixRequest(), proto.PassphraseRequest(), request_input(0), request_meta(TXHASH_d5f65e), request_input(0, TXHASH_d5f65e), request_input(1, TXHASH_d5f65e), request_output(0, TXHASH_d5f65e), request_output(0), proto.ButtonRequest(code=B.ConfirmOutput), proto.ButtonRequest(code=B.SignTx), request_input(0), request_output(0), request_output(0), request_finished(), ]) btc.sign_tx(client, "Bitcoin", [inp1], [out1], prev_txes=TxCache("Bitcoin"))
def test_ping(self): self.setup_mnemonic_pin_passphrase() with self.client: self.client.set_expected_responses([proto.Success()]) res = self.client.ping('random data') assert res == 'random data' with self.client: self.client.set_expected_responses([ proto.ButtonRequest(code=proto.ButtonRequestType.ProtectCall), proto.Success() ]) res = self.client.ping('random data', button_protection=True) assert res == 'random data' with self.client: self.client.set_expected_responses( [proto.PinMatrixRequest(), proto.Success()]) res = self.client.ping('random data', pin_protection=True) assert res == 'random data' with self.client: self.client.set_expected_responses( [proto.PassphraseRequest(), proto.Success()]) res = self.client.ping('random data', passphrase_protection=True) assert res == 'random data'
def test_cardano_sign_tx(client, protocol_magic, inputs, outputs, transactions, tx_hash, tx_body): inputs = [cardano.create_input(i) for i in inputs] outputs = [cardano.create_output(o) for o in outputs] expected_responses = [ messages.PassphraseRequest(), messages.PassphraseStateRequest(), ] expected_responses += [ messages.CardanoTxRequest(tx_index=i) for i in range(len(transactions)) ] expected_responses += [ messages.ButtonRequest(code=messages.ButtonRequestType.Other), messages.ButtonRequest(code=messages.ButtonRequestType.Other), messages.CardanoSignedTx(), ] def input_flow(): yield client.debug.swipe_down() client.debug.press_yes() yield client.debug.swipe_down() client.debug.press_yes() client.set_passphrase("TREZOR") with client: client.set_expected_responses(expected_responses) client.set_input_flow(input_flow) response = cardano.sign_tx(client, inputs, outputs, transactions, protocol_magic) assert response.tx_hash.hex() == tx_hash assert response.tx_body.hex() == tx_body
def test_passphrase_cached(self, client): with client: client.set_expected_responses([proto.PassphraseRequest(), proto.Address()]) btc.get_address(client, "Testnet", [0]) with client: client.set_expected_responses([proto.Address()]) btc.get_address(client, "Testnet", [0])
def test_signtx(self): self.setup_mnemonic_pin_passphrase() inp1 = proto.TxInputType( address_n=[0], # 14LmW5k4ssUrtbAB4255zdqv3b4w1TuX9e prev_hash=TXHASH_d5f65e, prev_index=0, ) out1 = proto.TxOutputType( address='1MJ2tj2ThBE62zXbBYA5ZaN3fdve5CPAz1', amount=390000 - 10000, script_type=proto.OutputScriptType.PAYTOADDRESS, ) with self.client: self.client.set_expected_responses([ proto.PinMatrixRequest(), proto.PassphraseRequest(), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0)), proto.TxRequest( request_type=proto.RequestType.TXMETA, details=proto.TxRequestDetailsType(tx_hash=TXHASH_d5f65e)), proto.TxRequest(request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType( request_index=0, tx_hash=TXHASH_d5f65e)), proto.TxRequest(request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType( request_index=1, tx_hash=TXHASH_d5f65e)), proto.TxRequest(request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType( request_index=0, tx_hash=TXHASH_d5f65e)), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0)), proto.ButtonRequest( code=proto.ButtonRequestType.ConfirmOutput), proto.ButtonRequest(code=proto.ButtonRequestType.SignTx), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0)), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0)), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0)), proto.TxRequest(request_type=proto.RequestType.TXFINISHED), ]) self.client.sign_tx('Bitcoin', [ inp1, ], [ out1, ])
def test_get_address(self): with self.client: self.setup_mnemonic_pin_passphrase() self.client.set_expected_responses([ proto.PinMatrixRequest(), proto.PassphraseRequest(), proto.Address() ]) self.client.get_address('Bitcoin', [])
def test_ping(self, client): with client: client.set_expected_responses([ proto.ButtonRequest(), proto.PinMatrixRequest(), proto.PassphraseRequest(), proto.Success(), ]) client.ping("msg", True, True, True)
def test_sign_message(self, client): with client: client.set_expected_responses([ proto.ButtonRequest(), proto.PinMatrixRequest(), proto.PassphraseRequest(), proto.MessageSignature(), ]) btc.sign_message(client, "Bitcoin", [], "testing message")
def test_get_public_key(self): with self.client: self.setup_mnemonic_pin_passphrase() self.client.set_expected_responses([ proto.PinMatrixRequest(), proto.PassphraseRequest(), proto.PublicKey() ]) self.client.get_public_node([])
def test_cardano_sign_tx( client, protocol_magic, network_id, inputs, outputs, fee, ttl, input_flow_sequences, tx_hash, serialized_tx, ): inputs = [cardano.create_input(i) for i in inputs] outputs = [cardano.create_output(o) for o in outputs] certificates = [] withdrawals = [] metadata = bytes() expected_responses = [ messages.PassphraseRequest(), ] expected_responses += [ messages.ButtonRequest(code=messages.ButtonRequestType.Other) for i in range(len(input_flow_sequences)) ] expected_responses.append(messages.CardanoSignedTx()) def input_flow(): for sequence in input_flow_sequences: yield for action in sequence: if action == InputAction.SWIPE: client.debug.swipe_up() elif action == InputAction.YES: client.debug.press_yes() else: raise ValueError("Invalid input action") client.use_passphrase("TREZOR") with client: client.set_expected_responses(expected_responses) client.set_input_flow(input_flow) response = cardano.sign_tx( client=client, inputs=inputs, outputs=outputs, fee=fee, ttl=ttl, certificates=certificates, withdrawals=withdrawals, metadata=metadata, protocol_magic=protocol_magic, network_id=network_id, ) assert response.tx_hash.hex() == tx_hash assert response.serialized_tx.hex() == serialized_tx
def test_sign_message(self): with self.client: self.setup_mnemonic_pin_passphrase() self.client.set_expected_responses([ proto.ButtonRequest(), proto.PinMatrixRequest(), proto.PassphraseRequest(), proto.MessageSignature() ]) self.client.sign_message('Bitcoin', [], 'testing message')
def test_ping(self): with self.client: self.setup_mnemonic_pin_passphrase() self.client.set_expected_responses([ proto.ButtonRequest(), proto.PinMatrixRequest(), proto.PassphraseRequest(), proto.Success() ]) self.client.ping('msg', True, True, True)
def test_passphrase_cached(self, client): assert client.features.passphrase_cached is False with client: client.set_expected_responses( [proto.ButtonRequest(), proto.PassphraseRequest(), proto.Success()] ) client.ping("msg", True, True, True) features = client.call(proto.GetFeatures()) assert features.passphrase_cached is True with client: client.set_expected_responses([proto.ButtonRequest(), proto.Success()]) client.ping("msg", True, True, True)
def test_cardano_sign_tx(client, parameters, result): inputs = [cardano.create_input(i) for i in parameters["inputs"]] outputs = [cardano.create_output(o) for o in parameters["outputs"]] certificates = [ cardano.create_certificate(c) for c in parameters["certificates"] ] withdrawals = [ cardano.create_withdrawal(w) for w in parameters["withdrawals"] ] expected_responses = [messages.PassphraseRequest()] expected_responses += [ messages.ButtonRequest(code=messages.ButtonRequestType.Other) for i in range(len(parameters["input_flow"])) ] expected_responses.append(messages.CardanoSignedTx()) def input_flow(): for sequence in parameters["input_flow"]: yield for action in sequence: if action == "SWIPE": client.debug.swipe_up() elif action == "YES": client.debug.press_yes() else: raise ValueError("Invalid input action") with client: client.set_expected_responses(expected_responses) client.set_input_flow(input_flow) response = cardano.sign_tx( client=client, inputs=inputs, outputs=outputs, fee=parameters["fee"], ttl=parameters.get("ttl"), validity_interval_start=parameters.get("validity_interval_start"), certificates=certificates, withdrawals=withdrawals, metadata=bytes.fromhex(parameters["metadata"]), protocol_magic=parameters["protocol_magic"], network_id=parameters["network_id"], ) assert response.tx_hash.hex() == result["tx_hash"] assert response.serialized_tx.hex() == result["serialized_tx"]
def test_cardano_sign_tx_with_multiple_chunks(client, parameters, result): 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"]) input_flow = parameters.get("input_flow", ()) expected_responses = [ messages.PassphraseRequest(), messages.ButtonRequest(), messages.ButtonRequest(), ] expected_responses += [ messages.CardanoSignedTxChunk( signed_tx_chunk=bytes.fromhex(signed_tx_chunk)) for signed_tx_chunk in result["signed_tx_chunks"] ] expected_responses += [ messages.CardanoSignedTx(tx_hash=bytes.fromhex(result["tx_hash"])) ] with client: client.set_input_flow(_to_device_actions(client, input_flow)) client.set_expected_responses(expected_responses) response = cardano.sign_tx( client=client, 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, ) assert response.tx_hash.hex() == result["tx_hash"] assert response.serialized_tx.hex() == result["serialized_tx"]
def _get_xpub(client, passphrase=None): """Get XPUB and check that the appropriate passphrase flow has happened.""" if passphrase is not None: expected_responses = [ messages.PassphraseRequest(), messages.ButtonRequest(), messages.ButtonRequest(), messages.PublicKey(), ] else: expected_responses = [messages.PublicKey()] with client: client.use_passphrase(passphrase or "") client.set_expected_responses(expected_responses) result = client.call(XPUB_REQUEST) return result.xpub
def test_expected_responses(self, client): # This is low-level test of set_expected_responses() # feature of debugging client with pytest.raises(AssertionError), client: # Scenario 1 - Received unexpected message client.set_expected_responses([]) self._some_protected_call(client, True, True, True) with pytest.raises(AssertionError), client: # Scenario 2 - Received other than expected message client.set_expected_responses([proto.Success()]) self._some_protected_call(client, True, True, True) with pytest.raises(AssertionError), client: # Scenario 3 - Not received expected message client.set_expected_responses( [proto.ButtonRequest(), proto.Success(), proto.Success()] ) # This is expected, but not received self._some_protected_call(client, True, False, False) with pytest.raises(AssertionError), client: # Scenario 4 - Received what expected client.set_expected_responses( [ proto.ButtonRequest(), proto.PinMatrixRequest(), proto.PassphraseRequest(), proto.Success(message="random data"), ] ) self._some_protected_call(client, True, True, True) with pytest.raises(AssertionError), client: # Scenario 5 - Failed message by field filter client.set_expected_responses( [proto.ButtonRequest(), proto.Success(message="wrong data")] ) self._some_protected_call(client, True, True, True)
def test_signtx(self, client): inp1 = proto.TxInputType( address_n=[0], # 14LmW5k4ssUrtbAB4255zdqv3b4w1TuX9e prev_hash=TXHASH_d5f65e, prev_index=0, ) out1 = proto.TxOutputType( address="1MJ2tj2ThBE62zXbBYA5ZaN3fdve5CPAz1", amount=390000 - 10000, script_type=proto.OutputScriptType.PAYTOADDRESS, ) with client: client.set_expected_responses([ proto.PinMatrixRequest(), proto.PassphraseRequest(), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXMETA, details=proto.TxRequestDetailsType(tx_hash=TXHASH_d5f65e), ), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0, tx_hash=TXHASH_d5f65e), ), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=1, tx_hash=TXHASH_d5f65e), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0, tx_hash=TXHASH_d5f65e), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.ButtonRequest( code=proto.ButtonRequestType.ConfirmOutput), proto.ButtonRequest(code=proto.ButtonRequestType.SignTx), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest(request_type=proto.RequestType.TXFINISHED), ]) btc.sign_tx(client, "Bitcoin", [inp1], [out1], prev_txes=tx_cache("Bitcoin"))
def test_clearsession(self, client): with client: client.set_expected_responses([ proto.ButtonRequest(code=proto.ButtonRequestType.ProtectCall), proto.PinMatrixRequest(), proto.PassphraseRequest(), proto.Success(), ]) res = client.ping( "random data", button_protection=True, pin_protection=True, passphrase_protection=True, ) assert res == "random data" with client: # pin and passphrase are cached client.set_expected_responses([ proto.ButtonRequest(code=proto.ButtonRequestType.ProtectCall), proto.Success(), ]) res = client.ping( "random data", button_protection=True, pin_protection=True, passphrase_protection=True, ) assert res == "random data" client.clear_session() # session cache is cleared with client: client.set_expected_responses([ proto.ButtonRequest(code=proto.ButtonRequestType.ProtectCall), proto.PinMatrixRequest(), proto.PassphraseRequest(), proto.Success(), ]) res = client.ping( "random data", button_protection=True, pin_protection=True, passphrase_protection=True, ) assert res == "random data" with client: # pin and passphrase are cached client.set_expected_responses([ proto.ButtonRequest(code=proto.ButtonRequestType.ProtectCall), proto.Success(), ]) res = client.ping( "random data", button_protection=True, pin_protection=True, passphrase_protection=True, ) assert res == "random data"