core/homeassistant/components/mobile_app/helpers.py

214 lines
6.2 KiB
Python
Raw Normal View History

mobile_app improvements (#21607) * First webhook commands for getting and deleting single registrations * Keep a list of deleted webhook IDs so we can 410 if the webhook receives traffic in the future * Return a empty JSON object instead of None * Split up mobile_app bits into individual files * Add typing * Sort keys * Remove unused async_setup_entry * New decorator method of registering webhooks * Add tests for cloud hook forwarding and improve error handling for cloud hooks * Initial implementation of platform specific logic * Add get registrations by user ID websocket call, minor style fixes * Stop using resp dictionary during registration * Move mobile_app/ios.py to ios/mobile_app.py * Log any errors encountered during webhook * Improve update registration call * Split up mobile_app tests to match split up component * Fix tests * Remove integration_map in favor of component name in registration * Add a few helper functions for custom logic components to use * Load the app_component platform at device registration or component setup time * Remove extraneous function * Use guard function for checking if component is in device * Inline websocket schemas * Rename ATTR_s used in storage to DATA_ prefix * squash flake8 and pylint issues * Remove ios.mobile_app platform * Dont mark websocket_api as a dependency * Return standard empty_okay_response with 400 if no JSON sent * Ensure deleted webhook IDs are registered at launch * Remove the creation of cloudhooks during handle_webhook * Rename device to registration everywhere applicable * Dont check if cloud is logged in, just check if cloud is in components * Dont ever use cloudhook_id * Remove component loading logic for a later PR * Cast exception to string * Remove unused functions
2019-03-09 07:44:56 +00:00
"""Helpers for mobile_app."""
2021-03-18 12:07:04 +00:00
from __future__ import annotations
from collections.abc import Callable
from http import HTTPStatus
mobile_app improvements (#21607) * First webhook commands for getting and deleting single registrations * Keep a list of deleted webhook IDs so we can 410 if the webhook receives traffic in the future * Return a empty JSON object instead of None * Split up mobile_app bits into individual files * Add typing * Sort keys * Remove unused async_setup_entry * New decorator method of registering webhooks * Add tests for cloud hook forwarding and improve error handling for cloud hooks * Initial implementation of platform specific logic * Add get registrations by user ID websocket call, minor style fixes * Stop using resp dictionary during registration * Move mobile_app/ios.py to ios/mobile_app.py * Log any errors encountered during webhook * Improve update registration call * Split up mobile_app tests to match split up component * Fix tests * Remove integration_map in favor of component name in registration * Add a few helper functions for custom logic components to use * Load the app_component platform at device registration or component setup time * Remove extraneous function * Use guard function for checking if component is in device * Inline websocket schemas * Rename ATTR_s used in storage to DATA_ prefix * squash flake8 and pylint issues * Remove ios.mobile_app platform * Dont mark websocket_api as a dependency * Return standard empty_okay_response with 400 if no JSON sent * Ensure deleted webhook IDs are registered at launch * Remove the creation of cloudhooks during handle_webhook * Rename device to registration everywhere applicable * Dont check if cloud is logged in, just check if cloud is in components * Dont ever use cloudhook_id * Remove component loading logic for a later PR * Cast exception to string * Remove unused functions
2019-03-09 07:44:56 +00:00
import json
import logging
mobile_app improvements (#21607) * First webhook commands for getting and deleting single registrations * Keep a list of deleted webhook IDs so we can 410 if the webhook receives traffic in the future * Return a empty JSON object instead of None * Split up mobile_app bits into individual files * Add typing * Sort keys * Remove unused async_setup_entry * New decorator method of registering webhooks * Add tests for cloud hook forwarding and improve error handling for cloud hooks * Initial implementation of platform specific logic * Add get registrations by user ID websocket call, minor style fixes * Stop using resp dictionary during registration * Move mobile_app/ios.py to ios/mobile_app.py * Log any errors encountered during webhook * Improve update registration call * Split up mobile_app tests to match split up component * Fix tests * Remove integration_map in favor of component name in registration * Add a few helper functions for custom logic components to use * Load the app_component platform at device registration or component setup time * Remove extraneous function * Use guard function for checking if component is in device * Inline websocket schemas * Rename ATTR_s used in storage to DATA_ prefix * squash flake8 and pylint issues * Remove ios.mobile_app platform * Dont mark websocket_api as a dependency * Return standard empty_okay_response with 400 if no JSON sent * Ensure deleted webhook IDs are registered at launch * Remove the creation of cloudhooks during handle_webhook * Rename device to registration everywhere applicable * Dont check if cloud is logged in, just check if cloud is in components * Dont ever use cloudhook_id * Remove component loading logic for a later PR * Cast exception to string * Remove unused functions
2019-03-09 07:44:56 +00:00
from aiohttp.web import Response, json_response
from nacl.encoding import Base64Encoder, HexEncoder, RawEncoder
from nacl.secret import SecretBox
mobile_app improvements (#21607) * First webhook commands for getting and deleting single registrations * Keep a list of deleted webhook IDs so we can 410 if the webhook receives traffic in the future * Return a empty JSON object instead of None * Split up mobile_app bits into individual files * Add typing * Sort keys * Remove unused async_setup_entry * New decorator method of registering webhooks * Add tests for cloud hook forwarding and improve error handling for cloud hooks * Initial implementation of platform specific logic * Add get registrations by user ID websocket call, minor style fixes * Stop using resp dictionary during registration * Move mobile_app/ios.py to ios/mobile_app.py * Log any errors encountered during webhook * Improve update registration call * Split up mobile_app tests to match split up component * Fix tests * Remove integration_map in favor of component name in registration * Add a few helper functions for custom logic components to use * Load the app_component platform at device registration or component setup time * Remove extraneous function * Use guard function for checking if component is in device * Inline websocket schemas * Rename ATTR_s used in storage to DATA_ prefix * squash flake8 and pylint issues * Remove ios.mobile_app platform * Dont mark websocket_api as a dependency * Return standard empty_okay_response with 400 if no JSON sent * Ensure deleted webhook IDs are registered at launch * Remove the creation of cloudhooks during handle_webhook * Rename device to registration everywhere applicable * Dont check if cloud is logged in, just check if cloud is in components * Dont ever use cloudhook_id * Remove component loading logic for a later PR * Cast exception to string * Remove unused functions
2019-03-09 07:44:56 +00:00
from homeassistant.const import ATTR_DEVICE_ID, CONTENT_TYPE_JSON
from homeassistant.core import Context, HomeAssistant
from homeassistant.helpers.entity import DeviceInfo
from homeassistant.helpers.json import JSONEncoder, json_loads
mobile_app improvements (#21607) * First webhook commands for getting and deleting single registrations * Keep a list of deleted webhook IDs so we can 410 if the webhook receives traffic in the future * Return a empty JSON object instead of None * Split up mobile_app bits into individual files * Add typing * Sort keys * Remove unused async_setup_entry * New decorator method of registering webhooks * Add tests for cloud hook forwarding and improve error handling for cloud hooks * Initial implementation of platform specific logic * Add get registrations by user ID websocket call, minor style fixes * Stop using resp dictionary during registration * Move mobile_app/ios.py to ios/mobile_app.py * Log any errors encountered during webhook * Improve update registration call * Split up mobile_app tests to match split up component * Fix tests * Remove integration_map in favor of component name in registration * Add a few helper functions for custom logic components to use * Load the app_component platform at device registration or component setup time * Remove extraneous function * Use guard function for checking if component is in device * Inline websocket schemas * Rename ATTR_s used in storage to DATA_ prefix * squash flake8 and pylint issues * Remove ios.mobile_app platform * Dont mark websocket_api as a dependency * Return standard empty_okay_response with 400 if no JSON sent * Ensure deleted webhook IDs are registered at launch * Remove the creation of cloudhooks during handle_webhook * Rename device to registration everywhere applicable * Dont check if cloud is logged in, just check if cloud is in components * Dont ever use cloudhook_id * Remove component loading logic for a later PR * Cast exception to string * Remove unused functions
2019-03-09 07:44:56 +00:00
2019-07-31 19:25:30 +00:00
from .const import (
ATTR_APP_DATA,
ATTR_APP_ID,
ATTR_APP_NAME,
ATTR_APP_VERSION,
ATTR_DEVICE_NAME,
ATTR_MANUFACTURER,
ATTR_MODEL,
ATTR_NO_LEGACY_ENCRYPTION,
2019-07-31 19:25:30 +00:00
ATTR_OS_VERSION,
ATTR_SUPPORTS_ENCRYPTION,
CONF_SECRET,
CONF_USER_ID,
DATA_DELETED_IDS,
DOMAIN,
)
mobile_app improvements (#21607) * First webhook commands for getting and deleting single registrations * Keep a list of deleted webhook IDs so we can 410 if the webhook receives traffic in the future * Return a empty JSON object instead of None * Split up mobile_app bits into individual files * Add typing * Sort keys * Remove unused async_setup_entry * New decorator method of registering webhooks * Add tests for cloud hook forwarding and improve error handling for cloud hooks * Initial implementation of platform specific logic * Add get registrations by user ID websocket call, minor style fixes * Stop using resp dictionary during registration * Move mobile_app/ios.py to ios/mobile_app.py * Log any errors encountered during webhook * Improve update registration call * Split up mobile_app tests to match split up component * Fix tests * Remove integration_map in favor of component name in registration * Add a few helper functions for custom logic components to use * Load the app_component platform at device registration or component setup time * Remove extraneous function * Use guard function for checking if component is in device * Inline websocket schemas * Rename ATTR_s used in storage to DATA_ prefix * squash flake8 and pylint issues * Remove ios.mobile_app platform * Dont mark websocket_api as a dependency * Return standard empty_okay_response with 400 if no JSON sent * Ensure deleted webhook IDs are registered at launch * Remove the creation of cloudhooks during handle_webhook * Rename device to registration everywhere applicable * Dont check if cloud is logged in, just check if cloud is in components * Dont ever use cloudhook_id * Remove component loading logic for a later PR * Cast exception to string * Remove unused functions
2019-03-09 07:44:56 +00:00
_LOGGER = logging.getLogger(__name__)
def setup_decrypt(key_encoder) -> tuple[int, Callable]:
mobile_app improvements (#21607) * First webhook commands for getting and deleting single registrations * Keep a list of deleted webhook IDs so we can 410 if the webhook receives traffic in the future * Return a empty JSON object instead of None * Split up mobile_app bits into individual files * Add typing * Sort keys * Remove unused async_setup_entry * New decorator method of registering webhooks * Add tests for cloud hook forwarding and improve error handling for cloud hooks * Initial implementation of platform specific logic * Add get registrations by user ID websocket call, minor style fixes * Stop using resp dictionary during registration * Move mobile_app/ios.py to ios/mobile_app.py * Log any errors encountered during webhook * Improve update registration call * Split up mobile_app tests to match split up component * Fix tests * Remove integration_map in favor of component name in registration * Add a few helper functions for custom logic components to use * Load the app_component platform at device registration or component setup time * Remove extraneous function * Use guard function for checking if component is in device * Inline websocket schemas * Rename ATTR_s used in storage to DATA_ prefix * squash flake8 and pylint issues * Remove ios.mobile_app platform * Dont mark websocket_api as a dependency * Return standard empty_okay_response with 400 if no JSON sent * Ensure deleted webhook IDs are registered at launch * Remove the creation of cloudhooks during handle_webhook * Rename device to registration everywhere applicable * Dont check if cloud is logged in, just check if cloud is in components * Dont ever use cloudhook_id * Remove component loading logic for a later PR * Cast exception to string * Remove unused functions
2019-03-09 07:44:56 +00:00
"""Return decryption function and length of key.
Async friendly.
"""
def decrypt(ciphertext, key):
"""Decrypt ciphertext using key."""
return SecretBox(key, encoder=key_encoder).decrypt(
ciphertext, encoder=Base64Encoder
)
2019-07-31 19:25:30 +00:00
mobile_app improvements (#21607) * First webhook commands for getting and deleting single registrations * Keep a list of deleted webhook IDs so we can 410 if the webhook receives traffic in the future * Return a empty JSON object instead of None * Split up mobile_app bits into individual files * Add typing * Sort keys * Remove unused async_setup_entry * New decorator method of registering webhooks * Add tests for cloud hook forwarding and improve error handling for cloud hooks * Initial implementation of platform specific logic * Add get registrations by user ID websocket call, minor style fixes * Stop using resp dictionary during registration * Move mobile_app/ios.py to ios/mobile_app.py * Log any errors encountered during webhook * Improve update registration call * Split up mobile_app tests to match split up component * Fix tests * Remove integration_map in favor of component name in registration * Add a few helper functions for custom logic components to use * Load the app_component platform at device registration or component setup time * Remove extraneous function * Use guard function for checking if component is in device * Inline websocket schemas * Rename ATTR_s used in storage to DATA_ prefix * squash flake8 and pylint issues * Remove ios.mobile_app platform * Dont mark websocket_api as a dependency * Return standard empty_okay_response with 400 if no JSON sent * Ensure deleted webhook IDs are registered at launch * Remove the creation of cloudhooks during handle_webhook * Rename device to registration everywhere applicable * Dont check if cloud is logged in, just check if cloud is in components * Dont ever use cloudhook_id * Remove component loading logic for a later PR * Cast exception to string * Remove unused functions
2019-03-09 07:44:56 +00:00
return (SecretBox.KEY_SIZE, decrypt)
def setup_encrypt(key_encoder) -> tuple[int, Callable]:
"""Return encryption function and length of key.
Async friendly.
"""
def encrypt(ciphertext, key):
"""Encrypt ciphertext using key."""
return SecretBox(key, encoder=key_encoder).encrypt(
ciphertext, encoder=Base64Encoder
)
2019-07-31 19:25:30 +00:00
return (SecretBox.KEY_SIZE, encrypt)
def _decrypt_payload_helper(
key: str | None,
ciphertext: str,
get_key_bytes: Callable[[str, int], str | bytes],
key_encoder,
) -> dict[str, str] | None:
mobile_app improvements (#21607) * First webhook commands for getting and deleting single registrations * Keep a list of deleted webhook IDs so we can 410 if the webhook receives traffic in the future * Return a empty JSON object instead of None * Split up mobile_app bits into individual files * Add typing * Sort keys * Remove unused async_setup_entry * New decorator method of registering webhooks * Add tests for cloud hook forwarding and improve error handling for cloud hooks * Initial implementation of platform specific logic * Add get registrations by user ID websocket call, minor style fixes * Stop using resp dictionary during registration * Move mobile_app/ios.py to ios/mobile_app.py * Log any errors encountered during webhook * Improve update registration call * Split up mobile_app tests to match split up component * Fix tests * Remove integration_map in favor of component name in registration * Add a few helper functions for custom logic components to use * Load the app_component platform at device registration or component setup time * Remove extraneous function * Use guard function for checking if component is in device * Inline websocket schemas * Rename ATTR_s used in storage to DATA_ prefix * squash flake8 and pylint issues * Remove ios.mobile_app platform * Dont mark websocket_api as a dependency * Return standard empty_okay_response with 400 if no JSON sent * Ensure deleted webhook IDs are registered at launch * Remove the creation of cloudhooks during handle_webhook * Rename device to registration everywhere applicable * Dont check if cloud is logged in, just check if cloud is in components * Dont ever use cloudhook_id * Remove component loading logic for a later PR * Cast exception to string * Remove unused functions
2019-03-09 07:44:56 +00:00
"""Decrypt encrypted payload."""
try:
keylen, decrypt = setup_decrypt(key_encoder)
mobile_app improvements (#21607) * First webhook commands for getting and deleting single registrations * Keep a list of deleted webhook IDs so we can 410 if the webhook receives traffic in the future * Return a empty JSON object instead of None * Split up mobile_app bits into individual files * Add typing * Sort keys * Remove unused async_setup_entry * New decorator method of registering webhooks * Add tests for cloud hook forwarding and improve error handling for cloud hooks * Initial implementation of platform specific logic * Add get registrations by user ID websocket call, minor style fixes * Stop using resp dictionary during registration * Move mobile_app/ios.py to ios/mobile_app.py * Log any errors encountered during webhook * Improve update registration call * Split up mobile_app tests to match split up component * Fix tests * Remove integration_map in favor of component name in registration * Add a few helper functions for custom logic components to use * Load the app_component platform at device registration or component setup time * Remove extraneous function * Use guard function for checking if component is in device * Inline websocket schemas * Rename ATTR_s used in storage to DATA_ prefix * squash flake8 and pylint issues * Remove ios.mobile_app platform * Dont mark websocket_api as a dependency * Return standard empty_okay_response with 400 if no JSON sent * Ensure deleted webhook IDs are registered at launch * Remove the creation of cloudhooks during handle_webhook * Rename device to registration everywhere applicable * Dont check if cloud is logged in, just check if cloud is in components * Dont ever use cloudhook_id * Remove component loading logic for a later PR * Cast exception to string * Remove unused functions
2019-03-09 07:44:56 +00:00
except OSError:
2019-07-31 19:25:30 +00:00
_LOGGER.warning("Ignoring encrypted payload because libsodium not installed")
mobile_app improvements (#21607) * First webhook commands for getting and deleting single registrations * Keep a list of deleted webhook IDs so we can 410 if the webhook receives traffic in the future * Return a empty JSON object instead of None * Split up mobile_app bits into individual files * Add typing * Sort keys * Remove unused async_setup_entry * New decorator method of registering webhooks * Add tests for cloud hook forwarding and improve error handling for cloud hooks * Initial implementation of platform specific logic * Add get registrations by user ID websocket call, minor style fixes * Stop using resp dictionary during registration * Move mobile_app/ios.py to ios/mobile_app.py * Log any errors encountered during webhook * Improve update registration call * Split up mobile_app tests to match split up component * Fix tests * Remove integration_map in favor of component name in registration * Add a few helper functions for custom logic components to use * Load the app_component platform at device registration or component setup time * Remove extraneous function * Use guard function for checking if component is in device * Inline websocket schemas * Rename ATTR_s used in storage to DATA_ prefix * squash flake8 and pylint issues * Remove ios.mobile_app platform * Dont mark websocket_api as a dependency * Return standard empty_okay_response with 400 if no JSON sent * Ensure deleted webhook IDs are registered at launch * Remove the creation of cloudhooks during handle_webhook * Rename device to registration everywhere applicable * Dont check if cloud is logged in, just check if cloud is in components * Dont ever use cloudhook_id * Remove component loading logic for a later PR * Cast exception to string * Remove unused functions
2019-03-09 07:44:56 +00:00
return None
if key is None:
2019-07-31 19:25:30 +00:00
_LOGGER.warning("Ignoring encrypted payload because no decryption key known")
mobile_app improvements (#21607) * First webhook commands for getting and deleting single registrations * Keep a list of deleted webhook IDs so we can 410 if the webhook receives traffic in the future * Return a empty JSON object instead of None * Split up mobile_app bits into individual files * Add typing * Sort keys * Remove unused async_setup_entry * New decorator method of registering webhooks * Add tests for cloud hook forwarding and improve error handling for cloud hooks * Initial implementation of platform specific logic * Add get registrations by user ID websocket call, minor style fixes * Stop using resp dictionary during registration * Move mobile_app/ios.py to ios/mobile_app.py * Log any errors encountered during webhook * Improve update registration call * Split up mobile_app tests to match split up component * Fix tests * Remove integration_map in favor of component name in registration * Add a few helper functions for custom logic components to use * Load the app_component platform at device registration or component setup time * Remove extraneous function * Use guard function for checking if component is in device * Inline websocket schemas * Rename ATTR_s used in storage to DATA_ prefix * squash flake8 and pylint issues * Remove ios.mobile_app platform * Dont mark websocket_api as a dependency * Return standard empty_okay_response with 400 if no JSON sent * Ensure deleted webhook IDs are registered at launch * Remove the creation of cloudhooks during handle_webhook * Rename device to registration everywhere applicable * Dont check if cloud is logged in, just check if cloud is in components * Dont ever use cloudhook_id * Remove component loading logic for a later PR * Cast exception to string * Remove unused functions
2019-03-09 07:44:56 +00:00
return None
key_bytes = get_key_bytes(key, keylen)
mobile_app improvements (#21607) * First webhook commands for getting and deleting single registrations * Keep a list of deleted webhook IDs so we can 410 if the webhook receives traffic in the future * Return a empty JSON object instead of None * Split up mobile_app bits into individual files * Add typing * Sort keys * Remove unused async_setup_entry * New decorator method of registering webhooks * Add tests for cloud hook forwarding and improve error handling for cloud hooks * Initial implementation of platform specific logic * Add get registrations by user ID websocket call, minor style fixes * Stop using resp dictionary during registration * Move mobile_app/ios.py to ios/mobile_app.py * Log any errors encountered during webhook * Improve update registration call * Split up mobile_app tests to match split up component * Fix tests * Remove integration_map in favor of component name in registration * Add a few helper functions for custom logic components to use * Load the app_component platform at device registration or component setup time * Remove extraneous function * Use guard function for checking if component is in device * Inline websocket schemas * Rename ATTR_s used in storage to DATA_ prefix * squash flake8 and pylint issues * Remove ios.mobile_app platform * Dont mark websocket_api as a dependency * Return standard empty_okay_response with 400 if no JSON sent * Ensure deleted webhook IDs are registered at launch * Remove the creation of cloudhooks during handle_webhook * Rename device to registration everywhere applicable * Dont check if cloud is logged in, just check if cloud is in components * Dont ever use cloudhook_id * Remove component loading logic for a later PR * Cast exception to string * Remove unused functions
2019-03-09 07:44:56 +00:00
msg_bytes = decrypt(ciphertext, key_bytes)
message = json_loads(msg_bytes)
_LOGGER.debug("Successfully decrypted mobile_app payload")
return message
def _decrypt_payload(key: str | None, ciphertext: str) -> dict[str, str] | None:
"""Decrypt encrypted payload."""
def get_key_bytes(key: str, keylen: int) -> str:
return key
return _decrypt_payload_helper(key, ciphertext, get_key_bytes, HexEncoder)
def _decrypt_payload_legacy(key: str | None, ciphertext: str) -> dict[str, str] | None:
"""Decrypt encrypted payload."""
def get_key_bytes(key: str, keylen: int) -> bytes:
key_bytes = key.encode("utf-8")
key_bytes = key_bytes[:keylen]
key_bytes = key_bytes.ljust(keylen, b"\0")
return key_bytes
return _decrypt_payload_helper(key, ciphertext, get_key_bytes, RawEncoder)
mobile_app improvements (#21607) * First webhook commands for getting and deleting single registrations * Keep a list of deleted webhook IDs so we can 410 if the webhook receives traffic in the future * Return a empty JSON object instead of None * Split up mobile_app bits into individual files * Add typing * Sort keys * Remove unused async_setup_entry * New decorator method of registering webhooks * Add tests for cloud hook forwarding and improve error handling for cloud hooks * Initial implementation of platform specific logic * Add get registrations by user ID websocket call, minor style fixes * Stop using resp dictionary during registration * Move mobile_app/ios.py to ios/mobile_app.py * Log any errors encountered during webhook * Improve update registration call * Split up mobile_app tests to match split up component * Fix tests * Remove integration_map in favor of component name in registration * Add a few helper functions for custom logic components to use * Load the app_component platform at device registration or component setup time * Remove extraneous function * Use guard function for checking if component is in device * Inline websocket schemas * Rename ATTR_s used in storage to DATA_ prefix * squash flake8 and pylint issues * Remove ios.mobile_app platform * Dont mark websocket_api as a dependency * Return standard empty_okay_response with 400 if no JSON sent * Ensure deleted webhook IDs are registered at launch * Remove the creation of cloudhooks during handle_webhook * Rename device to registration everywhere applicable * Dont check if cloud is logged in, just check if cloud is in components * Dont ever use cloudhook_id * Remove component loading logic for a later PR * Cast exception to string * Remove unused functions
2019-03-09 07:44:56 +00:00
2021-03-18 12:07:04 +00:00
def registration_context(registration: dict) -> Context:
mobile_app improvements (#21607) * First webhook commands for getting and deleting single registrations * Keep a list of deleted webhook IDs so we can 410 if the webhook receives traffic in the future * Return a empty JSON object instead of None * Split up mobile_app bits into individual files * Add typing * Sort keys * Remove unused async_setup_entry * New decorator method of registering webhooks * Add tests for cloud hook forwarding and improve error handling for cloud hooks * Initial implementation of platform specific logic * Add get registrations by user ID websocket call, minor style fixes * Stop using resp dictionary during registration * Move mobile_app/ios.py to ios/mobile_app.py * Log any errors encountered during webhook * Improve update registration call * Split up mobile_app tests to match split up component * Fix tests * Remove integration_map in favor of component name in registration * Add a few helper functions for custom logic components to use * Load the app_component platform at device registration or component setup time * Remove extraneous function * Use guard function for checking if component is in device * Inline websocket schemas * Rename ATTR_s used in storage to DATA_ prefix * squash flake8 and pylint issues * Remove ios.mobile_app platform * Dont mark websocket_api as a dependency * Return standard empty_okay_response with 400 if no JSON sent * Ensure deleted webhook IDs are registered at launch * Remove the creation of cloudhooks during handle_webhook * Rename device to registration everywhere applicable * Dont check if cloud is logged in, just check if cloud is in components * Dont ever use cloudhook_id * Remove component loading logic for a later PR * Cast exception to string * Remove unused functions
2019-03-09 07:44:56 +00:00
"""Generate a context from a request."""
return Context(user_id=registration[CONF_USER_ID])
def empty_okay_response(
2022-08-13 16:46:08 +00:00
headers: dict | None = None, status: HTTPStatus = HTTPStatus.OK
) -> Response:
mobile_app improvements (#21607) * First webhook commands for getting and deleting single registrations * Keep a list of deleted webhook IDs so we can 410 if the webhook receives traffic in the future * Return a empty JSON object instead of None * Split up mobile_app bits into individual files * Add typing * Sort keys * Remove unused async_setup_entry * New decorator method of registering webhooks * Add tests for cloud hook forwarding and improve error handling for cloud hooks * Initial implementation of platform specific logic * Add get registrations by user ID websocket call, minor style fixes * Stop using resp dictionary during registration * Move mobile_app/ios.py to ios/mobile_app.py * Log any errors encountered during webhook * Improve update registration call * Split up mobile_app tests to match split up component * Fix tests * Remove integration_map in favor of component name in registration * Add a few helper functions for custom logic components to use * Load the app_component platform at device registration or component setup time * Remove extraneous function * Use guard function for checking if component is in device * Inline websocket schemas * Rename ATTR_s used in storage to DATA_ prefix * squash flake8 and pylint issues * Remove ios.mobile_app platform * Dont mark websocket_api as a dependency * Return standard empty_okay_response with 400 if no JSON sent * Ensure deleted webhook IDs are registered at launch * Remove the creation of cloudhooks during handle_webhook * Rename device to registration everywhere applicable * Dont check if cloud is logged in, just check if cloud is in components * Dont ever use cloudhook_id * Remove component loading logic for a later PR * Cast exception to string * Remove unused functions
2019-03-09 07:44:56 +00:00
"""Return a Response with empty JSON object and a 200."""
2019-07-31 19:25:30 +00:00
return Response(
text="{}", status=status, content_type=CONTENT_TYPE_JSON, headers=headers
2019-07-31 19:25:30 +00:00
)
mobile_app improvements (#21607) * First webhook commands for getting and deleting single registrations * Keep a list of deleted webhook IDs so we can 410 if the webhook receives traffic in the future * Return a empty JSON object instead of None * Split up mobile_app bits into individual files * Add typing * Sort keys * Remove unused async_setup_entry * New decorator method of registering webhooks * Add tests for cloud hook forwarding and improve error handling for cloud hooks * Initial implementation of platform specific logic * Add get registrations by user ID websocket call, minor style fixes * Stop using resp dictionary during registration * Move mobile_app/ios.py to ios/mobile_app.py * Log any errors encountered during webhook * Improve update registration call * Split up mobile_app tests to match split up component * Fix tests * Remove integration_map in favor of component name in registration * Add a few helper functions for custom logic components to use * Load the app_component platform at device registration or component setup time * Remove extraneous function * Use guard function for checking if component is in device * Inline websocket schemas * Rename ATTR_s used in storage to DATA_ prefix * squash flake8 and pylint issues * Remove ios.mobile_app platform * Dont mark websocket_api as a dependency * Return standard empty_okay_response with 400 if no JSON sent * Ensure deleted webhook IDs are registered at launch * Remove the creation of cloudhooks during handle_webhook * Rename device to registration everywhere applicable * Dont check if cloud is logged in, just check if cloud is in components * Dont ever use cloudhook_id * Remove component loading logic for a later PR * Cast exception to string * Remove unused functions
2019-03-09 07:44:56 +00:00
2019-07-31 19:25:30 +00:00
def error_response(
code: str,
message: str,
status: HTTPStatus = HTTPStatus.BAD_REQUEST,
2022-08-13 16:46:08 +00:00
headers: dict | None = None,
2019-07-31 19:25:30 +00:00
) -> Response:
"""Return an error Response."""
2019-07-31 19:25:30 +00:00
return json_response(
{"success": False, "error": {"code": code, "message": message}},
status=status,
headers=headers,
)
mobile_app improvements (#21607) * First webhook commands for getting and deleting single registrations * Keep a list of deleted webhook IDs so we can 410 if the webhook receives traffic in the future * Return a empty JSON object instead of None * Split up mobile_app bits into individual files * Add typing * Sort keys * Remove unused async_setup_entry * New decorator method of registering webhooks * Add tests for cloud hook forwarding and improve error handling for cloud hooks * Initial implementation of platform specific logic * Add get registrations by user ID websocket call, minor style fixes * Stop using resp dictionary during registration * Move mobile_app/ios.py to ios/mobile_app.py * Log any errors encountered during webhook * Improve update registration call * Split up mobile_app tests to match split up component * Fix tests * Remove integration_map in favor of component name in registration * Add a few helper functions for custom logic components to use * Load the app_component platform at device registration or component setup time * Remove extraneous function * Use guard function for checking if component is in device * Inline websocket schemas * Rename ATTR_s used in storage to DATA_ prefix * squash flake8 and pylint issues * Remove ios.mobile_app platform * Dont mark websocket_api as a dependency * Return standard empty_okay_response with 400 if no JSON sent * Ensure deleted webhook IDs are registered at launch * Remove the creation of cloudhooks during handle_webhook * Rename device to registration everywhere applicable * Dont check if cloud is logged in, just check if cloud is in components * Dont ever use cloudhook_id * Remove component loading logic for a later PR * Cast exception to string * Remove unused functions
2019-03-09 07:44:56 +00:00
def supports_encryption() -> bool:
"""Test if we support encryption."""
try:
import nacl # noqa: F401 pylint: disable=unused-import, import-outside-toplevel
2019-07-31 19:25:30 +00:00
mobile_app improvements (#21607) * First webhook commands for getting and deleting single registrations * Keep a list of deleted webhook IDs so we can 410 if the webhook receives traffic in the future * Return a empty JSON object instead of None * Split up mobile_app bits into individual files * Add typing * Sort keys * Remove unused async_setup_entry * New decorator method of registering webhooks * Add tests for cloud hook forwarding and improve error handling for cloud hooks * Initial implementation of platform specific logic * Add get registrations by user ID websocket call, minor style fixes * Stop using resp dictionary during registration * Move mobile_app/ios.py to ios/mobile_app.py * Log any errors encountered during webhook * Improve update registration call * Split up mobile_app tests to match split up component * Fix tests * Remove integration_map in favor of component name in registration * Add a few helper functions for custom logic components to use * Load the app_component platform at device registration or component setup time * Remove extraneous function * Use guard function for checking if component is in device * Inline websocket schemas * Rename ATTR_s used in storage to DATA_ prefix * squash flake8 and pylint issues * Remove ios.mobile_app platform * Dont mark websocket_api as a dependency * Return standard empty_okay_response with 400 if no JSON sent * Ensure deleted webhook IDs are registered at launch * Remove the creation of cloudhooks during handle_webhook * Rename device to registration everywhere applicable * Dont check if cloud is logged in, just check if cloud is in components * Dont ever use cloudhook_id * Remove component loading logic for a later PR * Cast exception to string * Remove unused functions
2019-03-09 07:44:56 +00:00
return True
except OSError:
return False
2021-03-18 12:07:04 +00:00
def safe_registration(registration: dict) -> dict:
mobile_app improvements (#21607) * First webhook commands for getting and deleting single registrations * Keep a list of deleted webhook IDs so we can 410 if the webhook receives traffic in the future * Return a empty JSON object instead of None * Split up mobile_app bits into individual files * Add typing * Sort keys * Remove unused async_setup_entry * New decorator method of registering webhooks * Add tests for cloud hook forwarding and improve error handling for cloud hooks * Initial implementation of platform specific logic * Add get registrations by user ID websocket call, minor style fixes * Stop using resp dictionary during registration * Move mobile_app/ios.py to ios/mobile_app.py * Log any errors encountered during webhook * Improve update registration call * Split up mobile_app tests to match split up component * Fix tests * Remove integration_map in favor of component name in registration * Add a few helper functions for custom logic components to use * Load the app_component platform at device registration or component setup time * Remove extraneous function * Use guard function for checking if component is in device * Inline websocket schemas * Rename ATTR_s used in storage to DATA_ prefix * squash flake8 and pylint issues * Remove ios.mobile_app platform * Dont mark websocket_api as a dependency * Return standard empty_okay_response with 400 if no JSON sent * Ensure deleted webhook IDs are registered at launch * Remove the creation of cloudhooks during handle_webhook * Rename device to registration everywhere applicable * Dont check if cloud is logged in, just check if cloud is in components * Dont ever use cloudhook_id * Remove component loading logic for a later PR * Cast exception to string * Remove unused functions
2019-03-09 07:44:56 +00:00
"""Return a registration without sensitive values."""
# Sensitive values: webhook_id, secret, cloudhook_url
return {
ATTR_APP_DATA: registration[ATTR_APP_DATA],
ATTR_APP_ID: registration[ATTR_APP_ID],
ATTR_APP_NAME: registration[ATTR_APP_NAME],
ATTR_APP_VERSION: registration[ATTR_APP_VERSION],
ATTR_DEVICE_NAME: registration[ATTR_DEVICE_NAME],
ATTR_MANUFACTURER: registration[ATTR_MANUFACTURER],
ATTR_MODEL: registration[ATTR_MODEL],
ATTR_OS_VERSION: registration[ATTR_OS_VERSION],
ATTR_SUPPORTS_ENCRYPTION: registration[ATTR_SUPPORTS_ENCRYPTION],
}
def savable_state(hass: HomeAssistant) -> dict:
mobile_app improvements (#21607) * First webhook commands for getting and deleting single registrations * Keep a list of deleted webhook IDs so we can 410 if the webhook receives traffic in the future * Return a empty JSON object instead of None * Split up mobile_app bits into individual files * Add typing * Sort keys * Remove unused async_setup_entry * New decorator method of registering webhooks * Add tests for cloud hook forwarding and improve error handling for cloud hooks * Initial implementation of platform specific logic * Add get registrations by user ID websocket call, minor style fixes * Stop using resp dictionary during registration * Move mobile_app/ios.py to ios/mobile_app.py * Log any errors encountered during webhook * Improve update registration call * Split up mobile_app tests to match split up component * Fix tests * Remove integration_map in favor of component name in registration * Add a few helper functions for custom logic components to use * Load the app_component platform at device registration or component setup time * Remove extraneous function * Use guard function for checking if component is in device * Inline websocket schemas * Rename ATTR_s used in storage to DATA_ prefix * squash flake8 and pylint issues * Remove ios.mobile_app platform * Dont mark websocket_api as a dependency * Return standard empty_okay_response with 400 if no JSON sent * Ensure deleted webhook IDs are registered at launch * Remove the creation of cloudhooks during handle_webhook * Rename device to registration everywhere applicable * Dont check if cloud is logged in, just check if cloud is in components * Dont ever use cloudhook_id * Remove component loading logic for a later PR * Cast exception to string * Remove unused functions
2019-03-09 07:44:56 +00:00
"""Return a clean object containing things that should be saved."""
return {
DATA_DELETED_IDS: hass.data[DOMAIN][DATA_DELETED_IDS],
}
2019-07-31 19:25:30 +00:00
def webhook_response(
data,
*,
registration: dict,
status: HTTPStatus = HTTPStatus.OK,
2022-08-13 16:46:08 +00:00
headers: dict | None = None,
2019-07-31 19:25:30 +00:00
) -> Response:
"""Return a encrypted response if registration supports it."""
data = json.dumps(data, cls=JSONEncoder)
if registration[ATTR_SUPPORTS_ENCRYPTION]:
keylen, encrypt = setup_encrypt(
HexEncoder if ATTR_NO_LEGACY_ENCRYPTION in registration else RawEncoder
)
if ATTR_NO_LEGACY_ENCRYPTION in registration:
key = registration[CONF_SECRET]
else:
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")
2019-07-31 19:25:30 +00:00
data = json.dumps({"encrypted": True, "encrypted_data": enc_data})
2019-07-31 19:25:30 +00:00
return Response(
text=data, status=status, content_type=CONTENT_TYPE_JSON, headers=headers
2019-07-31 19:25:30 +00:00
)
def device_info(registration: dict) -> DeviceInfo:
"""Return the device info for this registration."""
2021-10-25 21:26:40 +00:00
return DeviceInfo(
identifiers={(DOMAIN, registration[ATTR_DEVICE_ID])},
manufacturer=registration[ATTR_MANUFACTURER],
model=registration[ATTR_MODEL],
name=registration[ATTR_DEVICE_NAME],
sw_version=registration[ATTR_OS_VERSION],
)