"""Permissions for Home Assistant.""" import logging from typing import ( # noqa: F401 cast, Any, Callable, Dict, List, Mapping, Set, Tuple, Union) import voluptuous as vol from homeassistant.core import State from .const import CAT_ENTITIES from .types import CategoryType, PolicyType from .entities import ENTITY_POLICY_SCHEMA, compile_entities from .merge import merge_policies # noqa POLICY_SCHEMA = vol.Schema({ vol.Optional(CAT_ENTITIES): ENTITY_POLICY_SCHEMA }) _LOGGER = logging.getLogger(__name__) class AbstractPermissions: """Default permissions class.""" def check_entity(self, entity_id: str, key: str) -> bool: """Test if we can access entity.""" raise NotImplementedError def filter_states(self, states: List[State]) -> List[State]: """Filter a list of states for what the user is allowed to see.""" raise NotImplementedError class PolicyPermissions(AbstractPermissions): """Handle permissions.""" def __init__(self, policy: PolicyType) -> None: """Initialize the permission class.""" self._policy = policy self._compiled = {} # type: Dict[str, Callable[..., bool]] def check_entity(self, entity_id: str, key: str) -> bool: """Test if we can access entity.""" func = self._policy_func(CAT_ENTITIES, compile_entities) return func(entity_id, (key,)) def filter_states(self, states: List[State]) -> List[State]: """Filter a list of states for what the user is allowed to see.""" func = self._policy_func(CAT_ENTITIES, compile_entities) keys = ('read',) return [entity for entity in states if func(entity.entity_id, keys)] def _policy_func(self, category: str, compile_func: Callable[[CategoryType], Callable]) \ -> Callable[..., bool]: """Get a policy function.""" func = self._compiled.get(category) if func: return func func = self._compiled[category] = compile_func( self._policy.get(category)) _LOGGER.debug("Compiled %s func: %s", category, func) return func def __eq__(self, other: Any) -> bool: """Equals check.""" # pylint: disable=protected-access return (isinstance(other, PolicyPermissions) and other._policy == self._policy) class _OwnerPermissions(AbstractPermissions): """Owner permissions.""" # pylint: disable=no-self-use def check_entity(self, entity_id: str, key: str) -> bool: """Test if we can access entity.""" return True def filter_states(self, states: List[State]) -> List[State]: """Filter a list of states for what the user is allowed to see.""" return states OwnerPermissions = _OwnerPermissions() # pylint: disable=invalid-name