From 7e7015db5597f7b72a7088f455f3fbca2d0defd8 Mon Sep 17 00:00:00 2001 From: Robbie Trencheny Date: Fri, 14 Feb 2020 00:25:39 -0800 Subject: [PATCH] Initial version of encrypted notifications support --- homeassistant/components/mobile_app/const.py | 1 + .../components/mobile_app/helpers.py | 24 ++++++++++++------- homeassistant/components/mobile_app/notify.py | 18 ++++++++++++++ 3 files changed, 35 insertions(+), 8 deletions(-) diff --git a/homeassistant/components/mobile_app/const.py b/homeassistant/components/mobile_app/const.py index f43f1c88396d3..114b4afd22f51 100644 --- a/homeassistant/components/mobile_app/const.py +++ b/homeassistant/components/mobile_app/const.py @@ -27,6 +27,7 @@ ATTR_MODEL = "model" ATTR_OS_NAME = "os_name" ATTR_OS_VERSION = "os_version" +ATTR_PUSH_SUPPORTS_ENCRYPTION = "push_supports_encryption" ATTR_PUSH_TOKEN = "push_token" ATTR_PUSH_URL = "push_url" ATTR_PUSH_RATE_LIMITS = "rateLimits" diff --git a/homeassistant/components/mobile_app/helpers.py b/homeassistant/components/mobile_app/helpers.py index 400ff31be89e3..d3a942d19e3fb 100644 --- a/homeassistant/components/mobile_app/helpers.py +++ b/homeassistant/components/mobile_app/helpers.py @@ -59,6 +59,16 @@ def encrypt(ciphertext, key): return (SecretBox.KEY_SIZE, encrypt) +def _encrypt_payload(reg_secret: str, payload: str) -> str: + keylen, encrypt = setup_encrypt() + + key = reg_secret.encode("utf-8") + key = key[:keylen] + key = key.ljust(keylen, b"\0") + + return encrypt(payload.encode("utf-8"), key).decode("utf-8") + + def _decrypt_payload(key: str, ciphertext: str) -> Dict[str, str]: """Decrypt encrypted payload.""" try: @@ -150,14 +160,12 @@ def webhook_response( data = json.dumps(data, cls=JSONEncoder) if registration[ATTR_SUPPORTS_ENCRYPTION]: - keylen, encrypt = setup_encrypt() - - key = registration[CONF_SECRET].encode("utf-8") - key = key[:keylen] - key = key.ljust(keylen, b"\0") - - enc_data = encrypt(data.encode("utf-8"), key).decode("utf-8") - data = json.dumps({"encrypted": True, "encrypted_data": enc_data}) + data = json.dumps( + { + "encrypted": True, + "encrypted_data": _encrypt_payload(registration[CONF_SECRET], data), + } + ) return Response( text=data, status=status, content_type="application/json", headers=headers diff --git a/homeassistant/components/mobile_app/notify.py b/homeassistant/components/mobile_app/notify.py index b16c47e29c0ed..72c6c9a68165f 100644 --- a/homeassistant/components/mobile_app/notify.py +++ b/homeassistant/components/mobile_app/notify.py @@ -20,17 +20,22 @@ ATTR_APP_ID, ATTR_APP_VERSION, ATTR_DEVICE_NAME, + ATTR_OS_NAME, ATTR_OS_VERSION, ATTR_PUSH_RATE_LIMITS, ATTR_PUSH_RATE_LIMITS_ERRORS, ATTR_PUSH_RATE_LIMITS_MAXIMUM, ATTR_PUSH_RATE_LIMITS_RESETS_AT, ATTR_PUSH_RATE_LIMITS_SUCCESSFUL, + ATTR_PUSH_SUPPORTS_ENCRYPTION, ATTR_PUSH_TOKEN, ATTR_PUSH_URL, + ATTR_SUPPORTS_ENCRYPTION, + CONF_SECRET, DATA_CONFIG_ENTRIES, DOMAIN, ) +from .helpers import _encrypt_payload _LOGGER = logging.getLogger(__name__) @@ -124,11 +129,24 @@ async def async_send_message(self, message="", **kwargs): ATTR_APP_ID: entry_data[ATTR_APP_ID], ATTR_APP_VERSION: entry_data[ATTR_APP_VERSION], } + if ATTR_OS_NAME in entry_data: + reg_info[ATTR_OS_NAME] = entry_data[ATTR_OS_NAME] if ATTR_OS_VERSION in entry_data: reg_info[ATTR_OS_VERSION] = entry_data[ATTR_OS_VERSION] data["registration_info"] = reg_info + if ( + entry_data[ATTR_SUPPORTS_ENCRYPTION] + and app_data[ATTR_PUSH_SUPPORTS_ENCRYPTION] + ): + data = { + "encrypted": True, + "encrypted_data": _encrypt_payload(entry_data[CONF_SECRET], data), + ATTR_PUSH_TOKEN: push_token, + "registration_info": reg_info, + } + try: with async_timeout.timeout(10): response = await self._session.post(push_url, json=data)