Disallow special characters in view URL (#26280)

* Disallow special characters in view URL
This commit is contained in:
karwosts 2025-07-24 11:58:26 -07:00 committed by GitHub
parent 43f1d9be44
commit e4b6c3fd4d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 29 additions and 1 deletions

View File

@ -25,6 +25,7 @@ export interface GUIModeChangedEvent {
export interface ViewEditEvent extends Event {
detail: {
config: LovelaceViewConfig;
valid?: boolean;
};
}

View File

@ -73,6 +73,8 @@ export class HuiDialogEditView extends LitElement {
@state() private _dirty = false;
@state() private _valid = true;
@state() private _yamlMode = false;
@query("ha-yaml-editor") private _editor?: HaYamlEditor;
@ -308,6 +310,7 @@ export class HuiDialogEditView extends LitElement {
?disabled=${!this._config ||
this._saving ||
!this._dirty ||
!this._valid ||
convertToSection ||
convertNotSupported}
@click=${this._save}
@ -579,6 +582,9 @@ export class HuiDialogEditView extends LitElement {
ev.detail.config &&
!deepEqual(this._config, ev.detail.config)
) {
if (ev.detail.valid !== undefined) {
this._valid = ev.detail.valid;
}
this._config = ev.detail.config;
this._dirty = true;
}

View File

@ -23,10 +23,13 @@ declare global {
interface HASSDomEvents {
"view-config-changed": {
config: LovelaceViewConfig;
valid?: boolean;
};
}
}
const VALID_PATH_REGEX = /^[a-zA-Z0-9_-]+$/;
@customElement("hui-view-editor")
export class HuiViewEditor extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@ -35,6 +38,8 @@ export class HuiViewEditor extends LitElement {
@state() private _config!: LovelaceViewConfig;
@state() private _error: Record<string, string> | undefined;
private _suggestedPath = false;
private _schema = memoizeOne(
@ -144,6 +149,8 @@ export class HuiViewEditor extends LitElement {
.schema=${schema}
.computeLabel=${this._computeLabel}
.computeHelper=${this._computeHelper}
.computeError=${this._computeError}
.error=${this._error}
@value-changed=${this._valueChanged}
></ha-form>
`;
@ -168,9 +175,20 @@ export class HuiViewEditor extends LitElement {
config.path = slugify(config.title || "", "-");
}
fireEvent(this, "view-config-changed", { config });
let valid = true;
this._error = undefined;
if (config.path && !VALID_PATH_REGEX.test(config.path)) {
valid = false;
this._error = { path: "error_invalid_path" };
}
fireEvent(this, "view-config-changed", { valid, config });
}
private _computeError = (error: string) =>
this.hass.localize(`ui.panel.lovelace.editor.edit_view.${error}` as any) ||
error;
private _computeLabel = (
schema: SchemaUnion<ReturnType<typeof this._schema>>
) => {
@ -197,6 +215,7 @@ export class HuiViewEditor extends LitElement {
schema: SchemaUnion<ReturnType<typeof this._schema>>
) => {
switch (schema.name) {
case "path":
case "subview":
case "dense_section_placement":
case "top_margin":

View File

@ -7028,10 +7028,12 @@
"top_margin": "Add additional space above",
"top_margin_helper": "Helps reveal more of the background",
"subview_helper": "Subviews don't appear in tabs and have a back button.",
"path_helper": "This value will become part of the URL path to open this view.",
"edit_ui": "Edit in visual editor",
"edit_yaml": "Edit in YAML",
"saving_failed": "Saving failed",
"error_same_url": "You cannot save a view with the same URL as a different existing view.",
"error_invalid_path": "URL contains invalid/reserved characters. Please enter a simple string only for the path of this view.",
"move_to_dashboard": "Move to dashboard"
},
"edit_view_header": {