Example #1
0
async def websocket_current_user(opp: OpenPeerPower,
                                 connection: websocket_api.ActiveConnection,
                                 msg):
    """Return the current user."""
    user = connection.user
    enabled_modules = await opp.auth.async_get_enabled_mfa(user)

    connection.send_message(
        websocket_api.result_message(
            msg["id"],
            {
                "id":
                user.id,
                "name":
                user.name,
                "is_owner":
                user.is_owner,
                "is_admin":
                user.is_admin,
                "credentials": [{
                    "auth_provider_type": c.auth_provider_type,
                    "auth_provider_id": c.auth_provider_id,
                } for c in user.credentials],
                "mfa_modules": [{
                    "id": module.id,
                    "name": module.name,
                    "enabled": module.id in enabled_modules,
                } for module in opp.auth.auth_mfa_modules],
            },
        ))
Example #2
0
def send_entry_not_found(
    connection: websocket_api.ActiveConnection, msg_id: int
) -> None:
    """Send Config entry not found error."""
    connection.send_error(
        msg_id, websocket_api.const.ERR_NOT_FOUND, "Config entry not found"
    )
def ws_list_person(opp: OpenPeerPowerType,
                   connection: websocket_api.ActiveConnection, msg):
    """List persons."""
    yaml, storage = opp.data[DOMAIN]
    connection.send_result(msg[ATTR_ID], {
        "storage": storage.async_items(),
        "config": yaml.async_items()
    })
Example #4
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"], {}))
Example #5
0
async def websocket_update_prefs(
    opp: OpenPeerPower, connection: ActiveConnection, msg: dict
) -> None:
    """Handle request for account info."""
    prefs = opp.data[DATA_CAMERA_PREFS]

    changes = dict(msg)
    changes.pop("id")
    changes.pop("type")
    entity_id = changes.pop("entity_id")
    await prefs.async_update(entity_id, **changes)

    connection.send_result(msg["id"], prefs.get(entity_id).as_dict())
Example #6
0
    async def ws_update_item(self, opp: OpenPeerPower,
                             connection: websocket_api.ActiveConnection,
                             msg: dict) -> None:
        """Update a item."""
        data = dict(msg)
        msg_id = data.pop("id")
        item_id = data.pop(self.item_id_key)
        data.pop("type")

        try:
            item = await self.storage_collection.async_update_item(
                item_id, data)
            connection.send_result(msg_id, item)
        except ItemNotFound:
            connection.send_error(
                msg["id"],
                websocket_api.const.ERR_NOT_FOUND,
                f"Unable to find {self.item_id_key} {item_id}",
            )
        except vol.Invalid as err:
            connection.send_error(
                msg["id"],
                websocket_api.const.ERR_INVALID_FORMAT,
                humanize_error(data, err),
            )
        except ValueError as err:
            connection.send_error(msg_id,
                                  websocket_api.const.ERR_INVALID_FORMAT,
                                  str(err))
Example #7
0
    async def ws_delete_item(self, opp: OpenPeerPower,
                             connection: websocket_api.ActiveConnection,
                             msg: dict) -> None:
        """Delete a item."""
        try:
            await self.storage_collection.async_delete_item(
                msg[self.item_id_key])
        except ItemNotFound:
            connection.send_error(
                msg["id"],
                websocket_api.const.ERR_NOT_FOUND,
                f"Unable to find {self.item_id_key} {msg[self.item_id_key]}",
            )

        connection.send_result(msg["id"])
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"]),
    )

    access_token = opp.auth.async_create_access_token(refresh_token)

    connection.send_message(websocket_api.result_message(msg["id"], access_token))
Example #9
0
def websocket_sign_path(opp: OpenPeerPower,
                        connection: websocket_api.ActiveConnection, msg):
    """Handle a sign path request."""
    connection.send_message(
        websocket_api.result_message(
            msg["id"],
            {
                "path":
                async_sign_path(
                    opp,
                    connection.refresh_token_id,
                    msg["path"],
                    timedelta(seconds=msg["expires"]),
                )
            },
        ))
Example #10
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))
Example #11
0
def websocket_refresh_tokens(opp: OpenPeerPower,
                             connection: websocket_api.ActiveConnection, msg):
    """Return metadata of users refresh tokens."""
    current_id = connection.refresh_token_id
    connection.send_message(
        websocket_api.result_message(
            msg["id"],
            [{
                "id": refresh.id,
                "client_id": refresh.client_id,
                "client_name": refresh.client_name,
                "client_icon": refresh.client_icon,
                "type": refresh.token_type,
                "created_at": refresh.created_at,
                "is_current": refresh.id == current_id,
                "last_used_at": refresh.last_used_at,
                "last_used_ip": refresh.last_used_ip,
            } for refresh in connection.user.refresh_tokens.values()],
        ))
Example #12
0
def websocket_get_notifications(
    opp: OpenPeerPower,
    connection: websocket_api.ActiveConnection,
    msg: Mapping[str, Any],
) -> None:
    """Return a list of persistent_notifications."""
    connection.send_message(
        websocket_api.result_message(
            msg["id"],
            [{
                key: data[key]
                for key in (
                    ATTR_NOTIFICATION_ID,
                    ATTR_MESSAGE,
                    ATTR_STATUS,
                    ATTR_TITLE,
                    ATTR_CREATED_AT,
                )
            } for data in opp.data[DOMAIN]["notifications"].values()],
        ))
Example #13
0
async def handle_info(opp: OpenPeerPowerType,
                      connection: websocket_api.ActiveConnection, msg: Dict):
    """Handle an info request."""
    info_callbacks = opp.data.get(DOMAIN, {}).get("info", {})
    data = OrderedDict()
    data[
        "openpeerpower"] = await opp.helpers.system_info.async_get_system_info(
        )

    if info_callbacks:
        for domain, domain_data in zip(
                info_callbacks,
                await
                asyncio.gather(*(_info_wrapper(opp, info_callback)
                                 for info_callback in info_callbacks.values())
                               ),
        ):
            data[domain] = domain_data

    connection.send_message(websocket_api.result_message(msg["id"], data))
Example #14
0
async def ws_get_statistics_during_period(
    opp: OpenPeerPower, connection: websocket_api.ActiveConnection, msg: dict
) -> None:
    """Handle statistics websocket command."""
    start_time_str = msg["start_time"]
    end_time_str = msg.get("end_time")

    start_time = dt_util.parse_datetime(start_time_str)
    if start_time:
        start_time = dt_util.as_utc(start_time)
    else:
        connection.send_error(msg["id"], "invalid_start_time", "Invalid start_time")
        return

    if end_time_str:
        end_time = dt_util.parse_datetime(end_time_str)
        if end_time:
            end_time = dt_util.as_utc(end_time)
        else:
            connection.send_error(msg["id"], "invalid_end_time", "Invalid end_time")
            return
    else:
        end_time = None

    statistics = await opp.async_add_executor_job(
        statistics_during_period,
        opp,
        start_time,
        end_time,
        msg.get("statistic_id"),
    )
    connection.send_result(msg["id"], {"statistics": statistics})
Example #15
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"
            )
        )
Example #16
0
async def ws_camera_stream(
    opp: OpenPeerPower, connection: ActiveConnection, msg: dict
) -> None:
    """Handle get camera stream websocket command.

    Async friendly.
    """
    try:
        entity_id = msg["entity_id"]
        camera = _get_camera_from_entity_id(opp, entity_id)
        url = await _async_stream_endpoint_url(opp, camera, fmt=msg["format"])
        connection.send_result(msg["id"], {"url": url})
    except OpenPeerPowerError as ex:
        _LOGGER.error("Error requesting stream: %s", ex)
        connection.send_error(msg["id"], "start_stream_failed", str(ex))
    except asyncio.TimeoutError:
        _LOGGER.error("Timeout getting stream source")
        connection.send_error(
            msg["id"], "start_stream_failed", "Timeout getting stream source"
        )
Example #17
0
 async def ws_create_item(self, opp: OpenPeerPower,
                          connection: websocket_api.ActiveConnection,
                          msg: dict) -> None:
     """Create a item."""
     try:
         data = dict(msg)
         data.pop("id")
         data.pop("type")
         item = await self.storage_collection.async_create_item(data)
         connection.send_result(msg["id"], item)
     except vol.Invalid as err:
         connection.send_error(
             msg["id"],
             websocket_api.const.ERR_INVALID_FORMAT,
             humanize_error(data, err),
         )
     except ValueError as err:
         connection.send_error(msg["id"],
                               websocket_api.const.ERR_INVALID_FORMAT,
                               str(err))
Example #18
0
 def ws_list_item(self, opp: OpenPeerPower,
                  connection: websocket_api.ActiveConnection,
                  msg: dict) -> None:
     """List items."""
     connection.send_result(msg["id"],
                            self.storage_collection.async_items())
Example #19
0
async def websocket_get_prefs(
    opp: OpenPeerPower, connection: ActiveConnection, msg: dict
) -> None:
    """Handle request for account info."""
    prefs = opp.data[DATA_CAMERA_PREFS].get(msg["entity_id"])
    connection.send_result(msg["id"], prefs.as_dict())
Example #20
0
async def handle_info(opp: OpenPeerPower,
                      connection: websocket_api.ActiveConnection, msg: dict):
    """Handle an info request via a subscription."""
    registrations: dict[str, SystemHealthRegistration] = opp.data[DOMAIN]
    data = {}
    pending_info = {}

    for domain, domain_data in zip(
            registrations,
            await
            asyncio.gather(*(get_integration_info(opp, registration)
                             for registration in registrations.values())),
    ):
        for key, value in domain_data["info"].items():
            if asyncio.iscoroutine(value):
                value = asyncio.create_task(value)
            if isinstance(value, asyncio.Task):
                pending_info[(domain, key)] = value
                domain_data["info"][key] = {"type": "pending"}
            else:
                domain_data["info"][key] = _format_value(value)

        data[domain] = domain_data

    # Confirm subscription
    connection.send_result(msg["id"])

    stop_event = asyncio.Event()
    connection.subscriptions[msg["id"]] = stop_event.set

    # Send initial data
    connection.send_message(
        websocket_api.messages.event_message(msg["id"], {
            "type": "initial",
            "data": data
        }))

    # If nothing pending, wrap it up.
    if not pending_info:
        connection.send_message(
            websocket_api.messages.event_message(msg["id"],
                                                 {"type": "finish"}))
        return

    tasks = [asyncio.create_task(stop_event.wait()), *pending_info.values()]
    pending_lookup = {val: key for key, val in pending_info.items()}

    # One task is the stop_event.wait() and is always there
    while len(tasks) > 1 and not stop_event.is_set():
        # Wait for first completed task
        done, tasks = await asyncio.wait(tasks,
                                         return_when=asyncio.FIRST_COMPLETED)

        if stop_event.is_set():
            for task in tasks:
                task.cancel()
            return

        # Update subscription of all finished tasks
        for result in done:
            domain, key = pending_lookup[result]
            event_msg = {
                "type": "update",
                "domain": domain,
                "key": key,
            }

            if result.exception():
                exception = result.exception()
                _LOGGER.error(
                    "Error fetching system info for %s - %s",
                    domain,
                    key,
                    exc_info=(type(exception), exception,
                              exception.__traceback__),
                )
                event_msg["success"] = False
                event_msg["error"] = {"type": "failed", "error": "unknown"}
            else:
                event_msg["success"] = True
                event_msg["data"] = _format_value(result.result())

            connection.send_message(
                websocket_api.messages.event_message(msg["id"], event_msg))

    connection.send_message(
        websocket_api.messages.event_message(msg["id"], {"type": "finish"}))