Fix blink 2fa auth flow (#174356)

This commit is contained in:
David Bayer
2026-06-22 17:29:18 +02:00
committed by GitHub
parent 11b49607bd
commit af6ae63eeb
2 changed files with 68 additions and 4 deletions
@@ -27,15 +27,17 @@ _LOGGER = logging.getLogger(__name__)
async def validate_input(blink: Blink) -> None:
"""Validate the user input allows us to connect."""
try:
await blink.start()
result = await blink.start()
except (LoginError, TokenRefreshFailed) as err:
raise InvalidAuth from err
if result is False:
raise InvalidAuth
async def _send_blink_2fa_pin(blink: Blink, pin: str | None) -> bool:
async def _send_blink_2fa_pin(blink: Blink, pin: str | None) -> None:
"""Send 2FA pin to blink servers."""
await blink.send_2fa_code(pin)
return True
if not await blink.send_2fa_code(pin):
raise InvalidAuth
class BlinkConfigFlow(ConfigFlow, domain=DOMAIN):
@@ -104,6 +106,8 @@ class BlinkConfigFlow(ConfigFlow, domain=DOMAIN):
errors["base"] = "cannot_connect"
except TokenRefreshFailed:
errors["base"] = "invalid_access_token"
except InvalidAuth:
errors["base"] = "invalid_auth"
except Exception:
_LOGGER.exception("Unexpected exception")
errors["base"] = "unknown"
@@ -173,6 +173,44 @@ async def test_form_2fa_unknown_error(hass: HomeAssistant) -> None:
assert result3["errors"] == {"base": "unknown"}
async def test_form_2fa_wrong_pin(hass: HomeAssistant) -> None:
"""Test we report invalid auth when send_2fa_code returns False."""
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_USER}
)
with patch(
"homeassistant.components.blink.config_flow.Blink.start",
side_effect=BlinkTwoFARequiredError,
):
result2 = await hass.config_entries.flow.async_configure(
result["flow_id"],
{"username": "blink@example.com", "password": "example"},
)
assert result2["type"] is FlowResultType.FORM
assert result2["step_id"] == "2fa"
with (
patch("homeassistant.components.blink.config_flow.Blink.start"),
patch(
"homeassistant.components.blink.config_flow.Blink.send_2fa_code",
return_value=False,
),
patch(
"homeassistant.components.blink.async_setup_entry",
return_value=True,
),
):
result3 = await hass.config_entries.flow.async_configure(
result2["flow_id"], {"pin": "1234"}
)
assert result3["type"] is FlowResultType.FORM
assert result3["errors"] == {"base": "invalid_auth"}
async def test_form_invalid_auth(hass: HomeAssistant) -> None:
"""Test we handle invalid auth."""
result = await hass.config_entries.flow.async_init(
@@ -191,6 +229,28 @@ async def test_form_invalid_auth(hass: HomeAssistant) -> None:
assert result2["errors"] == {"base": "invalid_auth"}
async def test_form_start_returns_false(hass: HomeAssistant) -> None:
"""Test we handle auth failure when blink.start() returns False without raising.
blink.start() catches LoginError/TokenRefreshFailed internally and returns
False instead of re-raising, so validate_input must check the return value.
"""
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_USER}
)
with patch(
"homeassistant.components.blink.config_flow.Blink.start",
return_value=False,
):
result2 = await hass.config_entries.flow.async_configure(
result["flow_id"], {"username": "blink@example.com", "password": "example"}
)
assert result2["type"] is FlowResultType.FORM
assert result2["errors"] == {"base": "invalid_auth"}
async def test_form_unknown_error(hass: HomeAssistant) -> None:
"""Test we handle unknown error at startup."""
result = await hass.config_entries.flow.async_init(