diff --git a/website/common/templates/security.txt b/website/common/templates/security.txt new file mode 100644 index 0000000..0cbb382 --- /dev/null +++ b/website/common/templates/security.txt @@ -0,0 +1,7 @@ +{% load wagtailcore_tags %} +{% if contact_page %} +Contact: {% pageurl contact_page %} +{% endif %} +Canonical: {{ security_txt }} +Expires: {{ expires }} +Preferred-Languages: en diff --git a/website/common/tests/test_views.py b/website/common/tests/test_views.py index fb6889e..238adf5 100644 --- a/website/common/tests/test_views.py +++ b/website/common/tests/test_views.py @@ -20,3 +20,16 @@ class RobotsViewTestCase(SimpleTestCase): def test_accessible(self) -> None: response = self.client.get(self.url) self.assertEqual(response.status_code, 200) + self.assertEqual(response.context["sitemap"], "http://testserver/sitemap.xml") + + +class SecurityViewTestCase(TestCase): + url = reverse("securitytxt") + + def test_accessible(self) -> None: + response = self.client.get(self.url) + self.assertEqual(response.status_code, 200) + self.assertEqual( + response.context["security_txt"], + "http://testserver/.well-known/security.txt", + ) diff --git a/website/common/views.py b/website/common/views.py index 2a33383..cc739e2 100644 --- a/website/common/views.py +++ b/website/common/views.py @@ -1,10 +1,13 @@ +from datetime import timedelta from typing import Any from django.http.response import HttpResponse from django.urls import reverse +from django.utils import timezone from django.views.defaults import ERROR_404_TEMPLATE_NAME from django.views.generic import TemplateView +from website.contact.models import ContactPage from website.home.models import HomePage @@ -32,3 +35,21 @@ class RobotsView(TemplateView): context = super().get_context_data(**kwargs) context["sitemap"] = self.request.build_absolute_uri(reverse("sitemap")) return context + + +class SecurityView(TemplateView): + template_name = "security.txt" + content_type = "text/plain" + + expires = timedelta(days=7) + + def get_context_data(self, **kwargs: dict) -> dict: + context = super().get_context_data(**kwargs) + context["security_txt"] = self.request.build_absolute_uri( + reverse("securitytxt") + ) + context["contact_page"] = ContactPage.objects.live().first() + context["expires"] = ( + (timezone.now() + self.expires).replace(microsecond=0).isoformat() + ) + return context diff --git a/website/urls.py b/website/urls.py index 657ef04..0fb510d 100644 --- a/website/urls.py +++ b/website/urls.py @@ -6,7 +6,7 @@ from wagtail.contrib.sitemaps.views import sitemap from wagtail.documents import urls as wagtaildocs_urls from wagtail.images.views.serve import ServeView -from website.common.views import RobotsView, page_not_found +from website.common.views import RobotsView, SecurityView, page_not_found urlpatterns = [ path("admin/", include(wagtailadmin_urls)), @@ -22,6 +22,7 @@ urlpatterns = [ ), path("sitemap.xml", sitemap, name="sitemap"), path("robots.txt", RobotsView.as_view(), name="robotstxt"), + path(".well-known/security.txt", SecurityView.as_view(), name="securitytxt"), path("404/", page_not_found, name="404"), ]