mirror of
https://github.com/home-assistant/supervisor.git
synced 2025-07-14 20:56:30 +00:00
Improve addon slug validation (#4188)
This commit is contained in:
parent
2a625defc0
commit
8fc036874a
@ -26,3 +26,5 @@ ADDON_UPDATE_CONDITIONS = [
|
|||||||
JobCondition.PLUGINS_UPDATED,
|
JobCondition.PLUGINS_UPDATED,
|
||||||
JobCondition.SUPERVISOR_UPDATED,
|
JobCondition.SUPERVISOR_UPDATED,
|
||||||
]
|
]
|
||||||
|
|
||||||
|
RE_SLUG = r"[-_.A-Za-z0-9]+"
|
||||||
|
@ -109,7 +109,7 @@ from ..validate import (
|
|||||||
uuid_match,
|
uuid_match,
|
||||||
version_tag,
|
version_tag,
|
||||||
)
|
)
|
||||||
from .const import ATTR_BACKUP, ATTR_CODENOTARY, AddonBackupMode
|
from .const import ATTR_BACKUP, ATTR_CODENOTARY, RE_SLUG, AddonBackupMode
|
||||||
from .options import RE_SCHEMA_ELEMENT
|
from .options import RE_SCHEMA_ELEMENT
|
||||||
|
|
||||||
_LOGGER: logging.Logger = logging.getLogger(__name__)
|
_LOGGER: logging.Logger = logging.getLogger(__name__)
|
||||||
@ -147,6 +147,8 @@ RE_MACHINE = re.compile(
|
|||||||
r")$"
|
r")$"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
RE_SLUG_FIELD = re.compile(r"^" + RE_SLUG + r"$")
|
||||||
|
|
||||||
|
|
||||||
def _warn_addon_config(config: dict[str, Any]):
|
def _warn_addon_config(config: dict[str, Any]):
|
||||||
"""Warn about miss configs."""
|
"""Warn about miss configs."""
|
||||||
@ -252,7 +254,7 @@ _SCHEMA_ADDON_CONFIG = vol.Schema(
|
|||||||
{
|
{
|
||||||
vol.Required(ATTR_NAME): str,
|
vol.Required(ATTR_NAME): str,
|
||||||
vol.Required(ATTR_VERSION): version_tag,
|
vol.Required(ATTR_VERSION): version_tag,
|
||||||
vol.Required(ATTR_SLUG): str,
|
vol.Required(ATTR_SLUG): vol.Match(RE_SLUG_FIELD),
|
||||||
vol.Required(ATTR_DESCRIPTON): str,
|
vol.Required(ATTR_DESCRIPTON): str,
|
||||||
vol.Required(ATTR_ARCH): [vol.In(ARCH_ALL)],
|
vol.Required(ATTR_ARCH): [vol.In(ARCH_ALL)],
|
||||||
vol.Optional(ATTR_MACHINE): vol.All([vol.Match(RE_MACHINE)], vol.Unique()),
|
vol.Optional(ATTR_MACHINE): vol.All([vol.Match(RE_MACHINE)], vol.Unique()),
|
||||||
|
@ -8,6 +8,7 @@ from aiohttp.web import Request, RequestHandler, Response, middleware
|
|||||||
from aiohttp.web_exceptions import HTTPBadRequest, HTTPForbidden, HTTPUnauthorized
|
from aiohttp.web_exceptions import HTTPBadRequest, HTTPForbidden, HTTPUnauthorized
|
||||||
from awesomeversion import AwesomeVersion
|
from awesomeversion import AwesomeVersion
|
||||||
|
|
||||||
|
from ...addons.const import RE_SLUG
|
||||||
from ...const import (
|
from ...const import (
|
||||||
REQUEST_FROM,
|
REQUEST_FROM,
|
||||||
ROLE_ADMIN,
|
ROLE_ADMIN,
|
||||||
@ -27,7 +28,7 @@ _CORE_VERSION: Final = AwesomeVersion("2023.3.0")
|
|||||||
|
|
||||||
_CORE_FRONTEND_PATHS: Final = (
|
_CORE_FRONTEND_PATHS: Final = (
|
||||||
r"|/app/.*\.(?:js|gz|json|map)"
|
r"|/app/.*\.(?:js|gz|json|map)"
|
||||||
r"|/(store/)?addons/[^/]+/(logo|icon)"
|
r"|/(store/)?addons/" + RE_SLUG + r"/(logo|icon)"
|
||||||
)
|
)
|
||||||
|
|
||||||
CORE_FRONTEND: Final = re.compile(
|
CORE_FRONTEND: Final = re.compile(
|
||||||
@ -51,7 +52,7 @@ NO_SECURITY_CHECK: Final = re.compile(
|
|||||||
r"|/core/api/.*"
|
r"|/core/api/.*"
|
||||||
r"|/core/websocket"
|
r"|/core/websocket"
|
||||||
r"|/supervisor/ping"
|
r"|/supervisor/ping"
|
||||||
r"|/ingress/[^/]+/.*"
|
r"|/ingress/[-_A-Za-z0-9]+/.*"
|
||||||
+ _CORE_FRONTEND_PATHS
|
+ _CORE_FRONTEND_PATHS
|
||||||
+ r")$"
|
+ r")$"
|
||||||
)
|
)
|
||||||
@ -98,7 +99,7 @@ ADDONS_ROLE_ACCESS: dict[str, re.Pattern] = {
|
|||||||
ROLE_MANAGER: re.compile(
|
ROLE_MANAGER: re.compile(
|
||||||
r"^(?:"
|
r"^(?:"
|
||||||
r"|/.+/info"
|
r"|/.+/info"
|
||||||
r"|/addons(?:/[^/]+/(?!security).+|/reload)?"
|
r"|/addons(?:/" + RE_SLUG + r"/(?!security).+|/reload)?"
|
||||||
r"|/audio/.+"
|
r"|/audio/.+"
|
||||||
r"|/auth/cache"
|
r"|/auth/cache"
|
||||||
r"|/cli/.+"
|
r"|/cli/.+"
|
||||||
|
@ -249,3 +249,38 @@ def test_watchdog_url():
|
|||||||
):
|
):
|
||||||
config["watchdog"] = test_options
|
config["watchdog"] = test_options
|
||||||
assert vd.SCHEMA_ADDON_CONFIG(config)
|
assert vd.SCHEMA_ADDON_CONFIG(config)
|
||||||
|
|
||||||
|
|
||||||
|
def test_valid_slug():
|
||||||
|
"""Test valid and invalid addon slugs."""
|
||||||
|
config = load_json_fixture("basic-addon-config.json")
|
||||||
|
|
||||||
|
# All examples pulled from https://analytics.home-assistant.io/addons.json
|
||||||
|
config["slug"] = "uptime-kuma"
|
||||||
|
assert vd.SCHEMA_ADDON_CONFIG(config)
|
||||||
|
|
||||||
|
config["slug"] = "hassio_google_drive_backup"
|
||||||
|
assert vd.SCHEMA_ADDON_CONFIG(config)
|
||||||
|
|
||||||
|
config["slug"] = "paradox_alarm_interface_3.x"
|
||||||
|
assert vd.SCHEMA_ADDON_CONFIG(config)
|
||||||
|
|
||||||
|
config["slug"] = "Lupusec2Mqtt"
|
||||||
|
assert vd.SCHEMA_ADDON_CONFIG(config)
|
||||||
|
|
||||||
|
# No whitespace
|
||||||
|
config["slug"] = "my addon"
|
||||||
|
with pytest.raises(vol.Invalid):
|
||||||
|
assert vd.SCHEMA_ADDON_CONFIG(config)
|
||||||
|
|
||||||
|
# No url control chars (or other non-word ascii characters)
|
||||||
|
config["slug"] = "a/b_&_c\\d_@ddon$:_test=#2?"
|
||||||
|
with pytest.raises(vol.Invalid):
|
||||||
|
assert vd.SCHEMA_ADDON_CONFIG(config)
|
||||||
|
|
||||||
|
# No unicode
|
||||||
|
config["slug"] = "complemento telefónico"
|
||||||
|
with pytest.raises(vol.Invalid):
|
||||||
|
assert vd.SCHEMA_ADDON_CONFIG(config)
|
||||||
|
|
||||||
|
#
|
||||||
|
Loading…
x
Reference in New Issue
Block a user