From 19fd80035e0bd57d7635ff6cffd20b9fd4a859b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joakim=20S=C3=B8rensen?= Date: Mon, 5 Jan 2026 15:35:49 +0100 Subject: [PATCH] Add connection check before registering cloudhook URL (#160284) --- .../components/mobile_app/http_api.py | 2 +- tests/components/mobile_app/test_http_api.py | 62 ++++++++++++++++++- 2 files changed, 62 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/mobile_app/http_api.py b/homeassistant/components/mobile_app/http_api.py index f4786b2914c..7acf3cfdd71 100644 --- a/homeassistant/components/mobile_app/http_api.py +++ b/homeassistant/components/mobile_app/http_api.py @@ -69,7 +69,7 @@ class RegistrationsView(HomeAssistantView): webhook_id = secrets.token_hex() - if cloud.async_active_subscription(hass): + if cloud.async_active_subscription(hass) and cloud.async_is_connected(hass): data[CONF_CLOUDHOOK_URL] = await async_create_cloud_hook( hass, webhook_id, None ) diff --git a/tests/components/mobile_app/test_http_api.py b/tests/components/mobile_app/test_http_api.py index b333f91d985..3c82f4f4d6f 100644 --- a/tests/components/mobile_app/test_http_api.py +++ b/tests/components/mobile_app/test_http_api.py @@ -7,8 +7,13 @@ from unittest.mock import patch from nacl.encoding import Base64Encoder from nacl.secret import SecretBox +import pytest -from homeassistant.components.mobile_app.const import CONF_SECRET, DOMAIN +from homeassistant.components.mobile_app.const import ( + CONF_CLOUDHOOK_URL, + CONF_SECRET, + DOMAIN, +) from homeassistant.const import CONF_WEBHOOK_ID from homeassistant.core import HomeAssistant from homeassistant.setup import async_setup_component @@ -101,6 +106,61 @@ async def test_registration_encryption( assert json.loads(decrypted_data) == {"one": "Hello world"} +@pytest.mark.parametrize( + "cloud_is_connected", + [ + True, + False, + ], +) +async def test_registration_with_cloud( + hass: HomeAssistant, + hass_client: ClientSessionGenerator, + hass_admin_user: MockUser, + cloud_is_connected: bool, +) -> None: + """Test that cloudhook_url is only returned when cloud is connected.""" + await async_setup_component(hass, DOMAIN, {DOMAIN: {}}) + + api_client = await hass_client() + + cloudhook_url = "https://hooks.nabu.casa/test123" + + with ( + patch( + "homeassistant.components.mobile_app.http_api.cloud.async_active_subscription", + return_value=True, + ), + patch( + "homeassistant.components.mobile_app.http_api.cloud.async_is_connected", + return_value=cloud_is_connected, + ), + patch( + "homeassistant.components.mobile_app.http_api.async_create_cloud_hook", + return_value=cloudhook_url, + ), + patch( + "homeassistant.components.mobile_app.http_api.cloud.async_remote_ui_url", + return_value="https://remote.ui", + ), + patch( + "homeassistant.components.person.async_add_user_device_tracker", + spec=True, + ), + ): + resp = await api_client.post( + "/api/mobile_app/registrations", json=REGISTER_CLEARTEXT + ) + + assert resp.status == HTTPStatus.CREATED + register_json = await resp.json() + assert CONF_WEBHOOK_ID in register_json + + assert register_json.get(CONF_CLOUDHOOK_URL) == ( + cloudhook_url if cloud_is_connected else None + ) + + async def test_registration_encryption_legacy( hass: HomeAssistant, hass_client: ClientSessionGenerator ) -> None: