More explicitly call out special cases with SimpliSafe authorization code (#76232)

pull/76386/head
Aaron Bach 2022-08-04 11:43:02 -06:00 committed by GitHub
parent 8ca5b5d4a4
commit b2dc810ea4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 71 additions and 34 deletions

View File

@ -81,17 +81,34 @@ class SimpliSafeFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
description_placeholders={CONF_URL: self._oauth_values.auth_url},
)
auth_code = user_input[CONF_AUTH_CODE]
if auth_code.startswith("="):
# Sometimes, users may include the "=" from the URL query param; in that
# case, strip it off and proceed:
LOGGER.debug('Stripping "=" from the start of the authorization code')
auth_code = auth_code[1:]
if len(auth_code) != 45:
# SimpliSafe authorization codes are 45 characters in length; if the user
# provides something different, stop them here:
return self.async_show_form(
step_id="user",
data_schema=STEP_USER_SCHEMA,
errors={CONF_AUTH_CODE: "invalid_auth_code_length"},
description_placeholders={CONF_URL: self._oauth_values.auth_url},
)
errors = {}
session = aiohttp_client.async_get_clientsession(self.hass)
try:
simplisafe = await API.async_from_auth(
user_input[CONF_AUTH_CODE],
auth_code,
self._oauth_values.code_verifier,
session=session,
)
except InvalidCredentialsError:
errors = {"base": "invalid_auth"}
errors = {CONF_AUTH_CODE: "invalid_auth"}
except SimplipyError as err:
LOGGER.error("Unknown error while logging into SimpliSafe: %s", err)
errors = {"base": "unknown"}

View File

@ -2,7 +2,7 @@
"config": {
"step": {
"user": {
"description": "SimpliSafe authenticates users via its web app. Due to technical limitations, there is a manual step at the end of this process; please ensure that you read the [documentation](http://home-assistant.io/integrations/simplisafe#getting-an-authorization-code) before starting.\n\nWhen you are ready, click [here]({url}) to open the SimpliSafe web app and input your credentials. When the process is complete, return here and input the authorization code from the SimpliSafe web app URL.",
"description": "SimpliSafe authenticates users via its web app. Due to technical limitations, there is a manual step at the end of this process; please ensure that you read the [documentation](http://home-assistant.io/integrations/simplisafe#getting-an-authorization-code) before starting.\n\nWhen you are ready, click [here]({url}) to open the SimpliSafe web app and input your credentials. If you've already logged into SimpliSafe in your browser, you may want to open a new tab, then copy/paste the above URL into that tab.\n\nWhen the process is complete, return here and input the authorization code from the `com.simplisafe.mobile` URL.",
"data": {
"auth_code": "Authorization Code"
}
@ -11,6 +11,7 @@
"error": {
"identifier_exists": "Account already registered",
"invalid_auth": "[%key:common::config_flow::error::invalid_auth%]",
"invalid_auth_code_length": "SimpliSafe authorization codes are 45 characters in length",
"unknown": "[%key:common::config_flow::error::unknown%]"
},
"abort": {

View File

@ -2,39 +2,21 @@
"config": {
"abort": {
"already_configured": "This SimpliSafe account is already in use.",
"email_2fa_timed_out": "Timed out while waiting for email-based two-factor authentication.",
"reauth_successful": "Re-authentication was successful",
"wrong_account": "The user credentials provided do not match this SimpliSafe account."
},
"error": {
"identifier_exists": "Account already registered",
"invalid_auth": "Invalid authentication",
"invalid_auth_code_length": "SimpliSafe authorization codes are 45 characters in length",
"unknown": "Unexpected error"
},
"progress": {
"email_2fa": "Check your email for a verification link from Simplisafe."
},
"step": {
"reauth_confirm": {
"data": {
"password": "Password"
},
"description": "Please re-enter the password for {username}.",
"title": "Reauthenticate Integration"
},
"sms_2fa": {
"data": {
"code": "Code"
},
"description": "Input the two-factor authentication code sent to you via SMS."
},
"user": {
"data": {
"auth_code": "Authorization Code",
"password": "Password",
"username": "Username"
"auth_code": "Authorization Code"
},
"description": "SimpliSafe authenticates users via its web app. Due to technical limitations, there is a manual step at the end of this process; please ensure that you read the [documentation](http://home-assistant.io/integrations/simplisafe#getting-an-authorization-code) before starting.\n\nWhen you are ready, click [here]({url}) to open the SimpliSafe web app and input your credentials. When the process is complete, return here and input the authorization code from the SimpliSafe web app URL."
"description": "SimpliSafe authenticates users via its web app. Due to technical limitations, there is a manual step at the end of this process; please ensure that you read the [documentation](http://home-assistant.io/integrations/simplisafe#getting-an-authorization-code) before starting.\n\nWhen you are ready, click [here]({url}) to open the SimpliSafe web app and input your credentials. If you've already logged into SimpliSafe in your browser, you may want to open a new tab, then copy/paste the above URL into that tab.\n\nWhen the process is complete, return here and input the authorization code from the `com.simplisafe.mobile` URL."
}
}
},

View File

@ -1,4 +1,5 @@
"""Define tests for the SimpliSafe config flow."""
import logging
from unittest.mock import patch
import pytest
@ -10,6 +11,8 @@ from homeassistant.components.simplisafe.config_flow import CONF_AUTH_CODE
from homeassistant.config_entries import SOURCE_REAUTH, SOURCE_USER
from homeassistant.const import CONF_CODE, CONF_TOKEN, CONF_USERNAME
VALID_AUTH_CODE = "code12345123451234512345123451234512345123451"
async def test_duplicate_error(config_entry, hass, setup_simplisafe):
"""Test that errors are shown when duplicates are added."""
@ -23,12 +26,27 @@ async def test_duplicate_error(config_entry, hass, setup_simplisafe):
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
result = await hass.config_entries.flow.async_configure(
result["flow_id"], user_input={CONF_AUTH_CODE: "code123"}
result["flow_id"], user_input={CONF_AUTH_CODE: VALID_AUTH_CODE}
)
assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT
assert result["reason"] == "already_configured"
async def test_invalid_auth_code_length(hass):
"""Test that an invalid auth code length show the correct error."""
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": SOURCE_USER}
)
assert result["step_id"] == "user"
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
result = await hass.config_entries.flow.async_configure(
result["flow_id"], user_input={CONF_AUTH_CODE: "too_short_code"}
)
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
assert result["errors"] == {CONF_AUTH_CODE: "invalid_auth_code_length"}
async def test_invalid_credentials(hass):
"""Test that invalid credentials show the correct error."""
with patch(
@ -42,10 +60,11 @@ async def test_invalid_credentials(hass):
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
result = await hass.config_entries.flow.async_configure(
result["flow_id"], user_input={CONF_AUTH_CODE: "code123"}
result["flow_id"],
user_input={CONF_AUTH_CODE: VALID_AUTH_CODE},
)
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
assert result["errors"] == {"base": "invalid_auth"}
assert result["errors"] == {CONF_AUTH_CODE: "invalid_auth"}
async def test_options_flow(config_entry, hass):
@ -80,7 +99,7 @@ async def test_step_reauth(config_entry, hass, setup_simplisafe):
"homeassistant.components.simplisafe.async_setup_entry", return_value=True
), patch("homeassistant.config_entries.ConfigEntries.async_reload"):
result = await hass.config_entries.flow.async_configure(
result["flow_id"], user_input={CONF_AUTH_CODE: "code123"}
result["flow_id"], user_input={CONF_AUTH_CODE: VALID_AUTH_CODE}
)
assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT
assert result["reason"] == "reauth_successful"
@ -104,14 +123,29 @@ async def test_step_reauth_wrong_account(config_entry, hass, setup_simplisafe):
"homeassistant.components.simplisafe.async_setup_entry", return_value=True
), patch("homeassistant.config_entries.ConfigEntries.async_reload"):
result = await hass.config_entries.flow.async_configure(
result["flow_id"], user_input={CONF_AUTH_CODE: "code123"}
result["flow_id"], user_input={CONF_AUTH_CODE: VALID_AUTH_CODE}
)
assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT
assert result["reason"] == "wrong_account"
async def test_step_user(hass, setup_simplisafe):
"""Test the user step."""
@pytest.mark.parametrize(
"auth_code,log_statement",
[
(
VALID_AUTH_CODE,
None,
),
(
f"={VALID_AUTH_CODE}",
'Stripping "=" from the start of the authorization code',
),
],
)
async def test_step_user(auth_code, caplog, hass, log_statement, setup_simplisafe):
"""Test successfully completion of the user step."""
caplog.set_level = logging.DEBUG
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": SOURCE_USER}
)
@ -121,10 +155,13 @@ async def test_step_user(hass, setup_simplisafe):
"homeassistant.components.simplisafe.async_setup_entry", return_value=True
), patch("homeassistant.config_entries.ConfigEntries.async_reload"):
result = await hass.config_entries.flow.async_configure(
result["flow_id"], user_input={CONF_AUTH_CODE: "code123"}
result["flow_id"], user_input={CONF_AUTH_CODE: auth_code}
)
assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
if log_statement:
assert any(m for m in caplog.messages if log_statement in m)
assert len(hass.config_entries.async_entries()) == 1
[config_entry] = hass.config_entries.async_entries(DOMAIN)
assert config_entry.data == {CONF_USERNAME: "12345", CONF_TOKEN: "token123"}
@ -143,7 +180,7 @@ async def test_unknown_error(hass, setup_simplisafe):
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
result = await hass.config_entries.flow.async_configure(
result["flow_id"], user_input={CONF_AUTH_CODE: "code123"}
result["flow_id"], user_input={CONF_AUTH_CODE: VALID_AUTH_CODE}
)
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
assert result["errors"] == {"base": "unknown"}