diff options
author | Andrew Godwin | 2022-11-06 21:30:07 -0700 |
---|---|---|
committer | Andrew Godwin | 2022-11-06 21:30:07 -0700 |
commit | fb6c409a9af5b8a686e977ee2251c359071e0ec3 (patch) | |
tree | 322469694585b766eb623b47955623b3e43c89b1 /users/views | |
parent | 0d5f7e7a891bec4b8af26c2d86d8be0209a3202d (diff) | |
download | takahe-fb6c409a9af5b8a686e977ee2251c359071e0ec3.tar.gz takahe-fb6c409a9af5b8a686e977ee2251c359071e0ec3.tar.bz2 takahe-fb6c409a9af5b8a686e977ee2251c359071e0ec3.zip |
Rework task system and fetching.
I can taste how close follow is to working.
Diffstat (limited to 'users/views')
-rw-r--r-- | users/views/identity.py | 59 |
1 files changed, 43 insertions, 16 deletions
diff --git a/users/views/identity.py b/users/views/identity.py index 7134cf9..7cba43e 100644 --- a/users/views/identity.py +++ b/users/views/identity.py @@ -5,9 +5,11 @@ from asgiref.sync import async_to_sync from django import forms from django.conf import settings from django.contrib.auth.decorators import login_required -from django.http import Http404, HttpResponseBadRequest, JsonResponse +from django.http import Http404, HttpResponse, HttpResponseBadRequest, JsonResponse from django.shortcuts import redirect +from django.utils import timezone from django.utils.decorators import method_decorator +from django.utils.http import parse_http_date from django.views.decorators.csrf import csrf_exempt from django.views.generic import FormView, TemplateView, View @@ -15,7 +17,8 @@ from core.forms import FormHelper from core.ld import canonicalise from core.signatures import HttpSignature from miniq.models import Task -from users.models import Domain, Identity +from users.decorators import identity_required +from users.models import Domain, Follow, Identity from users.shortcuts import by_handle_or_404 @@ -24,16 +27,39 @@ class ViewIdentity(TemplateView): template_name = "identity/view.html" def get_context_data(self, handle): - identity = by_handle_or_404(self.request, handle, local=False) + identity = by_handle_or_404( + self.request, + handle, + local=False, + fetch=True, + ) statuses = identity.statuses.all()[:100] if identity.data_age > settings.IDENTITY_MAX_AGE: Task.submit("identity_fetch", identity.handle) return { "identity": identity, "statuses": statuses, + "follow": Follow.maybe_get(self.request.identity, identity) + if self.request.identity + else None, } +@method_decorator(identity_required, name="dispatch") +class ActionIdentity(View): + def post(self, request, handle): + identity = by_handle_or_404(self.request, handle, local=False) + # See what action we should perform + action = self.request.POST["action"] + if action == "follow": + existing_follow = Follow.maybe_get(self.request.identity, identity) + if not existing_follow: + Follow.create_local(self.request.identity, identity) + else: + raise ValueError(f"Cannot handle identity action {action}") + return redirect(identity.urls.view) + + @method_decorator(login_required, name="dispatch") class SelectIdentity(TemplateView): @@ -158,42 +184,43 @@ class Inbox(View): if "HTTP_DIGEST" in request.META: expected_digest = HttpSignature.calculate_digest(request.body) if request.META["HTTP_DIGEST"] != expected_digest: - print("Bad digest") - return HttpResponseBadRequest() + return HttpResponseBadRequest("Digest is incorrect") + # Verify date header + if "HTTP_DATE" in request.META: + header_date = parse_http_date(request.META["HTTP_DATE"]) + if abs(timezone.now().timestamp() - header_date) > 60: + return HttpResponseBadRequest("Date is too far away") # Get the signature details if "HTTP_SIGNATURE" not in request.META: - print("No signature") - return HttpResponseBadRequest() + return HttpResponseBadRequest("No signature present") signature_details = HttpSignature.parse_signature( request.META["HTTP_SIGNATURE"] ) # Reject unknown algorithms if signature_details["algorithm"] != "rsa-sha256": - print("Unknown algorithm") - return HttpResponseBadRequest() + return HttpResponseBadRequest("Unknown signature algorithm") # Create the signature payload headers_string = HttpSignature.headers_from_request( request, signature_details["headers"] ) # Load the LD document = canonicalise(json.loads(request.body)) - print(signature_details) - print(headers_string) - print(document) # Find the Identity by the actor on the incoming item + # This ensures that the signature used for the headers matches the actor + # described in the payload. identity = Identity.by_actor_uri_with_create(document["actor"]) if not identity.public_key: # See if we can fetch it right now async_to_sync(identity.fetch_actor)() if not identity.public_key: - print("Cannot retrieve actor") return HttpResponseBadRequest("Cannot retrieve actor") if not identity.verify_signature( signature_details["signature"], headers_string ): - print("Bad signature") - # return HttpResponseBadRequest("Bad signature") - return JsonResponse({"status": "OK"}) + return HttpResponseBadRequest("Bad signature") + # Hand off the item to be processed by the queue + Task.submit("inbox_item", subject=identity.actor_uri, payload=document) + return HttpResponse(status=202) class Webfinger(View): |