From 005f9fc0797431e17b5f693d4b4d7575ef2a0cdd Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Tue, 27 Aug 2024 13:31:44 -0700 Subject: [PATCH] Adds decorator for views that require federation to be enabled --- bookwyrm/decorators.py | 13 +++++++++++++ bookwyrm/models/activitypub_mixin.py | 3 +++ bookwyrm/models/site.py | 6 ++++++ bookwyrm/views/follow.py | 5 +++++ bookwyrm/views/inbox.py | 2 ++ bookwyrm/views/wellknown.py | 8 ++++++++ 6 files changed, 37 insertions(+) create mode 100644 bookwyrm/decorators.py diff --git a/bookwyrm/decorators.py b/bookwyrm/decorators.py new file mode 100644 index 000000000..56eef8fda --- /dev/null +++ b/bookwyrm/decorators.py @@ -0,0 +1,13 @@ +""" Custom view decorators """ +from functools import wraps +from bookwyrm.models.site import SiteSettings + + +def require_federation(function): + """Ensure that federation is allowed before proceeding with this view""" + + @wraps(function) + def wrap(request, *args, **kwargs): # pylint: disable=unused-argument + SiteSettings.objects.get().raise_federation_disabled() + + return wrap diff --git a/bookwyrm/models/activitypub_mixin.py b/bookwyrm/models/activitypub_mixin.py index 54ad11511..7758ecc4f 100644 --- a/bookwyrm/models/activitypub_mixin.py +++ b/bookwyrm/models/activitypub_mixin.py @@ -129,6 +129,9 @@ class ActivitypubMixin: def broadcast(self, activity, sender, software=None, queue=BROADCAST): """send out an activity""" + site_model = apps.get_model("bookwyrm.SiteSettings", require_ready=True) + site_model.objects.get().raise_federation_disabled() + broadcast_task.apply_async( args=( sender.id, diff --git a/bookwyrm/models/site.py b/bookwyrm/models/site.py index 15af25c1c..09f67419a 100644 --- a/bookwyrm/models/site.py +++ b/bookwyrm/models/site.py @@ -12,6 +12,7 @@ from django.utils import timezone from model_utils import FieldTracker from bookwyrm.connectors.abstract_connector import get_data +from bookwyrm.connectors import ConnectorException from bookwyrm.preview_images import generate_site_preview_image_task from bookwyrm.settings import BASE_URL, ENABLE_PREVIEW_IMAGES, STATIC_FULL_URL from bookwyrm.settings import RELEASE_API @@ -133,6 +134,11 @@ class SiteSettings(SiteModel): """helper to build the logo url""" return self.get_url("favicon", "images/favicon.png") + def raise_federation_disabled(self): + """Don't connect to the outside world""" + if self.disable_federation: + raise ConnectorException("Federation is disabled") + def get_url(self, field, default_path): """get a media url or a default static path""" uploaded = getattr(self, field, None) diff --git a/bookwyrm/views/follow.py b/bookwyrm/views/follow.py index dcb1c695c..0ff0001f6 100644 --- a/bookwyrm/views/follow.py +++ b/bookwyrm/views/follow.py @@ -9,6 +9,7 @@ from django.template.response import TemplateResponse from django.views.decorators.http import require_POST from bookwyrm import models +from bookwyrm.decorators import require_federation from bookwyrm.models.relationship import clear_cache from .helpers import ( get_user_from_username, @@ -131,6 +132,7 @@ def delete_follow_request(request): return redirect(f"/user/{request.user.localname}") +@require_federation def ostatus_follow_request(request): """prepare an outgoing remote follow request""" uri = urllib.parse.unquote(request.GET.get("acct")) @@ -169,6 +171,7 @@ def ostatus_follow_request(request): @login_required +@require_federation def ostatus_follow_success(request): """display success message for remote follow""" user = get_user_from_username(request.user, request.GET.get("following")) @@ -176,6 +179,7 @@ def ostatus_follow_success(request): return TemplateResponse(request, "ostatus/success.html", data) +@require_federation def remote_follow_page(request): """display remote follow page""" user = get_user_from_username(request.user, request.GET.get("user")) @@ -184,6 +188,7 @@ def remote_follow_page(request): @require_POST +@require_federation def remote_follow(request): """direct user to follow from remote account using ostatus subscribe protocol""" remote_user = request.POST.get("remote_user") diff --git a/bookwyrm/views/inbox.py b/bookwyrm/views/inbox.py index 4b95469d9..4a1f954d6 100644 --- a/bookwyrm/views/inbox.py +++ b/bookwyrm/views/inbox.py @@ -13,6 +13,7 @@ from django.views import View from django.views.decorators.csrf import csrf_exempt from bookwyrm import activitypub, models +from bookwyrm.decorators import require_federation from bookwyrm.tasks import app, INBOX from bookwyrm.signatures import Signature from bookwyrm.utils import regex @@ -21,6 +22,7 @@ logger = logging.getLogger(__name__) @method_decorator(csrf_exempt, name="dispatch") +@method_decorator(require_federation, name="dispatch") # pylint: disable=no-self-use class Inbox(View): """requests sent by outside servers""" diff --git a/bookwyrm/views/wellknown.py b/bookwyrm/views/wellknown.py index e640c1c72..4e3d6e4d7 100644 --- a/bookwyrm/views/wellknown.py +++ b/bookwyrm/views/wellknown.py @@ -9,10 +9,12 @@ from django.utils import timezone from django.views.decorators.http import require_GET from bookwyrm import models +from bookwyrm.decorators import require_federation from bookwyrm.settings import BASE_URL, DOMAIN, VERSION, LANGUAGE_CODE @require_GET +@require_federation def webfinger(request): """allow other servers to ask about a user""" resource = request.GET.get("resource") @@ -42,6 +44,7 @@ def webfinger(request): @require_GET +@require_federation def nodeinfo_pointer(_): """direct servers to nodeinfo""" return JsonResponse( @@ -57,6 +60,7 @@ def nodeinfo_pointer(_): @require_GET +@require_federation def nodeinfo(_): """basic info about the server""" status_count = models.Status.objects.filter(user__local=True, deleted=False).count() @@ -92,6 +96,7 @@ def nodeinfo(_): @require_GET +@require_federation def instance_info(_): """let's talk about your cool unique instance""" user_count = models.User.objects.filter(is_active=True, local=True).count() @@ -121,6 +126,7 @@ def instance_info(_): @require_GET +@require_federation def peers(_): """list of federated servers this instance connects with""" names = models.FederatedServer.objects.filter(status="federated").values_list( @@ -130,12 +136,14 @@ def peers(_): @require_GET +@require_federation def host_meta(request): """meta of the host""" return TemplateResponse(request, "host_meta.xml", {"DOMAIN": DOMAIN}) @require_GET +@require_federation def opensearch(request): """Open Search xml spec""" site = models.SiteSettings.get()