diff --git a/homeassistant/components/hue/config_flow.py b/homeassistant/components/hue/config_flow.py index 265777814a8..3df17baad16 100644 --- a/homeassistant/components/hue/config_flow.py +++ b/homeassistant/components/hue/config_flow.py @@ -21,6 +21,7 @@ from homeassistant.core import callback from homeassistant.data_entry_flow import FlowResult from homeassistant.helpers import aiohttp_client, device_registry import homeassistant.helpers.config_validation as cv +from homeassistant.util.network import is_ipv6_address from .const import ( CONF_ALLOW_HUE_GROUPS, @@ -230,6 +231,10 @@ class HueFlowHandler(config_entries.ConfigFlow, domain=DOMAIN): if not url.hostname: return self.async_abort(reason="not_hue_bridge") + # Ignore if host is IPv6 + if is_ipv6_address(url.hostname): + return self.async_abort(reason="invalid_host") + # abort if we already have exactly this bridge id/host # reload the integration if the host got updated bridge_id = normalize_bridge_id(discovery_info.upnp[ssdp.ATTR_UPNP_SERIAL]) @@ -251,6 +256,10 @@ class HueFlowHandler(config_entries.ConfigFlow, domain=DOMAIN): This flow is triggered by the Zeroconf component. It will check if the host is already configured and delegate to the import step if not. """ + # Ignore if host is IPv6 + if is_ipv6_address(discovery_info.host): + return self.async_abort(reason="invalid_host") + # abort if we already have exactly this bridge id/host # reload the integration if the host got updated bridge_id = normalize_bridge_id(discovery_info.properties["bridgeid"]) diff --git a/homeassistant/components/hue/strings.json b/homeassistant/components/hue/strings.json index 266f26016c4..0d7c67ec84b 100644 --- a/homeassistant/components/hue/strings.json +++ b/homeassistant/components/hue/strings.json @@ -30,7 +30,8 @@ "cannot_connect": "[%key:common::config_flow::error::cannot_connect%]", "already_configured": "[%key:common::config_flow::abort::already_configured_device%]", "already_in_progress": "[%key:common::config_flow::abort::already_in_progress%]", - "not_hue_bridge": "Not a Hue bridge" + "not_hue_bridge": "Not a Hue bridge", + "invalid_host": "Invalid host" } }, "device_automation": { diff --git a/tests/components/hue/test_config_flow.py b/tests/components/hue/test_config_flow.py index 3c7a07ef5d6..d8be19f92c6 100644 --- a/tests/components/hue/test_config_flow.py +++ b/tests/components/hue/test_config_flow.py @@ -424,7 +424,14 @@ async def test_bridge_ssdp_missing_serial(hass): assert result["reason"] == "not_hue_bridge" -async def test_bridge_ssdp_invalid_location(hass): +@pytest.mark.parametrize( + "location,reason", + ( + ("http:///", "not_hue_bridge"), + ("http://[fd00::eeb5:faff:fe84:b17d]/description.xml", "invalid_host"), + ), +) +async def test_bridge_ssdp_invalid_location(hass, location, reason): """Test if discovery info is a serial attribute.""" result = await hass.config_entries.flow.async_init( const.DOMAIN, @@ -432,7 +439,7 @@ async def test_bridge_ssdp_invalid_location(hass): data=ssdp.SsdpServiceInfo( ssdp_usn="mock_usn", ssdp_st="mock_st", - ssdp_location="http:///", + ssdp_location=location, upnp={ ssdp.ATTR_UPNP_MANUFACTURER_URL: config_flow.HUE_MANUFACTURERURL[0], ssdp.ATTR_UPNP_SERIAL: "1234", @@ -441,7 +448,7 @@ async def test_bridge_ssdp_invalid_location(hass): ) assert result["type"] == "abort" - assert result["reason"] == "not_hue_bridge" + assert result["reason"] == reason async def test_bridge_ssdp_espalexa(hass): @@ -791,3 +798,27 @@ async def test_bridge_zeroconf_already_exists(hass, aioclient_mock): assert result["type"] == "abort" assert result["reason"] == "already_configured" assert entry.data["host"] == "192.168.1.217" + + +async def test_bridge_zeroconf_ipv6(hass): + """Test a bridge being discovered by zeroconf and ipv6 address.""" + result = await hass.config_entries.flow.async_init( + const.DOMAIN, + context={"source": config_entries.SOURCE_ZEROCONF}, + data=zeroconf.ZeroconfServiceInfo( + host="fd00::eeb5:faff:fe84:b17d", + addresses=["fd00::eeb5:faff:fe84:b17d"], + port=443, + hostname="Philips-hue.local", + type="_hue._tcp.local.", + name="Philips Hue - ABCABC._hue._tcp.local.", + properties={ + "_raw": {"bridgeid": b"ecb5faabcabc", "modelid": b"BSB002"}, + "bridgeid": "ecb5faabcabc", + "modelid": "BSB002", + }, + ), + ) + + assert result["type"] == "abort" + assert result["reason"] == "invalid_host"