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], }, ))
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"], {}))
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))
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"]), ) }, ))
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()], ))
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))
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()], ))
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))
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" ) )
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"}))