diff --git a/assets/app.js b/assets/app.js index 226b552..4f96f47 100755 --- a/assets/app.js +++ b/assets/app.js @@ -455,6 +455,10 @@ url.searchParams.set(key, value); } }); + const proxyToken = String(window.APP_BOOTSTRAP?.ui?.proxy_token || '').trim(); + if (proxyToken && !url.searchParams.has('token')) { + url.searchParams.set('token', proxyToken); + } return url.toString(); } diff --git a/config/addon-default-config.json b/config/addon-default-config.json index a6393d7..7b87dbb 100755 --- a/config/addon-default-config.json +++ b/config/addon-default-config.json @@ -1,6 +1,6 @@ { "app": { - "title": "Wall Panel", + "title": "Striker Panel", "poll_interval_ms": 5000, "main_room_name": "Главная", "main_room_icon": "mdi:home", diff --git a/custom_components/wall_panel/config_flow.py b/custom_components/wall_panel/config_flow.py index 73502e9..9d99066 100755 --- a/custom_components/wall_panel/config_flow.py +++ b/custom_components/wall_panel/config_flow.py @@ -30,7 +30,7 @@ from .helpers import config_to_json, normalize_config, parse_config_json def _schema(defaults: dict[str, Any]) -> vol.Schema: return vol.Schema({ - vol.Optional(CONF_NAME, default=defaults.get(CONF_NAME, "Wall Panel")): str, + vol.Optional(CONF_NAME, default=defaults.get(CONF_NAME, "Striker Panel")): str, vol.Optional(CONF_PANEL_URL, default=defaults.get(CONF_PANEL_URL, DEFAULT_PANEL_URL)): str, vol.Optional(CONF_SIDEBAR_TITLE, default=defaults.get(CONF_SIDEBAR_TITLE, DEFAULT_SIDEBAR_TITLE)): str, vol.Optional(CONF_SIDEBAR_ICON, default=defaults.get(CONF_SIDEBAR_ICON, DEFAULT_SIDEBAR_ICON)): str, @@ -61,7 +61,7 @@ class WallPanelConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): errors[CONF_CONFIG] = "invalid_json" else: data = { - CONF_NAME: user_input.get(CONF_NAME, "Wall Panel"), + CONF_NAME: user_input.get(CONF_NAME, "Striker Panel"), CONF_PANEL_URL: str(user_input.get(CONF_PANEL_URL, "") or ""), CONF_SIDEBAR_TITLE: str(user_input.get(CONF_SIDEBAR_TITLE, DEFAULT_SIDEBAR_TITLE) or DEFAULT_SIDEBAR_TITLE), CONF_SIDEBAR_ICON: str(user_input.get(CONF_SIDEBAR_ICON, DEFAULT_SIDEBAR_ICON) or DEFAULT_SIDEBAR_ICON), @@ -75,7 +75,7 @@ class WallPanelConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): return self.async_create_entry(title=data[CONF_SIDEBAR_TITLE], data={}, options=data) defaults = { - CONF_NAME: "Wall Panel", + CONF_NAME: "Striker Panel", CONF_PANEL_URL: DEFAULT_PANEL_URL, CONF_SIDEBAR_TITLE: DEFAULT_SIDEBAR_TITLE, CONF_SIDEBAR_ICON: DEFAULT_SIDEBAR_ICON, @@ -106,7 +106,7 @@ class WallPanelOptionsFlow(config_entries.OptionsFlow): else: data = dict(self.config_entry.options) data.update({ - CONF_NAME: user_input.get(CONF_NAME, data.get(CONF_NAME, "Wall Panel")), + CONF_NAME: user_input.get(CONF_NAME, data.get(CONF_NAME, "Striker Panel")), CONF_PANEL_URL: str(user_input.get(CONF_PANEL_URL, "") or ""), CONF_SIDEBAR_TITLE: str(user_input.get(CONF_SIDEBAR_TITLE, DEFAULT_SIDEBAR_TITLE) or DEFAULT_SIDEBAR_TITLE), CONF_SIDEBAR_ICON: str(user_input.get(CONF_SIDEBAR_ICON, DEFAULT_SIDEBAR_ICON) or DEFAULT_SIDEBAR_ICON), @@ -118,7 +118,7 @@ class WallPanelOptionsFlow(config_entries.OptionsFlow): return self.async_create_entry(title="", data=data) defaults = { - CONF_NAME: self.config_entry.options.get(CONF_NAME, "Wall Panel"), + CONF_NAME: self.config_entry.options.get(CONF_NAME, "Striker Panel"), CONF_PANEL_URL: self.config_entry.options.get(CONF_PANEL_URL, DEFAULT_PANEL_URL), CONF_SIDEBAR_TITLE: self.config_entry.options.get(CONF_SIDEBAR_TITLE, DEFAULT_SIDEBAR_TITLE), CONF_SIDEBAR_ICON: self.config_entry.options.get(CONF_SIDEBAR_ICON, DEFAULT_SIDEBAR_ICON), diff --git a/custom_components/wall_panel/const.py b/custom_components/wall_panel/const.py index 1bd768e..f0b8082 100755 --- a/custom_components/wall_panel/const.py +++ b/custom_components/wall_panel/const.py @@ -10,8 +10,8 @@ CONF_SIDEBAR_ICON = "sidebar_icon" CONF_FRONTEND_URL_PATH = "frontend_url_path" CONF_REQUIRE_ADMIN = "require_admin" -DEFAULT_NAME = "Wall Panel" +DEFAULT_NAME = "Striker Panel" DEFAULT_PANEL_URL = "" -DEFAULT_SIDEBAR_TITLE = "Wall Panel" +DEFAULT_SIDEBAR_TITLE = "Striker Panel" DEFAULT_SIDEBAR_ICON = "mdi:view-dashboard" -DEFAULT_FRONTEND_URL_PATH = "wall-panel" +DEFAULT_FRONTEND_URL_PATH = "striker-panel" diff --git a/custom_components/wall_panel/frontend.py b/custom_components/wall_panel/frontend.py index e19d25d..1468948 100755 --- a/custom_components/wall_panel/frontend.py +++ b/custom_components/wall_panel/frontend.py @@ -2,6 +2,7 @@ from __future__ import annotations +import time from pathlib import Path from homeassistant.components.frontend import async_register_built_in_panel @@ -43,6 +44,7 @@ async def async_setup_frontend(hass: HomeAssistant, entry) -> str: require_admin = bool(entry.options.get(CONF_REQUIRE_ADMIN, False)) panel_url = str(entry.options.get(CONF_PANEL_URL, "") or "").strip() sync_token = str(entry.options.get(CONF_SYNC_TOKEN, "") or "").strip() + asset_version = str(int(time.time())) async_register_built_in_panel( hass, @@ -52,8 +54,8 @@ async def async_setup_frontend(hass: HomeAssistant, entry) -> str: frontend_url_path=panel_url_path, config={ "_panel_custom": { - "name": "wall-panel-panel", - "module_url": f"/api/{DOMAIN}/frontend/panel.js", + "name": "striker-panel-panel", + "module_url": f"/api/{DOMAIN}/frontend/panel.js?v={asset_version}", "embed_iframe": False, "trust_external": False, "config": { diff --git a/custom_components/wall_panel/frontend/panel.js b/custom_components/wall_panel/frontend/panel.js index 32078f9..eb63e9f 100755 --- a/custom_components/wall_panel/frontend/panel.js +++ b/custom_components/wall_panel/frontend/panel.js @@ -81,7 +81,15 @@ class WallPanelPanel extends HTMLElement { return ''; } - return `/api/wall_panel/proxy/${encodeURIComponent(entryId)}/`; + const token = String(payload.sync_token || '').trim(); + const url = `/api/wall_panel/proxy/${encodeURIComponent(entryId)}/`; + if (!token) { + return url; + } + + const proxyUrl = new URL(url, window.location.href); + proxyUrl.searchParams.set('token', token); + return proxyUrl.pathname + proxyUrl.search + proxyUrl.hash; } _hasPanelUrl() { @@ -191,7 +199,7 @@ class WallPanelPanel extends HTMLElement { const panelUrl = this._resolveUrl(payload.panel_url || payload.ingress_url || ''); const configUrl = this._configUrl(); this._renderMessage( - 'Waiting for Wall Panel', + 'Waiting for Striker Panel', panelUrl ? 'Open this panel through Home Assistant after the add-on URL is configured.' : 'Set the PHP panel URL in the integration options.', @@ -216,6 +224,6 @@ class WallPanelPanel extends HTMLElement { } } -if (!customElements.get('wall-panel-panel')) { - customElements.define('wall-panel-panel', WallPanelPanel); +if (!customElements.get('striker-panel-panel')) { + customElements.define('striker-panel-panel', WallPanelPanel); } diff --git a/custom_components/wall_panel/helpers.py b/custom_components/wall_panel/helpers.py index d000aff..56b6a23 100755 --- a/custom_components/wall_panel/helpers.py +++ b/custom_components/wall_panel/helpers.py @@ -24,7 +24,7 @@ from .const import ( def default_config() -> dict[str, Any]: return { "app": { - "title": "Wall Panel", + "title": "Striker Panel", "poll_interval_ms": 5000, "main_room_name": "Главная", "main_room_icon": "mdi:home", diff --git a/custom_components/wall_panel/manifest.json b/custom_components/wall_panel/manifest.json index 6c8d9f8..6813804 100755 --- a/custom_components/wall_panel/manifest.json +++ b/custom_components/wall_panel/manifest.json @@ -1,8 +1,8 @@ { "domain": "wall_panel", - "name": "Wall Panel", + "name": "Striker Panel", "version": "1.0.0", - "documentation": "https://example.invalid/wall-panel", + "documentation": "https://example.invalid/striker-panel", "codeowners": [], "config_flow": true, "iot_class": "local_polling", diff --git a/custom_components/wall_panel/strings.json b/custom_components/wall_panel/strings.json index 7bb1b1c..1de6394 100755 --- a/custom_components/wall_panel/strings.json +++ b/custom_components/wall_panel/strings.json @@ -2,8 +2,8 @@ "config": { "step": { "user": { - "title": "Wall Panel", - "description": "Connect Wall Panel to Home Assistant.", + "title": "Striker Panel", + "description": "Connect Striker Panel to Home Assistant.", "data": { "name": "Name", "panel_url": "PHP panel URL", diff --git a/custom_components/wall_panel/translations/en.json b/custom_components/wall_panel/translations/en.json index 7bb1b1c..1de6394 100755 --- a/custom_components/wall_panel/translations/en.json +++ b/custom_components/wall_panel/translations/en.json @@ -2,8 +2,8 @@ "config": { "step": { "user": { - "title": "Wall Panel", - "description": "Connect Wall Panel to Home Assistant.", + "title": "Striker Panel", + "description": "Connect Striker Panel to Home Assistant.", "data": { "name": "Name", "panel_url": "PHP panel URL", diff --git a/custom_components/wall_panel/views.py b/custom_components/wall_panel/views.py index 6009fd4..89d1e7a 100755 --- a/custom_components/wall_panel/views.py +++ b/custom_components/wall_panel/views.py @@ -235,6 +235,9 @@ async def _handle_proxy_request(request: web.Request, entry_id: str, path: str, entry = _entry_from_hass(hass, entry_id) if entry is None: return _response({"ok": False, "error": "Unknown entry"}, 404) + if not _authorized(entry, request): + _LOGGER.warning("Wall Panel proxy denied for %s: unauthorized", entry_id) + return _response({"ok": False, "error": "Unauthorized"}, 401) base_url = str(entry.options.get(CONF_PANEL_URL, "") or "").strip() if not base_url: diff --git a/index.php b/index.php index 628351c..cfba1e6 100755 --- a/index.php +++ b/index.php @@ -27,6 +27,7 @@ $bootstrap['ui'] = [ 'mode' => $runtimeMode, 'shell' => $embedMode ? 'embed' : 'standalone', 'config_source' => app_remote_sync_enabled($config) ? 'ha' : 'file', + 'proxy_token' => trim((string)($_GET['token'] ?? '')), ]; $appTitle = htmlspecialchars((string)($config['app']['title'] ?? 'Wall Panel'), ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'); ?> diff --git a/lib/config.php b/lib/config.php index 0a17765..4d7ba93 100755 --- a/lib/config.php +++ b/lib/config.php @@ -5,7 +5,7 @@ function app_default_config(): array { return [ 'app' => [ - 'title' => 'Wall Panel', + 'title' => 'Striker Panel', 'poll_interval_ms' => 5000, 'main_room_name' => 'Главная', 'main_room_icon' => 'mdi:home', diff --git a/repository.yaml b/repository.yaml index 5f42115..995596d 100755 --- a/repository.yaml +++ b/repository.yaml @@ -1,3 +1,3 @@ -name: Wall Panel Add-ons +name: Striker Panel Add-ons url: https://git.striker72rus.ru/PHP/wallpanell.git maintainer: Striker72rus diff --git a/storage/popup_state.json b/storage/popup_state.json index 67b2fa5..b50645a 100755 --- a/storage/popup_state.json +++ b/storage/popup_state.json @@ -1,6 +1,6 @@ { "active": false, "sensor_entity_id": "binary_sensor.barn_all_occupancy", - "opened_at": 1774444953, + "opened_at": 1774445418, "expires_at": null } diff --git a/wall_panel/assets/app.js b/wall_panel/assets/app.js index 226b552..4f96f47 100755 --- a/wall_panel/assets/app.js +++ b/wall_panel/assets/app.js @@ -455,6 +455,10 @@ url.searchParams.set(key, value); } }); + const proxyToken = String(window.APP_BOOTSTRAP?.ui?.proxy_token || '').trim(); + if (proxyToken && !url.searchParams.has('token')) { + url.searchParams.set('token', proxyToken); + } return url.toString(); } diff --git a/wall_panel/config.yaml b/wall_panel/config.yaml index fe40acd..587243e 100755 --- a/wall_panel/config.yaml +++ b/wall_panel/config.yaml @@ -1,6 +1,6 @@ -name: Wall Panel -description: Wall Panel PHP interface as a Home Assistant add-on -version: "1.0.22" +name: Striker Panel +description: Striker Panel PHP interface as a Home Assistant add-on +version: "1.0.23" slug: wall_panel url: https://git.striker72rus.ru/PHP/wallpanell.git init: false @@ -15,14 +15,14 @@ ingress: true ingress_panel: true ingress_port: 8099 webui: "http://[HOST]:[PORT:8099]/" -panel_title: Wall Panel +panel_title: Striker Panel panel_icon: mdi:view-dashboard hassio_api: true hassio_role: default ports: 8099/tcp: 8099 ports_description: - 8099/tcp: Wall Panel web UI + 8099/tcp: Striker Panel web UI map: - type: homeassistant_config read_only: false @@ -30,7 +30,7 @@ map: homeassistant_api: true options: app: - title: Wall Panel + title: Striker Panel poll_interval_ms: 5000 main_room_name: Главная main_room_icon: mdi:home diff --git a/wall_panel/config/addon-default-config.json b/wall_panel/config/addon-default-config.json index a6393d7..7b87dbb 100755 --- a/wall_panel/config/addon-default-config.json +++ b/wall_panel/config/addon-default-config.json @@ -1,6 +1,6 @@ { "app": { - "title": "Wall Panel", + "title": "Striker Panel", "poll_interval_ms": 5000, "main_room_name": "Главная", "main_room_icon": "mdi:home", diff --git a/wall_panel/index.php b/wall_panel/index.php index ade890c..730984c 100755 --- a/wall_panel/index.php +++ b/wall_panel/index.php @@ -27,6 +27,7 @@ $bootstrap['ui'] = [ 'mode' => $runtimeMode, 'shell' => $embedMode ? 'embed' : 'standalone', 'config_source' => app_remote_sync_enabled($config) ? 'ha' : 'file', + 'proxy_token' => trim((string)($_GET['token'] ?? '')), ]; $appTitle = htmlspecialchars((string)($config['app']['title'] ?? 'Wall Panel'), ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'); ?> diff --git a/wall_panel/lib/config.php b/wall_panel/lib/config.php index 880afbd..1b01add 100755 --- a/wall_panel/lib/config.php +++ b/wall_panel/lib/config.php @@ -5,7 +5,7 @@ function app_default_config(): array { return [ 'app' => [ - 'title' => 'Wall Panel', + 'title' => 'Striker Panel', 'poll_interval_ms' => 5000, 'main_room_name' => 'Главная', 'main_room_icon' => 'mdi:home',