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:
Jan Bouwhuis 2023-12-04 11:48:29 +01:00 committed by Franck Nijhof
parent 204cc20bc2
commit 64f7855b94
No known key found for this signature in database
GPG key ID: D62583BA8AB11CA3
3 changed files with 38 additions and 10 deletions

View file

@ -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:

View file

@ -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."
}
} }
} }

View file

@ -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: