From adb61ab99b614feb91e1c56d278b6e6615817669 Mon Sep 17 00:00:00 2001 From: Philip Allgaier Date: Tue, 27 Dec 2022 22:00:37 +0100 Subject: [PATCH] Enforce valid entity ID in card config YAML (#14792) --- src/panels/lovelace/cards/hui-map-card.ts | 2 +- .../lovelace/common/process-config-entities.ts | 6 ++---- .../hui-alarm-panel-card-editor.ts | 11 ++++++----- .../config-elements/hui-button-card-editor.ts | 3 ++- .../config-elements/hui-entity-card-editor.ts | 7 ++++--- .../config-elements/hui-gauge-card-editor.ts | 7 ++++--- .../hui-humidifier-card-editor.ts | 5 +++-- .../config-elements/hui-light-card-editor.ts | 3 ++- .../config-elements/hui-map-card-editor.ts | 13 +++++++------ .../hui-media-control-card-editor.ts | 3 ++- .../hui-picture-entity-card-editor.ts | 5 +++-- .../hui-plant-status-card-editor.ts | 5 +++-- .../config-elements/hui-sensor-card-editor.ts | 5 +++-- .../hui-thermostat-card-editor.ts | 5 +++-- .../config-elements/hui-tile-card-editor.ts | 3 ++- .../hui-weather-forecast-card-editor.ts | 17 +++++++++-------- 16 files changed, 56 insertions(+), 44 deletions(-) diff --git a/src/panels/lovelace/cards/hui-map-card.ts b/src/panels/lovelace/cards/hui-map-card.ts index ca91c301e8..412ccf8f13 100644 --- a/src/panels/lovelace/cards/hui-map-card.ts +++ b/src/panels/lovelace/cards/hui-map-card.ts @@ -79,7 +79,7 @@ class HuiMapCard extends LitElement implements LovelaceCard { config.geo_location_sources && !Array.isArray(config.geo_location_sources) ) { - throw new Error("Geo_location_sources needs to be an array"); + throw new Error("Parameter geo_location_sources needs to be an array"); } this._config = config; diff --git a/src/panels/lovelace/common/process-config-entities.ts b/src/panels/lovelace/common/process-config-entities.ts index 2dfa9a92a7..1d4519ea5f 100644 --- a/src/panels/lovelace/common/process-config-entities.ts +++ b/src/panels/lovelace/common/process-config-entities.ts @@ -27,13 +27,11 @@ export const processConfigEntities = < config = { entity: entityConf } as T; } else if (typeof entityConf === "object" && !Array.isArray(entityConf)) { if (!("entity" in entityConf)) { - throw new Error( - `Entity object at position ${index} is missing entity field.` - ); + throw new Error(`Object at position ${index} is missing entity field`); } config = entityConf as T; } else { - throw new Error(`Invalid entity specified at position ${index}.`); + throw new Error(`Invalid entity ID at position ${index}`); } if (checkEntityId && !isValidEntityId((config as EntityConfig).entity!)) { diff --git a/src/panels/lovelace/editor/config-elements/hui-alarm-panel-card-editor.ts b/src/panels/lovelace/editor/config-elements/hui-alarm-panel-card-editor.ts index 97f5593057..f1c6168dbf 100644 --- a/src/panels/lovelace/editor/config-elements/hui-alarm-panel-card-editor.ts +++ b/src/panels/lovelace/editor/config-elements/hui-alarm-panel-card-editor.ts @@ -1,20 +1,21 @@ -import "../../../../components/ha-form/ha-form"; import { html, LitElement, TemplateResult } from "lit"; import { customElement, property, state } from "lit/decorators"; -import { array, assert, assign, object, optional, string } from "superstruct"; import memoizeOne from "memoize-one"; +import { array, assert, assign, object, optional, string } from "superstruct"; import { fireEvent } from "../../../../common/dom/fire_event"; +import { entityId } from "../../../../common/structs/is-entity-id"; +import type { LocalizeFunc } from "../../../../common/translations/localize"; +import "../../../../components/ha-form/ha-form"; +import type { SchemaUnion } from "../../../../components/ha-form/types"; import type { HomeAssistant } from "../../../../types"; import type { AlarmPanelCardConfig } from "../../cards/types"; import type { LovelaceCardEditor } from "../../types"; import { baseLovelaceCardConfig } from "../structs/base-card-struct"; -import type { SchemaUnion } from "../../../../components/ha-form/types"; -import type { LocalizeFunc } from "../../../../common/translations/localize"; const cardConfigStruct = assign( baseLovelaceCardConfig, object({ - entity: optional(string()), + entity: optional(entityId()), name: optional(string()), states: optional(array()), theme: optional(string()), diff --git a/src/panels/lovelace/editor/config-elements/hui-button-card-editor.ts b/src/panels/lovelace/editor/config-elements/hui-button-card-editor.ts index 7ac8bb39e9..da8436cf5b 100644 --- a/src/panels/lovelace/editor/config-elements/hui-button-card-editor.ts +++ b/src/panels/lovelace/editor/config-elements/hui-button-card-editor.ts @@ -6,6 +6,7 @@ import { assert, assign, boolean, object, optional, string } from "superstruct"; import { fireEvent } from "../../../../common/dom/fire_event"; import { computeDomain } from "../../../../common/entity/compute_domain"; import { domainIcon } from "../../../../common/entity/domain_icon"; +import { entityId } from "../../../../common/structs/is-entity-id"; import "../../../../components/ha-form/ha-form"; import type { SchemaUnion } from "../../../../components/ha-form/types"; import type { HomeAssistant } from "../../../../types"; @@ -18,7 +19,7 @@ import { configElementStyle } from "./config-elements-style"; const cardConfigStruct = assign( baseLovelaceCardConfig, object({ - entity: optional(string()), + entity: optional(entityId()), name: optional(string()), show_name: optional(boolean()), icon: optional(string()), diff --git a/src/panels/lovelace/editor/config-elements/hui-entity-card-editor.ts b/src/panels/lovelace/editor/config-elements/hui-entity-card-editor.ts index 334e84bc06..37e3c34874 100644 --- a/src/panels/lovelace/editor/config-elements/hui-entity-card-editor.ts +++ b/src/panels/lovelace/editor/config-elements/hui-entity-card-editor.ts @@ -1,12 +1,13 @@ -import "../../../../components/ha-form/ha-form"; +import type { HassEntity } from "home-assistant-js-websocket/dist/types"; import { html, LitElement, TemplateResult } from "lit"; import { customElement, property, state } from "lit/decorators"; import memoizeOne from "memoize-one"; import { assert, assign, boolean, object, optional, string } from "superstruct"; -import type { HassEntity } from "home-assistant-js-websocket/dist/types"; import { fireEvent } from "../../../../common/dom/fire_event"; import { computeDomain } from "../../../../common/entity/compute_domain"; import { domainIcon } from "../../../../common/entity/domain_icon"; +import { entityId } from "../../../../common/structs/is-entity-id"; +import "../../../../components/ha-form/ha-form"; import type { SchemaUnion } from "../../../../components/ha-form/types"; import type { HomeAssistant } from "../../../../types"; import type { EntityCardConfig } from "../../cards/types"; @@ -17,7 +18,7 @@ import { baseLovelaceCardConfig } from "../structs/base-card-struct"; const cardConfigStruct = assign( baseLovelaceCardConfig, object({ - entity: optional(string()), + entity: optional(entityId()), name: optional(string()), icon: optional(string()), attribute: optional(string()), diff --git a/src/panels/lovelace/editor/config-elements/hui-gauge-card-editor.ts b/src/panels/lovelace/editor/config-elements/hui-gauge-card-editor.ts index 477b949a78..55592f9132 100644 --- a/src/panels/lovelace/editor/config-elements/hui-gauge-card-editor.ts +++ b/src/panels/lovelace/editor/config-elements/hui-gauge-card-editor.ts @@ -1,6 +1,6 @@ -import "../../../../components/ha-form/ha-form"; import { html, LitElement, TemplateResult } from "lit"; import { customElement, property, state } from "lit/decorators"; +import memoizeOne from "memoize-one"; import { array, assert, @@ -11,8 +11,9 @@ import { optional, string, } from "superstruct"; -import memoizeOne from "memoize-one"; import { fireEvent } from "../../../../common/dom/fire_event"; +import { entityId } from "../../../../common/structs/is-entity-id"; +import "../../../../components/ha-form/ha-form"; import type { SchemaUnion } from "../../../../components/ha-form/types"; import type { HomeAssistant } from "../../../../types"; import type { GaugeCardConfig } from "../../cards/types"; @@ -29,7 +30,7 @@ const cardConfigStruct = assign( baseLovelaceCardConfig, object({ name: optional(string()), - entity: optional(string()), + entity: optional(entityId()), unit: optional(string()), min: optional(number()), max: optional(number()), diff --git a/src/panels/lovelace/editor/config-elements/hui-humidifier-card-editor.ts b/src/panels/lovelace/editor/config-elements/hui-humidifier-card-editor.ts index 055cdf68c9..7516347005 100644 --- a/src/panels/lovelace/editor/config-elements/hui-humidifier-card-editor.ts +++ b/src/panels/lovelace/editor/config-elements/hui-humidifier-card-editor.ts @@ -1,8 +1,9 @@ -import "../../../../components/ha-form/ha-form"; import { html, LitElement, TemplateResult } from "lit"; import { customElement, property, state } from "lit/decorators"; import { assert, assign, object, optional, string } from "superstruct"; import { fireEvent } from "../../../../common/dom/fire_event"; +import { entityId } from "../../../../common/structs/is-entity-id"; +import "../../../../components/ha-form/ha-form"; import type { SchemaUnion } from "../../../../components/ha-form/types"; import type { HomeAssistant } from "../../../../types"; import type { HumidifierCardConfig } from "../../cards/types"; @@ -12,7 +13,7 @@ import { baseLovelaceCardConfig } from "../structs/base-card-struct"; const cardConfigStruct = assign( baseLovelaceCardConfig, object({ - entity: optional(string()), + entity: optional(entityId()), name: optional(string()), theme: optional(string()), }) diff --git a/src/panels/lovelace/editor/config-elements/hui-light-card-editor.ts b/src/panels/lovelace/editor/config-elements/hui-light-card-editor.ts index e0e42f6fe7..e8247b9eb7 100644 --- a/src/panels/lovelace/editor/config-elements/hui-light-card-editor.ts +++ b/src/panels/lovelace/editor/config-elements/hui-light-card-editor.ts @@ -6,6 +6,7 @@ import { assert, assign, object, optional, string } from "superstruct"; import { fireEvent } from "../../../../common/dom/fire_event"; import { computeDomain } from "../../../../common/entity/compute_domain"; import { domainIcon } from "../../../../common/entity/domain_icon"; +import { entityId } from "../../../../common/structs/is-entity-id"; import "../../../../components/ha-form/ha-form"; import type { SchemaUnion } from "../../../../components/ha-form/types"; import type { HomeAssistant } from "../../../../types"; @@ -19,7 +20,7 @@ const cardConfigStruct = assign( baseLovelaceCardConfig, object({ name: optional(string()), - entity: optional(string()), + entity: optional(entityId()), theme: optional(string()), icon: optional(string()), hold_action: optional(actionConfigStruct), diff --git a/src/panels/lovelace/editor/config-elements/hui-map-card-editor.ts b/src/panels/lovelace/editor/config-elements/hui-map-card-editor.ts index 4c23122554..13161eac14 100644 --- a/src/panels/lovelace/editor/config-elements/hui-map-card-editor.ts +++ b/src/panels/lovelace/editor/config-elements/hui-map-card-editor.ts @@ -1,17 +1,19 @@ -import "../../../../components/ha-form/ha-form"; import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; import { customElement, property, state } from "lit/decorators"; import { array, assert, + assign, boolean, number, object, optional, string, - assign, } from "superstruct"; import { fireEvent } from "../../../../common/dom/fire_event"; +import { entityId } from "../../../../common/structs/is-entity-id"; +import "../../../../components/ha-form/ha-form"; +import { SchemaUnion } from "../../../../components/ha-form/types"; import "../../../../components/ha-formfield"; import "../../../../components/ha-switch"; import { PolymerChangedEvent } from "../../../../polymer-types"; @@ -22,11 +24,9 @@ import "../../components/hui-input-list-editor"; import { EntityConfig } from "../../entity-rows/types"; import { LovelaceCardEditor } from "../../types"; import { processEditorEntities } from "../process-editor-entities"; -import { entitiesConfigStruct } from "../structs/entities-struct"; +import { baseLovelaceCardConfig } from "../structs/base-card-struct"; import { EntitiesEditorEvent } from "../types"; import { configElementStyle } from "./config-elements-style"; -import { baseLovelaceCardConfig } from "../structs/base-card-struct"; -import { SchemaUnion } from "../../../../components/ha-form/types"; const cardConfigStruct = assign( baseLovelaceCardConfig, @@ -35,9 +35,10 @@ const cardConfigStruct = assign( aspect_ratio: optional(string()), default_zoom: optional(number()), dark_mode: optional(boolean()), - entities: array(entitiesConfigStruct), + entities: array(entityId()), hours_to_show: optional(number()), geo_location_sources: optional(array(string())), + auto_fit: optional(boolean()), }) ); diff --git a/src/panels/lovelace/editor/config-elements/hui-media-control-card-editor.ts b/src/panels/lovelace/editor/config-elements/hui-media-control-card-editor.ts index 9470be0a78..f7bd27249c 100644 --- a/src/panels/lovelace/editor/config-elements/hui-media-control-card-editor.ts +++ b/src/panels/lovelace/editor/config-elements/hui-media-control-card-editor.ts @@ -2,6 +2,7 @@ import { html, LitElement, TemplateResult } from "lit"; import { customElement, property, state } from "lit/decorators"; import { assert, assign, object, optional, string } from "superstruct"; import { fireEvent } from "../../../../common/dom/fire_event"; +import { entityId } from "../../../../common/structs/is-entity-id"; import "../../../../components/entity/ha-entity-picker"; import "../../../../components/ha-theme-picker"; import { HomeAssistant } from "../../../../types"; @@ -13,7 +14,7 @@ import { EditorTarget, EntitiesEditorEvent } from "../types"; const cardConfigStruct = assign( baseLovelaceCardConfig, object({ - entity: optional(string()), + entity: optional(entityId()), theme: optional(string()), }) ); diff --git a/src/panels/lovelace/editor/config-elements/hui-picture-entity-card-editor.ts b/src/panels/lovelace/editor/config-elements/hui-picture-entity-card-editor.ts index 4b24e2a523..5980b1e07a 100644 --- a/src/panels/lovelace/editor/config-elements/hui-picture-entity-card-editor.ts +++ b/src/panels/lovelace/editor/config-elements/hui-picture-entity-card-editor.ts @@ -2,6 +2,8 @@ import { CSSResultGroup, html, LitElement, TemplateResult } from "lit"; import { customElement, property, state } from "lit/decorators"; import { assert, assign, boolean, object, optional, string } from "superstruct"; import { fireEvent } from "../../../../common/dom/fire_event"; +import { entityId } from "../../../../common/structs/is-entity-id"; +import "../../../../components/ha-form/ha-form"; import type { SchemaUnion } from "../../../../components/ha-form/types"; import type { HomeAssistant } from "../../../../types"; import type { PictureEntityCardConfig } from "../../cards/types"; @@ -9,12 +11,11 @@ import type { LovelaceCardEditor } from "../../types"; import { actionConfigStruct } from "../structs/action-struct"; import { baseLovelaceCardConfig } from "../structs/base-card-struct"; import { configElementStyle } from "./config-elements-style"; -import "../../../../components/ha-form/ha-form"; const cardConfigStruct = assign( baseLovelaceCardConfig, object({ - entity: optional(string()), + entity: optional(entityId()), image: optional(string()), name: optional(string()), camera_image: optional(string()), diff --git a/src/panels/lovelace/editor/config-elements/hui-plant-status-card-editor.ts b/src/panels/lovelace/editor/config-elements/hui-plant-status-card-editor.ts index dbc19b69a3..bf3fe6e720 100644 --- a/src/panels/lovelace/editor/config-elements/hui-plant-status-card-editor.ts +++ b/src/panels/lovelace/editor/config-elements/hui-plant-status-card-editor.ts @@ -1,8 +1,9 @@ -import "../../../../components/ha-form/ha-form"; import { html, LitElement, TemplateResult } from "lit"; import { customElement, property, state } from "lit/decorators"; import { assert, assign, object, optional, string } from "superstruct"; import { fireEvent } from "../../../../common/dom/fire_event"; +import { entityId } from "../../../../common/structs/is-entity-id"; +import "../../../../components/ha-form/ha-form"; import type { SchemaUnion } from "../../../../components/ha-form/types"; import type { HomeAssistant } from "../../../../types"; import type { PlantStatusCardConfig } from "../../cards/types"; @@ -12,7 +13,7 @@ import { baseLovelaceCardConfig } from "../structs/base-card-struct"; const cardConfigStruct = assign( baseLovelaceCardConfig, object({ - entity: optional(string()), + entity: optional(entityId()), name: optional(string()), theme: optional(string()), }) diff --git a/src/panels/lovelace/editor/config-elements/hui-sensor-card-editor.ts b/src/panels/lovelace/editor/config-elements/hui-sensor-card-editor.ts index d3b06a385e..d9c6d314a7 100644 --- a/src/panels/lovelace/editor/config-elements/hui-sensor-card-editor.ts +++ b/src/panels/lovelace/editor/config-elements/hui-sensor-card-editor.ts @@ -1,4 +1,3 @@ -import "../../../../components/ha-form/ha-form"; import type { HassEntity } from "home-assistant-js-websocket"; import { CSSResultGroup, html, LitElement, TemplateResult } from "lit"; import { customElement, property, state } from "lit/decorators"; @@ -16,6 +15,8 @@ import { import { fireEvent } from "../../../../common/dom/fire_event"; import { computeDomain } from "../../../../common/entity/compute_domain"; import { domainIcon } from "../../../../common/entity/domain_icon"; +import { entityId } from "../../../../common/structs/is-entity-id"; +import "../../../../components/ha-form/ha-form"; import type { SchemaUnion } from "../../../../components/ha-form/types"; import type { HomeAssistant } from "../../../../types"; import type { SensorCardConfig } from "../../cards/types"; @@ -26,7 +27,7 @@ import { configElementStyle } from "./config-elements-style"; const cardConfigStruct = assign( baseLovelaceCardConfig, object({ - entity: optional(string()), + entity: optional(entityId()), name: optional(string()), icon: optional(string()), graph: optional(union([literal("line"), literal("none")])), diff --git a/src/panels/lovelace/editor/config-elements/hui-thermostat-card-editor.ts b/src/panels/lovelace/editor/config-elements/hui-thermostat-card-editor.ts index cf5af922f7..ebaa0331d9 100644 --- a/src/panels/lovelace/editor/config-elements/hui-thermostat-card-editor.ts +++ b/src/panels/lovelace/editor/config-elements/hui-thermostat-card-editor.ts @@ -1,8 +1,9 @@ -import "../../../../components/ha-form/ha-form"; import { html, LitElement, TemplateResult } from "lit"; import { customElement, property, state } from "lit/decorators"; import { assert, assign, object, optional, string } from "superstruct"; import { fireEvent } from "../../../../common/dom/fire_event"; +import { entityId } from "../../../../common/structs/is-entity-id"; +import "../../../../components/ha-form/ha-form"; import type { SchemaUnion } from "../../../../components/ha-form/types"; import type { HomeAssistant } from "../../../../types"; import type { ThermostatCardConfig } from "../../cards/types"; @@ -12,7 +13,7 @@ import { baseLovelaceCardConfig } from "../structs/base-card-struct"; const cardConfigStruct = assign( baseLovelaceCardConfig, object({ - entity: optional(string()), + entity: optional(entityId()), name: optional(string()), theme: optional(string()), }) diff --git a/src/panels/lovelace/editor/config-elements/hui-tile-card-editor.ts b/src/panels/lovelace/editor/config-elements/hui-tile-card-editor.ts index ba9b383512..65dbeac6d1 100644 --- a/src/panels/lovelace/editor/config-elements/hui-tile-card-editor.ts +++ b/src/panels/lovelace/editor/config-elements/hui-tile-card-editor.ts @@ -16,6 +16,7 @@ import { import { fireEvent, HASSDomEvent } from "../../../../common/dom/fire_event"; import { computeDomain } from "../../../../common/entity/compute_domain"; import { domainIcon } from "../../../../common/entity/domain_icon"; +import { entityId } from "../../../../common/structs/is-entity-id"; import "../../../../components/ha-form/ha-form"; import type { SchemaUnion } from "../../../../components/ha-form/types"; import type { HomeAssistant } from "../../../../types"; @@ -35,7 +36,7 @@ import "./hui-tile-card-features-editor"; const cardConfigStruct = assign( baseLovelaceCardConfig, object({ - entity: optional(string()), + entity: optional(entityId()), name: optional(string()), icon: optional(string()), color: optional(string()), diff --git a/src/panels/lovelace/editor/config-elements/hui-weather-forecast-card-editor.ts b/src/panels/lovelace/editor/config-elements/hui-weather-forecast-card-editor.ts index 410371bcdd..cc040c84d1 100644 --- a/src/panels/lovelace/editor/config-elements/hui-weather-forecast-card-editor.ts +++ b/src/panels/lovelace/editor/config-elements/hui-weather-forecast-card-editor.ts @@ -1,23 +1,24 @@ -import "../../../../components/ha-form/ha-form"; +import { memoize } from "@fullcalendar/common"; import { html, LitElement, TemplateResult } from "lit"; import { customElement, property, state } from "lit/decorators"; -import { assert, boolean, object, optional, string, assign } from "superstruct"; -import { memoize } from "@fullcalendar/common"; +import { assert, assign, boolean, object, optional, string } from "superstruct"; import { fireEvent } from "../../../../common/dom/fire_event"; +import { entityId } from "../../../../common/structs/is-entity-id"; +import type { LocalizeFunc } from "../../../../common/translations/localize"; +import "../../../../components/ha-form/ha-form"; +import type { SchemaUnion } from "../../../../components/ha-form/types"; +import { UNAVAILABLE } from "../../../../data/entity"; +import type { WeatherEntity } from "../../../../data/weather"; import type { HomeAssistant } from "../../../../types"; import type { WeatherForecastCardConfig } from "../../cards/types"; import type { LovelaceCardEditor } from "../../types"; import { actionConfigStruct } from "../structs/action-struct"; import { baseLovelaceCardConfig } from "../structs/base-card-struct"; -import { UNAVAILABLE } from "../../../../data/entity"; -import type { WeatherEntity } from "../../../../data/weather"; -import type { LocalizeFunc } from "../../../../common/translations/localize"; -import type { SchemaUnion } from "../../../../components/ha-form/types"; const cardConfigStruct = assign( baseLovelaceCardConfig, object({ - entity: optional(string()), + entity: optional(entityId()), name: optional(string()), theme: optional(string()), show_current: optional(boolean()),