"""Websocket API for mobile_app.""" import voluptuous as vol from homeassistant.components.cloud import async_delete_cloudhook from homeassistant.components.websocket_api import (ActiveConnection, async_register_command, async_response, error_message, result_message, websocket_command, ws_require_user) from homeassistant.components.websocket_api.const import (ERR_INVALID_FORMAT, ERR_NOT_FOUND, ERR_UNAUTHORIZED) from homeassistant.const import CONF_WEBHOOK_ID from homeassistant.exceptions import HomeAssistantError from homeassistant.helpers import config_validation as cv from homeassistant.helpers.typing import HomeAssistantType from .const import (CONF_CLOUDHOOK_URL, CONF_USER_ID, DATA_CONFIG_ENTRIES, DATA_DELETED_IDS, DATA_STORE, DOMAIN) from .helpers import safe_registration, savable_state def register_websocket_handlers(hass: HomeAssistantType) -> bool: """Register the websocket handlers.""" async_register_command(hass, websocket_get_user_registrations) async_register_command(hass, websocket_delete_registration) return True @ws_require_user() @async_response @websocket_command({ vol.Required('type'): 'mobile_app/get_user_registrations', vol.Optional(CONF_USER_ID): cv.string, }) async def websocket_get_user_registrations( hass: HomeAssistantType, connection: ActiveConnection, msg: dict) -> None: """Return all registrations or just registrations for given user ID.""" user_id = msg.get(CONF_USER_ID, connection.user.id) if user_id != connection.user.id and not connection.user.is_admin: # If user ID is provided and is not current user ID and current user # isn't an admin user connection.send_error(msg['id'], ERR_UNAUTHORIZED, "Unauthorized") return user_registrations = [] for config_entry in hass.config_entries.async_entries(domain=DOMAIN): registration = config_entry.data if connection.user.is_admin or registration[CONF_USER_ID] is user_id: user_registrations.append(safe_registration(registration)) connection.send_message( result_message(msg['id'], user_registrations)) @ws_require_user() @async_response @websocket_command({ vol.Required('type'): 'mobile_app/delete_registration', vol.Required(CONF_WEBHOOK_ID): cv.string, }) async def websocket_delete_registration(hass: HomeAssistantType, connection: ActiveConnection, msg: dict) -> None: """Delete the registration for the given webhook_id.""" user = connection.user webhook_id = msg.get(CONF_WEBHOOK_ID) if webhook_id is None: connection.send_error(msg['id'], ERR_INVALID_FORMAT, "Webhook ID not provided") return config_entry = hass.data[DOMAIN][DATA_CONFIG_ENTRIES][webhook_id] registration = config_entry.data if registration is None: connection.send_error(msg['id'], ERR_NOT_FOUND, "Webhook ID not found in storage") return if registration[CONF_USER_ID] != user.id and not user.is_admin: return error_message( msg['id'], ERR_UNAUTHORIZED, 'User is not registration owner') await hass.config_entries.async_remove(config_entry.entry_id) hass.data[DOMAIN][DATA_DELETED_IDS].append(webhook_id) store = hass.data[DOMAIN][DATA_STORE] try: await store.async_save(savable_state(hass)) except HomeAssistantError: return error_message( msg['id'], 'internal_error', 'Error deleting registration') if (CONF_CLOUDHOOK_URL in registration and "cloud" in hass.config.components): await async_delete_cloudhook(hass, webhook_id) connection.send_message(result_message(msg['id'], 'ok'))