From 31c08320bef877c439907c4f921a44a47a3277a2 Mon Sep 17 00:00:00 2001 From: Jordan Yates Date: Mon, 3 Aug 2026 20:30:31 +1000 Subject: [PATCH 1/2] database: context in key exceptions Add extra context to the key exceptions to ease debugging. Signed-off-by: Jordan Yates --- src/infuse_iot/database.py | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/src/infuse_iot/database.py b/src/infuse_iot/database.py index 68cbef1..427bfc1 100644 --- a/src/infuse_iot/database.py +++ b/src/infuse_iot/database.py @@ -30,10 +30,27 @@ class UnknownNetworkError(NoKeyError): class DeviceUnknownDeviceKey(NoKeyError): """Device key is not known for requested device""" + def __init__(self, infuse_id: int, interface: bytes, key_id: int | None): + self.infuse_id = infuse_id + self.interface = interface + self.key_id = key_id + + def __str__(self): + interface_str = self.interface.decode("utf-8") + return f"{self.infuse_id:016x}: {interface_str} {self.key_id}" + class DeviceUnknownNetworkKey(NoKeyError): """Network key is not known for requested device""" + def __init__(self, infuse_id: int, interface: bytes): + self.infuse_id = infuse_id + self.interface = interface + + def __str__(self): + interface_str = self.interface.decode("utf-8") + return f"{self.infuse_id:016x}: {interface_str}" + class DeviceKeyChangedError(KeyError): """Device key for the requested device has changed""" @@ -242,17 +259,17 @@ def infuse_id_from_bluetooth(self, bt_addr: InterfaceAddress.BluetoothLeAddr) -> def _get_network_key(self, infuse_id: int, name: bytes, gps_time: int) -> bytes: if infuse_id not in self.devices: - raise DeviceUnknownNetworkKey + raise DeviceUnknownNetworkKey(infuse_id, name) network_id = self.devices[infuse_id].network_id if network_id is None: - raise DeviceUnknownNetworkKey + raise DeviceUnknownNetworkKey(infuse_id, name) return self._network_key(network_id, name, gps_time) def _get_device_key( self, infuse_id: int, name: bytes, gps_time: int, key_id: int | None = None ) -> tuple[int, bytes]: if infuse_id not in self.devices: - raise DeviceUnknownDeviceKey + raise DeviceUnknownDeviceKey(infuse_id, name, key_id) d = self.devices[infuse_id] if key_id is None: if d.secondary_device_key_id: @@ -266,9 +283,9 @@ def _get_device_key( elif key_id == d.secondary_device_key_id: base = d.local_shared_key else: - raise DeviceUnknownDeviceKey + raise DeviceUnknownDeviceKey(infuse_id, name, key_id) if base is None: - raise DeviceUnknownDeviceKey + raise DeviceUnknownDeviceKey(infuse_id, name, key_id) assert key_id is not None time_idx = gps_time // (60 * 60 * 24) return key_id, hkdf_derive(base, time_idx.to_bytes(4, "little"), name) From 3068a77ed74ff80250fa25b5574aedf7354ca0de Mon Sep 17 00:00:00 2001 From: Jordan Yates Date: Mon, 3 Aug 2026 20:38:37 +1000 Subject: [PATCH 2/2] database: raise exception on query failure Raise an exception when querying the device key from the cloud fails. Signed-off-by: Jordan Yates --- src/infuse_iot/database.py | 20 +++++++++++++++++--- src/infuse_iot/tools/gateway.py | 23 ++++++++++++++--------- 2 files changed, 31 insertions(+), 12 deletions(-) diff --git a/src/infuse_iot/database.py b/src/infuse_iot/database.py index 427bfc1..045bc77 100644 --- a/src/infuse_iot/database.py +++ b/src/infuse_iot/database.py @@ -56,6 +56,18 @@ class DeviceKeyChangedError(KeyError): """Device key for the requested device has changed""" +class DeviceKeyQueryFailed(Exception): + """Querying a device key from the cloud failed""" + + def __init__(self, infuse_id: int, status_code: int, content: str): + self.infuse_id = infuse_id + self.status_code = status_code + self.content = content + + def __str__(self): + return f"{self.infuse_id:016x}: <{self.status_code}> {self.content}" + + class DeviceDatabase: """Database of current device state""" @@ -208,9 +220,11 @@ def observe_security_state( base64.b64encode(challenge_resp).decode("utf-8"), ) body = GetDeviceSharedSecretBody(f"{infuse_id:016x}", security_state) - response = get_device_shared_secret.sync(client=client, body=body) - if response is not None: - key = base64.b64decode(response.key) + response = get_device_shared_secret.sync_detailed(client=client, body=body) + if response.parsed is None: + raise DeviceKeyQueryFailed(infuse_id, response.status_code, response.content.decode("utf-8")) + else: + key = base64.b64decode(response.parsed.key) self.devices[infuse_id].shared_key = key self._update_cache(infuse_id, device_pub_key, key) diff --git a/src/infuse_iot/tools/gateway.py b/src/infuse_iot/tools/gateway.py index ce3bea9..ccad1b1 100644 --- a/src/infuse_iot/tools/gateway.py +++ b/src/infuse_iot/tools/gateway.py @@ -26,6 +26,7 @@ from infuse_iot.common import InfuseID, InfuseType from infuse_iot.database import ( DeviceDatabase, + DeviceKeyQueryFailed, NoKeyError, ) from infuse_iot.epacket.packet import ( @@ -80,15 +81,19 @@ def query_device_key(self, infuse_id: int, cb_event: threading.Event | None = No def security_state_done(pkt: PacketReceived, _rc: int, response: bytes, challenge): decoded = defs.security_state.response.vla_from_buffer_copy(response) - self.ddb.observe_security_state( - infuse_id, - bytes(decoded.cloud_public_key), - bytes(decoded.device_public_key), - decoded.network_id, - challenge, - decoded.challenge_response_type, - bytes(decoded.challenge_response), - ) + try: + self.ddb.observe_security_state( + infuse_id, + bytes(decoded.cloud_public_key), + bytes(decoded.device_public_key), + decoded.network_id, + challenge, + decoded.challenge_response_type, + bytes(decoded.challenge_response), + ) + except DeviceKeyQueryFailed as e: + Console.log_error(f"Failed to query key for {e.infuse_id:016x}: {e.content}") + return if cb_event is not None: cb_event.set()