Add check for HTML in translations (#35615)
* Add check for HTML in translations and remove existing html * Add test
This commit is contained in:
parent
a42a654590
commit
cb7b8d94c0
7 changed files with 47 additions and 18 deletions
|
@ -3,7 +3,7 @@
|
||||||
"step": {
|
"step": {
|
||||||
"auth": {
|
"auth": {
|
||||||
"title": "Authenticate Ambiclimate",
|
"title": "Authenticate Ambiclimate",
|
||||||
"description": "Please follow this [link]({authorization_url}) and <b>Allow</b> access to your Ambiclimate account, then come back and press <b>Submit</b> below.\n(Make sure the specified callback url is {cb_url})"
|
"description": "Please follow this [link]({authorization_url}) and **Allow** access to your Ambiclimate account, then come back and press **Submit** below.\n(Make sure the specified callback url is {cb_url})"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"create_entry": {
|
"create_entry": {
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
},
|
},
|
||||||
"auth": {
|
"auth": {
|
||||||
"title": "Authenticate with Logi Circle",
|
"title": "Authenticate with Logi Circle",
|
||||||
"description": "Please follow the link below and <b>Accept</b> access to your Logi Circle account, then come back and press <b>Submit</b> below.\n\n[Link]({authorization_url})"
|
"description": "Please follow the link below and **Accept** access to your Logi Circle account, then come back and press **Submit** below.\n\n[Link]({authorization_url})"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"create_entry": {
|
"create_entry": {
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
},
|
},
|
||||||
"auth": {
|
"auth": {
|
||||||
"title": "Authenticate Point",
|
"title": "Authenticate Point",
|
||||||
"description": "Please follow the link below and <b>Accept</b> access to your Minut account, then come back and press <b>Submit</b> below.\n\n[Link]({authorization_url})"
|
"description": "Please follow the link below and **Accept** access to your Minut account, then come back and press **Submit** below.\n\n[Link]({authorization_url})"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"create_entry": {
|
"create_entry": {
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
"step": {
|
"step": {
|
||||||
"auth_app": {
|
"auth_app": {
|
||||||
"title": "Application credentials",
|
"title": "Application credentials",
|
||||||
"description": "Application ID and secret code from <a href=\"https://my.starline.ru/developer\" target=\"_blank\">StarLine developer account</a>",
|
"description": "Application ID and secret code from [StarLine developer account](https://my.starline.ru/developer)",
|
||||||
"data": {
|
"data": {
|
||||||
"app_id": "App ID",
|
"app_id": "App ID",
|
||||||
"app_secret": "Secret"
|
"app_secret": "Secret"
|
||||||
|
|
|
@ -465,6 +465,15 @@ def string(value: Any) -> str:
|
||||||
return str(value)
|
return str(value)
|
||||||
|
|
||||||
|
|
||||||
|
def string_with_no_html(value: Any) -> str:
|
||||||
|
"""Validate that the value is a string without HTML."""
|
||||||
|
value = string(value)
|
||||||
|
regex = re.compile(r"<[a-z][\s\S]*>")
|
||||||
|
if regex.search(value):
|
||||||
|
raise vol.Invalid("the string should not contain HTML")
|
||||||
|
return str(value)
|
||||||
|
|
||||||
|
|
||||||
def temperature_unit(value: Any) -> str:
|
def temperature_unit(value: Any) -> str:
|
||||||
"""Validate and transform temperature unit."""
|
"""Validate and transform temperature unit."""
|
||||||
value = str(value).upper()
|
value = str(value).upper()
|
||||||
|
|
|
@ -91,20 +91,20 @@ def gen_data_entry_schema(
|
||||||
"""Generate a data entry schema."""
|
"""Generate a data entry schema."""
|
||||||
step_title_class = vol.Required if require_step_title else vol.Optional
|
step_title_class = vol.Required if require_step_title else vol.Optional
|
||||||
schema = {
|
schema = {
|
||||||
vol.Optional("flow_title"): str,
|
vol.Optional("flow_title"): cv.string_with_no_html,
|
||||||
vol.Required("step"): {
|
vol.Required("step"): {
|
||||||
str: {
|
str: {
|
||||||
step_title_class("title"): str,
|
step_title_class("title"): cv.string_with_no_html,
|
||||||
vol.Optional("description"): str,
|
vol.Optional("description"): cv.string_with_no_html,
|
||||||
vol.Optional("data"): {str: str},
|
vol.Optional("data"): {str: cv.string_with_no_html},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
vol.Optional("error"): {str: str},
|
vol.Optional("error"): {str: cv.string_with_no_html},
|
||||||
vol.Optional("abort"): {str: str},
|
vol.Optional("abort"): {str: cv.string_with_no_html},
|
||||||
vol.Optional("create_entry"): {str: str},
|
vol.Optional("create_entry"): {str: cv.string_with_no_html},
|
||||||
}
|
}
|
||||||
if flow_title == REQUIRED:
|
if flow_title == REQUIRED:
|
||||||
schema[vol.Required("title")] = str
|
schema[vol.Required("title")] = cv.string_with_no_html
|
||||||
elif flow_title == REMOVED:
|
elif flow_title == REMOVED:
|
||||||
schema[vol.Optional("title", msg=REMOVED_TITLE_MSG)] = partial(
|
schema[vol.Optional("title", msg=REMOVED_TITLE_MSG)] = partial(
|
||||||
removed_title_validator, config, integration
|
removed_title_validator, config, integration
|
||||||
|
@ -117,7 +117,7 @@ def gen_strings_schema(config: Config, integration: Integration):
|
||||||
"""Generate a strings schema."""
|
"""Generate a strings schema."""
|
||||||
return vol.Schema(
|
return vol.Schema(
|
||||||
{
|
{
|
||||||
vol.Optional("title"): str,
|
vol.Optional("title"): cv.string_with_no_html,
|
||||||
vol.Optional("config"): gen_data_entry_schema(
|
vol.Optional("config"): gen_data_entry_schema(
|
||||||
config=config,
|
config=config,
|
||||||
integration=integration,
|
integration=integration,
|
||||||
|
@ -131,10 +131,10 @@ def gen_strings_schema(config: Config, integration: Integration):
|
||||||
require_step_title=False,
|
require_step_title=False,
|
||||||
),
|
),
|
||||||
vol.Optional("device_automation"): {
|
vol.Optional("device_automation"): {
|
||||||
vol.Optional("action_type"): {str: str},
|
vol.Optional("action_type"): {str: cv.string_with_no_html},
|
||||||
vol.Optional("condition_type"): {str: str},
|
vol.Optional("condition_type"): {str: cv.string_with_no_html},
|
||||||
vol.Optional("trigger_type"): {str: str},
|
vol.Optional("trigger_type"): {str: cv.string_with_no_html},
|
||||||
vol.Optional("trigger_subtype"): {str: str},
|
vol.Optional("trigger_subtype"): {str: cv.string_with_no_html},
|
||||||
},
|
},
|
||||||
vol.Optional("state"): cv.schema_with_slug_keys(
|
vol.Optional("state"): cv.schema_with_slug_keys(
|
||||||
cv.schema_with_slug_keys(str, slug_validator=lowercase_validator),
|
cv.schema_with_slug_keys(str, slug_validator=lowercase_validator),
|
||||||
|
@ -203,7 +203,7 @@ def gen_platform_strings_schema(config: Config, integration: Integration):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
ONBOARDING_SCHEMA = vol.Schema({vol.Required("area"): {str: str}})
|
ONBOARDING_SCHEMA = vol.Schema({vol.Required("area"): {str: cv.string_with_no_html}})
|
||||||
|
|
||||||
|
|
||||||
def validate_translation_file(config: Config, integration: Integration, all_strings):
|
def validate_translation_file(config: Config, integration: Integration, all_strings):
|
||||||
|
|
|
@ -351,6 +351,26 @@ def test_string():
|
||||||
schema(value)
|
schema(value)
|
||||||
|
|
||||||
|
|
||||||
|
def test_string_with_no_html():
|
||||||
|
"""Test string with no html validation."""
|
||||||
|
schema = vol.Schema(cv.string_with_no_html)
|
||||||
|
|
||||||
|
with pytest.raises(vol.Invalid):
|
||||||
|
schema("This has HTML in it <a>Link</a>")
|
||||||
|
|
||||||
|
with pytest.raises(vol.Invalid):
|
||||||
|
schema("<b>Bold</b>")
|
||||||
|
|
||||||
|
for value in (
|
||||||
|
True,
|
||||||
|
3,
|
||||||
|
"Hello",
|
||||||
|
"**Hello**",
|
||||||
|
"This has no HTML [Link](https://home-assistant.io)",
|
||||||
|
):
|
||||||
|
schema(value)
|
||||||
|
|
||||||
|
|
||||||
def test_temperature_unit():
|
def test_temperature_unit():
|
||||||
"""Test temperature unit validation."""
|
"""Test temperature unit validation."""
|
||||||
schema = vol.Schema(cv.temperature_unit)
|
schema = vol.Schema(cv.temperature_unit)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue