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
8 changes: 7 additions & 1 deletion django-stubs/conf/global_settings.pyi
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from collections.abc import Sequence
from collections.abc import Collection, Mapping, Sequence
from re import Pattern

# This is defined here as a do-nothing function because we can't import
Expand Down Expand Up @@ -541,3 +541,9 @@ SECURE_REDIRECT_EXEMPT: list[str]
SECURE_REFERRER_POLICY: str
SECURE_SSL_HOST: str | None
SECURE_SSL_REDIRECT: bool

##################
# CSP MIDDLEWARE #
##################
SECURE_CSP: Mapping[str, Collection[str] | str]
SECURE_CSP_REPORT_ONLY: Mapping[str, Collection[str] | str]
10 changes: 10 additions & 0 deletions django-stubs/middleware/csp.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
from django.http import HttpRequest, HttpResponse
from django.utils.csp import CSP as CSP
from django.utils.csp import LazyNonce
from django.utils.deprecation import MiddlewareMixin

def get_nonce(request: HttpRequest) -> LazyNonce | None: ...

class ContentSecurityPolicyMiddleware(MiddlewareMixin):
def process_request(self, request: HttpRequest) -> None: ...
def process_response(self, request: HttpRequest, response: HttpResponse) -> HttpResponse: ...
1 change: 1 addition & 0 deletions django-stubs/template/context_processors.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ from django.utils.functional import SimpleLazyObject

_R = TypeVar("_R", bound=HttpRequest)

def csp(request: HttpRequest) -> dict[str, SimpleLazyObject | None]: ...
def csrf(request: HttpRequest) -> dict[str, SimpleLazyObject]: ...
def debug(request: HttpRequest) -> dict[str, Callable | bool]: ...
def i18n(request: HttpRequest) -> dict[str, list[tuple[str, str]] | bool | str]: ...
Expand Down
33 changes: 33 additions & 0 deletions django-stubs/utils/csp.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import sys
from collections.abc import Collection, Mapping

from django.utils.functional import SimpleLazyObject

if sys.version_info >= (3, 11):
from enum import StrEnum as _StrEnum
else:
from enum import Enum

class _ReprEnum(Enum): ... # type: ignore[misc]
class _StrEnum(str, _ReprEnum): ... # type: ignore[misc]

class CSP(_StrEnum):
HEADER_ENFORCE = "Content-Security-Policy"
HEADER_REPORT_ONLY = "Content-Security-Policy-Report-Only"

NONE = "'none'"
REPORT_SAMPLE = "'report-sample'"
SELF = "'self'"
STRICT_DYNAMIC = "'strict-dynamic'"
UNSAFE_EVAL = "'unsafe-eval'"
UNSAFE_HASHES = "'unsafe-hashes'"
UNSAFE_INLINE = "'unsafe-inline'"
WASM_UNSAFE_EVAL = "'wasm-unsafe-eval'"

NONCE = "<CSP_NONCE_SENTINEL>"

class LazyNonce(SimpleLazyObject):
def __init__(self) -> None: ...
def __bool__(self) -> bool: ...

def build_policy(config: Mapping[str, Collection[str] | str], nonce: SimpleLazyObject | str | None = None) -> str: ...
7 changes: 7 additions & 0 deletions django-stubs/views/decorators/csp.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
from collections.abc import Callable, Collection, Mapping
from typing import Any, TypeVar

_F = TypeVar("_F", bound=Callable[..., Any])

def csp_override(config: Mapping[str, Collection[str] | str]) -> Callable[[_F], _F]: ...
def csp_report_only_override(config: Mapping[str, Collection[str] | str]) -> Callable[[_F], _F]: ...
6 changes: 0 additions & 6 deletions scripts/stubtest/allowlist_todo_django60.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
django.conf.FORMS_URLFIELD_ASSUME_HTTPS_DEPRECATED_MSG
django.conf.global_settings.FORMS_URLFIELD_ASSUME_HTTPS
django.conf.global_settings.SECURE_CSP
django.conf.global_settings.SECURE_CSP_REPORT_ONLY
django.conf.global_settings.TASKS
django.conf.global_settings.URLIZE_ASSUME_HTTPS
django.contrib.admin.AdminSite.password_change_form
Expand Down Expand Up @@ -212,7 +210,6 @@ django.forms.ClearableFileInput.use_fieldset
django.forms.models.BaseModelForm.validate_constraints
django.forms.renderers.Jinja2DivFormRenderer
django.forms.widgets.ClearableFileInput.use_fieldset
django.middleware.csp
django.tasks
django.tasks.backends
django.tasks.backends.base
Expand All @@ -223,7 +220,6 @@ django.tasks.checks
django.tasks.exceptions
django.tasks.signals
django.template.base.PartialTemplate
django.template.context_processors.csp
django.template.defaulttags.PartialDefNode
django.template.defaulttags.PartialNode
django.template.defaulttags.partial_func
Expand All @@ -232,7 +228,6 @@ django.test.runner.QueryFormatter
django.test.selenium.SeleniumTestCase.get_browser_logs
django.test.testcases._AssertTemplateUsedContext.rendered_template_names
django.utils.copy
django.utils.csp
django.utils.datastructures.DeferredSubDict
django.utils.deprecation.RemovedInDjango60Warning
django.utils.deprecation.RemovedInDjango70Warning
Expand All @@ -245,4 +240,3 @@ django.utils.itercompat
django.utils.json
django.utils.log.log_message
django.utils.text.acompress_sequence
django.views.decorators.csp
27 changes: 27 additions & 0 deletions tests/assert_type/views/test_decorators.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
from django.http import HttpRequest, HttpResponse
from django.views.decorators.csp import csp_override, csp_report_only_override
from typing_extensions import assert_type


@csp_override(
{
"default-src": ["'self'"],
"script-src": ["'self'", "'unsafe-inline'"],
"report-uri": "/path/to/reports-endpoint/",
}
)
def my_view(request: HttpRequest) -> HttpResponse: ...


@csp_report_only_override(
{
"default-src": ["'self'"],
"script-src": ["'self'", "'unsafe-inline'"],
"report-uri": "/path/to/reports-endpoint/",
}
)
def my_view2(request: HttpRequest) -> HttpResponse: ...


assert_type(my_view(HttpRequest()), HttpResponse)
assert_type(my_view2(HttpRequest()), HttpResponse)
Loading