custom_components/bahmcloud_store/views.py aktualisiert

This commit is contained in:
2026-01-15 10:39:15 +00:00
parent 6f0f588b03
commit 35839d9c65

View File

@@ -6,11 +6,10 @@ from pathlib import Path
from typing import Any, TYPE_CHECKING from typing import Any, TYPE_CHECKING
from aiohttp import web from aiohttp import web
from homeassistant.components.http import HomeAssistantView from homeassistant.components.http import HomeAssistantView
if TYPE_CHECKING: if TYPE_CHECKING:
from .core import BCSCore # type hints only, avoids circular import from .core import BCSCore # typing only
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@@ -18,55 +17,50 @@ _LOGGER = logging.getLogger(__name__)
class StaticAssetsView(HomeAssistantView): class StaticAssetsView(HomeAssistantView):
url = "/api/bahmcloud_store_static/{path:.*}" url = "/api/bahmcloud_store_static/{path:.*}"
name = "api:bahmcloud_store_static" name = "api:bahmcloud_store_static"
requires_auth = True # keep as before (you said auth works)
# IMPORTANT:
# Custom panel JS is safe to serve without auth. Some setups (reverse proxies / cookie quirks)
# may cause 401 for module loads. Disabling auth here avoids "Unable to load custom panel".
requires_auth = False
async def get(self, request: web.Request, path: str) -> web.Response: async def get(self, request: web.Request, path: str) -> web.Response:
base = Path(__file__).resolve().parent / "panel" base = Path(__file__).resolve().parent / "panel"
base_resolved = base.resolve() base_resolved = base.resolve()
req_path = (path or "").lstrip("/") req_path = (path or "").lstrip("/")
# Default file
if req_path == "": if req_path == "":
req_path = "index.html" req_path = "index.html"
target = (base / req_path).resolve() target = (base / req_path).resolve()
# Security: prevent path traversal # Prevent path traversal
if not str(target).startswith(str(base_resolved)): if not str(target).startswith(str(base_resolved)):
return web.Response(status=404) return web.Response(status=404)
# If folder -> index.html
if target.is_dir(): if target.is_dir():
target = (target / "index.html").resolve() target = (target / "index.html").resolve()
if not target.exists(): if not target.exists():
_LOGGER.warning("BCS static asset not found: %s", target)
return web.Response(status=404) return web.Response(status=404)
# Content types # Content types (NO charset here!)
ct = "text/plain; charset=utf-8" content_type = "text/plain"
charset = None
if target.suffix == ".js": if target.suffix == ".js":
ct = "application/javascript; charset=utf-8" content_type = "application/javascript"
charset = "utf-8"
elif target.suffix == ".html": elif target.suffix == ".html":
ct = "text/html; charset=utf-8" content_type = "text/html"
charset = "utf-8"
elif target.suffix == ".css": elif target.suffix == ".css":
ct = "text/css; charset=utf-8" content_type = "text/css"
charset = "utf-8"
elif target.suffix == ".svg": elif target.suffix == ".svg":
ct = "image/svg+xml" content_type = "image/svg+xml"
elif target.suffix == ".png": elif target.suffix == ".png":
ct = "image/png" content_type = "image/png"
resp = web.Response(body=target.read_bytes(), content_type=ct) resp = web.Response(body=target.read_bytes(), content_type=content_type, charset=charset)
# During development: avoid stale caching issues
# Avoid stale caching issues during development
resp.headers["Cache-Control"] = "no-store, no-cache, must-revalidate, max-age=0" resp.headers["Cache-Control"] = "no-store, no-cache, must-revalidate, max-age=0"
resp.headers["Pragma"] = "no-cache" resp.headers["Pragma"] = "no-cache"
return resp return resp
@@ -139,7 +133,6 @@ class BCSReadmeView(HomeAssistantView):
try: try:
from homeassistant.util.markdown import async_render_markdown # type: ignore from homeassistant.util.markdown import async_render_markdown # type: ignore
html = await async_render_markdown(self.core.hass, md) html = await async_render_markdown(self.core.hass, md)
except Exception as e: except Exception as e:
_LOGGER.debug("Markdown render failed: %s", e) _LOGGER.debug("Markdown render failed: %s", e)
@@ -148,7 +141,6 @@ class BCSReadmeView(HomeAssistantView):
if html: if html:
try: try:
from homeassistant.util.sanitize_html import async_sanitize_html # type: ignore from homeassistant.util.sanitize_html import async_sanitize_html # type: ignore
html = await async_sanitize_html(self.core.hass, html) html = await async_sanitize_html(self.core.hass, html)
except Exception as e: except Exception as e:
_LOGGER.debug("HTML sanitize not available/failed: %s", e) _LOGGER.debug("HTML sanitize not available/failed: %s", e)