diff --git a/supervisor/api/security.py b/supervisor/api/security.py index d42fb9433..46a252a19 100644 --- a/supervisor/api/security.py +++ b/supervisor/api/security.py @@ -39,6 +39,13 @@ NO_SECURITY_CHECK = re.compile( r")$" ) +# Observer allow API calls +OBSERVER_CHECK = re.compile( + r"^(?:" + r"|/[^/]+/info" + r")$" +) + # Can called by every add-on ADDONS_API_BYPASS = re.compile( r"^(?:" @@ -95,7 +102,7 @@ ADDONS_ROLE_ACCESS = { ), } -# fmt: off +# fmt: on class SecurityMiddleware(CoreSysAttributes): @@ -136,6 +143,14 @@ class SecurityMiddleware(CoreSysAttributes): _LOGGER.debug("%s access from Host", request.path) request_from = self.sys_host + # Observer + if supervisor_token == self.sys_plugins.observer.supervisor_token: + if not OBSERVER_CHECK.match(request.url): + _LOGGER.warning("%s invalid Observer access", request.path) + raise HTTPForbidden() + _LOGGER.debug("%s access from Observer", request.path) + request_from = self.sys_plugins.observer + # Add-on addon = None if supervisor_token and not request_from: diff --git a/supervisor/const.py b/supervisor/const.py index 40a774726..7fde71dff 100644 --- a/supervisor/const.py +++ b/supervisor/const.py @@ -70,8 +70,7 @@ HEADER_TOKEN_OLD = "X-Hassio-Key" ENV_TIME = "TZ" ENV_TOKEN = "SUPERVISOR_TOKEN" -ENV_TOKEN_OLD = "HASSIO_TOKEN" -ENV_OBSERVER = "OBSERVER_TOKEN" +ENV_TOKEN_HASSIO = "HASSIO_TOKEN" ENV_HOMEASSISTANT_REPOSITORY = "HOMEASSISTANT_REPOSITORY" ENV_SUPERVISOR_DEV = "SUPERVISOR_DEV" diff --git a/supervisor/docker/addon.py b/supervisor/docker/addon.py index e6d7387d2..860695a15 100644 --- a/supervisor/docker/addon.py +++ b/supervisor/docker/addon.py @@ -15,7 +15,7 @@ from ..addons.build import AddonBuild from ..const import ( ENV_TIME, ENV_TOKEN, - ENV_TOKEN_OLD, + ENV_TOKEN_HASSIO, MAP_ADDONS, MAP_BACKUP, MAP_CONFIG, @@ -119,7 +119,7 @@ class DockerAddon(DockerInterface): **addon_env, ENV_TIME: self.sys_config.timezone, ENV_TOKEN: self.addon.supervisor_token, - ENV_TOKEN_OLD: self.addon.supervisor_token, + ENV_TOKEN_HASSIO: self.addon.supervisor_token, } @property diff --git a/supervisor/docker/cli.py b/supervisor/docker/cli.py index aec7f755d..808bd9793 100644 --- a/supervisor/docker/cli.py +++ b/supervisor/docker/cli.py @@ -1,7 +1,7 @@ """HA Cli docker object.""" import logging -from ..const import ENV_OBSERVER, ENV_TIME, ENV_TOKEN +from ..const import ENV_TIME, ENV_TOKEN from ..coresys import CoreSysAttributes from .interface import DockerInterface @@ -52,7 +52,6 @@ class DockerCli(DockerInterface, CoreSysAttributes): environment={ ENV_TIME: self.sys_config.timezone, ENV_TOKEN: self.sys_plugins.cli.supervisor_token, - ENV_OBSERVER: self.sys_plugins.observer.access_token, }, ) diff --git a/supervisor/docker/homeassistant.py b/supervisor/docker/homeassistant.py index 45fc493a0..8fbc4f08c 100644 --- a/supervisor/docker/homeassistant.py +++ b/supervisor/docker/homeassistant.py @@ -6,14 +6,7 @@ from typing import Awaitable, Dict, Optional import docker import requests -from ..const import ( - ENV_OBSERVER, - ENV_TIME, - ENV_TOKEN, - ENV_TOKEN_OLD, - LABEL_MACHINE, - MACHINE_ID, -) +from ..const import ENV_TIME, ENV_TOKEN, ENV_TOKEN_HASSIO, LABEL_MACHINE, MACHINE_ID from ..exceptions import DockerAPIError from .interface import CommandReturn, DockerInterface @@ -131,8 +124,7 @@ class DockerHomeAssistant(DockerInterface): "SUPERVISOR": self.sys_docker.network.supervisor, ENV_TIME: self.sys_config.timezone, ENV_TOKEN: self.sys_homeassistant.supervisor_token, - ENV_TOKEN_OLD: self.sys_homeassistant.supervisor_token, - ENV_OBSERVER: self.sys_plugins.observer.access_token, + ENV_TOKEN_HASSIO: self.sys_homeassistant.supervisor_token, }, ) diff --git a/supervisor/docker/observer.py b/supervisor/docker/observer.py index d15205a32..0d5ac9380 100644 --- a/supervisor/docker/observer.py +++ b/supervisor/docker/observer.py @@ -1,7 +1,7 @@ """Observer docker object.""" import logging -from ..const import ENV_OBSERVER, ENV_TIME +from ..const import ENV_TIME, ENV_TOKEN from ..coresys import CoreSysAttributes from .interface import DockerInterface @@ -47,7 +47,7 @@ class DockerObserver(DockerInterface, CoreSysAttributes): extra_hosts={"supervisor": self.sys_docker.network.supervisor}, environment={ ENV_TIME: self.sys_config.timezone, - ENV_OBSERVER: self.sys_plugins.observer.access_token, + ENV_TOKEN: self.sys_plugins.observer.supervisor_token, }, volumes={"/run/docker.sock": {"bind": "/run/docker.sock", "mode": "ro"}}, ports={"80/tcp": 4357}, diff --git a/supervisor/plugins/__init__.py b/supervisor/plugins/__init__.py index cbf366bd4..d2b43bd5b 100644 --- a/supervisor/plugins/__init__.py +++ b/supervisor/plugins/__init__.py @@ -21,7 +21,7 @@ class PluginManager(CoreSysAttributes): required_cli: LegacyVersion = pkg_parse("26") required_dns: LegacyVersion = pkg_parse("9") required_audio: LegacyVersion = pkg_parse("17") - required_observer: LegacyVersion = pkg_parse("1") + required_observer: LegacyVersion = pkg_parse("2") required_multicast: LegacyVersion = pkg_parse("3") def __init__(self, coresys: CoreSys): diff --git a/supervisor/plugins/observer.py b/supervisor/plugins/observer.py index 2b12cb803..bea5ad357 100644 --- a/supervisor/plugins/observer.py +++ b/supervisor/plugins/observer.py @@ -62,7 +62,7 @@ class Observer(CoreSysAttributes, JsonConfig): return self.version != self.latest_version @property - def access_token(self) -> str: + def supervisor_token(self) -> str: """Return an access token for the Observer API.""" return self._data.get(ATTR_ACCESS_TOKEN) @@ -149,7 +149,7 @@ class Observer(CoreSysAttributes, JsonConfig): async def start(self) -> None: """Run observer.""" # Create new API token - if not self.access_token: + if not self.supervisor_token: self._data[ATTR_ACCESS_TOKEN] = secrets.token_hex(56) self.save_data()