Skip to content

Commit

Permalink
Custom error on CSRF failures, closes #2390
Browse files Browse the repository at this point in the history
  • Loading branch information
simonw committed Aug 15, 2024
1 parent 9306766 commit 06d4ffb
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 1 deletion.
12 changes: 12 additions & 0 deletions datasette/app.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from asgi_csrf import Errors
import asyncio
from typing import Any, Dict, Iterable, List, Optional, Sequence, Tuple, Union
import asgi_csrf
Expand Down Expand Up @@ -1657,13 +1658,24 @@ async def setup_db():
if not database.is_mutable:
await database.table_counts(limit=60 * 60 * 1000)

async def custom_csrf_error(scope, send, message_id):
await asgi_send(
send,
await self.render_template(
"csrf_error.html",
{"message_id": message_id, "message_name": Errors(message_id).name},
),
403,
)

asgi = asgi_csrf.asgi_csrf(
DatasetteRouter(self, routes),
signing_secret=self._secret,
cookie_name="ds_csrftoken",
skip_if_scope=lambda scope: any(
pm.hook.skip_csrf(datasette=self, scope=scope)
),
send_csrf_failed=custom_csrf_error,
)
if self.setting("trace_debug"):
asgi = AsgiTracer(asgi)
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ def get_version():
"uvicorn>=0.11",
"aiofiles>=0.4",
"janus>=0.6.2",
"asgi-csrf>=0.9",
"asgi-csrf>=0.10",
"PyYAML>=5.3",
"mergedeep>=1.1.1",
"itsdangerous>=1.1",
Expand Down
14 changes: 14 additions & 0 deletions tests/test_html.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from asgi_csrf import Errors
from bs4 import BeautifulSoup as Soup
from datasette.app import Datasette
from datasette.utils import allowed_pragmas
Expand Down Expand Up @@ -1158,3 +1159,16 @@ async def test_database_color(ds_client):

pdb.set_trace()
assert any(fragment in response.text for fragment in expected_fragments)


@pytest.mark.asyncio
async def test_custom_csrf_error(ds_client):
response = await ds_client.post(
"/-/messages",
data={
"message": "A message",
},
cookies={"csrftoken": "x"},
)
assert response.status_code == 403
assert "Error code is FORM_URLENCODED_MISMATCH." in response.text

0 comments on commit 06d4ffb

Please sign in to comment.