Raise on smtp notification if attachment is not allowed (#104981)
* Raise smtp notification if attachment not allowed * Pass url as placeholder * Use variable in err message * Add allow_list as placeholder
This commit is contained in:
parent
204cc20bc2
commit
64f7855b94
3 changed files with 38 additions and 10 deletions
|
@ -32,6 +32,7 @@ from homeassistant.const import (
|
||||||
Platform,
|
Platform,
|
||||||
)
|
)
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
|
from homeassistant.exceptions import ServiceValidationError
|
||||||
import homeassistant.helpers.config_validation as cv
|
import homeassistant.helpers.config_validation as cv
|
||||||
from homeassistant.helpers.reload import setup_reload_service
|
from homeassistant.helpers.reload import setup_reload_service
|
||||||
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
|
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
|
||||||
|
@ -255,13 +256,26 @@ def _attach_file(hass, atch_name, content_id=""):
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
file_path = Path(atch_name).parent
|
file_path = Path(atch_name).parent
|
||||||
if not hass.config.is_allowed_path(str(file_path)):
|
if os.path.exists(file_path) and not hass.config.is_allowed_path(
|
||||||
_LOGGER.warning(
|
str(file_path)
|
||||||
"'%s' is not secure to load data from, ignoring attachment '%s'!",
|
):
|
||||||
file_path,
|
allow_list = "allowlist_external_dirs"
|
||||||
atch_name,
|
file_name = os.path.basename(atch_name)
|
||||||
|
url = "https://www.home-assistant.io/docs/configuration/basic/"
|
||||||
|
raise ServiceValidationError(
|
||||||
|
f"Cannot send email with attachment '{file_name} "
|
||||||
|
f"from directory '{file_path} which is not secure to load data from. "
|
||||||
|
f"Only folders added to `{allow_list}` are accessible. "
|
||||||
|
f"See {url} for more information.",
|
||||||
|
translation_domain=DOMAIN,
|
||||||
|
translation_key="remote_path_not_allowed",
|
||||||
|
translation_placeholders={
|
||||||
|
"allow_list": allow_list,
|
||||||
|
"file_path": file_path,
|
||||||
|
"file_name": file_name,
|
||||||
|
"url": url,
|
||||||
|
},
|
||||||
)
|
)
|
||||||
return
|
|
||||||
with open(atch_name, "rb") as attachment_file:
|
with open(atch_name, "rb") as attachment_file:
|
||||||
file_bytes = attachment_file.read()
|
file_bytes = attachment_file.read()
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
|
|
|
@ -4,5 +4,10 @@
|
||||||
"name": "[%key:common::action::reload%]",
|
"name": "[%key:common::action::reload%]",
|
||||||
"description": "Reloads smtp notify services."
|
"description": "Reloads smtp notify services."
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"exceptions": {
|
||||||
|
"remote_path_not_allowed": {
|
||||||
|
"message": "Cannot send email with attachment '{file_name} form directory '{file_path} which is not secure to load data from. Only folders added to `{allow_list}` are accessible. See {url} for more information."
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ from homeassistant.components.smtp.const import DOMAIN
|
||||||
from homeassistant.components.smtp.notify import MailNotificationService
|
from homeassistant.components.smtp.notify import MailNotificationService
|
||||||
from homeassistant.const import SERVICE_RELOAD
|
from homeassistant.const import SERVICE_RELOAD
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
|
from homeassistant.exceptions import ServiceValidationError
|
||||||
from homeassistant.setup import async_setup_component
|
from homeassistant.setup import async_setup_component
|
||||||
|
|
||||||
from tests.common import get_fixture_path
|
from tests.common import get_fixture_path
|
||||||
|
@ -111,7 +112,7 @@ EMAIL_DATA = [
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"Test msg",
|
"Test msg",
|
||||||
{"html": HTML, "images": ["test.jpg"]},
|
{"html": HTML, "images": ["tests/testing_config/notify/test_not_exists.jpg"]},
|
||||||
"Content-Type: multipart/related",
|
"Content-Type: multipart/related",
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
|
@ -156,7 +157,6 @@ def test_send_message(
|
||||||
)
|
)
|
||||||
def test_sending_insecure_files_fails(
|
def test_sending_insecure_files_fails(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
caplog: pytest.LogCaptureFixture,
|
|
||||||
message_data,
|
message_data,
|
||||||
data,
|
data,
|
||||||
content_type,
|
content_type,
|
||||||
|
@ -165,10 +165,19 @@ def test_sending_insecure_files_fails(
|
||||||
"""Verify if we cannot send messages with insecure attachments."""
|
"""Verify if we cannot send messages with insecure attachments."""
|
||||||
sample_email = "<mock@mock>"
|
sample_email = "<mock@mock>"
|
||||||
message.hass = hass
|
message.hass = hass
|
||||||
with patch("email.utils.make_msgid", return_value=sample_email):
|
with patch("email.utils.make_msgid", return_value=sample_email), pytest.raises(
|
||||||
|
ServiceValidationError
|
||||||
|
) as exc:
|
||||||
result, _ = message.send_message(message_data, data=data)
|
result, _ = message.send_message(message_data, data=data)
|
||||||
assert content_type in result
|
assert content_type in result
|
||||||
assert "test.jpg' is not secure to load data from, ignoring attachment"
|
assert exc.value.translation_key == "remote_path_not_allowed"
|
||||||
|
assert exc.value.translation_domain == DOMAIN
|
||||||
|
assert (
|
||||||
|
str(exc.value.translation_placeholders["file_path"])
|
||||||
|
== "tests/testing_config/notify"
|
||||||
|
)
|
||||||
|
assert exc.value.translation_placeholders["url"]
|
||||||
|
assert exc.value.translation_placeholders["file_name"] == "test.jpg"
|
||||||
|
|
||||||
|
|
||||||
def test_send_text_message(hass: HomeAssistant, message) -> None:
|
def test_send_text_message(hass: HomeAssistant, message) -> None:
|
||||||
|
|
Loading…
Add table
Reference in a new issue