Hue config flow to guard ipv6 (#70703)

* Hue config flow to guard ipv6

* Use helper
This commit is contained in:
Paulus Schoutsen 2022-04-25 10:52:57 -07:00 committed by GitHub
parent 5317bf02e6
commit 87dceaf238
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 45 additions and 4 deletions

View File

@ -21,6 +21,7 @@ from homeassistant.core import callback
from homeassistant.data_entry_flow import FlowResult from homeassistant.data_entry_flow import FlowResult
from homeassistant.helpers import aiohttp_client, device_registry from homeassistant.helpers import aiohttp_client, device_registry
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
from homeassistant.util.network import is_ipv6_address
from .const import ( from .const import (
CONF_ALLOW_HUE_GROUPS, CONF_ALLOW_HUE_GROUPS,
@ -230,6 +231,10 @@ class HueFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
if not url.hostname: if not url.hostname:
return self.async_abort(reason="not_hue_bridge") 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 # abort if we already have exactly this bridge id/host
# reload the integration if the host got updated # reload the integration if the host got updated
bridge_id = normalize_bridge_id(discovery_info.upnp[ssdp.ATTR_UPNP_SERIAL]) 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 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. 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 # abort if we already have exactly this bridge id/host
# reload the integration if the host got updated # reload the integration if the host got updated
bridge_id = normalize_bridge_id(discovery_info.properties["bridgeid"]) bridge_id = normalize_bridge_id(discovery_info.properties["bridgeid"])

View File

@ -30,7 +30,8 @@
"cannot_connect": "[%key:common::config_flow::error::cannot_connect%]", "cannot_connect": "[%key:common::config_flow::error::cannot_connect%]",
"already_configured": "[%key:common::config_flow::abort::already_configured_device%]", "already_configured": "[%key:common::config_flow::abort::already_configured_device%]",
"already_in_progress": "[%key:common::config_flow::abort::already_in_progress%]", "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": { "device_automation": {

View File

@ -424,7 +424,14 @@ async def test_bridge_ssdp_missing_serial(hass):
assert result["reason"] == "not_hue_bridge" 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.""" """Test if discovery info is a serial attribute."""
result = await hass.config_entries.flow.async_init( result = await hass.config_entries.flow.async_init(
const.DOMAIN, const.DOMAIN,
@ -432,7 +439,7 @@ async def test_bridge_ssdp_invalid_location(hass):
data=ssdp.SsdpServiceInfo( data=ssdp.SsdpServiceInfo(
ssdp_usn="mock_usn", ssdp_usn="mock_usn",
ssdp_st="mock_st", ssdp_st="mock_st",
ssdp_location="http:///", ssdp_location=location,
upnp={ upnp={
ssdp.ATTR_UPNP_MANUFACTURER_URL: config_flow.HUE_MANUFACTURERURL[0], ssdp.ATTR_UPNP_MANUFACTURER_URL: config_flow.HUE_MANUFACTURERURL[0],
ssdp.ATTR_UPNP_SERIAL: "1234", ssdp.ATTR_UPNP_SERIAL: "1234",
@ -441,7 +448,7 @@ async def test_bridge_ssdp_invalid_location(hass):
) )
assert result["type"] == "abort" assert result["type"] == "abort"
assert result["reason"] == "not_hue_bridge" assert result["reason"] == reason
async def test_bridge_ssdp_espalexa(hass): 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["type"] == "abort"
assert result["reason"] == "already_configured" assert result["reason"] == "already_configured"
assert entry.data["host"] == "192.168.1.217" 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"