Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion homeassistant/components/pushover/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"domain": "pushover",
"name": "Pushover",
"documentation": "https://www.home-assistant.io/integrations/pushover",
"requirements": ["python-pushover==0.4"],
"requirements": ["pushover_complete==1.1.1"],
"dependencies": [],
"codeowners": []
}
83 changes: 54 additions & 29 deletions homeassistant/components/pushover/notify.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"""Pushover platform for notify component."""
import logging

from pushover import Client, InitError, RequestError
from pushover_complete import PushoverAPI
import requests
import voluptuous as vol

Expand All @@ -19,6 +19,15 @@
_LOGGER = logging.getLogger(__name__)

ATTR_ATTACHMENT = "attachment"
ATTR_URL = "url"
ATTR_URL_TITLE = "url_title"
ATTR_PRIORITY = "priority"
ATTR_RETRY = "retry"
ATTR_SOUND = "sound"
ATTR_HTML = "html"
ATTR_CALLBACK_URL = "callback_url"
ATTR_EXPIRE = "expire"
ATTR_TIMESTAMP = "timestamp"

CONF_USER_KEY = "user_key"

Expand All @@ -29,13 +38,9 @@

def get_service(hass, config, discovery_info=None):
"""Get the Pushover notification service."""
try:
return PushoverNotificationService(
hass, config[CONF_USER_KEY], config[CONF_API_KEY]
)
except InitError:
_LOGGER.error("Wrong API key supplied")
return None
return PushoverNotificationService(
hass, config[CONF_USER_KEY], config[CONF_API_KEY]
)


class PushoverNotificationService(BaseNotificationService):
Expand All @@ -46,67 +51,87 @@ def __init__(self, hass, user_key, api_token):
self._hass = hass
self._user_key = user_key
self._api_token = api_token
self.pushover = Client(self._user_key, api_token=self._api_token)
self.pushover = PushoverAPI(self._api_token)

def send_message(self, message="", **kwargs):
"""Send a message to a user."""
# Make a copy and use empty dict if necessary
data = dict(kwargs.get(ATTR_DATA) or {})

data["title"] = kwargs.get(ATTR_TITLE, ATTR_TITLE_DEFAULT)

# Check for attachment.
if ATTR_ATTACHMENT in data:
# Extract params from data dict
title = kwargs.get(ATTR_TITLE, ATTR_TITLE_DEFAULT)
data = dict(kwargs.get(ATTR_DATA) or {})
url = data.get(ATTR_URL, None)
url_title = data.get(ATTR_URL_TITLE, None)
priority = data.get(ATTR_PRIORITY, None)
retry = data.get(ATTR_PRIORITY, None)
expire = data.get(ATTR_EXPIRE, None)
callback_url = data.get(ATTR_CALLBACK_URL, None)
timestamp = data.get(ATTR_TIMESTAMP, None)
sound = data.get(ATTR_SOUND, None)
html = 1 if data.get(ATTR_HTML, False) else 0

image = data.get(ATTR_ATTACHMENT, None)
# Check for attachment
if image is not None:
# If attachment is a URL, use requests to open it as a stream.
if data[ATTR_ATTACHMENT].startswith("http"):
if image.startswith("http"):
try:
response = requests.get(
data[ATTR_ATTACHMENT], stream=True, timeout=5

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove this. We should not allow Home Assistant to download URLs and then send it out in a notification. Sending out urls is fine. Sending out from a whitelisted path is fine too.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I'm fine with removing it, I'm not using it anyways.

But this was also possible before.

And I think it is not possible to call from outside or without authentication, so I guess it's not harmful? What about sending a picture from a camera with the notification? I guess it would be useful to download urls then?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was possible before but it will be removed from all notification integrations. It's dangerous because the Home Assistant machine can now download anything, including pages that are localhost only and send it to another computer.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. Now it only checks agains whitelisted path and refuse other attachments.

)
if response.status_code == 200:
# Replace the attachment identifier with file object.
data[ATTR_ATTACHMENT] = response.content
image = response.content
else:
_LOGGER.error(
"Failed to download image %s, response code: %d",
data[ATTR_ATTACHMENT],
response.status_code,
)
# Remove attachment key to send without attachment.
del data[ATTR_ATTACHMENT]
image = None
except requests.exceptions.RequestException as ex_val:
_LOGGER.error(ex_val)
# Remove attachment key to try sending without attachment
del data[ATTR_ATTACHMENT]
# Remove attachment key to send without attachment.
image = None
else:
# Not a URL, check valid path first
if self._hass.config.is_allowed_path(data[ATTR_ATTACHMENT]):
# try to open it as a normal file.
try:
file_handle = open(data[ATTR_ATTACHMENT], "rb")
# Replace the attachment identifier with file object.
data[ATTR_ATTACHMENT] = file_handle
image = file_handle
except OSError as ex_val:
_LOGGER.error(ex_val)
# Remove attachment key to send without attachment.
del data[ATTR_ATTACHMENT]
image = None
else:
_LOGGER.error("Path is not whitelisted")
# Remove attachment key to send without attachment.
del data[ATTR_ATTACHMENT]
image = None

targets = kwargs.get(ATTR_TARGET)

if not isinstance(targets, list):
targets = [targets]

for target in targets:
if target is not None:
data["device"] = target

try:
self.pushover.send_message(message, **data)
self.pushover.send_message(
self._user_key,
message,
target,
title,
url,
url_title,
image,
priority,
retry,
expire,
callback_url,
timestamp,
sound,
html,
)
except ValueError as val_err:
_LOGGER.error(val_err)
except RequestError:
_LOGGER.exception("Could not send pushover notification")
6 changes: 3 additions & 3 deletions requirements_all.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1064,6 +1064,9 @@ pushbullet.py==0.11.0
# homeassistant.components.pushetta
pushetta==1.0.15

# homeassistant.components.pushover
pushover_complete==1.1.1

# homeassistant.components.rpi_gpio_pwm
pwmled==1.4.1

Expand Down Expand Up @@ -1605,9 +1608,6 @@ python-nest==4.1.0
# homeassistant.components.nmap_tracker
python-nmap==0.6.1

# homeassistant.components.pushover
python-pushover==0.4

# homeassistant.components.qbittorrent
python-qbittorrent==0.4.1

Expand Down