|
1 | 1 | import structlog
|
| 2 | +from django.conf import settings |
2 | 3 | from django.http import HttpResponse
|
3 | 4 |
|
4 | 5 | log = structlog.get_logger(__name__)
|
@@ -33,3 +34,46 @@ def __call__(self, request):
|
33 | 34 | status=400,
|
34 | 35 | )
|
35 | 36 | return self.get_response(request)
|
| 37 | + |
| 38 | + |
| 39 | +class UpdateCSPMiddleware: |
| 40 | + """ |
| 41 | + Middleware to update the CSP headers for specific views given its URL name. |
| 42 | +
|
| 43 | + This is useful for views that we don't have much control over, |
| 44 | + like views from third-party packages. For views that we have control over, |
| 45 | + we should update the CSP headers directly in the view. |
| 46 | +
|
| 47 | + Use the `RTD_CSP_UPDATE_HEADERS` setting to define the views that need to |
| 48 | + update the CSP headers. The setting should be a dictionary where the key is |
| 49 | + the URL name of the view and the value is a dictionary with the CSP headers, |
| 50 | + for example: |
| 51 | +
|
| 52 | + .. code-block:: python |
| 53 | +
|
| 54 | + RTD_CSP_UPDATE_HEADERS = { |
| 55 | + "login": {"form-action": ["https:"]}, |
| 56 | + } |
| 57 | + """ |
| 58 | + |
| 59 | + def __init__(self, get_response): |
| 60 | + self.get_response = get_response |
| 61 | + |
| 62 | + def __call__(self, request): |
| 63 | + response = self.get_response(request) |
| 64 | + |
| 65 | + # Views that raised an exception don't have a resolver_match object. |
| 66 | + resolver_match = request.resolver_match |
| 67 | + if not resolver_match: |
| 68 | + return response |
| 69 | + |
| 70 | + url_name = resolver_match.url_name |
| 71 | + update_csp_headers = settings.RTD_CSP_UPDATE_HEADERS |
| 72 | + if settings.RTD_EXT_THEME_ENABLED and url_name in update_csp_headers: |
| 73 | + if hasattr(response, "_csp_update"): |
| 74 | + raise ValueError( |
| 75 | + "Can't update CSP headers at the view and middleware at the same time, use one or the other." |
| 76 | + ) |
| 77 | + response._csp_update = update_csp_headers[url_name] |
| 78 | + |
| 79 | + return response |
0 commit comments