Provide clearer feedback in Coinbase when authentication fails (#62627)

pull/62663/head
Tom Brien 2021-12-23 09:52:22 +00:00 committed by GitHub
parent 8e8e49d3e7
commit fa7739937d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 81 additions and 8 deletions

View File

@ -51,6 +51,15 @@ async def validate_api(hass: core.HomeAssistant, data):
get_user_from_client, data[CONF_API_KEY], data[CONF_API_TOKEN]
)
except AuthenticationError as error:
if "api key" in str(error):
_LOGGER.debug("Coinbase rejected API credentials due to an invalid API key")
raise InvalidKey from error
if "invalid signature" in str(error):
_LOGGER.debug(
"Coinbase rejected API credentials due to an invalid API secret"
)
raise InvalidSecret from error
_LOGGER.debug("Coinbase rejected API credentials due to an unknown error")
raise InvalidAuth from error
except ConnectionError as error:
raise CannotConnect from error
@ -110,6 +119,10 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
info = await validate_api(self.hass, user_input)
except CannotConnect:
errors["base"] = "cannot_connect"
except InvalidKey:
errors["base"] = "invalid_auth_key"
except InvalidSecret:
errors["base"] = "invalid_auth_secret"
except InvalidAuth:
errors["base"] = "invalid_auth"
except Exception: # pylint: disable=broad-except
@ -218,6 +231,14 @@ class InvalidAuth(exceptions.HomeAssistantError):
"""Error to indicate there is invalid auth."""
class InvalidSecret(exceptions.HomeAssistantError):
"""Error to indicate auth failed due to invalid secret."""
class InvalidKey(exceptions.HomeAssistantError):
"""Error to indicate auth failed due to invalid key."""
class AlreadyConfigured(exceptions.HomeAssistantError):
"""Error to indicate Coinbase API Key is already configured."""

View File

@ -13,6 +13,8 @@
"error": {
"cannot_connect": "[%key:common::config_flow::error::cannot_connect%]",
"invalid_auth": "[%key:common::config_flow::error::invalid_auth%]",
"invalid_auth_key": "API credentials rejected by Coinbase due to an invalid API Key.",
"invalid_auth_secret": "API credentials rejected by Coinbase due to an invalid API Secret.",
"unknown": "[%key:common::config_flow::error::unknown%]"
},
"abort": {

View File

@ -6,15 +6,15 @@
"error": {
"cannot_connect": "Failed to connect",
"invalid_auth": "Invalid authentication",
"invalid_auth_key": "API credentials rejected by Coinbase due to an invalid API Key.",
"invalid_auth_secret": "API credentials rejected by Coinbase due to an invalid API Secret.",
"unknown": "Unexpected error"
},
"step": {
"user": {
"data": {
"api_key": "API Key",
"api_token": "API Secret",
"currencies": "Account Balance Currencies",
"exchange_rates": "Exchange Rates"
"api_token": "API Secret"
},
"description": "Please enter the details of your API key as provided by Coinbase.",
"title": "Coinbase API Key Details"

View File

@ -1,4 +1,5 @@
"""Test the Coinbase config flow."""
import logging
from unittest.mock import patch
from coinbase.wallet.error import AuthenticationError
@ -63,23 +64,25 @@ async def test_form(hass):
assert len(mock_setup_entry.mock_calls) == 1
async def test_form_invalid_auth(hass):
async def test_form_invalid_auth(hass, caplog):
"""Test we handle invalid auth."""
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_USER}
)
caplog.set_level(logging.DEBUG)
response = Response()
response.status_code = 401
api_auth_error = AuthenticationError(
api_auth_error_unknown = AuthenticationError(
response,
"authentication_error",
"invalid signature",
[{"id": "authentication_error", "message": "invalid signature"}],
"unknown error",
[{"id": "authentication_error", "message": "unknown error"}],
)
with patch(
"coinbase.wallet.client.Client.get_current_user",
side_effect=api_auth_error,
side_effect=api_auth_error_unknown,
):
result2 = await hass.config_entries.flow.async_configure(
result["flow_id"],
@ -91,6 +94,53 @@ async def test_form_invalid_auth(hass):
assert result2["type"] == "form"
assert result2["errors"] == {"base": "invalid_auth"}
assert "Coinbase rejected API credentials due to an unknown error" in caplog.text
api_auth_error_key = AuthenticationError(
response,
"authentication_error",
"invalid api key",
[{"id": "authentication_error", "message": "invalid api key"}],
)
with patch(
"coinbase.wallet.client.Client.get_current_user",
side_effect=api_auth_error_key,
):
result2 = await hass.config_entries.flow.async_configure(
result["flow_id"],
{
CONF_API_KEY: "123456",
CONF_API_TOKEN: "AbCDeF",
},
)
assert result2["type"] == "form"
assert result2["errors"] == {"base": "invalid_auth_key"}
assert "Coinbase rejected API credentials due to an invalid API key" in caplog.text
api_auth_error_secret = AuthenticationError(
response,
"authentication_error",
"invalid signature",
[{"id": "authentication_error", "message": "invalid signature"}],
)
with patch(
"coinbase.wallet.client.Client.get_current_user",
side_effect=api_auth_error_secret,
):
result2 = await hass.config_entries.flow.async_configure(
result["flow_id"],
{
CONF_API_KEY: "123456",
CONF_API_TOKEN: "AbCDeF",
},
)
assert result2["type"] == "form"
assert result2["errors"] == {"base": "invalid_auth_secret"}
assert (
"Coinbase rejected API credentials due to an invalid API secret" in caplog.text
)
async def test_form_cannot_connect(hass):