Sanitize calendar export filenames (#2840)
This commit is contained in:
@@ -324,3 +324,21 @@ def test_export_ics_rejects_cross_owner_calendar_at_route_boundary(monkeypatch):
|
||||
assert exc.value.status_code == 404
|
||||
assert not session.event_query.all_called
|
||||
session.close.assert_called_once()
|
||||
|
||||
|
||||
def test_export_ics_sanitizes_calendar_name_for_download_header(monkeypatch):
|
||||
calendar_routes = _import_calendar_routes(monkeypatch)
|
||||
cal = _calendar("alice")
|
||||
cal.name = 'Work\r\nX-Injected: yes";/..\\evil'
|
||||
session = _FakeSession(calendars=[cal])
|
||||
monkeypatch.setattr(calendar_routes, "SessionLocal", lambda: session)
|
||||
export_ics = _route_endpoint(calendar_routes, "/export/{cal_id}", "GET")
|
||||
|
||||
response = asyncio.run(export_ics(_request(), cal_id="cal-target"))
|
||||
|
||||
assert (
|
||||
response.headers["content-disposition"]
|
||||
== 'attachment; filename="Work__X-Injected__yes___.._evil.ics"'
|
||||
)
|
||||
assert response.headers["x-content-type-options"] == "nosniff"
|
||||
session.close.assert_called_once()
|
||||
|
||||
@@ -23,3 +23,19 @@ def test_newlines_become_literal_backslash_n():
|
||||
def test_empty_and_none_safe():
|
||||
assert _esc()("") == ""
|
||||
assert _esc()(None) == ""
|
||||
|
||||
|
||||
def test_safe_ics_filename_strips_header_metacharacters():
|
||||
safe_filename = _import_calendar_helpers()._safe_ics_filename
|
||||
|
||||
assert (
|
||||
safe_filename('Work\r\nX-Injected: yes";/..\\evil')
|
||||
== "Work__X-Injected__yes___.._evil.ics"
|
||||
)
|
||||
|
||||
|
||||
def test_safe_ics_filename_falls_back_for_empty_names():
|
||||
safe_filename = _import_calendar_helpers()._safe_ics_filename
|
||||
|
||||
assert safe_filename("////") == "calendar.ics"
|
||||
assert safe_filename(None) == "calendar.ics"
|
||||
|
||||
Reference in New Issue
Block a user