mirror of
https://github.com/home-assistant/supervisor.git
synced 2025-07-25 18:16:32 +00:00
commit
3b45fb417b
44
API.md
44
API.md
@ -456,6 +456,7 @@ Get all available addons.
|
|||||||
"name": "xy bla",
|
"name": "xy bla",
|
||||||
"slug": "xy",
|
"slug": "xy",
|
||||||
"description": "description",
|
"description": "description",
|
||||||
|
"advanced": "bool",
|
||||||
"repository": "core|local|REP_ID",
|
"repository": "core|local|REP_ID",
|
||||||
"version": "LAST_VERSION",
|
"version": "LAST_VERSION",
|
||||||
"installed": "none|INSTALL_VERSION",
|
"installed": "none|INSTALL_VERSION",
|
||||||
@ -494,6 +495,7 @@ Get all available addons.
|
|||||||
"url": "null|url of addon",
|
"url": "null|url of addon",
|
||||||
"detached": "bool",
|
"detached": "bool",
|
||||||
"available": "bool",
|
"available": "bool",
|
||||||
|
"advanced": "bool",
|
||||||
"arch": ["armhf", "aarch64", "i386", "amd64"],
|
"arch": ["armhf", "aarch64", "i386", "amd64"],
|
||||||
"machine": "[raspberrypi2, tinker]",
|
"machine": "[raspberrypi2, tinker]",
|
||||||
"homeassistant": "null|min Home Assistant version",
|
"homeassistant": "null|min Home Assistant version",
|
||||||
@ -504,6 +506,7 @@ Get all available addons.
|
|||||||
"boot": "auto|manual",
|
"boot": "auto|manual",
|
||||||
"build": "bool",
|
"build": "bool",
|
||||||
"options": "{}",
|
"options": "{}",
|
||||||
|
"schema": "{}|null",
|
||||||
"network": "{}|null",
|
"network": "{}|null",
|
||||||
"network_description": "{}|null",
|
"network_description": "{}|null",
|
||||||
"host_network": "bool",
|
"host_network": "bool",
|
||||||
@ -518,6 +521,7 @@ Get all available addons.
|
|||||||
"icon": "bool",
|
"icon": "bool",
|
||||||
"logo": "bool",
|
"logo": "bool",
|
||||||
"changelog": "bool",
|
"changelog": "bool",
|
||||||
|
"documentation": "bool",
|
||||||
"hassio_api": "bool",
|
"hassio_api": "bool",
|
||||||
"hassio_role": "default|homeassistant|manager|admin",
|
"hassio_role": "default|homeassistant|manager|admin",
|
||||||
"homeassistant_api": "bool",
|
"homeassistant_api": "bool",
|
||||||
@ -551,6 +555,8 @@ Get all available addons.
|
|||||||
|
|
||||||
- GET `/addons/{addon}/changelog`
|
- GET `/addons/{addon}/changelog`
|
||||||
|
|
||||||
|
- GET `/addons/{addon}/documentation`
|
||||||
|
|
||||||
- POST `/addons/{addon}/options`
|
- POST `/addons/{addon}/options`
|
||||||
|
|
||||||
```json
|
```json
|
||||||
@ -746,6 +752,33 @@ return:
|
|||||||
|
|
||||||
- DEL `/services/mqtt`
|
- DEL `/services/mqtt`
|
||||||
|
|
||||||
|
#### MySQL
|
||||||
|
|
||||||
|
- GET `/services/mysql`
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"addon": "name",
|
||||||
|
"host": "xy",
|
||||||
|
"port": "8883",
|
||||||
|
"username": "optional",
|
||||||
|
"password": "optional"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
- POST `/services/mysql`
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"host": "xy",
|
||||||
|
"port": "8883",
|
||||||
|
"username": "optional",
|
||||||
|
"password": "optional"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
- DEL `/services/mysql`
|
||||||
|
|
||||||
### Misc
|
### Misc
|
||||||
|
|
||||||
- GET `/info`
|
- GET `/info`
|
||||||
@ -797,6 +830,8 @@ return:
|
|||||||
|
|
||||||
- POST `/dns/restart`
|
- POST `/dns/restart`
|
||||||
|
|
||||||
|
- POST `/dns/reset`
|
||||||
|
|
||||||
- GET `/dns/logs`
|
- GET `/dns/logs`
|
||||||
|
|
||||||
- GET `/dns/stats`
|
- GET `/dns/stats`
|
||||||
@ -826,3 +861,12 @@ We support:
|
|||||||
- Json `{ "user|name": "...", "password": "..." }`
|
- Json `{ "user|name": "...", "password": "..." }`
|
||||||
- application/x-www-form-urlencoded `user|name=...&password=...`
|
- application/x-www-form-urlencoded `user|name=...&password=...`
|
||||||
- BasicAuth
|
- BasicAuth
|
||||||
|
|
||||||
|
* POST `/auth/reset`
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"username": "xy",
|
||||||
|
"password": "new-password"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
@ -19,7 +19,7 @@ variables:
|
|||||||
- name: versionHadolint
|
- name: versionHadolint
|
||||||
value: "v1.16.3"
|
value: "v1.16.3"
|
||||||
- name: versionBuilder
|
- name: versionBuilder
|
||||||
value: "4.4"
|
value: "6.9"
|
||||||
- name: versionWheels
|
- name: versionWheels
|
||||||
value: "1.6-3.7-alpine3.11"
|
value: "1.6-3.7-alpine3.11"
|
||||||
- group: docker
|
- group: docker
|
||||||
|
@ -6,6 +6,7 @@ from packaging import version as pkg_version
|
|||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
|
||||||
from ..const import (
|
from ..const import (
|
||||||
|
ATTR_ADVANCED,
|
||||||
ATTR_APPARMOR,
|
ATTR_APPARMOR,
|
||||||
ATTR_ARCH,
|
ATTR_ARCH,
|
||||||
ATTR_AUDIO,
|
ATTR_AUDIO,
|
||||||
@ -61,7 +62,7 @@ from ..const import (
|
|||||||
SECURITY_PROFILE,
|
SECURITY_PROFILE,
|
||||||
)
|
)
|
||||||
from ..coresys import CoreSysAttributes
|
from ..coresys import CoreSysAttributes
|
||||||
from .validate import RE_SERVICE, RE_VOLUME, validate_options
|
from .validate import RE_SERVICE, RE_VOLUME, validate_options, schema_ui_options
|
||||||
|
|
||||||
Data = Dict[str, Any]
|
Data = Dict[str, Any]
|
||||||
|
|
||||||
@ -189,6 +190,11 @@ class AddonModel(CoreSysAttributes):
|
|||||||
"""Return startup type of add-on."""
|
"""Return startup type of add-on."""
|
||||||
return self.data.get(ATTR_STARTUP)
|
return self.data.get(ATTR_STARTUP)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def advanced(self) -> bool:
|
||||||
|
"""Return advanced mode of add-on."""
|
||||||
|
return self.data[ATTR_ADVANCED]
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def services_role(self) -> Dict[str, str]:
|
def services_role(self) -> Dict[str, str]:
|
||||||
"""Return dict of services with rights."""
|
"""Return dict of services with rights."""
|
||||||
@ -405,6 +411,11 @@ class AddonModel(CoreSysAttributes):
|
|||||||
"""Return True if a changelog exists."""
|
"""Return True if a changelog exists."""
|
||||||
return self.path_changelog.exists()
|
return self.path_changelog.exists()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def with_documentation(self) -> bool:
|
||||||
|
"""Return True if a documentation exists."""
|
||||||
|
return self.path_documentation.exists()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def supported_arch(self) -> List[str]:
|
def supported_arch(self) -> List[str]:
|
||||||
"""Return list of supported arch."""
|
"""Return list of supported arch."""
|
||||||
@ -455,6 +466,11 @@ class AddonModel(CoreSysAttributes):
|
|||||||
"""Return path to add-on changelog."""
|
"""Return path to add-on changelog."""
|
||||||
return Path(self.path_location, "CHANGELOG.md")
|
return Path(self.path_location, "CHANGELOG.md")
|
||||||
|
|
||||||
|
@property
|
||||||
|
def path_documentation(self) -> Path:
|
||||||
|
"""Return path to add-on changelog."""
|
||||||
|
return Path(self.path_location, "DOCS.md")
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def path_apparmor(self) -> Path:
|
def path_apparmor(self) -> Path:
|
||||||
"""Return path to custom AppArmor profile."""
|
"""Return path to custom AppArmor profile."""
|
||||||
@ -469,6 +485,15 @@ class AddonModel(CoreSysAttributes):
|
|||||||
return vol.Schema(dict)
|
return vol.Schema(dict)
|
||||||
return vol.Schema(vol.All(dict, validate_options(self.coresys, raw_schema)))
|
return vol.Schema(vol.All(dict, validate_options(self.coresys, raw_schema)))
|
||||||
|
|
||||||
|
@property
|
||||||
|
def schema_ui(self) -> Optional[List[Dict[str, Any]]]:
|
||||||
|
"""Create a UI schema for add-on options."""
|
||||||
|
raw_schema = self.data[ATTR_SCHEMA]
|
||||||
|
|
||||||
|
if isinstance(raw_schema, bool):
|
||||||
|
return None
|
||||||
|
return schema_ui_options(raw_schema)
|
||||||
|
|
||||||
def __eq__(self, other):
|
def __eq__(self, other):
|
||||||
"""Compaired add-on objects."""
|
"""Compaired add-on objects."""
|
||||||
if not isinstance(other, AddonModel):
|
if not isinstance(other, AddonModel):
|
||||||
|
@ -39,8 +39,10 @@ def rating_security(addon: AddonModel) -> int:
|
|||||||
elif addon.apparmor == SECURITY_PROFILE:
|
elif addon.apparmor == SECURITY_PROFILE:
|
||||||
rating += 1
|
rating += 1
|
||||||
|
|
||||||
# Home Assistant Login
|
# Home Assistant Login & Ingress
|
||||||
if addon.access_auth_api:
|
if addon.with_ingress:
|
||||||
|
rating += 2
|
||||||
|
elif addon.access_auth_api:
|
||||||
rating += 1
|
rating += 1
|
||||||
|
|
||||||
# Privileged options
|
# Privileged options
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
import logging
|
import logging
|
||||||
import re
|
import re
|
||||||
import secrets
|
import secrets
|
||||||
from typing import Any, Dict
|
from typing import Any, Dict, List
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
@ -10,6 +10,7 @@ import voluptuous as vol
|
|||||||
from ..const import (
|
from ..const import (
|
||||||
ARCH_ALL,
|
ARCH_ALL,
|
||||||
ATTR_ACCESS_TOKEN,
|
ATTR_ACCESS_TOKEN,
|
||||||
|
ATTR_ADVANCED,
|
||||||
ATTR_APPARMOR,
|
ATTR_APPARMOR,
|
||||||
ATTR_ARCH,
|
ATTR_ARCH,
|
||||||
ATTR_ARGS,
|
ATTR_ARGS,
|
||||||
@ -90,9 +91,9 @@ from ..const import (
|
|||||||
from ..coresys import CoreSys
|
from ..coresys import CoreSys
|
||||||
from ..discovery.validate import valid_discovery_service
|
from ..discovery.validate import valid_discovery_service
|
||||||
from ..validate import (
|
from ..validate import (
|
||||||
alsa_device,
|
|
||||||
DOCKER_PORTS,
|
DOCKER_PORTS,
|
||||||
DOCKER_PORTS_DESCRIPTION,
|
DOCKER_PORTS_DESCRIPTION,
|
||||||
|
alsa_device,
|
||||||
network_port,
|
network_port,
|
||||||
token,
|
token,
|
||||||
uuid_match,
|
uuid_match,
|
||||||
@ -102,12 +103,13 @@ _LOGGER: logging.Logger = logging.getLogger(__name__)
|
|||||||
|
|
||||||
|
|
||||||
RE_VOLUME = re.compile(r"^(config|ssl|addons|backup|share)(?::(rw|ro))?$")
|
RE_VOLUME = re.compile(r"^(config|ssl|addons|backup|share)(?::(rw|ro))?$")
|
||||||
RE_SERVICE = re.compile(r"^(?P<service>mqtt):(?P<rights>provide|want|need)$")
|
RE_SERVICE = re.compile(r"^(?P<service>mqtt|mysql):(?P<rights>provide|want|need)$")
|
||||||
|
|
||||||
V_STR = "str"
|
V_STR = "str"
|
||||||
V_INT = "int"
|
V_INT = "int"
|
||||||
V_FLOAT = "float"
|
V_FLOAT = "float"
|
||||||
V_BOOL = "bool"
|
V_BOOL = "bool"
|
||||||
|
V_PASSWORD = "password"
|
||||||
V_EMAIL = "email"
|
V_EMAIL = "email"
|
||||||
V_URL = "url"
|
V_URL = "url"
|
||||||
V_PORT = "port"
|
V_PORT = "port"
|
||||||
@ -118,6 +120,7 @@ RE_SCHEMA_ELEMENT = re.compile(
|
|||||||
r"^(?:"
|
r"^(?:"
|
||||||
r"|bool|email|url|port"
|
r"|bool|email|url|port"
|
||||||
r"|str(?:\((?P<s_min>\d+)?,(?P<s_max>\d+)?\))?"
|
r"|str(?:\((?P<s_min>\d+)?,(?P<s_max>\d+)?\))?"
|
||||||
|
r"|password(?:\((?P<p_min>\d+)?,(?P<p_max>\d+)?\))?"
|
||||||
r"|int(?:\((?P<i_min>\d+)?,(?P<i_max>\d+)?\))?"
|
r"|int(?:\((?P<i_min>\d+)?,(?P<i_max>\d+)?\))?"
|
||||||
r"|float(?:\((?P<f_min>[\d\.]+)?,(?P<f_max>[\d\.]+)?\))?"
|
r"|float(?:\((?P<f_min>[\d\.]+)?,(?P<f_max>[\d\.]+)?\))?"
|
||||||
r"|match\((?P<match>.*)\)"
|
r"|match\((?P<match>.*)\)"
|
||||||
@ -125,7 +128,16 @@ RE_SCHEMA_ELEMENT = re.compile(
|
|||||||
r")\??$"
|
r")\??$"
|
||||||
)
|
)
|
||||||
|
|
||||||
_SCHEMA_LENGTH_PARTS = ("i_min", "i_max", "f_min", "f_max", "s_min", "s_max")
|
_SCHEMA_LENGTH_PARTS = (
|
||||||
|
"i_min",
|
||||||
|
"i_max",
|
||||||
|
"f_min",
|
||||||
|
"f_max",
|
||||||
|
"s_min",
|
||||||
|
"s_max",
|
||||||
|
"p_min",
|
||||||
|
"p_max",
|
||||||
|
)
|
||||||
|
|
||||||
RE_DOCKER_IMAGE = re.compile(r"^([a-zA-Z\-\.:\d{}]+/)*?([\-\w{}]+)/([\-\w{}]+)$")
|
RE_DOCKER_IMAGE = re.compile(r"^([a-zA-Z\-\.:\d{}]+/)*?([\-\w{}]+)/([\-\w{}]+)$")
|
||||||
RE_DOCKER_IMAGE_BUILD = re.compile(
|
RE_DOCKER_IMAGE_BUILD = re.compile(
|
||||||
@ -138,18 +150,18 @@ SCHEMA_ELEMENT = vol.Match(RE_SCHEMA_ELEMENT)
|
|||||||
MACHINE_ALL = [
|
MACHINE_ALL = [
|
||||||
"intel-nuc",
|
"intel-nuc",
|
||||||
"odroid-c2",
|
"odroid-c2",
|
||||||
|
"odroid-n2",
|
||||||
"odroid-xu",
|
"odroid-xu",
|
||||||
"orangepi-prime",
|
|
||||||
"qemux86",
|
|
||||||
"qemux86-64",
|
|
||||||
"qemuarm",
|
|
||||||
"qemuarm-64",
|
"qemuarm-64",
|
||||||
|
"qemuarm",
|
||||||
|
"qemux86-64",
|
||||||
|
"qemux86",
|
||||||
"raspberrypi",
|
"raspberrypi",
|
||||||
"raspberrypi2",
|
"raspberrypi2",
|
||||||
"raspberrypi3",
|
|
||||||
"raspberrypi3-64",
|
"raspberrypi3-64",
|
||||||
"raspberrypi4",
|
"raspberrypi3",
|
||||||
"raspberrypi4-64",
|
"raspberrypi4-64",
|
||||||
|
"raspberrypi4",
|
||||||
"tinker",
|
"tinker",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -175,6 +187,7 @@ SCHEMA_ADDON_CONFIG = vol.Schema(
|
|||||||
vol.Optional(ATTR_URL): vol.Url(),
|
vol.Optional(ATTR_URL): vol.Url(),
|
||||||
vol.Required(ATTR_STARTUP): vol.All(_simple_startup, vol.In(STARTUP_ALL)),
|
vol.Required(ATTR_STARTUP): vol.All(_simple_startup, vol.In(STARTUP_ALL)),
|
||||||
vol.Required(ATTR_BOOT): vol.In([BOOT_AUTO, BOOT_MANUAL]),
|
vol.Required(ATTR_BOOT): vol.In([BOOT_AUTO, BOOT_MANUAL]),
|
||||||
|
vol.Optional(ATTR_ADVANCED, default=False): vol.Boolean(),
|
||||||
vol.Optional(ATTR_PORTS): DOCKER_PORTS,
|
vol.Optional(ATTR_PORTS): DOCKER_PORTS,
|
||||||
vol.Optional(ATTR_PORTS_DESCRIPTION): DOCKER_PORTS_DESCRIPTION,
|
vol.Optional(ATTR_PORTS_DESCRIPTION): DOCKER_PORTS_DESCRIPTION,
|
||||||
vol.Optional(ATTR_WEBUI): vol.Match(
|
vol.Optional(ATTR_WEBUI): vol.Match(
|
||||||
@ -373,7 +386,7 @@ def _single_validate(coresys: CoreSys, typ: str, value: Any, key: str):
|
|||||||
if group_value:
|
if group_value:
|
||||||
range_args[group_name[2:]] = float(group_value)
|
range_args[group_name[2:]] = float(group_value)
|
||||||
|
|
||||||
if typ.startswith(V_STR):
|
if typ.startswith(V_STR) or typ.startswith(V_PASSWORD):
|
||||||
return vol.All(str(value), vol.Range(**range_args))(value)
|
return vol.All(str(value), vol.Range(**range_args))(value)
|
||||||
elif typ.startswith(V_INT):
|
elif typ.startswith(V_INT):
|
||||||
return vol.All(vol.Coerce(int), vol.Range(**range_args))(value)
|
return vol.All(vol.Coerce(int), vol.Range(**range_args))(value)
|
||||||
@ -439,3 +452,117 @@ def _check_missing_options(origin, exists, root):
|
|||||||
if isinstance(origin[miss_opt], str) and origin[miss_opt].endswith("?"):
|
if isinstance(origin[miss_opt], str) and origin[miss_opt].endswith("?"):
|
||||||
continue
|
continue
|
||||||
raise vol.Invalid(f"Missing option {miss_opt} in {root}")
|
raise vol.Invalid(f"Missing option {miss_opt} in {root}")
|
||||||
|
|
||||||
|
|
||||||
|
def schema_ui_options(raw_schema: Dict[str, Any]) -> List[Dict[str, Any]]:
|
||||||
|
"""Generate UI schema."""
|
||||||
|
ui_schema = []
|
||||||
|
|
||||||
|
# read options
|
||||||
|
for key, value in raw_schema.items():
|
||||||
|
if isinstance(value, list):
|
||||||
|
# nested value list
|
||||||
|
_nested_ui_list(ui_schema, value, key)
|
||||||
|
elif isinstance(value, dict):
|
||||||
|
# nested value dict
|
||||||
|
_nested_ui_dict(ui_schema, value, key)
|
||||||
|
else:
|
||||||
|
# normal value
|
||||||
|
_single_ui_option(ui_schema, value, key)
|
||||||
|
|
||||||
|
return ui_schema
|
||||||
|
|
||||||
|
|
||||||
|
def _single_ui_option(
|
||||||
|
ui_schema: List[Dict[str, Any]], value: str, key: str, multiple: bool = False
|
||||||
|
) -> None:
|
||||||
|
"""Validate a single element."""
|
||||||
|
ui_node = {"name": key}
|
||||||
|
|
||||||
|
# If multiple
|
||||||
|
if multiple:
|
||||||
|
ui_node["multiple"] = True
|
||||||
|
|
||||||
|
# Parse extend data from type
|
||||||
|
match = RE_SCHEMA_ELEMENT.match(value)
|
||||||
|
|
||||||
|
# Prepare range
|
||||||
|
for group_name in _SCHEMA_LENGTH_PARTS:
|
||||||
|
group_value = match.group(group_name)
|
||||||
|
if not group_value:
|
||||||
|
continue
|
||||||
|
if group_name[2:] == "min":
|
||||||
|
ui_node["lengthMin"] = float(group_value)
|
||||||
|
elif group_name[2:] == "max":
|
||||||
|
ui_node["lengthMax"] = float(group_value)
|
||||||
|
|
||||||
|
# If required
|
||||||
|
if value.endswith("?"):
|
||||||
|
ui_node["optional"] = True
|
||||||
|
else:
|
||||||
|
ui_node["required"] = True
|
||||||
|
|
||||||
|
# Data types
|
||||||
|
if value.startswith(V_STR):
|
||||||
|
ui_node["type"] = "string"
|
||||||
|
elif value.startswith(V_PASSWORD):
|
||||||
|
ui_node["type"] = "string"
|
||||||
|
ui_node["format"] = "password"
|
||||||
|
elif value.startswith(V_INT):
|
||||||
|
ui_node["type"] = "integer"
|
||||||
|
elif value.startswith(V_FLOAT):
|
||||||
|
ui_node["type"] = "float"
|
||||||
|
elif value.startswith(V_BOOL):
|
||||||
|
ui_node["type"] = "boolean"
|
||||||
|
elif value.startswith(V_EMAIL):
|
||||||
|
ui_node["type"] = "string"
|
||||||
|
ui_node["format"] = "email"
|
||||||
|
elif value.startswith(V_URL):
|
||||||
|
ui_node["type"] = "string"
|
||||||
|
ui_node["format"] = "url"
|
||||||
|
elif value.startswith(V_PORT):
|
||||||
|
ui_node["type"] = "integer"
|
||||||
|
elif value.startswith(V_MATCH):
|
||||||
|
ui_node["type"] = "string"
|
||||||
|
elif value.startswith(V_LIST):
|
||||||
|
ui_node["type"] = "select"
|
||||||
|
ui_node["options"] = match.group("list").split("|")
|
||||||
|
|
||||||
|
ui_schema.append(ui_node)
|
||||||
|
|
||||||
|
|
||||||
|
def _nested_ui_list(
|
||||||
|
ui_schema: List[Dict[str, Any]], option_list: List[Any], key: str
|
||||||
|
) -> None:
|
||||||
|
"""UI nested list items."""
|
||||||
|
try:
|
||||||
|
element = option_list[0]
|
||||||
|
except IndexError:
|
||||||
|
_LOGGER.error("Invalid schema %s", key)
|
||||||
|
return
|
||||||
|
|
||||||
|
if isinstance(element, dict):
|
||||||
|
_nested_ui_dict(ui_schema, element, key, multiple=True)
|
||||||
|
else:
|
||||||
|
_single_ui_option(ui_schema, element, key, multiple=True)
|
||||||
|
|
||||||
|
|
||||||
|
def _nested_ui_dict(
|
||||||
|
ui_schema: List[Dict[str, Any]],
|
||||||
|
option_dict: Dict[str, Any],
|
||||||
|
key: str,
|
||||||
|
multiple: bool = False,
|
||||||
|
) -> None:
|
||||||
|
"""UI nested dict items."""
|
||||||
|
ui_node = {"name": key, "type": "schema", "optional": True, "multiple": multiple}
|
||||||
|
|
||||||
|
nested_schema = []
|
||||||
|
for c_key, c_value in option_dict.items():
|
||||||
|
# Nested?
|
||||||
|
if isinstance(c_value, list):
|
||||||
|
_nested_ui_list(nested_schema, c_value, c_key)
|
||||||
|
else:
|
||||||
|
_single_ui_option(nested_schema, c_value, c_key)
|
||||||
|
|
||||||
|
ui_node["schema"] = nested_schema
|
||||||
|
ui_schema.append(ui_node)
|
||||||
|
@ -121,7 +121,9 @@ class RestAPI(CoreSysAttributes):
|
|||||||
api_auth = APIAuth()
|
api_auth = APIAuth()
|
||||||
api_auth.coresys = self.coresys
|
api_auth.coresys = self.coresys
|
||||||
|
|
||||||
self.webapp.add_routes([web.post("/auth", api_auth.auth)])
|
self.webapp.add_routes(
|
||||||
|
[web.post("/auth", api_auth.auth), web.post("/auth/reset", api_auth.reset)]
|
||||||
|
)
|
||||||
|
|
||||||
def _register_supervisor(self) -> None:
|
def _register_supervisor(self) -> None:
|
||||||
"""Register Supervisor functions."""
|
"""Register Supervisor functions."""
|
||||||
@ -199,6 +201,7 @@ class RestAPI(CoreSysAttributes):
|
|||||||
web.get("/addons/{addon}/icon", api_addons.icon),
|
web.get("/addons/{addon}/icon", api_addons.icon),
|
||||||
web.get("/addons/{addon}/logo", api_addons.logo),
|
web.get("/addons/{addon}/logo", api_addons.logo),
|
||||||
web.get("/addons/{addon}/changelog", api_addons.changelog),
|
web.get("/addons/{addon}/changelog", api_addons.changelog),
|
||||||
|
web.get("/addons/{addon}/documentation", api_addons.documentation),
|
||||||
web.post("/addons/{addon}/stdin", api_addons.stdin),
|
web.post("/addons/{addon}/stdin", api_addons.stdin),
|
||||||
web.post("/addons/{addon}/security", api_addons.security),
|
web.post("/addons/{addon}/security", api_addons.security),
|
||||||
web.get("/addons/{addon}/stats", api_addons.stats),
|
web.get("/addons/{addon}/stats", api_addons.stats),
|
||||||
@ -284,6 +287,7 @@ class RestAPI(CoreSysAttributes):
|
|||||||
web.post("/dns/update", api_dns.update),
|
web.post("/dns/update", api_dns.update),
|
||||||
web.post("/dns/options", api_dns.options),
|
web.post("/dns/options", api_dns.options),
|
||||||
web.post("/dns/restart", api_dns.restart),
|
web.post("/dns/restart", api_dns.restart),
|
||||||
|
web.post("/dns/reset", api_dns.reset),
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -7,10 +7,10 @@ from aiohttp import web
|
|||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
|
||||||
from ..addons import AnyAddon
|
from ..addons import AnyAddon
|
||||||
from ..docker.stats import DockerStats
|
|
||||||
from ..addons.utils import rating_security
|
from ..addons.utils import rating_security
|
||||||
from ..const import (
|
from ..const import (
|
||||||
ATTR_ADDONS,
|
ATTR_ADDONS,
|
||||||
|
ATTR_ADVANCED,
|
||||||
ATTR_APPARMOR,
|
ATTR_APPARMOR,
|
||||||
ATTR_ARCH,
|
ATTR_ARCH,
|
||||||
ATTR_AUDIO,
|
ATTR_AUDIO,
|
||||||
@ -32,6 +32,7 @@ from ..const import (
|
|||||||
ATTR_DISCOVERY,
|
ATTR_DISCOVERY,
|
||||||
ATTR_DNS,
|
ATTR_DNS,
|
||||||
ATTR_DOCKER_API,
|
ATTR_DOCKER_API,
|
||||||
|
ATTR_DOCUMENTATION,
|
||||||
ATTR_FULL_ACCESS,
|
ATTR_FULL_ACCESS,
|
||||||
ATTR_GPIO,
|
ATTR_GPIO,
|
||||||
ATTR_HASSIO_API,
|
ATTR_HASSIO_API,
|
||||||
@ -71,6 +72,7 @@ from ..const import (
|
|||||||
ATTR_RATING,
|
ATTR_RATING,
|
||||||
ATTR_REPOSITORIES,
|
ATTR_REPOSITORIES,
|
||||||
ATTR_REPOSITORY,
|
ATTR_REPOSITORY,
|
||||||
|
ATTR_SCHEMA,
|
||||||
ATTR_SERVICES,
|
ATTR_SERVICES,
|
||||||
ATTR_SLUG,
|
ATTR_SLUG,
|
||||||
ATTR_SOURCE,
|
ATTR_SOURCE,
|
||||||
@ -89,8 +91,9 @@ from ..const import (
|
|||||||
STATE_NONE,
|
STATE_NONE,
|
||||||
)
|
)
|
||||||
from ..coresys import CoreSysAttributes
|
from ..coresys import CoreSysAttributes
|
||||||
|
from ..docker.stats import DockerStats
|
||||||
from ..exceptions import APIError
|
from ..exceptions import APIError
|
||||||
from ..validate import alsa_device, DOCKER_PORTS
|
from ..validate import DOCKER_PORTS, alsa_device
|
||||||
from .utils import api_process, api_process_raw, api_validate
|
from .utils import api_process, api_process_raw, api_validate
|
||||||
|
|
||||||
_LOGGER: logging.Logger = logging.getLogger(__name__)
|
_LOGGER: logging.Logger = logging.getLogger(__name__)
|
||||||
@ -145,6 +148,7 @@ class APIAddons(CoreSysAttributes):
|
|||||||
ATTR_NAME: addon.name,
|
ATTR_NAME: addon.name,
|
||||||
ATTR_SLUG: addon.slug,
|
ATTR_SLUG: addon.slug,
|
||||||
ATTR_DESCRIPTON: addon.description,
|
ATTR_DESCRIPTON: addon.description,
|
||||||
|
ATTR_ADVANCED: addon.advanced,
|
||||||
ATTR_VERSION: addon.latest_version,
|
ATTR_VERSION: addon.latest_version,
|
||||||
ATTR_INSTALLED: addon.version if addon.is_installed else None,
|
ATTR_INSTALLED: addon.version if addon.is_installed else None,
|
||||||
ATTR_AVAILABLE: addon.available,
|
ATTR_AVAILABLE: addon.available,
|
||||||
@ -188,6 +192,7 @@ class APIAddons(CoreSysAttributes):
|
|||||||
ATTR_DNS: addon.dns,
|
ATTR_DNS: addon.dns,
|
||||||
ATTR_DESCRIPTON: addon.description,
|
ATTR_DESCRIPTON: addon.description,
|
||||||
ATTR_LONG_DESCRIPTION: addon.long_description,
|
ATTR_LONG_DESCRIPTION: addon.long_description,
|
||||||
|
ATTR_ADVANCED: addon.advanced,
|
||||||
ATTR_AUTO_UPDATE: None,
|
ATTR_AUTO_UPDATE: None,
|
||||||
ATTR_REPOSITORY: addon.repository,
|
ATTR_REPOSITORY: addon.repository,
|
||||||
ATTR_VERSION: None,
|
ATTR_VERSION: None,
|
||||||
@ -196,6 +201,7 @@ class APIAddons(CoreSysAttributes):
|
|||||||
ATTR_RATING: rating_security(addon),
|
ATTR_RATING: rating_security(addon),
|
||||||
ATTR_BOOT: addon.boot,
|
ATTR_BOOT: addon.boot,
|
||||||
ATTR_OPTIONS: addon.options,
|
ATTR_OPTIONS: addon.options,
|
||||||
|
ATTR_SCHEMA: addon.schema_ui,
|
||||||
ATTR_ARCH: addon.supported_arch,
|
ATTR_ARCH: addon.supported_arch,
|
||||||
ATTR_MACHINE: addon.supported_machine,
|
ATTR_MACHINE: addon.supported_machine,
|
||||||
ATTR_HOMEASSISTANT: addon.homeassistant_version,
|
ATTR_HOMEASSISTANT: addon.homeassistant_version,
|
||||||
@ -217,6 +223,7 @@ class APIAddons(CoreSysAttributes):
|
|||||||
ATTR_ICON: addon.with_icon,
|
ATTR_ICON: addon.with_icon,
|
||||||
ATTR_LOGO: addon.with_logo,
|
ATTR_LOGO: addon.with_logo,
|
||||||
ATTR_CHANGELOG: addon.with_changelog,
|
ATTR_CHANGELOG: addon.with_changelog,
|
||||||
|
ATTR_DOCUMENTATION: addon.with_documentation,
|
||||||
ATTR_STDIN: addon.with_stdin,
|
ATTR_STDIN: addon.with_stdin,
|
||||||
ATTR_WEBUI: None,
|
ATTR_WEBUI: None,
|
||||||
ATTR_HASSIO_API: addon.access_hassio_api,
|
ATTR_HASSIO_API: addon.access_hassio_api,
|
||||||
@ -407,6 +414,16 @@ class APIAddons(CoreSysAttributes):
|
|||||||
with addon.path_changelog.open("r") as changelog:
|
with addon.path_changelog.open("r") as changelog:
|
||||||
return changelog.read()
|
return changelog.read()
|
||||||
|
|
||||||
|
@api_process_raw(CONTENT_TYPE_TEXT)
|
||||||
|
async def documentation(self, request: web.Request) -> str:
|
||||||
|
"""Return documentation from add-on."""
|
||||||
|
addon: AnyAddon = self._extract_addon(request, check_installed=False)
|
||||||
|
if not addon.with_documentation:
|
||||||
|
raise APIError("No documentation found!")
|
||||||
|
|
||||||
|
with addon.path_documentation.open("r") as documentation:
|
||||||
|
return documentation.read()
|
||||||
|
|
||||||
@api_process
|
@api_process
|
||||||
async def stdin(self, request: web.Request) -> None:
|
async def stdin(self, request: web.Request) -> None:
|
||||||
"""Write to stdin of add-on."""
|
"""Write to stdin of add-on."""
|
||||||
|
@ -1,22 +1,39 @@
|
|||||||
"""Init file for Hass.io auth/SSO RESTful API."""
|
"""Init file for Hass.io auth/SSO RESTful API."""
|
||||||
|
import asyncio
|
||||||
import logging
|
import logging
|
||||||
|
from typing import Dict
|
||||||
|
|
||||||
from aiohttp import BasicAuth
|
from aiohttp import BasicAuth, web
|
||||||
|
from aiohttp.hdrs import AUTHORIZATION, CONTENT_TYPE, WWW_AUTHENTICATE
|
||||||
from aiohttp.web_exceptions import HTTPUnauthorized
|
from aiohttp.web_exceptions import HTTPUnauthorized
|
||||||
from aiohttp.hdrs import CONTENT_TYPE, AUTHORIZATION, WWW_AUTHENTICATE
|
import voluptuous as vol
|
||||||
|
|
||||||
from .utils import api_process
|
from ..addons.addon import Addon
|
||||||
from ..const import REQUEST_FROM, CONTENT_TYPE_JSON, CONTENT_TYPE_URL
|
from ..const import (
|
||||||
|
ATTR_PASSWORD,
|
||||||
|
ATTR_USERNAME,
|
||||||
|
CONTENT_TYPE_JSON,
|
||||||
|
CONTENT_TYPE_URL,
|
||||||
|
REQUEST_FROM,
|
||||||
|
)
|
||||||
from ..coresys import CoreSysAttributes
|
from ..coresys import CoreSysAttributes
|
||||||
from ..exceptions import APIForbidden
|
from ..exceptions import APIForbidden
|
||||||
|
from .utils import api_process, api_validate
|
||||||
|
|
||||||
_LOGGER: logging.Logger = logging.getLogger(__name__)
|
_LOGGER: logging.Logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
SCHEMA_PASSWORD_RESET = vol.Schema(
|
||||||
|
{
|
||||||
|
vol.Required(ATTR_USERNAME): vol.Coerce(str),
|
||||||
|
vol.Required(ATTR_PASSWORD): vol.Coerce(str),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class APIAuth(CoreSysAttributes):
|
class APIAuth(CoreSysAttributes):
|
||||||
"""Handle RESTful API for auth functions."""
|
"""Handle RESTful API for auth functions."""
|
||||||
|
|
||||||
def _process_basic(self, request, addon):
|
def _process_basic(self, request: web.Request, addon: Addon) -> bool:
|
||||||
"""Process login request with basic auth.
|
"""Process login request with basic auth.
|
||||||
|
|
||||||
Return a coroutine.
|
Return a coroutine.
|
||||||
@ -24,7 +41,9 @@ class APIAuth(CoreSysAttributes):
|
|||||||
auth = BasicAuth.decode(request.headers[AUTHORIZATION])
|
auth = BasicAuth.decode(request.headers[AUTHORIZATION])
|
||||||
return self.sys_auth.check_login(addon, auth.login, auth.password)
|
return self.sys_auth.check_login(addon, auth.login, auth.password)
|
||||||
|
|
||||||
def _process_dict(self, request, addon, data):
|
def _process_dict(
|
||||||
|
self, request: web.Request, addon: Addon, data: Dict[str, str]
|
||||||
|
) -> bool:
|
||||||
"""Process login with dict data.
|
"""Process login with dict data.
|
||||||
|
|
||||||
Return a coroutine.
|
Return a coroutine.
|
||||||
@ -35,7 +54,7 @@ class APIAuth(CoreSysAttributes):
|
|||||||
return self.sys_auth.check_login(addon, username, password)
|
return self.sys_auth.check_login(addon, username, password)
|
||||||
|
|
||||||
@api_process
|
@api_process
|
||||||
async def auth(self, request):
|
async def auth(self, request: web.Request) -> bool:
|
||||||
"""Process login request."""
|
"""Process login request."""
|
||||||
addon = request[REQUEST_FROM]
|
addon = request[REQUEST_FROM]
|
||||||
|
|
||||||
@ -59,3 +78,11 @@ class APIAuth(CoreSysAttributes):
|
|||||||
raise HTTPUnauthorized(
|
raise HTTPUnauthorized(
|
||||||
headers={WWW_AUTHENTICATE: 'Basic realm="Hass.io Authentication"'}
|
headers={WWW_AUTHENTICATE: 'Basic realm="Hass.io Authentication"'}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@api_process
|
||||||
|
async def reset(self, request: web.Request) -> None:
|
||||||
|
"""Process reset password request."""
|
||||||
|
body: Dict[str, str] = await api_validate(SCHEMA_PASSWORD_RESET, request)
|
||||||
|
await asyncio.shield(
|
||||||
|
self.sys_auth.change_password(body[ATTR_USERNAME], body[ATTR_PASSWORD])
|
||||||
|
)
|
||||||
|
@ -95,3 +95,8 @@ class APICoreDNS(CoreSysAttributes):
|
|||||||
def restart(self, request: web.Request) -> Awaitable[None]:
|
def restart(self, request: web.Request) -> Awaitable[None]:
|
||||||
"""Restart CoreDNS plugin."""
|
"""Restart CoreDNS plugin."""
|
||||||
return asyncio.shield(self.sys_dns.restart())
|
return asyncio.shield(self.sys_dns.restart())
|
||||||
|
|
||||||
|
@api_process
|
||||||
|
def reset(self, request: web.Request) -> Awaitable[None]:
|
||||||
|
"""Reset CoreDNS plugin."""
|
||||||
|
return asyncio.shield(self.sys_dns.reset())
|
||||||
|
2
hassio/api/panel/201359fd5a526afe13ef.worker.js
Normal file
2
hassio/api/panel/201359fd5a526afe13ef.worker.js
Normal file
File diff suppressed because one or more lines are too long
BIN
hassio/api/panel/201359fd5a526afe13ef.worker.js.gz
Normal file
BIN
hassio/api/panel/201359fd5a526afe13ef.worker.js.gz
Normal file
Binary file not shown.
1
hassio/api/panel/201359fd5a526afe13ef.worker.js.map
Normal file
1
hassio/api/panel/201359fd5a526afe13ef.worker.js.map
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
3
hassio/api/panel/chunk.12902324b918e12549ba.js
Normal file
3
hassio/api/panel/chunk.12902324b918e12549ba.js
Normal file
File diff suppressed because one or more lines are too long
@ -51,6 +51,27 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
@license
|
||||||
|
Copyright (c) 2016 The Polymer Project Authors. All rights reserved.
|
||||||
|
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
||||||
|
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
||||||
|
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
|
||||||
|
Code distributed by Google as part of the polymer project is also
|
||||||
|
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
@license
|
||||||
|
Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
|
||||||
|
This code may only be used under the BSD style license found at
|
||||||
|
http://polymer.github.io/LICENSE.txt The complete set of authors may be found at
|
||||||
|
http://polymer.github.io/AUTHORS.txt The complete set of contributors may be
|
||||||
|
found at http://polymer.github.io/CONTRIBUTORS.txt Code distributed by Google as
|
||||||
|
part of the polymer project is also subject to an additional IP rights grant
|
||||||
|
found at http://polymer.github.io/PATENTS.txt
|
||||||
|
*/
|
||||||
|
|
||||||
/*! *****************************************************************************
|
/*! *****************************************************************************
|
||||||
Copyright (c) Microsoft Corporation. All rights reserved.
|
Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
|
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
|
||||||
@ -66,6 +87,31 @@ See the Apache Version 2.0 License for specific language governing permissions
|
|||||||
and limitations under the License.
|
and limitations under the License.
|
||||||
***************************************************************************** */
|
***************************************************************************** */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @license
|
||||||
|
* Copyright (c) 2018 The Polymer Project Authors. All rights reserved.
|
||||||
|
* This code may only be used under the BSD style license found at
|
||||||
|
* http://polymer.github.io/LICENSE.txt
|
||||||
|
* The complete set of authors may be found at
|
||||||
|
* http://polymer.github.io/AUTHORS.txt
|
||||||
|
* The complete set of contributors may be found at
|
||||||
|
* http://polymer.github.io/CONTRIBUTORS.txt
|
||||||
|
* Code distributed by Google as part of the polymer project is also
|
||||||
|
* subject to an additional IP rights grant found at
|
||||||
|
* http://polymer.github.io/PATENTS.txt
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
@license
|
||||||
|
Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
|
||||||
|
This code may only be used under the BSD style license found at
|
||||||
|
http://polymer.github.io/LICENSE.txt The complete set of authors may be found at
|
||||||
|
http://polymer.github.io/AUTHORS.txt The complete set of contributors may be
|
||||||
|
found at http://polymer.github.io/CONTRIBUTORS.txt Code distributed by Google as
|
||||||
|
part of the polymer project is also subject to an additional IP rights grant
|
||||||
|
found at http://polymer.github.io/PATENTS.txt
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @license
|
* @license
|
||||||
* Copyright 2016 Google Inc.
|
* Copyright 2016 Google Inc.
|
||||||
@ -89,6 +135,39 @@ and limitations under the License.
|
|||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
@license
|
||||||
|
Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
|
||||||
|
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
||||||
|
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
||||||
|
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
|
||||||
|
Code distributed by Google as part of the polymer project is also
|
||||||
|
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @license
|
||||||
|
* Copyright 2019 Google Inc.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @license
|
* @license
|
||||||
* Copyright 2018 Google Inc.
|
* Copyright 2018 Google Inc.
|
||||||
@ -112,62 +191,6 @@ and limitations under the License.
|
|||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
|
||||||
@license
|
|
||||||
Copyright (c) 2016 The Polymer Project Authors. All rights reserved.
|
|
||||||
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
|
||||||
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
|
||||||
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
|
|
||||||
Code distributed by Google as part of the polymer project is also
|
|
||||||
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
@license
|
|
||||||
Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
|
|
||||||
This code may only be used under the BSD style license found at
|
|
||||||
http://polymer.github.io/LICENSE.txt The complete set of authors may be found at
|
|
||||||
http://polymer.github.io/AUTHORS.txt The complete set of contributors may be
|
|
||||||
found at http://polymer.github.io/CONTRIBUTORS.txt Code distributed by Google as
|
|
||||||
part of the polymer project is also subject to an additional IP rights grant
|
|
||||||
found at http://polymer.github.io/PATENTS.txt
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @license
|
|
||||||
* Copyright (c) 2018 The Polymer Project Authors. All rights reserved.
|
|
||||||
* This code may only be used under the BSD style license found at
|
|
||||||
* http://polymer.github.io/LICENSE.txt
|
|
||||||
* The complete set of authors may be found at
|
|
||||||
* http://polymer.github.io/AUTHORS.txt
|
|
||||||
* The complete set of contributors may be found at
|
|
||||||
* http://polymer.github.io/CONTRIBUTORS.txt
|
|
||||||
* Code distributed by Google as part of the polymer project is also
|
|
||||||
* subject to an additional IP rights grant found at
|
|
||||||
* http://polymer.github.io/PATENTS.txt
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
@license
|
|
||||||
Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
|
|
||||||
This code may only be used under the BSD style license found at
|
|
||||||
http://polymer.github.io/LICENSE.txt The complete set of authors may be found at
|
|
||||||
http://polymer.github.io/AUTHORS.txt The complete set of contributors may be
|
|
||||||
found at http://polymer.github.io/CONTRIBUTORS.txt Code distributed by Google as
|
|
||||||
part of the polymer project is also subject to an additional IP rights grant
|
|
||||||
found at http://polymer.github.io/PATENTS.txt
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
@license
|
|
||||||
Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
|
|
||||||
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
|
||||||
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
|
||||||
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
|
|
||||||
Code distributed by Google as part of the polymer project is also
|
|
||||||
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@license
|
@license
|
||||||
Copyright (c) 2016 The Polymer Project Authors. All rights reserved.
|
Copyright (c) 2016 The Polymer Project Authors. All rights reserved.
|
BIN
hassio/api/panel/chunk.12902324b918e12549ba.js.gz
Normal file
BIN
hassio/api/panel/chunk.12902324b918e12549ba.js.gz
Normal file
Binary file not shown.
1
hassio/api/panel/chunk.12902324b918e12549ba.js.map
Normal file
1
hassio/api/panel/chunk.12902324b918e12549ba.js.map
Normal file
File diff suppressed because one or more lines are too long
3
hassio/api/panel/chunk.50202a3f8d4670c9454d.js
Normal file
3
hassio/api/panel/chunk.50202a3f8d4670c9454d.js
Normal file
File diff suppressed because one or more lines are too long
BIN
hassio/api/panel/chunk.50202a3f8d4670c9454d.js.gz
Normal file
BIN
hassio/api/panel/chunk.50202a3f8d4670c9454d.js.gz
Normal file
Binary file not shown.
1
hassio/api/panel/chunk.50202a3f8d4670c9454d.js.map
Normal file
1
hassio/api/panel/chunk.50202a3f8d4670c9454d.js.map
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.
@ -1 +0,0 @@
|
|||||||
{"version":3,"sources":["webpack:///./src/ingress-view/hassio-ingress-view.ts"],"names":["customElement","HassioIngressView","property","this","_addon","html","_templateObject2","name","ingress_url","_templateObject","changedProps","_get","_getPrototypeOf","prototype","call","has","addon","route","path","substr","oldRoute","get","oldAddon","undefined","_fetchData","_callee","addonSlug","_ref","_ref2","regeneratorRuntime","wrap","_context","prev","next","Promise","all","fetchHassioAddonInfo","hass","catch","Error","createHassioSession","sent","_slicedToArray","ingress","t0","console","error","alert","message","history","back","stop","css","_templateObject3","LitElement"],"mappings":"4gSAmBCA,YAAc,0CACTC,smBACHC,kEACAA,mEACAA,4EAED,WACE,OAAKC,KAAKC,OAMHC,YAAPC,IAC0BH,KAAKC,OAAOG,KACpBJ,KAAKC,OAAOI,aAPrBH,YAAPI,0CAYJ,SAAkBC,GAGhB,GAFAC,EAAAC,EApBEX,EAoBFY,WAAA,eAAAV,MAAAW,KAAAX,KAAmBO,GAEdA,EAAaK,IAAI,SAAtB,CAIA,IAAMC,EAAQb,KAAKc,MAAMC,KAAKC,OAAO,GAE/BC,EAAWV,EAAaW,IAAI,SAC5BC,EAAWF,EAAWA,EAASF,KAAKC,OAAO,QAAKI,EAElDP,GAASA,IAAUM,GACrBnB,KAAKqB,WAAWR,0FAIpB,SAAAS,EAAyBC,GAAzB,IAAAC,EAAAC,EAAAZ,EAAA,OAAAa,mBAAAC,KAAA,SAAAC,GAAA,cAAAA,EAAAC,KAAAD,EAAAE,MAAA,cAAAF,EAAAC,KAAA,EAAAD,EAAAE,KAAA,EAE0BC,QAAQC,IAAI,CAChCC,YAAqBjC,KAAKkC,KAAMX,GAAWY,MAAM,WAC/C,MAAM,IAAIC,MAAM,iCAElBC,YAAoBrC,KAAKkC,MAAMC,MAAM,WACnC,MAAM,IAAIC,MAAM,2CAPxB,UAAAZ,EAAAI,EAAAU,KAAAb,EAAAc,EAAAf,EAAA,IAEWX,EAFXY,EAAA,IAWee,QAXf,CAAAZ,EAAAE,KAAA,cAYY,IAAIM,MAAM,wCAZtB,OAeIpC,KAAKC,OAASY,EAflBe,EAAAE,KAAA,iBAAAF,EAAAC,KAAA,GAAAD,EAAAa,GAAAb,EAAA,SAkBIc,QAAQC,MAARf,EAAAa,IACAG,MAAMhB,EAAAa,GAAII,SAAW,mCACrBC,QAAQC,OApBZ,yBAAAnB,EAAAoB,SAAA1B,EAAAtB,KAAA,yRAwBA,WACE,OAAOiD,YAAPC,UA7D4BC","file":"chunk.5dd33a3a20657ed46a19.js","sourcesContent":["import {\n LitElement,\n customElement,\n property,\n TemplateResult,\n html,\n PropertyValues,\n CSSResult,\n css,\n} from \"lit-element\";\nimport { HomeAssistant, Route } from \"../../../src/types\";\nimport {\n createHassioSession,\n HassioAddonDetails,\n fetchHassioAddonInfo,\n} from \"../../../src/data/hassio\";\nimport \"../../../src/layouts/hass-loading-screen\";\nimport \"../../../src/layouts/hass-subpage\";\n\n@customElement(\"hassio-ingress-view\")\nclass HassioIngressView extends LitElement {\n @property() public hass!: HomeAssistant;\n @property() public route!: Route;\n @property() private _addon?: HassioAddonDetails;\n\n protected render(): TemplateResult | void {\n if (!this._addon) {\n return html`\n <hass-loading-screen></hass-loading-screen>\n `;\n }\n\n return html`\n <hass-subpage .header=${this._addon.name} hassio>\n <iframe src=${this._addon.ingress_url}></iframe>\n </hass-subpage>\n `;\n }\n\n protected updated(changedProps: PropertyValues) {\n super.firstUpdated(changedProps);\n\n if (!changedProps.has(\"route\")) {\n return;\n }\n\n const addon = this.route.path.substr(1);\n\n const oldRoute = changedProps.get(\"route\") as this[\"route\"] | undefined;\n const oldAddon = oldRoute ? oldRoute.path.substr(1) : undefined;\n\n if (addon && addon !== oldAddon) {\n this._fetchData(addon);\n }\n }\n\n private async _fetchData(addonSlug: string) {\n try {\n const [addon] = await Promise.all([\n fetchHassioAddonInfo(this.hass, addonSlug).catch(() => {\n throw new Error(\"Failed to fetch add-on info\");\n }),\n createHassioSession(this.hass).catch(() => {\n throw new Error(\"Failed to create an ingress session\");\n }),\n ]);\n\n if (!addon.ingress) {\n throw new Error(\"This add-on does not support ingress\");\n }\n\n this._addon = addon;\n } catch (err) {\n // tslint:disable-next-line\n console.error(err);\n alert(err.message || \"Unknown error starting ingress.\");\n history.back();\n }\n }\n\n static get styles(): CSSResult {\n return css`\n iframe {\n display: block;\n width: 100%;\n height: 100%;\n border: 0;\n }\n paper-icon-button {\n color: var(--text-primary-color);\n }\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"hassio-ingress-view\": HassioIngressView;\n }\n}\n"],"sourceRoot":""}
|
|
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1,21 +0,0 @@
|
|||||||
/**
|
|
||||||
@license
|
|
||||||
Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
|
|
||||||
This code may only be used under the BSD style license found at
|
|
||||||
http://polymer.github.io/LICENSE.txt The complete set of authors may be found at
|
|
||||||
http://polymer.github.io/AUTHORS.txt The complete set of contributors may be
|
|
||||||
found at http://polymer.github.io/CONTRIBUTORS.txt Code distributed by Google as
|
|
||||||
part of the polymer project is also subject to an additional IP rights grant
|
|
||||||
found at http://polymer.github.io/PATENTS.txt
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
@license
|
|
||||||
Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
|
|
||||||
This code may only be used under the BSD style license found at
|
|
||||||
http://polymer.github.io/LICENSE.txt The complete set of authors may be found at
|
|
||||||
http://polymer.github.io/AUTHORS.txt The complete set of contributors may be
|
|
||||||
found at http://polymer.github.io/CONTRIBUTORS.txt Code distributed by Google as
|
|
||||||
part of the polymer project is also subject to an additional IP rights grant
|
|
||||||
found at http://polymer.github.io/PATENTS.txt
|
|
||||||
*/
|
|
Binary file not shown.
File diff suppressed because one or more lines are too long
@ -1,2 +0,0 @@
|
|||||||
(window.webpackJsonp=window.webpackJsonp||[]).push([[9],{101:function(n,r,t){"use strict";t.r(r),t.d(r,"marked",function(){return a}),t.d(r,"filterXSS",function(){return c});var e=t(124),i=t.n(e),o=t(126),u=t.n(o),a=i.a,c=u.a}}]);
|
|
||||||
//# sourceMappingURL=chunk.7f8cce5798f837214ef8.js.map
|
|
Binary file not shown.
@ -1 +0,0 @@
|
|||||||
{"version":3,"sources":["webpack:///../src/resources/load_markdown.js"],"names":["__webpack_require__","r","__webpack_exports__","d","marked","filterXSS","marked__WEBPACK_IMPORTED_MODULE_0__","marked__WEBPACK_IMPORTED_MODULE_0___default","n","xss__WEBPACK_IMPORTED_MODULE_1__","xss__WEBPACK_IMPORTED_MODULE_1___default","marked_","filterXSS_"],"mappings":"0FAAAA,EAAAC,EAAAC,GAAAF,EAAAG,EAAAD,EAAA,2BAAAE,IAAAJ,EAAAG,EAAAD,EAAA,8BAAAG,IAAA,IAAAC,EAAAN,EAAA,KAAAO,EAAAP,EAAAQ,EAAAF,GAAAG,EAAAT,EAAA,KAAAU,EAAAV,EAAAQ,EAAAC,GAGaL,EAASO,IACTN,EAAYO","file":"chunk.7f8cce5798f837214ef8.js","sourcesContent":["import marked_ from \"marked\";\nimport filterXSS_ from \"xss\";\n\nexport const marked = marked_;\nexport const filterXSS = filterXSS_;\n"],"sourceRoot":""}
|
|
3
hassio/api/panel/chunk.84aaaba4c4734f1c2e21.js
Normal file
3
hassio/api/panel/chunk.84aaaba4c4734f1c2e21.js
Normal file
File diff suppressed because one or more lines are too long
@ -1,3 +1,20 @@
|
|||||||
|
/**
|
||||||
|
@license
|
||||||
|
Copyright 2018 Google Inc. All Rights Reserved.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@license
|
@license
|
||||||
Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
|
Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
|
||||||
@ -9,16 +26,6 @@ part of the polymer project is also subject to an additional IP rights grant
|
|||||||
found at http://polymer.github.io/PATENTS.txt
|
found at http://polymer.github.io/PATENTS.txt
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
|
||||||
@license
|
|
||||||
Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
|
|
||||||
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
|
||||||
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
|
||||||
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
|
|
||||||
Code distributed by Google as part of the polymer project is also
|
|
||||||
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@license
|
@license
|
||||||
Copyright (c) 2016 The Polymer Project Authors. All rights reserved.
|
Copyright (c) 2016 The Polymer Project Authors. All rights reserved.
|
BIN
hassio/api/panel/chunk.84aaaba4c4734f1c2e21.js.gz
Normal file
BIN
hassio/api/panel/chunk.84aaaba4c4734f1c2e21.js.gz
Normal file
Binary file not shown.
1
hassio/api/panel/chunk.84aaaba4c4734f1c2e21.js.map
Normal file
1
hassio/api/panel/chunk.84aaaba4c4734f1c2e21.js.map
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
2
hassio/api/panel/chunk.884d6e32c83f99e41040.js
Normal file
2
hassio/api/panel/chunk.884d6e32c83f99e41040.js
Normal file
File diff suppressed because one or more lines are too long
BIN
hassio/api/panel/chunk.884d6e32c83f99e41040.js.gz
Normal file
BIN
hassio/api/panel/chunk.884d6e32c83f99e41040.js.gz
Normal file
Binary file not shown.
1
hassio/api/panel/chunk.884d6e32c83f99e41040.js.map
Normal file
1
hassio/api/panel/chunk.884d6e32c83f99e41040.js.map
Normal file
File diff suppressed because one or more lines are too long
2
hassio/api/panel/chunk.900c5d3fab8b6ebdcbc6.js
Normal file
2
hassio/api/panel/chunk.900c5d3fab8b6ebdcbc6.js
Normal file
File diff suppressed because one or more lines are too long
BIN
hassio/api/panel/chunk.900c5d3fab8b6ebdcbc6.js.gz
Normal file
BIN
hassio/api/panel/chunk.900c5d3fab8b6ebdcbc6.js.gz
Normal file
Binary file not shown.
1
hassio/api/panel/chunk.900c5d3fab8b6ebdcbc6.js.map
Normal file
1
hassio/api/panel/chunk.900c5d3fab8b6ebdcbc6.js.map
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"version":3,"sources":["webpack:///./hassio/src/ingress-view/hassio-ingress-view.ts"],"names":["customElement","HassioIngressView","property","this","_addon","html","_templateObject2","name","ingress_url","_templateObject","changedProps","_get","_getPrototypeOf","prototype","call","has","addon","route","path","substr","oldRoute","get","oldAddon","undefined","_fetchData","addonSlug","_ref","_ref2","regeneratorRuntime","async","_context","prev","next","awrap","Promise","all","fetchHassioAddonInfo","hass","Error","createHassioSession","sent","_slicedToArray","ingress","t0","console","error","alert","message","history","back","stop","css","_templateObject3","LitElement"],"mappings":"2/RAmBCA,YAAc,0CACTC,smBACHC,kEACAA,mEACAA,4EAED,WACE,OAAKC,KAAKC,OAMHC,YAAPC,IAC0BH,KAAKC,OAAOG,KACpBJ,KAAKC,OAAOI,aAPrBH,YAAPI,0CAYJ,SAAkBC,GAGhB,GAFAC,EAAAC,EApBEX,EAoBFY,WAAA,eAAAV,MAAAW,KAAAX,KAAmBO,GAEdA,EAAaK,IAAI,SAAtB,CAIA,IAAMC,EAAQb,KAAKc,MAAMC,KAAKC,OAAO,GAE/BC,EAAWV,EAAaW,IAAI,SAC5BC,EAAWF,EAAWA,EAASF,KAAKC,OAAO,QAAKI,EAElDP,GAASA,IAAUM,GACrBnB,KAAKqB,WAAWR,4CAIpB,SAAyBS,GAAzB,IAAAC,EAAAC,EAAAX,EAAA,OAAAY,mBAAAC,MAAA,SAAAC,GAAA,cAAAA,EAAAC,KAAAD,EAAAE,MAAA,cAAAF,EAAAC,KAAA,EAAAD,EAAAE,KAAA,EAAAJ,mBAAAK,MAE0BC,QAAQC,IAAI,CAChCC,YAAqBjC,KAAKkC,KAAMZ,GAAhC,MAAiD,WAC/C,MAAM,IAAIa,MAAM,iCAElBC,YAAoBpC,KAAKkC,MAAzB,MAAqC,WACnC,MAAM,IAAIC,MAAM,4CAPxB,UAAAZ,EAAAI,EAAAU,KAAAb,EAAAc,EAAAf,EAAA,IAEWV,EAFXW,EAAA,IAWee,QAXf,CAAAZ,EAAAE,KAAA,cAYY,IAAIM,MAAM,wCAZtB,OAeInC,KAAKC,OAASY,EAflBc,EAAAE,KAAA,iBAAAF,EAAAC,KAAA,GAAAD,EAAAa,GAAAb,EAAA,SAkBIc,QAAQC,MAARf,EAAAa,IACAG,MAAMhB,EAAAa,GAAII,SAAW,mCACrBC,QAAQC,OApBZ,yBAAAnB,EAAAoB,SAAA,KAAA/C,KAAA,qDAwBA,WACE,OAAOgD,YAAPC,UA7D4BC","file":"chunk.900c5d3fab8b6ebdcbc6.js","sourcesContent":["import {\n LitElement,\n customElement,\n property,\n TemplateResult,\n html,\n PropertyValues,\n CSSResult,\n css,\n} from \"lit-element\";\nimport { HomeAssistant, Route } from \"../../../src/types\";\nimport { createHassioSession } from \"../../../src/data/hassio/supervisor\";\nimport {\n HassioAddonDetails,\n fetchHassioAddonInfo,\n} from \"../../../src/data/hassio/addon\";\nimport \"../../../src/layouts/hass-loading-screen\";\nimport \"../../../src/layouts/hass-subpage\";\n\n@customElement(\"hassio-ingress-view\")\nclass HassioIngressView extends LitElement {\n @property() public hass!: HomeAssistant;\n @property() public route!: Route;\n @property() private _addon?: HassioAddonDetails;\n\n protected render(): TemplateResult {\n if (!this._addon) {\n return html`\n <hass-loading-screen></hass-loading-screen>\n `;\n }\n\n return html`\n <hass-subpage .header=${this._addon.name} hassio>\n <iframe src=${this._addon.ingress_url}></iframe>\n </hass-subpage>\n `;\n }\n\n protected updated(changedProps: PropertyValues) {\n super.firstUpdated(changedProps);\n\n if (!changedProps.has(\"route\")) {\n return;\n }\n\n const addon = this.route.path.substr(1);\n\n const oldRoute = changedProps.get(\"route\") as this[\"route\"] | undefined;\n const oldAddon = oldRoute ? oldRoute.path.substr(1) : undefined;\n\n if (addon && addon !== oldAddon) {\n this._fetchData(addon);\n }\n }\n\n private async _fetchData(addonSlug: string) {\n try {\n const [addon] = await Promise.all([\n fetchHassioAddonInfo(this.hass, addonSlug).catch(() => {\n throw new Error(\"Failed to fetch add-on info\");\n }),\n createHassioSession(this.hass).catch(() => {\n throw new Error(\"Failed to create an ingress session\");\n }),\n ]);\n\n if (!addon.ingress) {\n throw new Error(\"This add-on does not support ingress\");\n }\n\n this._addon = addon;\n } catch (err) {\n // tslint:disable-next-line\n console.error(err);\n alert(err.message || \"Unknown error starting ingress.\");\n history.back();\n }\n }\n\n static get styles(): CSSResult {\n return css`\n iframe {\n display: block;\n width: 100%;\n height: 100%;\n border: 0;\n }\n paper-icon-button {\n color: var(--text-primary-color);\n }\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"hassio-ingress-view\": HassioIngressView;\n }\n}\n"],"sourceRoot":""}
|
3
hassio/api/panel/chunk.9cea224f33b375867edd.js
Normal file
3
hassio/api/panel/chunk.9cea224f33b375867edd.js
Normal file
File diff suppressed because one or more lines are too long
BIN
hassio/api/panel/chunk.9cea224f33b375867edd.js.gz
Normal file
BIN
hassio/api/panel/chunk.9cea224f33b375867edd.js.gz
Normal file
Binary file not shown.
1
hassio/api/panel/chunk.9cea224f33b375867edd.js.map
Normal file
1
hassio/api/panel/chunk.9cea224f33b375867edd.js.map
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
2
hassio/api/panel/chunk.a1b6b616fc89c412f5b6.js
Normal file
2
hassio/api/panel/chunk.a1b6b616fc89c412f5b6.js
Normal file
File diff suppressed because one or more lines are too long
BIN
hassio/api/panel/chunk.a1b6b616fc89c412f5b6.js.gz
Normal file
BIN
hassio/api/panel/chunk.a1b6b616fc89c412f5b6.js.gz
Normal file
Binary file not shown.
1
hassio/api/panel/chunk.a1b6b616fc89c412f5b6.js.map
Normal file
1
hassio/api/panel/chunk.a1b6b616fc89c412f5b6.js.map
Normal file
File diff suppressed because one or more lines are too long
2
hassio/api/panel/chunk.a4f9950b101883805252.js
Normal file
2
hassio/api/panel/chunk.a4f9950b101883805252.js
Normal file
File diff suppressed because one or more lines are too long
BIN
hassio/api/panel/chunk.a4f9950b101883805252.js.gz
Normal file
BIN
hassio/api/panel/chunk.a4f9950b101883805252.js.gz
Normal file
Binary file not shown.
1
hassio/api/panel/chunk.a4f9950b101883805252.js.map
Normal file
1
hassio/api/panel/chunk.a4f9950b101883805252.js.map
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
2
hassio/api/panel/chunk.b21a4609308c9b8ef180.js
Normal file
2
hassio/api/panel/chunk.b21a4609308c9b8ef180.js
Normal file
File diff suppressed because one or more lines are too long
BIN
hassio/api/panel/chunk.b21a4609308c9b8ef180.js.gz
Normal file
BIN
hassio/api/panel/chunk.b21a4609308c9b8ef180.js.gz
Normal file
Binary file not shown.
1
hassio/api/panel/chunk.b21a4609308c9b8ef180.js.map
Normal file
1
hassio/api/panel/chunk.b21a4609308c9b8ef180.js.map
Normal file
File diff suppressed because one or more lines are too long
3
hassio/api/panel/chunk.c0a46a38d689ab648885.js
Normal file
3
hassio/api/panel/chunk.c0a46a38d689ab648885.js
Normal file
File diff suppressed because one or more lines are too long
BIN
hassio/api/panel/chunk.c0a46a38d689ab648885.js.gz
Normal file
BIN
hassio/api/panel/chunk.c0a46a38d689ab648885.js.gz
Normal file
Binary file not shown.
1
hassio/api/panel/chunk.c0a46a38d689ab648885.js.map
Normal file
1
hassio/api/panel/chunk.c0a46a38d689ab648885.js.map
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
2
hassio/api/panel/entrypoint.582baa2f.js
Normal file
2
hassio/api/panel/entrypoint.582baa2f.js
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
!function(e){function n(n){for(var t,o,a=n[0],i=n[1],c=0,f=[];c<a.length;c++)o=a[c],Object.prototype.hasOwnProperty.call(r,o)&&r[o]&&f.push(r[o][0]),r[o]=0;for(t in i)Object.prototype.hasOwnProperty.call(i,t)&&(e[t]=i[t]);for(u&&u(n);f.length;)f.shift()()}var t={},r={3:0};function o(n){if(t[n])return t[n].exports;var r=t[n]={i:n,l:!1,exports:{}};return e[n].call(r.exports,r,r.exports,o),r.l=!0,r.exports}o.e=function(e){var n=[],t=r[e];if(0!==t)if(t)n.push(t[2]);else{var a=new Promise(function(n,o){t=r[e]=[n,o]});n.push(t[2]=a);var i,c=document.createElement("script");c.charset="utf-8",c.timeout=120,o.nc&&c.setAttribute("nonce",o.nc),c.src=function(e){return o.p+"chunk."+{0:"50202a3f8d4670c9454d",1:"9cea224f33b375867edd",2:"c0a46a38d689ab648885",4:"b21a4609308c9b8ef180",5:"a1b6b616fc89c412f5b6",6:"900c5d3fab8b6ebdcbc6",7:"a4f9950b101883805252",8:"884d6e32c83f99e41040",9:"84aaaba4c4734f1c2e21",10:"12902324b918e12549ba"}[e]+".js"}(e);var u=new Error;i=function(n){c.onerror=c.onload=null,clearTimeout(f);var t=r[e];if(0!==t){if(t){var o=n&&("load"===n.type?"missing":n.type),a=n&&n.target&&n.target.src;u.message="Loading chunk "+e+" failed.\n("+o+": "+a+")",u.name="ChunkLoadError",u.type=o,u.request=a,t[1](u)}r[e]=void 0}};var f=setTimeout(function(){i({type:"timeout",target:c})},12e4);c.onerror=c.onload=i,document.head.appendChild(c)}return Promise.all(n)},o.m=e,o.c=t,o.d=function(e,n,t){o.o(e,n)||Object.defineProperty(e,n,{enumerable:!0,get:t})},o.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},o.t=function(e,n){if(1&n&&(e=o(e)),8&n)return e;if(4&n&&"object"==typeof e&&e&&e.__esModule)return e;var t=Object.create(null);if(o.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:e}),2&n&&"string"!=typeof e)for(var r in e)o.d(t,r,function(n){return e[n]}.bind(null,r));return t},o.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return o.d(n,"a",n),n},o.o=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},o.p="/api/hassio/app/",o.oe=function(e){throw console.error(e),e};var a=self.webpackJsonp=self.webpackJsonp||[],i=a.push.bind(a);a.push=n,a=a.slice();for(var c=0;c<a.length;c++)n(a[c]);var u=i;o(o.s=0)}([function(e,n,t){window.loadES5Adapter().then(function(){Promise.all([t.e(0),t.e(5)]).then(t.bind(null,2)),Promise.all([t.e(0),t.e(10),t.e(7)]).then(t.bind(null,1))});var r=document.createElement("style");r.innerHTML="\nbody {\n font-family: Roboto, sans-serif;\n -moz-osx-font-smoothing: grayscale;\n -webkit-font-smoothing: antialiased;\n font-weight: 400;\n margin: 0;\n padding: 0;\n height: 100vh;\n}\n",document.head.appendChild(r)}]);
|
||||||
|
//# sourceMappingURL=entrypoint.582baa2f.js.map
|
BIN
hassio/api/panel/entrypoint.582baa2f.js.gz
Normal file
BIN
hassio/api/panel/entrypoint.582baa2f.js.gz
Normal file
Binary file not shown.
1
hassio/api/panel/entrypoint.582baa2f.js.map
Normal file
1
hassio/api/panel/entrypoint.582baa2f.js.map
Normal file
File diff suppressed because one or more lines are too long
@ -1,2 +1,2 @@
|
|||||||
!function(e){function n(n){for(var t,o,a=n[0],i=n[1],f=0,c=[];f<a.length;f++)o=a[f],r[o]&&c.push(r[o][0]),r[o]=0;for(t in i)Object.prototype.hasOwnProperty.call(i,t)&&(e[t]=i[t]);for(u&&u(n);c.length;)c.shift()()}var t={},r={4:0};function o(n){if(t[n])return t[n].exports;var r=t[n]={i:n,l:!1,exports:{}};return e[n].call(r.exports,r,r.exports,o),r.l=!0,r.exports}o.e=function(e){var n=[],t=r[e];if(0!==t)if(t)n.push(t[2]);else{var a=new Promise(function(n,o){t=r[e]=[n,o]});n.push(t[2]=a);var i,f=document.createElement("script");f.charset="utf-8",f.timeout=120,o.nc&&f.setAttribute("nonce",o.nc),f.src=function(e){return o.p+"chunk."+{0:"7f411ffa9df152cb8f05",1:"598ae99dfd641ab3a30c",2:"af7784dbf07df8e24819",3:"b15efbd4fb2c8cac0ad4",5:"87d3a6d0178fb26762cf",6:"6f4702eafe52425373ed",7:"5dd33a3a20657ed46a19",8:"7c785f796f428abae18d",9:"7f8cce5798f837214ef8",10:"04bcaa18b59728e10be9",11:"9d7374dae6137783dda4",12:"6685a7f98b13655ab808",13:"f1156b978f6f3143a651"}[e]+".js"}(e),i=function(n){f.onerror=f.onload=null,clearTimeout(u);var t=r[e];if(0!==t){if(t){var o=n&&("load"===n.type?"missing":n.type),a=n&&n.target&&n.target.src,i=new Error("Loading chunk "+e+" failed.\n("+o+": "+a+")");i.type=o,i.request=a,t[1](i)}r[e]=void 0}};var u=setTimeout(function(){i({type:"timeout",target:f})},12e4);f.onerror=f.onload=i,document.head.appendChild(f)}return Promise.all(n)},o.m=e,o.c=t,o.d=function(e,n,t){o.o(e,n)||Object.defineProperty(e,n,{enumerable:!0,get:t})},o.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},o.t=function(e,n){if(1&n&&(e=o(e)),8&n)return e;if(4&n&&"object"==typeof e&&e&&e.__esModule)return e;var t=Object.create(null);if(o.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:e}),2&n&&"string"!=typeof e)for(var r in e)o.d(t,r,function(n){return e[n]}.bind(null,r));return t},o.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return o.d(n,"a",n),n},o.o=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},o.p="/api/hassio/app/",o.oe=function(e){throw console.error(e),e};var a=window.webpackJsonp=window.webpackJsonp||[],i=a.push.bind(a);a.push=n,a=a.slice();for(var f=0;f<a.length;f++)n(a[f]);var u=i;o(o.s=0)}([function(e,n,t){window.loadES5Adapter().then(function(){Promise.all([t.e(1),t.e(6)]).then(t.bind(null,2)),Promise.all([t.e(1),t.e(12),t.e(8)]).then(t.bind(null,1))});var r=document.createElement("style");r.innerHTML="\nbody {\n font-family: Roboto, sans-serif;\n -moz-osx-font-smoothing: grayscale;\n -webkit-font-smoothing: antialiased;\n font-weight: 400;\n margin: 0;\n padding: 0;\n height: 100vh;\n}\n",document.head.appendChild(r)}]);
|
!function(e){function n(n){for(var t,o,a=n[0],i=n[1],c=0,f=[];c<a.length;c++)o=a[c],Object.prototype.hasOwnProperty.call(r,o)&&r[o]&&f.push(r[o][0]),r[o]=0;for(t in i)Object.prototype.hasOwnProperty.call(i,t)&&(e[t]=i[t]);for(u&&u(n);f.length;)f.shift()()}var t={},r={3:0};function o(n){if(t[n])return t[n].exports;var r=t[n]={i:n,l:!1,exports:{}};return e[n].call(r.exports,r,r.exports,o),r.l=!0,r.exports}o.e=function(e){var n=[],t=r[e];if(0!==t)if(t)n.push(t[2]);else{var a=new Promise(function(n,o){t=r[e]=[n,o]});n.push(t[2]=a);var i,c=document.createElement("script");c.charset="utf-8",c.timeout=120,o.nc&&c.setAttribute("nonce",o.nc),c.src=function(e){return o.p+"chunk."+{0:"50202a3f8d4670c9454d",1:"9cea224f33b375867edd",2:"c0a46a38d689ab648885",4:"b21a4609308c9b8ef180",5:"a1b6b616fc89c412f5b6",6:"900c5d3fab8b6ebdcbc6",7:"a4f9950b101883805252",8:"884d6e32c83f99e41040",9:"84aaaba4c4734f1c2e21",10:"12902324b918e12549ba"}[e]+".js"}(e);var u=new Error;i=function(n){c.onerror=c.onload=null,clearTimeout(f);var t=r[e];if(0!==t){if(t){var o=n&&("load"===n.type?"missing":n.type),a=n&&n.target&&n.target.src;u.message="Loading chunk "+e+" failed.\n("+o+": "+a+")",u.name="ChunkLoadError",u.type=o,u.request=a,t[1](u)}r[e]=void 0}};var f=setTimeout(function(){i({type:"timeout",target:c})},12e4);c.onerror=c.onload=i,document.head.appendChild(c)}return Promise.all(n)},o.m=e,o.c=t,o.d=function(e,n,t){o.o(e,n)||Object.defineProperty(e,n,{enumerable:!0,get:t})},o.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},o.t=function(e,n){if(1&n&&(e=o(e)),8&n)return e;if(4&n&&"object"==typeof e&&e&&e.__esModule)return e;var t=Object.create(null);if(o.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:e}),2&n&&"string"!=typeof e)for(var r in e)o.d(t,r,function(n){return e[n]}.bind(null,r));return t},o.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return o.d(n,"a",n),n},o.o=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},o.p="/api/hassio/app/",o.oe=function(e){throw console.error(e),e};var a=self.webpackJsonp=self.webpackJsonp||[],i=a.push.bind(a);a.push=n,a=a.slice();for(var c=0;c<a.length;c++)n(a[c]);var u=i;o(o.s=0)}([function(e,n,t){window.loadES5Adapter().then(function(){Promise.all([t.e(0),t.e(5)]).then(t.bind(null,2)),Promise.all([t.e(0),t.e(10),t.e(7)]).then(t.bind(null,1))});var r=document.createElement("style");r.innerHTML="\nbody {\n font-family: Roboto, sans-serif;\n -moz-osx-font-smoothing: grayscale;\n -webkit-font-smoothing: antialiased;\n font-weight: 400;\n margin: 0;\n padding: 0;\n height: 100vh;\n}\n",document.head.appendChild(r)}]);
|
||||||
//# sourceMappingURL=entrypoint.js.map
|
//# sourceMappingURL=entrypoint.js.map
|
Binary file not shown.
File diff suppressed because one or more lines are too long
31
hassio/api/panel/manifest.json
Normal file
31
hassio/api/panel/manifest.json
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
{
|
||||||
|
"vendors~hassio-icons~hassio-main.js": "/api/hassio/app/chunk.50202a3f8d4670c9454d.js",
|
||||||
|
"vendors~hassio-icons~hassio-main.js.map": "/api/hassio/app/chunk.50202a3f8d4670c9454d.js.map",
|
||||||
|
"dialog-hassio-markdown.js": "/api/hassio/app/chunk.9cea224f33b375867edd.js",
|
||||||
|
"dialog-hassio-markdown.js.map": "/api/hassio/app/chunk.9cea224f33b375867edd.js.map",
|
||||||
|
"dialog-hassio-snapshot.js": "/api/hassio/app/chunk.c0a46a38d689ab648885.js",
|
||||||
|
"dialog-hassio-snapshot.js.map": "/api/hassio/app/chunk.c0a46a38d689ab648885.js.map",
|
||||||
|
"entrypoint.js": "/api/hassio/app/entrypoint.js",
|
||||||
|
"entrypoint.js.map": "/api/hassio/app/entrypoint.js.map",
|
||||||
|
"hassio-addon-view.js": "/api/hassio/app/chunk.b21a4609308c9b8ef180.js",
|
||||||
|
"hassio-addon-view.js.map": "/api/hassio/app/chunk.b21a4609308c9b8ef180.js.map",
|
||||||
|
"hassio-icons.js": "/api/hassio/app/chunk.a1b6b616fc89c412f5b6.js",
|
||||||
|
"hassio-icons.js.map": "/api/hassio/app/chunk.a1b6b616fc89c412f5b6.js.map",
|
||||||
|
"hassio-ingress-view.js": "/api/hassio/app/chunk.900c5d3fab8b6ebdcbc6.js",
|
||||||
|
"hassio-ingress-view.js.map": "/api/hassio/app/chunk.900c5d3fab8b6ebdcbc6.js.map",
|
||||||
|
"hassio-main.js": "/api/hassio/app/chunk.a4f9950b101883805252.js",
|
||||||
|
"hassio-main.js.map": "/api/hassio/app/chunk.a4f9950b101883805252.js.map",
|
||||||
|
"mdi-icons.js": "/api/hassio/app/chunk.884d6e32c83f99e41040.js",
|
||||||
|
"mdi-icons.js.map": "/api/hassio/app/chunk.884d6e32c83f99e41040.js.map",
|
||||||
|
"vendors~hassio-addon-view.js": "/api/hassio/app/chunk.84aaaba4c4734f1c2e21.js",
|
||||||
|
"vendors~hassio-addon-view.js.map": "/api/hassio/app/chunk.84aaaba4c4734f1c2e21.js.map",
|
||||||
|
"vendors~hassio-main.js": "/api/hassio/app/chunk.12902324b918e12549ba.js",
|
||||||
|
"vendors~hassio-main.js.map": "/api/hassio/app/chunk.12902324b918e12549ba.js.map",
|
||||||
|
"201359fd5a526afe13ef.worker.js": "/api/hassio/app/201359fd5a526afe13ef.worker.js",
|
||||||
|
"201359fd5a526afe13ef.worker.js.map": "/api/hassio/app/201359fd5a526afe13ef.worker.js.map",
|
||||||
|
"chunk.12902324b918e12549ba.js.LICENSE": "/api/hassio/app/chunk.12902324b918e12549ba.js.LICENSE",
|
||||||
|
"chunk.50202a3f8d4670c9454d.js.LICENSE": "/api/hassio/app/chunk.50202a3f8d4670c9454d.js.LICENSE",
|
||||||
|
"chunk.84aaaba4c4734f1c2e21.js.LICENSE": "/api/hassio/app/chunk.84aaaba4c4734f1c2e21.js.LICENSE",
|
||||||
|
"chunk.9cea224f33b375867edd.js.LICENSE": "/api/hassio/app/chunk.9cea224f33b375867edd.js.LICENSE",
|
||||||
|
"chunk.c0a46a38d689ab648885.js.LICENSE": "/api/hassio/app/chunk.c0a46a38d689ab648885.js.LICENSE"
|
||||||
|
}
|
@ -1,12 +1,13 @@
|
|||||||
"""Manage SSO for Add-ons with Home Assistant user."""
|
"""Manage SSO for Add-ons with Home Assistant user."""
|
||||||
import logging
|
|
||||||
import hashlib
|
import hashlib
|
||||||
|
import logging
|
||||||
|
|
||||||
from .const import FILE_HASSIO_AUTH, ATTR_PASSWORD, ATTR_USERNAME, ATTR_ADDON
|
from .addons.addon import Addon
|
||||||
from .coresys import CoreSysAttributes
|
from .const import ATTR_ADDON, ATTR_PASSWORD, ATTR_USERNAME, FILE_HASSIO_AUTH
|
||||||
|
from .coresys import CoreSys, CoreSysAttributes
|
||||||
|
from .exceptions import AuthError, AuthPasswordResetError, HomeAssistantAPIError
|
||||||
from .utils.json import JsonConfig
|
from .utils.json import JsonConfig
|
||||||
from .validate import SCHEMA_AUTH_CONFIG
|
from .validate import SCHEMA_AUTH_CONFIG
|
||||||
from .exceptions import AuthError, HomeAssistantAPIError
|
|
||||||
|
|
||||||
_LOGGER: logging.Logger = logging.getLogger(__name__)
|
_LOGGER: logging.Logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -14,15 +15,15 @@ _LOGGER: logging.Logger = logging.getLogger(__name__)
|
|||||||
class Auth(JsonConfig, CoreSysAttributes):
|
class Auth(JsonConfig, CoreSysAttributes):
|
||||||
"""Manage SSO for Add-ons with Home Assistant user."""
|
"""Manage SSO for Add-ons with Home Assistant user."""
|
||||||
|
|
||||||
def __init__(self, coresys):
|
def __init__(self, coresys: CoreSys) -> None:
|
||||||
"""Initialize updater."""
|
"""Initialize updater."""
|
||||||
super().__init__(FILE_HASSIO_AUTH, SCHEMA_AUTH_CONFIG)
|
super().__init__(FILE_HASSIO_AUTH, SCHEMA_AUTH_CONFIG)
|
||||||
self.coresys = coresys
|
self.coresys: CoreSys = coresys
|
||||||
|
|
||||||
def _check_cache(self, username, password):
|
def _check_cache(self, username: str, password: str) -> bool:
|
||||||
"""Check password in cache."""
|
"""Check password in cache."""
|
||||||
username_h = _rehash(username)
|
username_h = self._rehash(username)
|
||||||
password_h = _rehash(password, username)
|
password_h = self._rehash(password, username)
|
||||||
|
|
||||||
if self._data.get(username_h) == password_h:
|
if self._data.get(username_h) == password_h:
|
||||||
_LOGGER.info("Cache hit for %s", username)
|
_LOGGER.info("Cache hit for %s", username)
|
||||||
@ -31,10 +32,10 @@ class Auth(JsonConfig, CoreSysAttributes):
|
|||||||
_LOGGER.warning("No cache hit for %s", username)
|
_LOGGER.warning("No cache hit for %s", username)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def _update_cache(self, username, password):
|
def _update_cache(self, username: str, password: str) -> None:
|
||||||
"""Cache a username, password."""
|
"""Cache a username, password."""
|
||||||
username_h = _rehash(username)
|
username_h = self._rehash(username)
|
||||||
password_h = _rehash(password, username)
|
password_h = self._rehash(password, username)
|
||||||
|
|
||||||
if self._data.get(username_h) == password_h:
|
if self._data.get(username_h) == password_h:
|
||||||
return
|
return
|
||||||
@ -42,10 +43,10 @@ class Auth(JsonConfig, CoreSysAttributes):
|
|||||||
self._data[username_h] = password_h
|
self._data[username_h] = password_h
|
||||||
self.save_data()
|
self.save_data()
|
||||||
|
|
||||||
def _dismatch_cache(self, username, password):
|
def _dismatch_cache(self, username: str, password: str) -> None:
|
||||||
"""Remove user from cache."""
|
"""Remove user from cache."""
|
||||||
username_h = _rehash(username)
|
username_h = self._rehash(username)
|
||||||
password_h = _rehash(password, username)
|
password_h = self._rehash(password, username)
|
||||||
|
|
||||||
if self._data.get(username_h) != password_h:
|
if self._data.get(username_h) != password_h:
|
||||||
return
|
return
|
||||||
@ -53,7 +54,7 @@ class Auth(JsonConfig, CoreSysAttributes):
|
|||||||
self._data.pop(username_h, None)
|
self._data.pop(username_h, None)
|
||||||
self.save_data()
|
self.save_data()
|
||||||
|
|
||||||
async def check_login(self, addon, username, password):
|
async def check_login(self, addon: Addon, username: str, password: str) -> bool:
|
||||||
"""Check username login."""
|
"""Check username login."""
|
||||||
if password is None:
|
if password is None:
|
||||||
_LOGGER.error("None as password is not supported!")
|
_LOGGER.error("None as password is not supported!")
|
||||||
@ -89,9 +90,27 @@ class Auth(JsonConfig, CoreSysAttributes):
|
|||||||
|
|
||||||
raise AuthError()
|
raise AuthError()
|
||||||
|
|
||||||
|
async def change_password(self, username: str, password: str) -> None:
|
||||||
|
"""Change user password login."""
|
||||||
|
try:
|
||||||
|
async with self.sys_homeassistant.make_request(
|
||||||
|
"post",
|
||||||
|
"api/hassio_auth/password_reset",
|
||||||
|
json={ATTR_USERNAME: username, ATTR_PASSWORD: password},
|
||||||
|
) as req:
|
||||||
|
if req.status == 200:
|
||||||
|
_LOGGER.info("Success password reset %s", username)
|
||||||
|
return
|
||||||
|
|
||||||
def _rehash(value, salt2=""):
|
_LOGGER.warning("Unknown user %s for password reset", username)
|
||||||
"""Rehash a value."""
|
except HomeAssistantAPIError:
|
||||||
for idx in range(1, 20):
|
_LOGGER.error("Can't request password reset on Home Assistant!")
|
||||||
value = hashlib.sha256(f"{value}{idx}{salt2}".encode()).hexdigest()
|
|
||||||
return value
|
raise AuthPasswordResetError()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _rehash(value: str, salt2: str = "") -> str:
|
||||||
|
"""Rehash a value."""
|
||||||
|
for idx in range(1, 20):
|
||||||
|
value = hashlib.sha256(f"{value}{idx}{salt2}".encode()).hexdigest()
|
||||||
|
return value
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from ipaddress import ip_network
|
from ipaddress import ip_network
|
||||||
|
|
||||||
HASSIO_VERSION = "195"
|
HASSIO_VERSION = "196"
|
||||||
|
|
||||||
|
|
||||||
URL_HASSIO_ADDONS = "https://github.com/home-assistant/hassio-addons"
|
URL_HASSIO_ADDONS = "https://github.com/home-assistant/hassio-addons"
|
||||||
@ -222,6 +222,8 @@ ATTR_LOCALS = "locals"
|
|||||||
ATTR_UDEV = "udev"
|
ATTR_UDEV = "udev"
|
||||||
ATTR_VALUE = "value"
|
ATTR_VALUE = "value"
|
||||||
ATTR_SNAPSHOT_EXCLUDE = "snapshot_exclude"
|
ATTR_SNAPSHOT_EXCLUDE = "snapshot_exclude"
|
||||||
|
ATTR_DOCUMENTATION = "documentation"
|
||||||
|
ATTR_ADVANCED = "advanced"
|
||||||
|
|
||||||
PROVIDE_SERVICE = "provide"
|
PROVIDE_SERVICE = "provide"
|
||||||
NEED_SERVICE = "need"
|
NEED_SERVICE = "need"
|
||||||
|
11
hassio/discovery/services/unifi.py
Normal file
11
hassio/discovery/services/unifi.py
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
"""Discovery service for UniFi."""
|
||||||
|
import voluptuous as vol
|
||||||
|
|
||||||
|
from hassio.validate import network_port
|
||||||
|
|
||||||
|
from ..const import ATTR_HOST, ATTR_PORT
|
||||||
|
|
||||||
|
|
||||||
|
SCHEMA = vol.Schema(
|
||||||
|
{vol.Required(ATTR_HOST): vol.Coerce(str), vol.Required(ATTR_PORT): network_port}
|
||||||
|
)
|
@ -97,6 +97,10 @@ class AuthError(HassioError):
|
|||||||
"""Auth errors."""
|
"""Auth errors."""
|
||||||
|
|
||||||
|
|
||||||
|
class AuthPasswordResetError(HassioError):
|
||||||
|
"""Auth error if password reset fails."""
|
||||||
|
|
||||||
|
|
||||||
# Host
|
# Host
|
||||||
|
|
||||||
|
|
||||||
|
@ -2,12 +2,13 @@
|
|||||||
from typing import Dict, List
|
from typing import Dict, List
|
||||||
|
|
||||||
from ..coresys import CoreSys, CoreSysAttributes
|
from ..coresys import CoreSys, CoreSysAttributes
|
||||||
from .const import SERVICE_MQTT
|
from .const import SERVICE_MQTT, SERVICE_MYSQL
|
||||||
from .data import ServicesData
|
from .data import ServicesData
|
||||||
from .interface import ServiceInterface
|
from .interface import ServiceInterface
|
||||||
from .modules.mqtt import MQTTService
|
from .modules.mqtt import MQTTService
|
||||||
|
from .modules.mysql import MySQLService
|
||||||
|
|
||||||
AVAILABLE_SERVICES = {SERVICE_MQTT: MQTTService}
|
AVAILABLE_SERVICES = {SERVICE_MQTT: MQTTService, SERVICE_MYSQL: MySQLService}
|
||||||
|
|
||||||
|
|
||||||
class ServiceManager(CoreSysAttributes):
|
class ServiceManager(CoreSysAttributes):
|
||||||
|
@ -9,3 +9,4 @@ ATTR_SSL = "ssl"
|
|||||||
ATTR_USERNAME = "username"
|
ATTR_USERNAME = "username"
|
||||||
|
|
||||||
SERVICE_MQTT = "mqtt"
|
SERVICE_MQTT = "mqtt"
|
||||||
|
SERVICE_MYSQL = "mysql"
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user