Пример #1
0
    def otp_redis(self) -> Redis:
        """
        Return the Redis manager to store OtpData.

        :return: the Redis manager to store OtpData.
        :raise: ImmuniException if the manager is not initialized.
        """
        if self._otp_redis is None:
            raise ImmuniException("Cannot use the Redis manager before initialising it.")
        return self._otp_redis
 def exposure_mongo(self) -> MongoClient:
     """
     Return the MongoDB manager to handle TEKs.
     :return: the MongoDB manager to handle TEKs.
     :raise: ImmuniException if the manager is not initialized.
     """
     if self._exposure_mongo is None:
         raise ImmuniException(
             "Cannot use the MongoDB manager before initializing it.")
     return self._exposure_mongo
Пример #3
0
    def celery_redis(self) -> Redis:
        """
        Return the Celery Redis manager to store analytics.

        :return: the Celery Redis manager to store analytics.
        :raise: ImmuniException if the manager is not initialized.
        """
        if self._celery_redis is None:
            raise ImmuniException(
                "Cannot use the Celery Redis manager before initialising it.")
        return self._celery_redis
Пример #4
0
    def app_configuration_mongo(self) -> MongoClient:
        """
        Return the MongoDB manager to handle app configurations.

        :return: the MongoDB manager to handle app configurations.
        :raise: ImmuniException if the manager is not initialized.
        """
        if self._app_configuration_mongo is None:
            raise ImmuniException(
                "Cannot use the MongoDB manager before initializing it.")
        return self._app_configuration_mongo
Пример #5
0
    def from_env_var(cls: Type[T], value: str) -> T:
        """
        Parse the environment variable value and provide an informative error message on failure.

        :param value: the environment variable value.
        :return: the corresponding Enum entry.
        """
        try:
            return cls(value)  # type: ignore
        except ValueError:
            allowed = ", ".join(e.value for e in cls)  # type: ignore
            raise ImmuniException(
                f"Invalid environment: {value} (allowed: {allowed})")
Пример #6
0
def weighted_random(pairs: List[WeightedPayload[T]]) -> T:
    """
    Returns one of the values in the WeightedPair list randomly based on the
    weights defined in the given WeightedPair list.

    :param pairs: The list of WeightedPair to pick the random value from.
    """

    # Note: We allow 0 weights so that this function is testable and tests are not random.
    if any(pair.weight < 0 for pair in pairs):
        raise ImmuniException("Cannot perform a weighted random with negative weights.")

    return random.choices(
        population=tuple(p.payload for p in pairs), weights=tuple(p.weight for p in pairs), k=1,
    )[0]
Пример #7
0
    def from_env_var(cls, value: str) -> LogLevel:
        """
        Parse the environment variable value and provide an informative error message on failure.

        :param value: the environment variable value.
        :return: the corresponding LogLevel entry.
        :raises: ImmuniException if the given log level is deprecated in the logging library.
        """
        environment = super().from_env_var(value)

        if environment.name not in logging._nameToLevel:  # pylint: disable=protected-access
            raise ImmuniException(
                f"Deprecated log level: {value}. Code update needed.")

        return environment
Пример #8
0
        async def _wrapper(*args: Any, **kwargs: Any) -> HTTPResponse:
            response = await f(*args, **kwargs)

            if not config.CACHE_ENABLED:
                return response

            if _CACHE_CONTROL in response.headers:
                raise ImmuniException(
                    f"Attempt to redefine {_CACHE_CONTROL} headers.")

            # NOTE: Check for both defined or both undefined has already been done outside.
            if max_age:
                response.headers[
                    _CACHE_CONTROL] = f"public, max-age={int(max_age.total_seconds())}"
            if no_store:
                response.headers[_CACHE_CONTROL] = "no-store"

            return response
Пример #9
0
def cache(max_age: Optional[timedelta] = None,
          no_store: Optional[bool] = None) -> Callable:
    """
    Decorator to add cache headers to an endpoint response.

    :param max_age: the timedelta, if any, after which the cache would expire.
    :param no_store: True if the response shall not be cached.
    :return: the decorator.
    :raises:
      ImmuniException: if none or all arguments are defined.
      ImmuniException: if attempting to redefine the Cache-Control header.
    """
    def _decorator(
        f: Callable[..., Awaitable[HTTPResponse]]
    ) -> Callable[..., Awaitable[HTTPResponse]]:
        @wraps(f)
        async def _wrapper(*args: Any, **kwargs: Any) -> HTTPResponse:
            response = await f(*args, **kwargs)

            if not config.CACHE_ENABLED:
                return response

            if _CACHE_CONTROL in response.headers:
                raise ImmuniException(
                    f"Attempt to redefine {_CACHE_CONTROL} headers.")

            # NOTE: Check for both defined or both undefined has already been done outside.
            if max_age:
                response.headers[
                    _CACHE_CONTROL] = f"public, max-age={int(max_age.total_seconds())}"
            if no_store:
                response.headers[_CACHE_CONTROL] = "no-store"

            return response

        return _wrapper

    if not bool(max_age) ^ bool(no_store):
        raise ImmuniException(
            f"{cache.__name__} decorator arguments are mutually exclusive, and at least one shall "
            f"be defined (max_age: {max_age}, no_store: {no_store}).")

    return _decorator
Пример #10
0
        async def _wrapper(request: Request, *args: Any,
                           **kwargs: Any) -> HTTPResponse:
            data = getattr(request, location.value, {})
            if location == Location.HEADERS:
                data = _remap_data_keys(data)
            elif location == Location.QUERY:
                _validate_query_args_length(data)
            elif location == Location.JSON:
                _validate_json_content_type(request)
            schema = Schema.from_dict(fields)
            try:
                valid_data = schema().load(data)  # pylint: disable=no-member
            except ValidationError as exc:
                raise SchemaValidationException(exc.messages) from exc

            if intersection := set(kwargs.keys()).intersection(
                    set(valid_data.keys())):
                raise ImmuniException(
                    f"Trying to validate some fields more than once: {list(intersection)}."
                )
Пример #11
0
 def _validate_crontab(value: str) -> str:
     if not croniter.is_valid(value):
         raise ImmuniException(
             f"Invalid crontab string for {config_name}: {value}.")
     return value