summaryrefslogtreecommitdiffstats
path: root/users/views/identity.py
diff options
context:
space:
mode:
authorAndrew Godwin2022-11-06 21:30:07 -0700
committerAndrew Godwin2022-11-06 21:30:07 -0700
commitfb6c409a9af5b8a686e977ee2251c359071e0ec3 (patch)
tree322469694585b766eb623b47955623b3e43c89b1 /users/views/identity.py
parent0d5f7e7a891bec4b8af26c2d86d8be0209a3202d (diff)
downloadtakahe-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/identity.py')
-rw-r--r--users/views/identity.py59
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):