Skip to content

Commit 165d121

Browse files
committed
refactor(python): refactor THP-related exception types
[no changelog]
1 parent 7150c88 commit 165d121

File tree

6 files changed

+41
-49
lines changed

6 files changed

+41
-49
lines changed

python/src/trezorlib/cli/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -293,7 +293,7 @@ def session_context(
293293
empty_passphrase=empty_passphrase,
294294
must_resume=must_resume,
295295
)
296-
except exceptions.DeviceLockedException:
296+
except exceptions.DeviceLocked:
297297
click.echo(
298298
"Device is locked, enter a pin on the device.",
299299
err=True,

python/src/trezorlib/debuglink.py

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -34,12 +34,7 @@
3434

3535
from . import btc, mapping, messages, models, protobuf
3636
from .client import ProtocolVersion, TrezorClient
37-
from .exceptions import (
38-
Cancelled,
39-
DeviceLockedException,
40-
TrezorFailure,
41-
UnexpectedMessageError,
42-
)
37+
from .exceptions import Cancelled, TrezorFailure, UnexpectedMessageError
4338
from .log import DUMP_BYTES
4439
from .messages import DebugTouchEventType, DebugWaitType
4540
from .tools import parse_path
@@ -1317,14 +1312,7 @@ def get_pin(_msg: messages.PinMatrixRequest) -> str:
13171312
self.pin_callback = get_pin
13181313
self.button_callback = self.ui.button_request
13191314

1320-
try:
1321-
super().__init__(transport)
1322-
except DeviceLockedException:
1323-
LOG.debug("Locked device handling")
1324-
self.debug.input("")
1325-
self.debug.input(self.debug.encode_pin("1234"))
1326-
super().__init__(transport)
1327-
1315+
super().__init__(transport)
13281316
self.sync_responses()
13291317

13301318
# So that we can choose right screenshotting logic (T1 vs TT)

python/src/trezorlib/exceptions.py

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -111,13 +111,33 @@ class DerivationOnUninitaizedDeviceError(TrezorException):
111111
To communicate with uninitialized device, use seedless session instead."""
112112

113113

114-
class DeviceLockedException(TrezorException):
114+
class UnexpectedCodeEntryTagException(TrezorException):
115115
pass
116116

117117

118-
class UnexpectedCodeEntryTagException(TrezorException):
118+
class ThpError(TrezorException):
119119
pass
120120

121121

122-
class ThpError(TrezorException):
122+
class TransportBusy(ThpError):
123+
pass
124+
125+
126+
class UnallocatedChannel(ThpError):
127+
pass
128+
129+
130+
class DecryptionFailed(ThpError):
131+
pass
132+
133+
134+
class InvalidData(ThpError):
135+
pass
136+
137+
138+
class DeviceLocked(ThpError):
139+
pass
140+
141+
142+
class ThpUnknownError(ThpError):
123143
pass

python/src/trezorlib/transport/thp/protocol_v2.py

Lines changed: 11 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -231,11 +231,6 @@ def _send_handshake_init_request(self) -> None:
231231

232232
def _read_handshake_init_response(self) -> bytes:
233233
header, payload = self._read_until_valid_crc_check()
234-
if control_byte.is_error(header.ctrl_byte):
235-
if payload == b"\x05":
236-
raise exceptions.DeviceLockedException()
237-
else:
238-
raise exceptions.ThpError(_get_error_from_int(payload[0]))
239234

240235
if not header.is_handshake_init_response():
241236
LOG.error("Received message is not a valid handshake init response message")
@@ -278,8 +273,6 @@ def _read_handshake_completion_response(self) -> int:
278273
header, data = self._read_until_valid_crc_check()
279274
if not header.is_handshake_comp_response():
280275
LOG.error("Received message is not a valid handshake completion response")
281-
if control_byte.is_error(header.ctrl_byte):
282-
raise exceptions.ThpError(_get_error_from_int(data[0]))
283276
trezor_state = self._noise.decrypt(bytes(data))
284277
assert trezor_state == b"\x00" or trezor_state == b"\x01"
285278
self._send_ack_bit(bit=1)
@@ -289,8 +282,6 @@ def _read_ack(self):
289282
header, payload = self._read_until_valid_crc_check()
290283
if not header.is_ack() or len(payload) > 0:
291284
LOG.error("Received message is not a valid ACK")
292-
if control_byte.is_error(header.ctrl_byte):
293-
raise exceptions.ThpError(_get_error_from_int(payload[0]))
294285

295286
def _send_ack_bit(self, bit: int):
296287
if bit not in (0, 1):
@@ -336,8 +327,6 @@ def read_and_decrypt(
336327
continue
337328
if control_byte.is_ack(header.ctrl_byte):
338329
continue
339-
if control_byte.is_error(header.ctrl_byte):
340-
raise exceptions.ThpError(_get_error_from_int(raw_payload[0]))
341330
if not header.is_encrypted_transport():
342331
LOG.error(
343332
"Trying to decrypt not encrypted message! ("
@@ -392,6 +381,10 @@ def _read_until_valid_crc_check(
392381

393382
self.sync_bit_receive = 1 - self.sync_bit_receive
394383

384+
if control_byte.is_error(header.ctrl_byte):
385+
code = payload[0]
386+
raise _ERRORS_MAP.get(code) or exceptions.ThpUnknownError(code)
387+
395388
return header, payload
396389

397390
def _is_valid_channel_allocation_response(
@@ -420,16 +413,10 @@ def _is_valid_pong(
420413
return True
421414

422415

423-
def _get_error_from_int(error_code: int) -> str:
424-
# TODO FIXME improve this (ThpErrorType)
425-
if error_code == 1:
426-
return "TRANSPORT BUSY"
427-
if error_code == 2:
428-
return "UNALLOCATED CHANNEL"
429-
if error_code == 3:
430-
return "DECRYPTION FAILED"
431-
if error_code == 4:
432-
return "INVALID DATA"
433-
if error_code == 5:
434-
return "DEVICE LOCKED"
435-
raise Exception("Not Implemented error case")
416+
_ERRORS_MAP = {
417+
1: exceptions.TransportBusy,
418+
2: exceptions.UnallocatedChannel,
419+
3: exceptions.DecryptionFailed,
420+
4: exceptions.InvalidData,
421+
5: exceptions.DeviceLocked,
422+
}

tests/device_tests/thp/test_multiple_hosts.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,9 @@ def test_concurrent_handshakes(client: Client) -> None:
3131
# The second host starts handshake
3232
protocol_2._send_handshake_init_request()
3333

34-
# The second host should not be able to interrupt the first host's handshake
35-
with pytest.raises(exceptions.ThpError) as e:
34+
# The second host should not be able to interrupt the first host's handshake immediately
35+
with pytest.raises(exceptions.TransportBusy):
3636
protocol_2._read_ack()
37-
assert e.value.args[0] == "TRANSPORT BUSY"
3837

3938
# The first host can complete handshake
4039
protocol_1._send_handshake_completion_request()

tests/device_tests/thp/test_pairing.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -406,9 +406,8 @@ def test_credential_phase(client: Client) -> None:
406406
protocol._noise.noise_protocol.cipher_state_encrypt.n = 250
407407

408408
protocol._send_message(ButtonAck())
409-
with pytest.raises(exceptions.ThpError) as e:
409+
with pytest.raises(exceptions.DecryptionFailed):
410410
protocol.read(1)
411-
assert e.value.args[0] == "DECRYPTION FAILED"
412411

413412
# Connect using credential with confirmation and ask for autoconnect credential.
414413
protocol = prepare_protocol_for_handshake(client)
@@ -457,9 +456,8 @@ def test_credential_phase(client: Client) -> None:
457456
protocol._noise.noise_protocol.cipher_state_encrypt.n = 100
458457

459458
protocol._send_message(ButtonAck())
460-
with pytest.raises(exceptions.ThpError) as e:
459+
with pytest.raises(exceptions.DecryptionFailed):
461460
protocol.read(1)
462-
assert e.value.args[0] == "DECRYPTION FAILED"
463461

464462
# Connect using autoconnect credential - should work the same as above
465463
protocol = prepare_protocol_for_handshake(client)

0 commit comments

Comments
 (0)