Skip to content

Commit

Permalink
Ignore messages on shared topic when not authenticated
Browse files Browse the repository at this point in the history
  • Loading branch information
zpieslak committed Nov 17, 2024
1 parent 1017e02 commit dd7dc4c
Show file tree
Hide file tree
Showing 4 changed files with 18 additions and 4 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

![test workflow](https://github.com/zpieslak/mobilus-client/actions/workflows/test.yml/badge.svg)

This code provides a native Python client for the Mobilus Cosmo GTW. It connects directly to the gateway's MQTT broker and sends message commands to control the associated devices. The connection is established locally, so the client must be run on the same network as the gateway. Currently, the only tested and supported devices are radio shutters (Mobilus COSMO 2WAY).
This code provides a native Python client for the Mobilus Cosmo GTW. It connects directly to the gateway's MQTT broker and sends message commands to control the associated devices. The connection is established locally, so the client must be run on the same network as the gateway. Note: internet access is not required and can be disabled on the device. Currently, the only tested and supported devices are radio shutters (Mobilus COSMO 2WAY).

In order to use the client, configuration and setup need to be done on the Mobilus Cosmo GTW side. This includes creating a user and pairing the devices with the gateway.

Expand Down
1 change: 0 additions & 1 deletion mobilus_client/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ def call(self, commands: list[tuple[str, dict[str, str]]]) -> str:
if not client.connect_and_authenticate():
return self._empty_response()


# Execute the provided commands
for command, params in commands:
client.send_request(command, **params)
Expand Down
11 changes: 9 additions & 2 deletions mobilus_client/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ def __init__(
self, client_id: str, config: Config, key_registry: KeyRegistry, message_registry: MessageRegistry) -> None:
self.config = config
self.client_id = client_id
self.shared_topic = "clients"
self.command_topic = "module"
self.key_registry = key_registry
self.message_registry = message_registry
self.authenticated_event = threading.Event()
Expand Down Expand Up @@ -68,7 +70,7 @@ def send_request(self, command: str, **params: str | bytes | int | None) -> None
self.key_registry,
)

self.mqtt_client.publish("module", encrypted_message)
self.mqtt_client.publish(self.command_topic, encrypted_message)

def terminate(self) -> None:
self.mqtt_client.disconnect()
Expand All @@ -81,7 +83,7 @@ def on_connect_callback(
self, _client: mqtt.Client, _userdata: None, _flags: dict[str, Any], _reason_code: int) -> None:
self.mqtt_client.subscribe([
(self.client_id, 0),
("clients", 0),
(self.shared_topic, 0),
])

def on_subscribe_callback(self, _client: mqtt.Client, _userdata: None, _mid: int, _granted_qos: tuple[int]) -> None:
Expand All @@ -94,6 +96,11 @@ def on_subscribe_callback(self, _client: mqtt.Client, _userdata: None, _mid: int
def on_message_callback(self, _client: mqtt.Client, _userdata: None, mqtt_message: mqtt.MQTTMessage) -> None:
logger.info("Received message on topic - %s", mqtt_message.topic)

# Ignore messages from the shared topic sent by other clients until the client is authenticated.
if mqtt_message.topic == self.shared_topic and not self.authenticated_event.is_set():
logger.info("Client is not authenticated yet. Ignoring message.")
return

message = MessageEncryptor.decrypt(mqtt_message.payload, self.key_registry)
logger.info("Decrypted message - %s", type(message).__name__)

Expand Down
8 changes: 8 additions & 0 deletions tests/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -245,3 +245,11 @@ def test_on_message_devices_list_response_not_all_completed(self) -> None:
self.client.on_message_callback(self.client.mqtt_client, None, message)
self.assertEqual(self.message_registry.get_responses(), [devices_list_response])
self.assertFalse(self.client.completed_event.is_set())

def test_on_message_shared_topic_when_not_authenticated(self) -> None:
login_response = LoginResponseFactory(private_key=b"test_private_key")
devices_list_response = DevicesListResponseFactory()
encrypted_message = encrypt_message(devices_list_response, login_response.private_key)
message = Mock(payload=encrypted_message, topic="clients")

self.client.on_message_callback(self.client.mqtt_client, None, message)

0 comments on commit dd7dc4c

Please sign in to comment.