Ejemplo n.º 1
0
    def test_default_rate_limit_values(self):
        """Ensure that the default rate limits are called for endpoints without overrides."""

        class TestEndpoint(Endpoint):
            pass

        assert get_rate_limit_value(
            "GET", TestEndpoint, RateLimitCategory.IP
        ) == get_default_rate_limits_for_group("default", RateLimitCategory.IP)
        assert get_rate_limit_value(
            "POST", TestEndpoint, RateLimitCategory.ORGANIZATION
        ) == get_default_rate_limits_for_group("default", RateLimitCategory.ORGANIZATION)
        assert get_rate_limit_value(
            "DELETE", TestEndpoint, RateLimitCategory.USER
        ) == get_default_rate_limits_for_group("default", RateLimitCategory.USER)
Ejemplo n.º 2
0
    def test_multiple_inheritance(self):
        class ParentEndpoint(Endpoint):
            rate_limits = {"GET": {RateLimitCategory.IP: RateLimit(100, 5)}}

        class Mixin:
            rate_limits = {"GET": {RateLimitCategory.IP: RateLimit(2, 4)}}

        class ChildEndpoint(ParentEndpoint, Mixin):
            pass

        class ChildEndpointReverse(Mixin, ParentEndpoint):
            pass

        assert get_rate_limit_value("GET", ChildEndpoint, RateLimitCategory.IP) == RateLimit(100, 5)
        assert get_rate_limit_value("GET", ChildEndpointReverse, RateLimitCategory.IP) == RateLimit(
            2, 4
        )
Ejemplo n.º 3
0
    def test_override_rate_limit(self):
        """Override one or more of the default rate limits."""

        class TestEndpoint(Endpoint):
            rate_limits = {
                "GET": {RateLimitCategory.IP: RateLimit(100, 5)},
                "POST": {RateLimitCategory.USER: RateLimit(20, 4)},
            }

        assert get_rate_limit_value("GET", TestEndpoint, RateLimitCategory.IP) == RateLimit(100, 5)
        assert get_rate_limit_value(
            "GET", TestEndpoint, RateLimitCategory.USER
        ) == get_default_rate_limits_for_group("default", RateLimitCategory.USER)
        assert get_rate_limit_value(
            "POST", TestEndpoint, RateLimitCategory.IP
        ) == get_default_rate_limits_for_group("default", RateLimitCategory.IP)
        assert get_rate_limit_value("POST", TestEndpoint, RateLimitCategory.USER) == RateLimit(
            20, 4
        )
Ejemplo n.º 4
0
    def test_inherit(self):
        class ParentEndpoint(Endpoint):
            rate_limits = RateLimitConfig(
                group="foo", limit_overrides={"GET": {RateLimitCategory.IP: RateLimit(100, 5)}}
            )

        class ChildEndpoint(ParentEndpoint):
            rate_limits = RateLimitConfig(group="foo", limit_overrides={"GET": {}})

        assert get_rate_limit_value(
            "GET", ChildEndpoint, RateLimitCategory.IP
        ) == get_default_rate_limits_for_group("foo", RateLimitCategory.IP)
Ejemplo n.º 5
0
    def process_view(self, request: Request, view_func, view_args,
                     view_kwargs) -> Response | None:
        """Check if the endpoint call will violate."""
        try:
            # TODO: put these fields into their own object
            request.will_be_rate_limited = False
            request.rate_limit_category = None
            request.rate_limit_uid = uuid.uuid4().hex
            request.rate_limit_key = get_rate_limit_key(view_func, request)
            if request.rate_limit_key is None:
                return
            category_str = request.rate_limit_key.split(":", 1)[0]
            request.rate_limit_category = category_str

            rate_limit = get_rate_limit_value(
                http_method=request.method,
                endpoint=view_func.view_class,
                category=RateLimitCategory(category_str),
            )
            if rate_limit is None:
                return

            request.rate_limit_metadata = above_rate_limit_check(
                request.rate_limit_key, rate_limit, request.rate_limit_uid)
            # TODO: also limit by concurrent window once we have the data
            rate_limit_cond = (request.rate_limit_metadata.rate_limit_type !=
                               RateLimitType.NOT_LIMITED
                               if ENFORCE_CONCURRENT_RATE_LIMITS else
                               request.rate_limit_metadata.rate_limit_type
                               == RateLimitType.FIXED_WINDOW)
            if rate_limit_cond:
                request.will_be_rate_limited = True
                enforce_rate_limit = getattr(view_func.view_class,
                                             "enforce_rate_limit", False)
                if enforce_rate_limit:
                    return HttpResponse(
                        {
                            "detail":
                            DEFAULT_ERROR_MESSAGE.format(
                                limit=request.rate_limit_metadata.limit,
                                window=request.rate_limit_metadata.window,
                            )
                        },
                        status=429,
                    )
        except Exception:
            logging.exception(
                "Error during rate limiting, failing open. THIS SHOULD NOT HAPPEN"
            )
Ejemplo n.º 6
0
    def process_view(self, request: Request, view_func, view_args,
                     view_kwargs) -> Response | None:
        """Check if the endpoint call will violate."""
        request.will_be_rate_limited = False
        request.rate_limit_category = None

        key = get_rate_limit_key(view_func, request)
        if key is None:
            return
        category_str = key.split(":", 1)[0]
        request.rate_limit_category = category_str

        rate_limit = get_rate_limit_value(
            http_method=request.method,
            endpoint=view_func.view_class,
            category=RateLimitCategory(category_str),
        )
        if rate_limit is None:
            return

        request.rate_limit_metadata = above_rate_limit_check(key, rate_limit)

        if request.rate_limit_metadata.is_limited:
            request.will_be_rate_limited = True
            enforce_rate_limit = getattr(view_func.view_class,
                                         "enforce_rate_limit", False)
            if enforce_rate_limit:
                return HttpResponse(
                    {
                        "detail":
                        DEFAULT_ERROR_MESSAGE.format(
                            limit=request.rate_limit_metadata.limit,
                            window=request.rate_limit_metadata.window,
                        )
                    },
                    status=429,
                )