custom_components/bahmcloud_store/store.py aktualisiert
This commit is contained in:
@@ -23,7 +23,7 @@ DOMAIN = "bahmcloud_store"
|
|||||||
|
|
||||||
|
|
||||||
class StoreError(Exception):
|
class StoreError(Exception):
|
||||||
pass
|
"""Store error."""
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
@@ -114,6 +114,7 @@ class BahmcloudStore:
|
|||||||
|
|
||||||
async def refresh(self) -> None:
|
async def refresh(self) -> None:
|
||||||
session = async_get_clientsession(self.hass)
|
session = async_get_clientsession(self.hass)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
async with session.get(self.config.store_url, timeout=20) as resp:
|
async with session.get(self.config.store_url, timeout=20) as resp:
|
||||||
if resp.status != 200:
|
if resp.status != 200:
|
||||||
@@ -146,7 +147,7 @@ class BahmcloudStore:
|
|||||||
pkg.zip_url = self._zip_url(pkg.repo, pkg.branch)
|
pkg.zip_url = self._zip_url(pkg.repo, pkg.branch)
|
||||||
parsed[pkg.id] = pkg
|
parsed[pkg.id] = pkg
|
||||||
|
|
||||||
# update latest versions (sequential, safe)
|
# compute latest versions
|
||||||
for pkg in parsed.values():
|
for pkg in parsed.values():
|
||||||
latest, rel_url = await self._fetch_latest_version(pkg)
|
latest, rel_url = await self._fetch_latest_version(pkg)
|
||||||
pkg.latest_version = latest or "unknown"
|
pkg.latest_version = latest or "unknown"
|
||||||
@@ -176,6 +177,7 @@ class BahmcloudStore:
|
|||||||
raise StoreError("zip_url not set")
|
raise StoreError("zip_url not set")
|
||||||
|
|
||||||
session = async_get_clientsession(self.hass)
|
session = async_get_clientsession(self.hass)
|
||||||
|
|
||||||
with tempfile.TemporaryDirectory() as td:
|
with tempfile.TemporaryDirectory() as td:
|
||||||
zip_path = Path(td) / "repo.zip"
|
zip_path = Path(td) / "repo.zip"
|
||||||
extract_dir = Path(td) / "extract"
|
extract_dir = Path(td) / "extract"
|
||||||
@@ -224,27 +226,46 @@ class BahmcloudStore:
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
async def register_http_views(self) -> None:
|
async def register_http_views(self) -> None:
|
||||||
|
"""Register HTTP views for static panel assets and JSON API."""
|
||||||
self.hass.http.register_view(_StaticView())
|
self.hass.http.register_view(_StaticView())
|
||||||
self.hass.http.register_view(_APIListView(self))
|
self.hass.http.register_view(_APIListView(self))
|
||||||
|
|
||||||
|
|
||||||
class _StaticView(HomeAssistantView):
|
class _StaticView(HomeAssistantView):
|
||||||
|
"""
|
||||||
|
Serves panel assets from: custom_components/bahmcloud_store/panel/
|
||||||
|
|
||||||
|
URLs:
|
||||||
|
/api/bahmcloud_store_static/index.html
|
||||||
|
/api/bahmcloud_store_static/panel.js
|
||||||
|
/api/bahmcloud_store_static/app.js
|
||||||
|
/api/bahmcloud_store_static/styles.css
|
||||||
|
"""
|
||||||
requires_auth = True
|
requires_auth = True
|
||||||
name = "bahmcloud_store_static"
|
name = "bahmcloud_store_static"
|
||||||
url = "/api/bahmcloud_store_static/{path:.*}"
|
url = "/api/bahmcloud_store_static/{path:.*}"
|
||||||
|
|
||||||
async def get(self, request, path):
|
async def get(self, request, path):
|
||||||
base = Path(__file__).resolve().parent / "panel"
|
base = Path(__file__).resolve().parent / "panel"
|
||||||
f = (base / path).resolve()
|
if not path:
|
||||||
if not str(f).startswith(str(base)) or not f.exists():
|
path = "index.html"
|
||||||
return web.Response(status=404)
|
|
||||||
|
|
||||||
if f.suffix == ".js":
|
f = (base / path).resolve()
|
||||||
|
|
||||||
|
# Prevent path traversal
|
||||||
|
if not str(f).startswith(str(base)) or not f.exists() or not f.is_file():
|
||||||
|
return web.Response(status=404, text="Not found")
|
||||||
|
|
||||||
|
suffix = f.suffix.lower()
|
||||||
|
if suffix == ".js":
|
||||||
return web.Response(body=f.read_bytes(), content_type="application/javascript")
|
return web.Response(body=f.read_bytes(), content_type="application/javascript")
|
||||||
if f.suffix == ".css":
|
if suffix == ".css":
|
||||||
return web.Response(body=f.read_bytes(), content_type="text/css")
|
return web.Response(body=f.read_bytes(), content_type="text/css")
|
||||||
|
if suffix in (".html", ".htm"):
|
||||||
return web.Response(body=f.read_bytes(), content_type="text/html")
|
return web.Response(body=f.read_bytes(), content_type="text/html")
|
||||||
|
|
||||||
|
return web.Response(body=f.read_bytes(), content_type="application/octet-stream")
|
||||||
|
|
||||||
|
|
||||||
class _APIListView(HomeAssistantView):
|
class _APIListView(HomeAssistantView):
|
||||||
requires_auth = True
|
requires_auth = True
|
||||||
|
|||||||
Reference in New Issue
Block a user