async def websocket_handle_thumbnail(opp, connection, msg):
    """Handle get media player cover command.

    Async friendly.
    """
    component = opp.data[DOMAIN]
    player = component.get_entity(msg["entity_id"])

    if player is None:
        connection.send_message(
            websocket_api.error_message(msg["id"], "entity_not_found",
                                        "Entity not found"))
        return

    data, content_type = await player.async_get_media_image()

    if data is None:
        connection.send_message(
            websocket_api.error_message(msg["id"], "thumbnail_fetch_failed",
                                        "Failed to fetch thumbnail"))
        return

    await connection.send_big_result(
        msg["id"],
        {
            "content_type": content_type,
            "content": base64.b64encode(data).decode("utf-8"),
        },
    )
Exemple #2
0
async def websocket_handle_thumbnail(opp, connection, msg):
    """Handle get media player cover command.

    Async friendly.
    """
    component = opp.data[DOMAIN]
    player = component.get_entity(msg["entity_id"])

    if player is None:
        connection.send_message(
            websocket_api.error_message(msg["id"], ERR_NOT_FOUND,
                                        "Entity not found"))
        return

    _LOGGER.warning(
        "The websocket command media_player_thumbnail is deprecated. Use /api/media_player_proxy instead"
    )

    data, content_type = await player.async_get_media_image()

    if data is None:
        connection.send_message(
            websocket_api.error_message(msg["id"], "thumbnail_fetch_failed",
                                        "Failed to fetch thumbnail"))
        return

    await connection.send_big_result(
        msg["id"],
        {
            "content_type": content_type,
            "content": base64.b64encode(data).decode("utf-8"),
        },
    )
async def websocket_update(opp, connection, msg):
    """Update a user."""
    user = await opp.auth.async_get_user(msg.pop("user_id"))

    if not user:
        connection.send_message(
            websocket_api.error_message(msg["id"],
                                        websocket_api.const.ERR_NOT_FOUND,
                                        "User not found"))
        return

    if user.system_generated:
        connection.send_message(
            websocket_api.error_message(
                msg["id"],
                "cannot_modify_system_generated",
                "Unable to update system generated users.",
            ))
        return

    msg.pop("type")
    msg_id = msg.pop("id")

    await opp.auth.async_update_user(user, **msg)

    connection.send_message(
        websocket_api.result_message(msg_id, {"user": _user_info(user)}))
async def websocket_update_entity(opp, connection, msg):
    """Handle update entity websocket command.

    Async friendly.
    """
    registry = await async_get_registry(opp)

    if msg["entity_id"] not in registry.entities:
        connection.send_message(
            websocket_api.error_message(msg["id"], ERR_NOT_FOUND,
                                        "Entity not found"))
        return

    changes = {}

    for key in ("name", "icon", "area_id", "disabled_by"):
        if key in msg:
            changes[key] = msg[key]

    if "new_entity_id" in msg and msg["new_entity_id"] != msg["entity_id"]:
        changes["new_entity_id"] = msg["new_entity_id"]
        if opp.states.get(msg["new_entity_id"]) is not None:
            connection.send_message(
                websocket_api.error_message(
                    msg["id"],
                    "invalid_info",
                    "Entity with this ID is already registered",
                ))
            return

    if "disabled_by" in msg and msg["disabled_by"] is None:
        entity = registry.entities[msg["entity_id"]]
        if entity.device_id:
            device_registry = await opp.helpers.device_registry.async_get_registry(
            )
            device = device_registry.async_get(entity.device_id)
            if device.disabled:
                connection.send_message(
                    websocket_api.error_message(msg["id"], "invalid_info",
                                                "Device is disabled"))
                return

    try:
        if changes:
            entry = registry.async_update_entity(msg["entity_id"], **changes)
    except ValueError as err:
        connection.send_message(
            websocket_api.error_message(msg["id"], "invalid_info", str(err)))
        return
    result = {"entity_entry": _entry_ext_dict(entry)}
    if "disabled_by" in changes and changes["disabled_by"] is None:
        config_entry = opp.config_entries.async_get_entry(
            entry.config_entry_id)
        if config_entry and not config_entry.supports_unload:
            result["require_restart"] = True
        else:
            result["reload_delay"] = config_entries.RELOAD_AFTER_UPDATE_DELAY
    connection.send_result(msg["id"], result)
Exemple #5
0
async def websocket_browse_media(opp, connection, msg):
    """
    Browse media available to the media_player entity.

    To use, media_player integrations can implement MediaPlayerEntity.async_browse_media()
    """
    component = opp.data[DOMAIN]
    player: MediaPlayerDevice | None = component.get_entity(msg["entity_id"])

    if player is None:
        connection.send_error(msg["id"], "entity_not_found",
                              "Entity not found")
        return

    if not player.supported_features & SUPPORT_BROWSE_MEDIA:
        connection.send_message(
            websocket_api.error_message(
                msg["id"], ERR_NOT_SUPPORTED,
                "Player does not support browsing media"))
        return

    media_content_type = msg.get(ATTR_MEDIA_CONTENT_TYPE)
    media_content_id = msg.get(ATTR_MEDIA_CONTENT_ID)

    try:
        payload = await player.async_browse_media(media_content_type,
                                                  media_content_id)
    except NotImplementedError:
        _LOGGER.error(
            "%s allows media browsing but its integration (%s) does not",
            player.entity_id,
            player.platform.platform_name,
        )
        connection.send_message(
            websocket_api.error_message(
                msg["id"],
                ERR_NOT_SUPPORTED,
                "Integration does not support browsing media",
            ))
        return
    except BrowseError as err:
        connection.send_message(
            websocket_api.error_message(msg["id"], ERR_UNKNOWN_ERROR,
                                        str(err)))
        return

    # For backwards compat
    if isinstance(payload, BrowseMedia):
        payload = payload.as_dict()
    else:
        _LOGGER.warning("Browse Media should use new BrowseMedia class")

    connection.send_result(msg["id"], payload)
Exemple #6
0
async def websocket_subscription(opp, connection, msg):
    """Handle request for account info."""

    cloud = opp.data[DOMAIN]

    with async_timeout.timeout(REQUEST_TIMEOUT):
        response = await cloud.fetch_subscription_info()

    if response.status != 200:
        connection.send_message(
            websocket_api.error_message(
                msg["id"], "request_failed", "Failed to request subscription"
            )
        )

    data = await response.json()

    # Check if a user is subscribed but local info is outdated
    # In that case, let's refresh and reconnect
    if data.get("provider") and not cloud.is_connected:
        _LOGGER.debug("Found disconnected account with valid subscriotion, connecting")
        await opp.async_add_executor_job(cloud.auth.renew_access_token)

        # Cancel reconnect in progress
        if cloud.iot.state != STATE_DISCONNECTED:
            await cloud.iot.disconnect()

        opp.async_create_task(cloud.iot.connect())

    connection.send_message(websocket_api.result_message(msg["id"], data))
async def websocket_delete(opp, connection, msg):
    """Delete username and related credential."""
    provider = _get_provider(opp)
    await provider.async_initialize()

    credentials = await provider.async_get_or_create_credentials(
        {"username": msg["username"]})

    # if not new, an existing credential exists.
    # Removing the credential will also remove the auth.
    if not credentials.is_new:
        await opp.auth.async_remove_credentials(credentials)

        connection.send_message(websocket_api.result_message(msg["id"]))
        return

    try:
        provider.data.async_remove_auth(msg["username"])
        await provider.data.async_save()
    except auth_ha.InvalidUser:
        connection.send_message(
            websocket_api.error_message(msg["id"], "auth_not_found",
                                        "Given username was not found."))
        return

    connection.send_message(websocket_api.result_message(msg["id"]))
    async def async_setup_flow(msg):
        """Return a setup flow for mfa auth module."""
        flow_manager = opp.data[DATA_SETUP_FLOW_MGR]

        flow_id = msg.get("flow_id")
        if flow_id is not None:
            result = await flow_manager.async_configure(
                flow_id, msg.get("user_input"))
            connection.send_message(
                websocket_api.result_message(msg["id"],
                                             _prepare_result_json(result)))
            return

        mfa_module_id = msg.get("mfa_module_id")
        mfa_module = opp.auth.get_auth_mfa_module(mfa_module_id)
        if mfa_module is None:
            connection.send_message(
                websocket_api.error_message(
                    msg["id"], "no_module",
                    f"MFA module {mfa_module_id} is not found"))
            return

        result = await flow_manager.async_init(
            mfa_module_id, data={"user_id": connection.user.id})

        connection.send_message(
            websocket_api.result_message(msg["id"],
                                         _prepare_result_json(result)))
async def websocket_delete(opp, connection, msg):
    """Delete a user."""
    if msg["user_id"] == connection.user.id:
        connection.send_message(
            websocket_api.error_message(msg["id"], "no_delete_self",
                                        "Unable to delete your own account"))
        return

    user = await opp.auth.async_get_user(msg["user_id"])

    if not user:
        connection.send_message(
            websocket_api.error_message(msg["id"], "not_found",
                                        "User not found"))
        return

    await opp.auth.async_remove_user(user)

    connection.send_message(websocket_api.result_message(msg["id"]))
Exemple #10
0
async def websocket_create_area(opp, connection, msg):
    """Create area command."""
    registry = await async_get_registry(opp)
    try:
        entry = registry.async_create(msg["name"])
    except ValueError as err:
        connection.send_message(
            websocket_api.error_message(msg["id"], "invalid_info", str(err)))
    else:
        connection.send_message(
            websocket_api.result_message(msg["id"], _entry_dict(entry)))
Exemple #11
0
    def with_cloud_auth(opp, connection, msg):
        """Require to be logged into the cloud."""
        cloud = opp.data[DOMAIN]
        if not cloud.is_logged_in:
            connection.send_message(
                websocket_api.error_message(
                    msg["id"], "not_logged_in", "You need to be logged in to the cloud."
                )
            )
            return

        handler(opp, connection, msg)
Exemple #12
0
async def websocket_delete_refresh_token(
        opp: OpenPeerPower, connection: websocket_api.ActiveConnection, msg):
    """Handle a delete refresh token request."""
    refresh_token = connection.user.refresh_tokens.get(msg["refresh_token_id"])

    if refresh_token is None:
        return websocket_api.error_message(msg["id"], "invalid_token_id",
                                           "Received invalid token")

    await opp.auth.async_remove_refresh_token(refresh_token)

    connection.send_message(websocket_api.result_message(msg["id"], {}))
Exemple #13
0
async def websocket_delete_area(opp, connection, msg):
    """Delete area command."""
    registry = await async_get_registry(opp)

    try:
        await registry.async_delete(msg["area_id"])
    except KeyError:
        connection.send_message(
            websocket_api.error_message(msg["id"], "invalid_info",
                                        "Area ID doesn't exist"))
    else:
        connection.send_message(
            websocket_api.result_message(msg["id"], "success"))
Exemple #14
0
async def websocket_get_device(opp, connection, msg):
    """Get ZHA devices."""
    zha_gateway = opp.data[DATA_ZHA][DATA_ZHA_GATEWAY]
    ieee = msg[ATTR_IEEE]
    device = None
    if ieee in zha_gateway.devices:
        device = zha_gateway.devices[ieee].zha_device_info
    if not device:
        connection.send_message(
            websocket_api.error_message(msg[ID],
                                        websocket_api.const.ERR_NOT_FOUND,
                                        "ZHA Device not found"))
        return
    connection.send_result(msg[ID], device)
async def websocket_create(opp, connection, msg):
    """Create credentials and attach to a user."""
    provider = _get_provider(opp)
    await provider.async_initialize()

    user = await opp.auth.async_get_user(msg["user_id"])

    if user is None:
        connection.send_message(
            websocket_api.error_message(msg["id"], "not_found",
                                        "User not found"))
        return

    if user.system_generated:
        connection.send_message(
            websocket_api.error_message(
                msg["id"],
                "system_generated",
                "Cannot add credentials to a system generated user.",
            ))
        return

    try:
        await opp.async_add_executor_job(provider.data.add_auth,
                                         msg["username"], msg["password"])
    except auth_ha.InvalidUser:
        connection.send_message(
            websocket_api.error_message(msg["id"], "username_exists",
                                        "Username already exists"))
        return

    credentials = await provider.async_get_or_create_credentials(
        {"username": msg["username"]})
    await opp.auth.async_link_user(user, credentials)

    await provider.data.async_save()
    connection.send_message(websocket_api.result_message(msg["id"]))
async def websocket_change_password(opp, connection, msg):
    """Change user password."""
    user = connection.user
    if user is None:
        connection.send_message(
            websocket_api.error_message(msg["id"], "user_not_found",
                                        "User not found"))
        return

    provider = _get_provider(opp)
    await provider.async_initialize()

    username = None
    for credential in user.credentials:
        if credential.auth_provider_type == provider.type:
            username = credential.data["username"]
            break

    if username is None:
        connection.send_message(
            websocket_api.error_message(msg["id"], "credentials_not_found",
                                        "Credentials not found"))
        return

    try:
        await provider.async_validate_login(username, msg["current_password"])
    except auth_ha.InvalidAuth:
        connection.send_message(
            websocket_api.error_message(msg["id"], "invalid_password",
                                        "Invalid password"))
        return

    await opp.async_add_executor_job(provider.data.change_password, username,
                                     msg["new_password"])
    await provider.data.async_save()

    connection.send_message(websocket_api.result_message(msg["id"]))
Exemple #17
0
async def websocket_migrate_zwave(opp, connection, msg):
    """Migrate the zwave integration device and entity data to ozw integration."""
    if "zwave" not in opp.config.components:
        _LOGGER.error("Can not migrate, zwave integration is not loaded")
        connection.send_message(
            websocket_api.error_message(msg["id"], "zwave_not_loaded",
                                        "Integration zwave is not loaded"))
        return

    zwave = opp.components.zwave
    zwave_data = await zwave.async_get_ozw_migration_data(opp)
    _LOGGER.debug("Migration zwave data: %s", zwave_data)

    ozw_data = await async_get_migration_data(opp)
    _LOGGER.debug("Migration ozw data: %s", ozw_data)

    can_migrate = map_node_values(zwave_data, ozw_data)

    zwave_entity_ids = [
        entry["entity_entry"].entity_id for entry in zwave_data.values()
    ]
    ozw_entity_ids = [
        entry["entity_entry"].entity_id for entry in ozw_data.values()
    ]
    migration_device_map = {
        zwave_device_id: ozw_device_id
        for ozw_device_id, zwave_device_id in
        can_migrate["device_entries"].items()
    }
    migration_entity_map = {
        zwave_entry["entity_entry"].entity_id: ozw_entity_id
        for ozw_entity_id, zwave_entry in
        can_migrate["entity_entries"].items()
    }
    _LOGGER.debug("Migration entity map: %s", migration_entity_map)

    if not msg[DRY_RUN]:
        await async_migrate(opp, can_migrate)

    connection.send_result(
        msg[ID],
        {
            "migration_device_map": migration_device_map,
            "zwave_entity_ids": zwave_entity_ids,
            "ozw_entity_ids": ozw_entity_ids,
            "migration_entity_map": migration_entity_map,
            "migrated": not msg[DRY_RUN],
        },
    )
Exemple #18
0
async def websocket_handle_update(opp, connection, msg):
    """Handle update shopping_list item."""
    msg_id = msg.pop("id")
    item_id = msg.pop("item_id")
    msg.pop("type")
    data = msg

    try:
        item = await opp.data[DOMAIN].async_update(item_id, data)
        opp.bus.async_fire(EVENT, {"action": "update", "item": item})
        connection.send_message(websocket_api.result_message(msg_id, item))
    except KeyError:
        connection.send_message(
            websocket_api.error_message(msg_id, "item_not_found", "Item not found")
        )
Exemple #19
0
async def websocket_get_group(opp, connection, msg):
    """Get ZHA group."""
    zha_gateway = opp.data[DATA_ZHA][DATA_ZHA_GATEWAY]
    group_id = msg[GROUP_ID]
    group = None

    if group_id in zha_gateway.groups:
        group = zha_gateway.groups.get(group_id).group_info
    if not group:
        connection.send_message(
            websocket_api.error_message(msg[ID],
                                        websocket_api.const.ERR_NOT_FOUND,
                                        "ZHA Group not found"))
        return
    connection.send_result(msg[ID], group)
Exemple #20
0
async def websocket_update_entity(opp, connection, msg):
    """Handle update entity websocket command.

    Async friendly.
    """
    registry = await async_get_registry(opp)

    if msg["entity_id"] not in registry.entities:
        connection.send_message(
            websocket_api.error_message(msg["id"], ERR_NOT_FOUND,
                                        "Entity not found"))
        return

    changes = {}

    for key in ("name", "icon", "disabled_by"):
        if key in msg:
            changes[key] = msg[key]

    if "new_entity_id" in msg and msg["new_entity_id"] != msg["entity_id"]:
        changes["new_entity_id"] = msg["new_entity_id"]
        if opp.states.get(msg["new_entity_id"]) is not None:
            connection.send_message(
                websocket_api.error_message(msg["id"], "invalid_info",
                                            "Entity is already registered"))
            return

    try:
        if changes:
            entry = registry.async_update_entity(msg["entity_id"], **changes)
    except ValueError as err:
        connection.send_message(
            websocket_api.error_message(msg["id"], "invalid_info", str(err)))
    else:
        connection.send_message(
            websocket_api.result_message(msg["id"], _entry_dict(entry)))
Exemple #21
0
async def websocket_remove_entity(opp, connection, msg):
    """Handle remove entity websocket command.

    Async friendly.
    """
    registry = await async_get_registry(opp)

    if msg["entity_id"] not in registry.entities:
        connection.send_message(
            websocket_api.error_message(msg["id"], ERR_NOT_FOUND,
                                        "Entity not found"))
        return

    registry.async_remove(msg["entity_id"])
    connection.send_message(websocket_api.result_message(msg["id"]))
Exemple #22
0
async def websocket_get_entity(opp, connection, msg):
    """Handle get entity registry entry command.

    Async friendly.
    """
    registry = await async_get_registry(opp)
    entry = registry.entities.get(msg["entity_id"])

    if entry is None:
        connection.send_message(
            websocket_api.error_message(msg["id"], ERR_NOT_FOUND,
                                        "Entity not found"))
        return

    connection.send_message(
        websocket_api.result_message(msg["id"], _entry_ext_dict(entry)))
    async def async_depose(msg):
        """Remove user from mfa auth module."""
        mfa_module_id = msg["mfa_module_id"]
        try:
            await opp.auth.async_disable_user_mfa(connection.user,
                                                  msg["mfa_module_id"])
        except ValueError as err:
            connection.send_message(
                websocket_api.error_message(
                    msg["id"],
                    "disable_failed",
                    f"Cannot disable MFA Module {mfa_module_id}: {err}",
                ))
            return

        connection.send_message(websocket_api.result_message(
            msg["id"], "done"))
Exemple #24
0
async def websocket_remove_group_members(opp, connection, msg):
    """Remove members from a ZHA group."""
    zha_gateway = opp.data[DATA_ZHA][DATA_ZHA_GATEWAY]
    group_id = msg[GROUP_ID]
    members = msg[ATTR_MEMBERS]
    zha_group = None

    if group_id in zha_gateway.groups:
        zha_group = zha_gateway.groups.get(group_id)
        await zha_group.async_remove_members(members)
    if not zha_group:
        connection.send_message(
            websocket_api.error_message(msg[ID],
                                        websocket_api.const.ERR_NOT_FOUND,
                                        "ZHA Group not found"))
        return
    ret_group = zha_group.group_info
    connection.send_result(msg[ID], ret_group)
Exemple #25
0
async def websocket_camera_thumbnail(opp, connection, msg):
    """Handle get camera thumbnail websocket command.

    Async friendly.
    """
    try:
        image = await async_get_image(opp, msg["entity_id"])
        await connection.send_big_result(
            msg["id"],
            {
                "content_type": image.content_type,
                "content": base64.b64encode(image.content).decode("utf-8"),
            },
        )
    except OpenPeerPowerError:
        connection.send_message(
            websocket_api.error_message(msg["id"], "image_fetch_failed",
                                        "Unable to fetch image"))
Exemple #26
0
async def websocket_create_long_lived_access_token(
        opp: OpenPeerPower, connection: websocket_api.ActiveConnection, msg):
    """Create or a long-lived access token."""
    refresh_token = await opp.auth.async_create_refresh_token(
        connection.user,
        client_name=msg["client_name"],
        client_icon=msg.get("client_icon"),
        token_type=TOKEN_TYPE_LONG_LIVED_ACCESS_TOKEN,
        access_token_expiration=timedelta(days=msg["lifespan"]),
    )

    try:
        access_token = opp.auth.async_create_access_token(refresh_token)
    except InvalidAuthError as exc:
        return websocket_api.error_message(
            msg["id"], websocket_api.const.ERR_UNAUTHORIZED, str(exc))

    connection.send_message(
        websocket_api.result_message(msg["id"], access_token))
Exemple #27
0
async def websocket_camera_thumbnail(
    opp: OpenPeerPower, connection: ActiveConnection, msg: dict
) -> None:
    """Handle get camera thumbnail websocket command.

    Async friendly.
    """
    _LOGGER.warning("The websocket command 'camera_thumbnail' has been deprecated")
    try:
        image = await async_get_image(opp, msg["entity_id"])
        await connection.send_big_result(
            msg["id"],
            {
                "content_type": image.content_type,
                "content": base64.b64encode(image.content).decode("utf-8"),
            },
        )
    except OpenPeerPowerError:
        connection.send_message(
            websocket_api.error_message(
                msg["id"], "image_fetch_failed", "Unable to fetch image"
            )
        )