django-datastar 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (28) hide show
  1. django_datastar-0.1.0/.gitignore +10 -0
  2. django_datastar-0.1.0/LICENSE +21 -0
  3. django_datastar-0.1.0/PKG-INFO +170 -0
  4. django_datastar-0.1.0/README.md +138 -0
  5. django_datastar-0.1.0/docs/api.rst +13 -0
  6. django_datastar-0.1.0/docs/compatibility.rst +63 -0
  7. django_datastar-0.1.0/docs/conf.py +22 -0
  8. django_datastar-0.1.0/docs/csrf.rst +64 -0
  9. django_datastar-0.1.0/docs/index.rst +23 -0
  10. django_datastar-0.1.0/docs/installation.rst +80 -0
  11. django_datastar-0.1.0/docs/security.rst +43 -0
  12. django_datastar-0.1.0/pyproject.toml +96 -0
  13. django_datastar-0.1.0/src/django_datastar/__init__.py +13 -0
  14. django_datastar-0.1.0/src/django_datastar/apps.py +8 -0
  15. django_datastar-0.1.0/src/django_datastar/middleware.py +80 -0
  16. django_datastar-0.1.0/src/django_datastar/py.typed +0 -0
  17. django_datastar-0.1.0/src/django_datastar/static/django_datastar/datastar-csrf.js +154 -0
  18. django_datastar-0.1.0/src/django_datastar/templatetags/__init__.py +0 -0
  19. django_datastar-0.1.0/src/django_datastar/templatetags/django_datastar.py +44 -0
  20. django_datastar-0.1.0/tests/__init__.py +0 -0
  21. django_datastar-0.1.0/tests/installed_package_check.py +43 -0
  22. django_datastar-0.1.0/tests/settings.py +33 -0
  23. django_datastar-0.1.0/tests/templates/bootstrap.html +11 -0
  24. django_datastar-0.1.0/tests/test_csrf.py +88 -0
  25. django_datastar-0.1.0/tests/test_datastar_csrf.mjs +376 -0
  26. django_datastar-0.1.0/tests/test_middleware.py +107 -0
  27. django_datastar-0.1.0/tests/typing_example.py +13 -0
  28. django_datastar-0.1.0/tests/urls.py +20 -0
@@ -0,0 +1,10 @@
1
+ .coverage
2
+ .mypy_cache/
3
+ .pytest_cache/
4
+ .ruff_cache/
5
+ .venv/
6
+ __pycache__/
7
+ build/
8
+ dist/
9
+ docs/_build/
10
+ *.egg-info/
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Marcus A. Lee
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,170 @@
1
+ Metadata-Version: 2.5
2
+ Name: django-datastar
3
+ Version: 0.1.0
4
+ Summary: Request metadata and opt-in CSRF integration for Django and Datastar
5
+ Project-URL: Documentation, https://django-datastar.readthedocs.io/
6
+ Project-URL: Repository, https://github.com/MarcusL11/django_datastar
7
+ Project-URL: Issues, https://github.com/MarcusL11/django_datastar/issues
8
+ Author-email: "Marcus A. Lee" <hello@marcusalee.com>
9
+ License-Expression: MIT
10
+ License-File: LICENSE
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Framework :: Django
13
+ Classifier: Framework :: Django :: 5.2
14
+ Classifier: Framework :: Django :: 6.0
15
+ Classifier: Intended Audience :: Developers
16
+ Classifier: Programming Language :: Python :: 3 :: Only
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Programming Language :: Python :: 3.13
19
+ Classifier: Programming Language :: Python :: 3.14
20
+ Classifier: Typing :: Typed
21
+ Requires-Python: >=3.12
22
+ Requires-Dist: django<6.1,>=5.2
23
+ Provides-Extra: docs
24
+ Requires-Dist: furo>=2024.8.6; extra == 'docs'
25
+ Requires-Dist: sphinx>=8.1; extra == 'docs'
26
+ Provides-Extra: tests
27
+ Requires-Dist: django-stubs>=5.2; extra == 'tests'
28
+ Requires-Dist: mypy>=1.15; extra == 'tests'
29
+ Requires-Dist: pytest-django>=4.10; extra == 'tests'
30
+ Requires-Dist: pytest>=8.3; extra == 'tests'
31
+ Description-Content-Type: text/markdown
32
+
33
+ # django-datastar
34
+
35
+ `django-datastar` provides small, focused integration points between Django and
36
+ [Datastar](https://data-star.dev/):
37
+
38
+ - exact request classification through `Datastar-Request: true`;
39
+ - sync/async middleware-backed `request.datastar` metadata; and
40
+ - an opt-in bridge that supplies Django CSRF tokens to qualifying Datastar
41
+ backend-action requests.
42
+
43
+ It does not provide Datastar response or SSE APIs. Use
44
+ [`datastar-py`](https://github.com/starfederation/datastar/tree/main/sdk/python)
45
+ as a companion when those APIs are needed.
46
+
47
+ > The `Datastar-Request` header is client-controlled metadata. Never use it for
48
+ > authentication, authorization, permissions, or a CSRF bypass.
49
+
50
+ ## Installation
51
+
52
+ Install the package from PyPI:
53
+
54
+ ```console
55
+ python -m pip install django-datastar
56
+ ```
57
+
58
+ To install a development checkout instead, run `python -m pip install .` from
59
+ the repository root.
60
+
61
+ Add the middleware before Django's CSRF middleware:
62
+
63
+ ```python
64
+ MIDDLEWARE = [
65
+ # ...
66
+ "django_datastar.middleware.DatastarMiddleware",
67
+ "django.middleware.csrf.CsrfViewMiddleware",
68
+ # ...
69
+ ]
70
+ ```
71
+
72
+ Use either the helper or the attached details in a view:
73
+
74
+ ```python
75
+ from django.http import HttpResponse
76
+ from django_datastar import DatastarHttpRequest
77
+
78
+
79
+ def update(request: DatastarHttpRequest) -> HttpResponse:
80
+ if request.datastar:
81
+ return HttpResponse("Datastar request")
82
+ return HttpResponse("ordinary request")
83
+ ```
84
+
85
+ `DatastarHttpRequest` is an annotation for requests processed by the middleware;
86
+ Django still creates the actual request object.
87
+
88
+ When middleware-backed request details are not needed, classify a request directly:
89
+
90
+ ```python
91
+ from django.http import HttpRequest
92
+ from django.http import HttpResponse
93
+ from django_datastar import is_datastar
94
+
95
+
96
+ def update(request: HttpRequest) -> HttpResponse:
97
+ if is_datastar(request):
98
+ return HttpResponse("Datastar request")
99
+ return HttpResponse("ordinary request")
100
+ ```
101
+
102
+ ## Automatic CSRF headers
103
+
104
+ The bridge is optional. Add the app when you want its template tag and static
105
+ module:
106
+
107
+ ```python
108
+ INSTALLED_APPS = [
109
+ # ...
110
+ "django_datastar",
111
+ ]
112
+ ```
113
+
114
+ Load the tag before your chosen Datastar bundle:
115
+
116
+ ```django
117
+ {% load django_datastar static %}
118
+
119
+ {% datastar_csrf %}
120
+ <script type="module" src="{% static 'js/datastar.js' %}"></script>
121
+ ```
122
+
123
+ For nonce-based Content Security Policies:
124
+
125
+ ```django
126
+ {% datastar_csrf nonce=request.csp_nonce %}
127
+ ```
128
+
129
+ The tag calls Django's CSRF token machinery and emits a masked token in the DOM,
130
+ so it works with `CSRF_COOKIE_HTTPONLY=True`. The external module reads that token
131
+ at request time and injects `X-CSRFToken` only when all of these conditions hold:
132
+
133
+ - the effective method is unsafe;
134
+ - `Datastar-Request` is exactly `true`;
135
+ - the effective target is same-origin;
136
+ - the request mode is compatible with `same-origin`;
137
+ - no CSRF header was supplied explicitly; and
138
+ - a DOM token is present.
139
+
140
+ Django's `CsrfViewMiddleware` remains solely responsible for validation. The
141
+ bridge assumes Datastar resolves `window.fetch` at request time; see the
142
+ [compatibility documentation](https://django-datastar.readthedocs.io/en/latest/compatibility.html)
143
+ before upgrading Datastar.
144
+
145
+ ## Documentation
146
+
147
+ Build the documentation locally with:
148
+
149
+ ```console
150
+ python -m pip install ".[docs]"
151
+ sphinx-build -W --keep-going -b html docs docs/_build/html
152
+ ```
153
+
154
+ ## Development
155
+
156
+ ```console
157
+ uv sync --group dev
158
+ uv run pytest
159
+ node --test tests/test_datastar_csrf.mjs
160
+ uv run ruff check .
161
+ uv run ruff format --check .
162
+ uv run mypy
163
+ ```
164
+
165
+ Node is contributor and CI tooling only. It is not a runtime dependency for
166
+ Django applications.
167
+
168
+ ## License
169
+
170
+ MIT
@@ -0,0 +1,138 @@
1
+ # django-datastar
2
+
3
+ `django-datastar` provides small, focused integration points between Django and
4
+ [Datastar](https://data-star.dev/):
5
+
6
+ - exact request classification through `Datastar-Request: true`;
7
+ - sync/async middleware-backed `request.datastar` metadata; and
8
+ - an opt-in bridge that supplies Django CSRF tokens to qualifying Datastar
9
+ backend-action requests.
10
+
11
+ It does not provide Datastar response or SSE APIs. Use
12
+ [`datastar-py`](https://github.com/starfederation/datastar/tree/main/sdk/python)
13
+ as a companion when those APIs are needed.
14
+
15
+ > The `Datastar-Request` header is client-controlled metadata. Never use it for
16
+ > authentication, authorization, permissions, or a CSRF bypass.
17
+
18
+ ## Installation
19
+
20
+ Install the package from PyPI:
21
+
22
+ ```console
23
+ python -m pip install django-datastar
24
+ ```
25
+
26
+ To install a development checkout instead, run `python -m pip install .` from
27
+ the repository root.
28
+
29
+ Add the middleware before Django's CSRF middleware:
30
+
31
+ ```python
32
+ MIDDLEWARE = [
33
+ # ...
34
+ "django_datastar.middleware.DatastarMiddleware",
35
+ "django.middleware.csrf.CsrfViewMiddleware",
36
+ # ...
37
+ ]
38
+ ```
39
+
40
+ Use either the helper or the attached details in a view:
41
+
42
+ ```python
43
+ from django.http import HttpResponse
44
+ from django_datastar import DatastarHttpRequest
45
+
46
+
47
+ def update(request: DatastarHttpRequest) -> HttpResponse:
48
+ if request.datastar:
49
+ return HttpResponse("Datastar request")
50
+ return HttpResponse("ordinary request")
51
+ ```
52
+
53
+ `DatastarHttpRequest` is an annotation for requests processed by the middleware;
54
+ Django still creates the actual request object.
55
+
56
+ When middleware-backed request details are not needed, classify a request directly:
57
+
58
+ ```python
59
+ from django.http import HttpRequest
60
+ from django.http import HttpResponse
61
+ from django_datastar import is_datastar
62
+
63
+
64
+ def update(request: HttpRequest) -> HttpResponse:
65
+ if is_datastar(request):
66
+ return HttpResponse("Datastar request")
67
+ return HttpResponse("ordinary request")
68
+ ```
69
+
70
+ ## Automatic CSRF headers
71
+
72
+ The bridge is optional. Add the app when you want its template tag and static
73
+ module:
74
+
75
+ ```python
76
+ INSTALLED_APPS = [
77
+ # ...
78
+ "django_datastar",
79
+ ]
80
+ ```
81
+
82
+ Load the tag before your chosen Datastar bundle:
83
+
84
+ ```django
85
+ {% load django_datastar static %}
86
+
87
+ {% datastar_csrf %}
88
+ <script type="module" src="{% static 'js/datastar.js' %}"></script>
89
+ ```
90
+
91
+ For nonce-based Content Security Policies:
92
+
93
+ ```django
94
+ {% datastar_csrf nonce=request.csp_nonce %}
95
+ ```
96
+
97
+ The tag calls Django's CSRF token machinery and emits a masked token in the DOM,
98
+ so it works with `CSRF_COOKIE_HTTPONLY=True`. The external module reads that token
99
+ at request time and injects `X-CSRFToken` only when all of these conditions hold:
100
+
101
+ - the effective method is unsafe;
102
+ - `Datastar-Request` is exactly `true`;
103
+ - the effective target is same-origin;
104
+ - the request mode is compatible with `same-origin`;
105
+ - no CSRF header was supplied explicitly; and
106
+ - a DOM token is present.
107
+
108
+ Django's `CsrfViewMiddleware` remains solely responsible for validation. The
109
+ bridge assumes Datastar resolves `window.fetch` at request time; see the
110
+ [compatibility documentation](https://django-datastar.readthedocs.io/en/latest/compatibility.html)
111
+ before upgrading Datastar.
112
+
113
+ ## Documentation
114
+
115
+ Build the documentation locally with:
116
+
117
+ ```console
118
+ python -m pip install ".[docs]"
119
+ sphinx-build -W --keep-going -b html docs docs/_build/html
120
+ ```
121
+
122
+ ## Development
123
+
124
+ ```console
125
+ uv sync --group dev
126
+ uv run pytest
127
+ node --test tests/test_datastar_csrf.mjs
128
+ uv run ruff check .
129
+ uv run ruff format --check .
130
+ uv run mypy
131
+ ```
132
+
133
+ Node is contributor and CI tooling only. It is not a runtime dependency for
134
+ Django applications.
135
+
136
+ ## License
137
+
138
+ MIT
@@ -0,0 +1,13 @@
1
+ API reference
2
+ =============
3
+
4
+ .. autofunction:: django_datastar.is_datastar
5
+
6
+ .. autoclass:: django_datastar.DatastarDetails
7
+ :members:
8
+
9
+ .. autoclass:: django_datastar.DatastarHttpRequest
10
+ :members:
11
+
12
+ .. autoclass:: django_datastar.DatastarMiddleware
13
+ :members:
@@ -0,0 +1,63 @@
1
+ Compatibility
2
+ =============
3
+
4
+ Supported matrix
5
+ ----------------
6
+
7
+ The initial compatibility target is:
8
+
9
+ .. list-table::
10
+ :header-rows: 1
11
+
12
+ * - Python
13
+ - Django 5.2
14
+ - Django 6.0
15
+ * - 3.12
16
+ - tested
17
+ - tested
18
+ * - 3.13
19
+ - tested
20
+ - tested
21
+ * - 3.14
22
+ - tested
23
+ - tested
24
+
25
+ All six combinations pass locally and in CI against the built wheel. The
26
+ runtime dependency is ``Django>=5.2,<6.1``. Node 20 and 22 test the JavaScript
27
+ extracted from the wheel in CI; consuming Django projects do not need Node.
28
+
29
+ Datastar and global fetch
30
+ -------------------------
31
+
32
+ The CSRF bridge wraps ``window.fetch`` before the consumer's Datastar module
33
+ loads. Compatibility therefore assumes that the Datastar bundle resolves the
34
+ global fetch function when it sends a request rather than capturing an earlier
35
+ reference or using another transport.
36
+
37
+ Keep the bridge script before Datastar and repeat a real-browser Network-panel
38
+ check when upgrading Datastar. Confirm that an unsafe same-origin backend action
39
+ contains both ``Datastar-Request: true`` and ``X-CSRFToken`` and is accepted by
40
+ Django.
41
+
42
+ Companion Python package
43
+ ------------------------
44
+
45
+ ``datastar-py`` supplies response and SSE helpers and can be installed
46
+ separately. This package neither imports nor pins it.
47
+
48
+ Extraction acceptance
49
+ ---------------------
50
+
51
+ Before the first release, build a wheel and install it into the original Django
52
+ application that proved the behavior. Replace the local middleware and static
53
+ bridge with the package, render ``{% datastar_csrf %}``, and run that
54
+ application's focused tests, Node tests, full suite, lint, formatting, Django
55
+ checks, and staticfiles collection.
56
+
57
+ Then repeat the real-browser backend-action check. Verify the exact marker and
58
+ masked CSRF header, successful Django response, truthy ``request.datastar``, and
59
+ continued rejection of missing or invalid tokens. Include a temporary
60
+ same-origin endpoint that redirects to a second local origin: the qualifying
61
+ fetch must reject in ``same-origin`` mode, and the second origin must receive
62
+ neither the redirected request nor the CSRF header. Do not remove the local
63
+ implementation until the package-backed path passes.
@@ -0,0 +1,22 @@
1
+ from __future__ import annotations
2
+
3
+ from importlib.metadata import version as package_version
4
+
5
+ project = "django-datastar"
6
+ author = "Marcus A. Lee"
7
+ release = package_version("django-datastar")
8
+ version = release
9
+
10
+ extensions = [
11
+ "sphinx.ext.autodoc",
12
+ "sphinx.ext.intersphinx",
13
+ ]
14
+
15
+ intersphinx_mapping = {
16
+ "django": ("https://docs.djangoproject.com/en/stable/", None),
17
+ "python": ("https://docs.python.org/3/", None),
18
+ }
19
+
20
+ templates_path = ["_templates"]
21
+ exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"]
22
+ html_theme = "furo"
@@ -0,0 +1,64 @@
1
+ Automatic CSRF bridge
2
+ =====================
3
+
4
+ Django's ``CsrfViewMiddleware`` remains authoritative. This bridge does not
5
+ validate tokens, exempt views, or bypass Django's protection. It only supplies
6
+ a masked token to a narrow class of requests.
7
+
8
+ Template setup
9
+ --------------
10
+
11
+ Load the package tag and render it before the consumer's Datastar module:
12
+
13
+ .. code-block:: django
14
+
15
+ {% load django_datastar static %}
16
+
17
+ {% datastar_csrf %}
18
+ <script type="module" src="{% static 'js/datastar.js' %}"></script>
19
+
20
+ The tag requires a request-aware template context. It calls Django's
21
+ ``get_token(request)`` and renders:
22
+
23
+ * ``<meta name="datastar-csrf-token" ...>`` containing the escaped masked token;
24
+ * the namespaced ``django_datastar/datastar-csrf.js`` external module.
25
+
26
+ Calling Django's token machinery maintains the CSRF cookie and ``Vary: Cookie``
27
+ response behavior. Because JavaScript reads the masked DOM token rather than the
28
+ cookie, ``CSRF_COOKIE_HTTPONLY=True`` is supported.
29
+
30
+ The order is required: the bridge wraps ``window.fetch``, so it must execute
31
+ before Datastar's module initializes.
32
+
33
+ Content Security Policy
34
+ -----------------------
35
+
36
+ A conventional ``script-src 'self'`` policy can permit the packaged same-origin
37
+ external module. For a nonce-based policy, pass the nonce explicitly:
38
+
39
+ .. code-block:: django
40
+
41
+ {% datastar_csrf nonce=request.csp_nonce %}
42
+
43
+ The nonce value is escaped as an HTML attribute. The package emits no inline
44
+ JavaScript. Applications remain responsible for their complete CSP and for
45
+ configuring their static asset origin.
46
+
47
+ Injection rules
48
+ ---------------
49
+
50
+ The bridge adds ``X-CSRFToken`` only when the effective request:
51
+
52
+ * uses an unsafe method;
53
+ * has ``Datastar-Request`` with the exact value ``true``;
54
+ * targets ``window.location.origin``;
55
+ * has a request mode compatible with ``same-origin``;
56
+ * has no explicit case-insensitive CSRF header; and
57
+ * has a current DOM token.
58
+
59
+ It resolves URL, method, headers, and mode from both ``Request`` input and
60
+ ``fetch`` init overrides. Token-bearing requests use or preserve
61
+ ``mode: "same-origin"``. Accessor-backed ``RequestInit`` members are left to
62
+ native ``fetch`` unchanged rather than being read or rebound by the bridge. If
63
+ the request cannot be safely inspected or transformed, ordinary ``fetch``
64
+ behavior is used without modifying the input.
@@ -0,0 +1,23 @@
1
+ django-datastar
2
+ ===============
3
+
4
+ ``django-datastar`` provides request metadata and an opt-in automatic CSRF
5
+ bridge for Django applications using Datastar.
6
+
7
+ It deliberately does not duplicate Datastar response or SSE APIs. The
8
+ ``datastar-py`` project can be used alongside it when those APIs are needed.
9
+
10
+ .. warning::
11
+
12
+ ``Datastar-Request: true`` is client-controlled metadata. It is never an
13
+ authentication, authorization, permission, or CSRF boundary.
14
+
15
+ .. toctree::
16
+ :maxdepth: 2
17
+ :caption: Contents
18
+
19
+ installation
20
+ csrf
21
+ security
22
+ compatibility
23
+ api
@@ -0,0 +1,80 @@
1
+ Installation
2
+ ============
3
+
4
+ Install the package from PyPI:
5
+
6
+ .. code-block:: console
7
+
8
+ python -m pip install django-datastar
9
+
10
+ To install a development checkout instead, run ``python -m pip install .`` from
11
+ the repository root.
12
+
13
+ Request metadata
14
+ ----------------
15
+
16
+ Add the middleware before Django's CSRF middleware:
17
+
18
+ .. code-block:: python
19
+
20
+ MIDDLEWARE = [
21
+ # ...
22
+ "django_datastar.middleware.DatastarMiddleware",
23
+ "django.middleware.csrf.CsrfViewMiddleware",
24
+ # ...
25
+ ]
26
+
27
+ Every request that reaches the rest of the middleware chain then has a
28
+ ``datastar`` details object. Its truth value is true only when the
29
+ ``Datastar-Request`` header value is exactly ``true``.
30
+
31
+ For a typed view annotation:
32
+
33
+ .. code-block:: python
34
+
35
+ from django.http import HttpResponse
36
+ from django_datastar import DatastarHttpRequest
37
+
38
+ def update(request: DatastarHttpRequest) -> HttpResponse:
39
+ if request.datastar:
40
+ return HttpResponse("Datastar request")
41
+ return HttpResponse("ordinary request")
42
+
43
+ ``DatastarHttpRequest`` describes the middleware-added attribute for type
44
+ checkers. Django continues to construct its normal request object; do not use
45
+ the annotation class as a runtime ``isinstance`` test.
46
+
47
+ Direct request classification
48
+ -----------------------------
49
+
50
+ Use ``is_datastar`` when middleware-backed request details are not needed:
51
+
52
+ .. code-block:: python
53
+
54
+ from django.http import HttpRequest
55
+ from django.http import HttpResponse
56
+ from django_datastar import is_datastar
57
+
58
+ def update(request: HttpRequest) -> HttpResponse:
59
+ if is_datastar(request):
60
+ return HttpResponse("Datastar request")
61
+ return HttpResponse("ordinary request")
62
+
63
+ The helper and ``request.datastar`` use the same exact, case-sensitive header
64
+ check. The header remains client-controlled metadata and must not authorize a
65
+ request or bypass CSRF protection.
66
+
67
+ Optional CSRF bridge
68
+ --------------------
69
+
70
+ To use the template tag and packaged static module, add the app:
71
+
72
+ .. code-block:: python
73
+
74
+ INSTALLED_APPS = [
75
+ # ...
76
+ "django_datastar",
77
+ ]
78
+
79
+ Django's ``staticfiles`` app and a normal staticfiles deployment are required.
80
+ Continue with :doc:`csrf` for template setup.
@@ -0,0 +1,43 @@
1
+ Security
2
+ ========
3
+
4
+ Untrusted marker
5
+ ----------------
6
+
7
+ The ``Datastar-Request`` header can be sent by any client. Its exact ``true``
8
+ value identifies the request format; it does not prove that Datastar, this
9
+ package, or a trusted browser originated the request.
10
+
11
+ Never use the marker or ``request.datastar`` to:
12
+
13
+ * authenticate a user;
14
+ * grant a permission;
15
+ * authorize an operation;
16
+ * skip CSRF checks; or
17
+ * weaken any other security control.
18
+
19
+ Normal Django authentication, authorization, method, origin, and CSRF controls
20
+ must still run.
21
+
22
+ CSRF authority
23
+ --------------
24
+
25
+ ``CsrfViewMiddleware`` performs all server-side CSRF validation. A missing,
26
+ invalid, or inapplicable token is rejected exactly as it would be without this
27
+ package. Do not decorate Datastar endpoints with ``csrf_exempt`` merely because
28
+ the bridge is installed.
29
+
30
+ Header disclosure boundary
31
+ --------------------------
32
+
33
+ The browser bridge limits token injection to same-origin effective targets and
34
+ sets ``mode: "same-origin"``. Cross-origin, explicitly incompatible-mode, safe,
35
+ unmarked, and uninspectable requests pass through unchanged. Explicit CSRF
36
+ headers always win and are not validated or replaced by the bridge.
37
+
38
+ Caching
39
+ -------
40
+
41
+ If a cacheable response changes according to ``request.datastar``, include the
42
+ marker in the cache key, for example with Django's
43
+ ``vary_on_headers("Datastar-Request")`` decorator.