Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion djangoapi_guard/adapters.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,11 @@ def read_body_prefix(self, max_bytes: int) -> bytes:

class DjangoResponseFactory:
def create_response(self, content: str, status_code: int) -> DjangoGuardResponse:
return DjangoGuardResponse(HttpResponse(content, status=status_code))
return DjangoGuardResponse(
HttpResponse(
content, status=status_code, content_type="text/plain; charset=utf-8"
)
)

def create_redirect_response(
self, url: str, status_code: int
Expand Down
1 change: 1 addition & 0 deletions tests/test_adapters.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ def test_django_response_factory_create() -> None:
factory = DjangoResponseFactory()
guard_resp = factory.create_response("error", 403)
assert guard_resp.status_code == 403
assert guard_resp.headers["Content-Type"] == "text/plain; charset=utf-8"


def test_django_response_factory_redirect() -> None:
Expand Down
71 changes: 71 additions & 0 deletions tests/test_block_response_content_type.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
from django.http import HttpRequest, HttpResponse
from django.test import RequestFactory
from guard_core.models import SecurityConfig
from guard_core.protocols.response_protocol import GuardResponse

from djangoapi_guard.middleware import DjangoAPIGuard

BLOCKED_IP = "203.0.113.10"


def _config(**overrides: object) -> SecurityConfig:
return SecurityConfig(
blacklist=[BLOCKED_IP],
enable_rate_limiting=False,
enable_redis=False,
enable_agent=False,
enable_penetration_detection=False,
**overrides, # type: ignore[arg-type]
)


def _make_middleware(config: SecurityConfig) -> DjangoAPIGuard:
import django.conf

django.conf.settings.GUARD_SECURITY_CONFIG = config

def get_response(request: HttpRequest) -> HttpResponse:
return HttpResponse("OK", status=200)

return DjangoAPIGuard(get_response)


def _blocked_response_headers(config: SecurityConfig) -> tuple[int, str, str]:
middleware = _make_middleware(config)
factory = RequestFactory()
request = factory.get("/ping")
request.META["REMOTE_ADDR"] = BLOCKED_IP
response = middleware(request)
return (
response.status_code,
response.get("Content-Type", ""),
response.get("X-Content-Type-Options", ""),
)


def test_block_response_is_plain_text() -> None:
assert _blocked_response_headers(_config()) == (
403,
"text/plain; charset=utf-8",
"nosniff",
)


def test_custom_error_message_is_plain_text() -> None:
config = _config(custom_error_responses={403: "Access denied"})

status_code, content_type, _nosniff = _blocked_response_headers(config)

assert (status_code, content_type) == (403, "text/plain; charset=utf-8")


def test_response_modifier_can_still_set_its_own_content_type() -> None:
def problem_json(response: GuardResponse) -> GuardResponse:
response.headers["Content-Type"] = "application/problem+json"
return response

config = _config(custom_response_modifier=problem_json)

status_code, content_type, _nosniff = _blocked_response_headers(config)

assert (status_code, content_type) == (403, "application/problem+json")
Loading