Enable config flow for html5 (#112806)
* html5: Enable config flow * Add tests * attempt check create_issue * replace len with call_count * fix config flow tests * test user config * more tests * remove whitespace * Update homeassistant/components/html5/issues.py Co-authored-by: Steven B. <51370195+sdb9696@users.noreply.github.com> * Update homeassistant/components/html5/issues.py Co-authored-by: Steven B. <51370195+sdb9696@users.noreply.github.com> * fix config * Adjust issues log * lint * lint * rename create issue * fix typing * update codeowners * fix test * fix tests * Update issues.py * Update tests/components/html5/test_config_flow.py Co-authored-by: J. Nick Koston <nick@koston.org> * Update tests/components/html5/test_config_flow.py Co-authored-by: J. Nick Koston <nick@koston.org> * Update tests/components/html5/test_config_flow.py Co-authored-by: J. Nick Koston <nick@koston.org> * update from review * remove ternary * fix * fix missing service * fix tests * updates * adress review comments * fix indent * fix * fix format * cleanup from review * Restore config schema and use HA issue * Restore config schema and use HA issue --------- Co-authored-by: alexyao2015 <alexyao2015@users.noreply.github.com> Co-authored-by: Steven B. <51370195+sdb9696@users.noreply.github.com> Co-authored-by: J. Nick Koston <nick@koston.org> Co-authored-by: Joostlek <joostlek@outlook.com>
This commit is contained in:
parent
ac39bf991f
commit
26281662b5
13 changed files with 497 additions and 37 deletions
103
homeassistant/components/html5/config_flow.py
Normal file
103
homeassistant/components/html5/config_flow.py
Normal file
|
@ -0,0 +1,103 @@
|
|||
"""Config flow for the html5 component."""
|
||||
|
||||
import binascii
|
||||
from typing import Any, cast
|
||||
|
||||
from cryptography.hazmat.backends import default_backend
|
||||
from cryptography.hazmat.primitives import serialization
|
||||
from cryptography.hazmat.primitives.asymmetric import ec
|
||||
from py_vapid import Vapid
|
||||
from py_vapid.utils import b64urlencode
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.config_entries import ConfigFlow, ConfigFlowResult
|
||||
from homeassistant.const import CONF_NAME
|
||||
from homeassistant.core import callback
|
||||
|
||||
from .const import ATTR_VAPID_EMAIL, ATTR_VAPID_PRV_KEY, ATTR_VAPID_PUB_KEY, DOMAIN
|
||||
from .issues import async_create_html5_issue
|
||||
|
||||
|
||||
def vapid_generate_private_key() -> str:
|
||||
"""Generate a VAPID private key."""
|
||||
private_key = ec.generate_private_key(ec.SECP256R1(), default_backend())
|
||||
return b64urlencode(
|
||||
binascii.unhexlify(f"{private_key.private_numbers().private_value:x}".zfill(64))
|
||||
)
|
||||
|
||||
|
||||
def vapid_get_public_key(private_key: str) -> str:
|
||||
"""Get the VAPID public key from a private key."""
|
||||
vapid = Vapid.from_string(private_key)
|
||||
public_key = cast(ec.EllipticCurvePublicKey, vapid.public_key)
|
||||
return b64urlencode(
|
||||
public_key.public_bytes(
|
||||
serialization.Encoding.X962, serialization.PublicFormat.UncompressedPoint
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
class HTML5ConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||
"""Handle a config flow for HTML5."""
|
||||
|
||||
@callback
|
||||
def _async_create_html5_entry(
|
||||
self: "HTML5ConfigFlow", data: dict[str, str]
|
||||
) -> tuple[dict[str, str], ConfigFlowResult | None]:
|
||||
"""Create an HTML5 entry."""
|
||||
errors = {}
|
||||
flow_result = None
|
||||
|
||||
if not data.get(ATTR_VAPID_PRV_KEY):
|
||||
data[ATTR_VAPID_PRV_KEY] = vapid_generate_private_key()
|
||||
|
||||
# we will always generate the corresponding public key
|
||||
try:
|
||||
data[ATTR_VAPID_PUB_KEY] = vapid_get_public_key(data[ATTR_VAPID_PRV_KEY])
|
||||
except (ValueError, binascii.Error):
|
||||
errors[ATTR_VAPID_PRV_KEY] = "invalid_prv_key"
|
||||
|
||||
if not errors:
|
||||
config = {
|
||||
ATTR_VAPID_EMAIL: data[ATTR_VAPID_EMAIL],
|
||||
ATTR_VAPID_PRV_KEY: data[ATTR_VAPID_PRV_KEY],
|
||||
ATTR_VAPID_PUB_KEY: data[ATTR_VAPID_PUB_KEY],
|
||||
CONF_NAME: DOMAIN,
|
||||
}
|
||||
flow_result = self.async_create_entry(title="HTML5", data=config)
|
||||
return errors, flow_result
|
||||
|
||||
async def async_step_user(
|
||||
self: "HTML5ConfigFlow", user_input: dict[str, Any] | None = None
|
||||
) -> ConfigFlowResult:
|
||||
"""Handle a flow initialized by the user."""
|
||||
errors: dict[str, str] = {}
|
||||
if user_input:
|
||||
errors, flow_result = self._async_create_html5_entry(user_input)
|
||||
if flow_result:
|
||||
return flow_result
|
||||
else:
|
||||
user_input = {}
|
||||
|
||||
return self.async_show_form(
|
||||
data_schema=vol.Schema(
|
||||
{
|
||||
vol.Required(
|
||||
ATTR_VAPID_EMAIL, default=user_input.get(ATTR_VAPID_EMAIL, "")
|
||||
): str,
|
||||
vol.Optional(ATTR_VAPID_PRV_KEY): str,
|
||||
}
|
||||
),
|
||||
errors=errors,
|
||||
)
|
||||
|
||||
async def async_step_import(
|
||||
self: "HTML5ConfigFlow", import_config: dict
|
||||
) -> ConfigFlowResult:
|
||||
"""Handle config import from yaml."""
|
||||
_, flow_result = self._async_create_html5_entry(import_config)
|
||||
if not flow_result:
|
||||
async_create_html5_issue(self.hass, False)
|
||||
return self.async_abort(reason="invalid_config")
|
||||
async_create_html5_issue(self.hass, True)
|
||||
return flow_result
|
Loading…
Add table
Add a link
Reference in a new issue