From f88efa40d497995a5f645d03f99345c804f808d7 Mon Sep 17 00:00:00 2001 From: Michael Manfre Date: Tue, 22 Nov 2022 23:53:02 -0500 Subject: [PATCH] Code dedupe Webfinger and fix SystemActor inbox URL --- takahe/settings/development.py | 6 ++- tests/conftest.py | 2 +- tests/users/views/test_activitypub.py | 34 +++++++------- users/models/system_actor.py | 5 +- users/views/activitypub.py | 67 ++++++++++----------------- 5 files changed, 53 insertions(+), 61 deletions(-) diff --git a/takahe/settings/development.py b/takahe/settings/development.py index 06e5278..ce75c85 100644 --- a/takahe/settings/development.py +++ b/takahe/settings/development.py @@ -1,4 +1,5 @@ import os +import sys from .base import * # noqa @@ -18,7 +19,10 @@ SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https") EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend" SERVER_EMAIL = "test@example.com" -MAIN_DOMAIN = os.environ.get("TAKAHE_MAIN_DOMAIN", "https://example.com") +MAIN_DOMAIN = os.environ.get("TAKAHE_MAIN_DOMAIN", "example.com") +if "/" in MAIN_DOMAIN: + print("TAKAHE_MAIN_DOMAIN should be just the domain name - no https:// or path") + sys.exit(1) MEDIA_URL = os.environ.get("TAKAHE_MEDIA_URL", "/media/") MEDIA_ROOT = os.environ.get("TAKAHE_MEDIA_ROOT", BASE_DIR / "media") diff --git a/tests/conftest.py b/tests/conftest.py index 69e8e7a..48ee95a 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -74,7 +74,7 @@ def identity(user): """ domain = Domain.objects.create(domain="example.com", local=True, public=True) identity = Identity.objects.create( - actor_uri="https://example.com/test-actor/", + actor_uri="https://example.com/@test@example.com/", username="test", domain=domain, name="Test User", diff --git a/tests/users/views/test_activitypub.py b/tests/users/views/test_activitypub.py index 72ab8c3..d9ad578 100644 --- a/tests/users/views/test_activitypub.py +++ b/tests/users/views/test_activitypub.py @@ -1,26 +1,11 @@ import pytest -from users.models import Domain, Identity, User - @pytest.mark.django_db -def test_webfinger_actor(client): +def test_webfinger_actor(client, identity): """ Ensures the webfinger and actor URLs are working properly """ - # Make a user - user = User.objects.create(email="test@example.com") - # Make a domain - domain = Domain.objects.create(domain="example.com", local=True) - domain.users.add(user) - # Make an identity for them - identity = Identity.objects.create( - actor_uri="https://example.com/@test@example.com/", - username="test", - domain=domain, - name="Test User", - local=True, - ) identity.generate_keypair() # Fetch their webfinger data = client.get("/.well-known/webfinger?resource=acct:test@example.com").json() @@ -29,3 +14,20 @@ def test_webfinger_actor(client): # Fetch their actor data = client.get("/@test@example.com/", HTTP_ACCEPT="application/ld+json").json() assert data["id"] == "https://example.com/@test@example.com/" + + +@pytest.mark.django_db +def test_webfinger_system_actor(client): + """ + Ensures the webfinger and actor URLs are working properly for system actor + """ + # Fetch their webfinger + data = client.get( + "/.well-known/webfinger?resource=acct:__system__@example.com" + ).json() + assert data["subject"] == "acct:__system__@example.com" + assert data["aliases"][0] == "https://example.com/about/" + # Fetch their actor + data = client.get("/actor/", HTTP_ACCEPT="application/ld+json").json() + assert data["id"] == "https://example.com/actor/" + assert data["inbox"] == "https://example.com/actor/inbox/" diff --git a/users/models/system_actor.py b/users/models/system_actor.py index 28ef1a8..c337d78 100644 --- a/users/models/system_actor.py +++ b/users/models/system_actor.py @@ -22,6 +22,9 @@ class SystemActor: self.profile_uri = f"https://{settings.MAIN_DOMAIN}/about/" self.username = "__system__" + def absolute_profile_uri(self): + return self.profile_uri + def generate_keys(self): self.private_key, self.public_key = RsaKeys.generate_keypair() Config.set_system("system_actor_private_key", self.private_key) @@ -39,7 +42,7 @@ class SystemActor: return { "id": self.actor_uri, "type": "Application", - "inbox": self.actor_uri + "/inbox/", + "inbox": self.actor_uri + "inbox/", "preferredUsername": self.username, "url": self.profile_uri, "as:manuallyApprovesFollowers": True, diff --git a/users/views/activitypub.py b/users/views/activitypub.py index 1ca80a1..2c7020a 100644 --- a/users/views/activitypub.py +++ b/users/views/activitypub.py @@ -99,51 +99,34 @@ class Webfinger(View): if not resource.startswith("acct:"): return HttpResponseBadRequest("Not an account resource") handle = resource[5:] + if handle.startswith("__system__@"): # They are trying to webfinger the system actor - system_actor = SystemActor() - return JsonResponse( - { - "subject": f"acct:{handle}", - "aliases": [ - system_actor.profile_uri, - ], - "links": [ - { - "rel": "http://webfinger.net/rel/profile-page", - "type": "text/html", - "href": system_actor.profile_uri, - }, - { - "rel": "self", - "type": "application/activity+json", - "href": system_actor.actor_uri, - }, - ], - } - ) + actor = SystemActor() else: - identity = by_handle_or_404(request, handle) - return JsonResponse( - { - "subject": f"acct:{identity.handle}", - "aliases": [ - identity.absolute_profile_uri(), - ], - "links": [ - { - "rel": "http://webfinger.net/rel/profile-page", - "type": "text/html", - "href": identity.absolute_profile_uri(), - }, - { - "rel": "self", - "type": "application/activity+json", - "href": identity.actor_uri, - }, - ], - } - ) + actor = by_handle_or_404(request, handle) + handle = actor.handle + + return JsonResponse( + { + "subject": f"acct:{handle}", + "aliases": [ + actor.absolute_profile_uri(), + ], + "links": [ + { + "rel": "http://webfinger.net/rel/profile-page", + "type": "text/html", + "href": actor.absolute_profile_uri(), + }, + { + "rel": "self", + "type": "application/activity+json", + "href": actor.actor_uri, + }, + ], + } + ) @method_decorator(csrf_exempt, name="dispatch")