core/homeassistant/components/http/decorators.py

92 lines
2.5 KiB
Python

"""Decorators for the Home Assistant API."""
from __future__ import annotations
from collections.abc import Callable, Coroutine
from functools import wraps
from typing import Any, Concatenate, overload
from aiohttp.web import Request, Response, StreamResponse
from homeassistant.auth.models import User
from homeassistant.exceptions import Unauthorized
from .view import HomeAssistantView
type _ResponseType = Response | StreamResponse
type _FuncType[_T, **_P, _R] = Callable[
Concatenate[_T, Request, _P], Coroutine[Any, Any, _R]
]
@overload
def require_admin[
_HomeAssistantViewT: HomeAssistantView,
**_P,
_ResponseT: _ResponseType,
](
_func: None = None,
*,
error: Unauthorized | None = None,
) -> Callable[
[_FuncType[_HomeAssistantViewT, _P, _ResponseT]],
_FuncType[_HomeAssistantViewT, _P, _ResponseT],
]: ...
@overload
def require_admin[
_HomeAssistantViewT: HomeAssistantView,
**_P,
_ResponseT: _ResponseType,
](
_func: _FuncType[_HomeAssistantViewT, _P, _ResponseT],
) -> _FuncType[_HomeAssistantViewT, _P, _ResponseT]: ...
def require_admin[
_HomeAssistantViewT: HomeAssistantView,
**_P,
_ResponseT: _ResponseType,
](
_func: _FuncType[_HomeAssistantViewT, _P, _ResponseT] | None = None,
*,
error: Unauthorized | None = None,
) -> (
Callable[
[_FuncType[_HomeAssistantViewT, _P, _ResponseT]],
_FuncType[_HomeAssistantViewT, _P, _ResponseT],
]
| _FuncType[_HomeAssistantViewT, _P, _ResponseT]
):
"""Home Assistant API decorator to require user to be an admin."""
def decorator_require_admin(
func: _FuncType[_HomeAssistantViewT, _P, _ResponseT],
) -> _FuncType[_HomeAssistantViewT, _P, _ResponseT]:
"""Wrap the provided with_admin function."""
@wraps(func)
async def with_admin(
self: _HomeAssistantViewT,
request: Request,
*args: _P.args,
**kwargs: _P.kwargs,
) -> _ResponseT:
"""Check admin and call function."""
user: User = request["hass_user"]
if not user.is_admin:
raise error or Unauthorized()
return await func(self, request, *args, **kwargs)
return with_admin
# See if we're being called as @require_admin or @require_admin().
if _func is None:
# We're called with brackets.
return decorator_require_admin
# We're called as @require_admin without brackets.
return decorator_require_admin(_func)