From 37cf309bb008af25c3811f982e219dfc1b0ee9ba Mon Sep 17 00:00:00 2001 From: Jake Howard Date: Thu, 17 Nov 2022 22:36:22 +0000 Subject: [PATCH] Add activitypub well-known forwarding Disabled until needed --- requirements.txt | 1 + website/settings.py | 3 +++ website/well_known/tests.py | 42 ++++++++++++++++++++++++++++++++++++- website/well_known/urls.py | 15 +++++++++++++ website/well_known/views.py | 17 +++++++++++++-- 5 files changed, 75 insertions(+), 3 deletions(-) diff --git a/requirements.txt b/requirements.txt index ef9b846..f312be8 100644 --- a/requirements.txt +++ b/requirements.txt @@ -29,6 +29,7 @@ django-cors-headers==3.13.0 django-csp==3.7 django-permissions-policy==4.13.0 django-enforce-host==1.1.0 +django-proxy==1.2.1 # DRF OpenAPI dependencies uritemplate diff --git a/website/settings.py b/website/settings.py index 2097543..81884a4 100644 --- a/website/settings.py +++ b/website/settings.py @@ -14,6 +14,7 @@ env = environ.Env( SENTRY_DSN=(str, ""), TEST=(bool, False), ALLOWED_HOSTS=(list, ["*"]), + ACTIVITYPUB_HOST=(str, ""), ) # Read local secrets @@ -305,6 +306,8 @@ WAGTAIL_MODERATION_ENABLED = False UNSPLASH_CLIENT_ID = env("UNSPLASH_CLIENT_ID") SPOTIFY_PROXY_HOST = env("SPOTIFY_PROXY_HOST") +ACTIVITYPUB_HOST = env("ACTIVITYPUB_HOST") + SEO_INDEX = env("SEO_INDEX") if DEBUG: diff --git a/website/well_known/tests.py b/website/well_known/tests.py index fe8a8f3..ed3b340 100644 --- a/website/well_known/tests.py +++ b/website/well_known/tests.py @@ -1,4 +1,7 @@ -from django.test import SimpleTestCase, TestCase +from unittest.mock import patch + +from django.http.response import HttpResponse +from django.test import SimpleTestCase, TestCase, override_settings from django.urls import reverse @@ -36,3 +39,40 @@ class MatrixClientViewTestCase(SimpleTestCase): self.assertEqual(response.status_code, 200) self.assertEqual(response["Content-Type"], "application/json") self.assertTemplateUsed(response, "well-known/matrix-client.json") + + +class ActivityPubProxyView(TestCase): + PROXIED_PATHS = [ + reverse("well-known:webfinger"), + reverse("well-known:hostmeta"), + reverse("well-known:nodeinfo"), + ] + + def setUp(self): + super().setUp() + + proxy_view_patcher = patch("website.well_known.views.proxy_view") + self.proxy_view = proxy_view_patcher.start() + self.addCleanup(proxy_view_patcher.stop) + + self.proxy_view.return_value = HttpResponse() + + @override_settings(ACTIVITYPUB_HOST="activitypub.example.com") + def test_urls(self): + for path in self.PROXIED_PATHS: + with self.subTest(path): + response = self.client.get(path) + self.assertEqual(response.status_code, 200) + self.assertEqual( + self.proxy_view.call_args[0][1], + f"https://activitypub.example.com{path}", + ) + self.assertEqual(response["Cache-Control"], "max-age=60") + + @override_settings(ACTIVITYPUB_HOST="") + def test_unconfigured(self): + for path in self.PROXIED_PATHS: + with self.subTest(path): + response = self.client.get(path) + self.assertEqual(response.status_code, 404) + self.assertFalse(self.proxy_view.called) diff --git a/website/well_known/urls.py b/website/well_known/urls.py index c50ac29..9a915a6 100644 --- a/website/well_known/urls.py +++ b/website/well_known/urls.py @@ -20,4 +20,19 @@ urlpatterns = [ views.MatrixClientView.as_view(), name="matrix-client", ), + path( + "webfinger", + views.activitypub_proxy, + name="webfinger", + ), + path( + "hostmeta", + views.activitypub_proxy, + name="hostmeta", + ), + path( + "nodeinfo", + views.activitypub_proxy, + name="nodeinfo", + ), ] diff --git a/website/well_known/views.py b/website/well_known/views.py index a573cfb..066e598 100644 --- a/website/well_known/views.py +++ b/website/well_known/views.py @@ -1,11 +1,13 @@ from datetime import timedelta +from django.conf import settings from django.http.request import HttpRequest -from django.http.response import HttpResponse +from django.http.response import Http404, HttpResponse from django.utils import timezone from django.utils.decorators import method_decorator -from django.views.decorators.cache import cache_control +from django.views.decorators.cache import cache_control, cache_page from django.views.generic import TemplateView +from proxy.views import proxy_view from website.contact.models import ContactPage from website.contrib.singleton_page.utils import SingletonPageCache @@ -46,3 +48,14 @@ class MatrixServerView(TemplateView): class MatrixClientView(TemplateView): template_name = "well-known/matrix-client.json" content_type = "application/json" + + +@cache_page(60) +def activitypub_proxy(request: HttpRequest) -> HttpResponse: + if not settings.ACTIVITYPUB_HOST: + raise Http404 + + return proxy_view( + request, + f"https://{settings.ACTIVITYPUB_HOST}{request.path}", + )