1 """Config flow for One-Time Password (OTP) integration."""
3 from __future__
import annotations
11 import voluptuous
as vol
17 BooleanSelectorConfig,
20 QrErrorCorrectionLevel,
23 from .const
import CONF_NEW_TOKEN, DEFAULT_NAME, DOMAIN
25 _LOGGER = logging.getLogger(__name__)
27 STEP_USER_DATA_SCHEMA = vol.Schema(
29 vol.Optional(CONF_TOKEN): str,
31 vol.Required(CONF_NAME, default=DEFAULT_NAME): str,
35 STEP_CONFIRM_DATA_SCHEMA = vol.Schema({vol.Required(CONF_CODE): str})
39 """Handle a config flow for One-Time Password (OTP)."""
42 user_input: dict[str, Any]
45 self, user_input: dict[str, Any] |
None =
None
46 ) -> ConfigFlowResult:
47 """Handle the initial step."""
48 errors: dict[str, str] = {}
49 if user_input
is not None:
50 if user_input.get(CONF_TOKEN)
and not user_input.get(CONF_NEW_TOKEN):
51 user_input[CONF_TOKEN] = sub(
r"\s+",
"", user_input[CONF_TOKEN])
53 await self.hass.async_add_executor_job(
54 pyotp.TOTP(user_input[CONF_TOKEN]).now
56 except binascii.Error:
57 errors[
"base"] =
"invalid_token"
59 _LOGGER.exception(
"Unexpected exception")
60 errors[
"base"] =
"unknown"
65 title=user_input[CONF_NAME],
68 elif user_input.get(CONF_NEW_TOKEN):
69 user_input[CONF_TOKEN] = await self.hass.async_add_executor_job(
75 errors[
"base"] =
"invalid_token"
80 data_schema=STEP_USER_DATA_SCHEMA, suggested_values=user_input
86 """Import config from yaml."""
92 title=import_data.get(CONF_NAME, DEFAULT_NAME),
97 self, user_input: dict[str, Any] |
None =
None
98 ) -> ConfigFlowResult:
99 """Handle the confirmation step."""
101 errors: dict[str, str] = {}
103 if user_input
is not None:
104 if await self.hass.async_add_executor_job(
105 pyotp.TOTP(self.
user_inputuser_input[CONF_TOKEN]).verify, user_input[
"code"]
110 CONF_NAME: self.
user_inputuser_input[CONF_NAME],
111 CONF_TOKEN: self.
user_inputuser_input[CONF_TOKEN],
115 errors[
"base"] =
"invalid_code"
117 provisioning_uri = await self.hass.async_add_executor_job(
118 pyotp.TOTP(self.
user_inputuser_input[CONF_TOKEN]).provisioning_uri,
122 data_schema = STEP_CONFIRM_DATA_SCHEMA.extend(
126 data=provisioning_uri,
128 error_correction_level=QrErrorCorrectionLevel.QUARTILE,
135 data_schema=data_schema,
136 description_placeholders={
137 "auth_app1":
"[Google Authenticator](https://support.google.com/accounts/answer/1066447)",
138 "auth_app2":
"[Authy](https://authy.com/)",
139 "code": self.
user_inputuser_input[CONF_TOKEN],
ConfigFlowResult async_step_user(self, dict[str, Any]|None user_input=None)
ConfigFlowResult async_step_import(self, dict[str, Any] import_data)
ConfigFlowResult async_step_confirm(self, dict[str, Any]|None user_input=None)
None _abort_if_unique_id_configured(self, dict[str, Any]|None updates=None, bool reload_on_update=True, *str error="already_configured")
ConfigEntry|None async_set_unique_id(self, str|None unique_id=None, *bool raise_on_progress=True)
ConfigFlowResult async_create_entry(self, *str title, Mapping[str, Any] data, str|None description=None, Mapping[str, str]|None description_placeholders=None, Mapping[str, Any]|None options=None)
ConfigFlowResult async_show_form(self, *str|None step_id=None, vol.Schema|None data_schema=None, dict[str, str]|None errors=None, Mapping[str, str]|None description_placeholders=None, bool|None last_step=None, str|None preview=None)
vol.Schema add_suggested_values_to_schema(self, vol.Schema data_schema, Mapping[str, Any]|None suggested_values)
_FlowResultT async_show_form(self, *str|None step_id=None, vol.Schema|None data_schema=None, dict[str, str]|None errors=None, Mapping[str, str]|None description_placeholders=None, bool|None last_step=None, str|None preview=None)
_FlowResultT async_create_entry(self, *str|None title=None, Mapping[str, Any] data, str|None description=None, Mapping[str, str]|None description_placeholders=None)