157 lines
7.7 KiB
Python
157 lines
7.7 KiB
Python
import secrets
|
|
|
|
from django.urls import path
|
|
from rest_framework import status
|
|
from rest_framework.decorators import api_view, authentication_classes, permission_classes
|
|
from rest_framework.generics import get_object_or_404
|
|
from rest_framework.permissions import IsAuthenticated
|
|
from rest_framework.response import Response
|
|
from rest_framework.views import APIView
|
|
from rest_framework.viewsets import ViewSetMixin
|
|
|
|
from authentication.models import KnownIdentity, FriendRequestIncoming, FriendRequestOutgoing, ToolshedUser
|
|
from authentication.signature_auth import verify_incoming_friend_request, split_userhandle_or_throw, \
|
|
authenticate_request_against_local_users, SignatureAuthenticationLocal, SignatureAuthentication
|
|
from toolshed.serializers import FriendSerializer, FriendRequestSerializer
|
|
|
|
|
|
class Friends(APIView, ViewSetMixin):
|
|
authentication_classes = [SignatureAuthentication]
|
|
permission_classes = [IsAuthenticated]
|
|
|
|
def get(self, request, format=None):
|
|
user = request.user
|
|
friends = user.friends.all()
|
|
serializer = FriendSerializer(friends, many=True)
|
|
return Response(serializer.data)
|
|
|
|
def post(self, request, format=None):
|
|
# only for local users
|
|
try:
|
|
user = request.user
|
|
incoming_request = FriendRequestIncoming.objects.get(
|
|
pk=request.data.get('friend_request_id'),
|
|
secret=request.data.get('secret'))
|
|
befriender, _ = KnownIdentity.objects.get_or_create(
|
|
username=incoming_request.befriender_username,
|
|
domain=incoming_request.befriender_domain,
|
|
public_key=incoming_request.befriender_public_key
|
|
)
|
|
befriender.save()
|
|
user.user.get().friends.add(befriender)
|
|
user.user.get().save()
|
|
incoming_request.delete()
|
|
return Response(status=status.HTTP_201_CREATED, data={'status': 'accepted'})
|
|
except FriendRequestIncoming.DoesNotExist:
|
|
return Response(status=status.HTTP_404_NOT_FOUND, data={'status': 'not found'})
|
|
|
|
|
|
class FriendsRequests(APIView, ViewSetMixin):
|
|
def get(self, request, format=None):
|
|
raw_request = request.body.decode('utf-8')
|
|
if user := authenticate_request_against_local_users(request, raw_request):
|
|
friends_requests = user.friend_requests_incoming.all()
|
|
serializer = FriendRequestSerializer(friends_requests, many=True)
|
|
return Response(serializer.data)
|
|
else:
|
|
return Response(status=status.HTTP_401_UNAUTHORIZED, data={'status': 'unauthorized'})
|
|
|
|
def post(self, request, format=None):
|
|
raw_request = request.body.decode('utf-8')
|
|
if 'befriender' not in request.data or 'befriendee' not in request.data:
|
|
return Response(status=status.HTTP_400_BAD_REQUEST, data={'status': 'missing parameters'})
|
|
befriender_username, befriender_domain = split_userhandle_or_throw(request.data['befriender'])
|
|
befriendee_username, befriendee_domain = split_userhandle_or_throw(request.data['befriendee'])
|
|
if befriender_domain == befriendee_domain and befriender_username == befriendee_username:
|
|
return Response(status=status.HTTP_400_BAD_REQUEST, data={'status': 'cannot befriend yourself'})
|
|
if user := authenticate_request_against_local_users(request, raw_request): # befriender is local
|
|
secret = secrets.token_hex(64)
|
|
befriendee_user = ToolshedUser.objects.filter(username=befriendee_username, domain=befriendee_domain)
|
|
if befriendee_user.exists(): # befriendee is local (both are local)
|
|
if user.friends.filter(username=befriendee_username, domain=befriendee_domain).exists():
|
|
return Response(status=status.HTTP_208_ALREADY_REPORTED, data={'status': "exists"})
|
|
existing_request = FriendRequestIncoming.objects.filter(
|
|
befriender_username=befriender_username,
|
|
befriender_domain=befriender_domain,
|
|
befriendee_user=befriendee_user.get())
|
|
if existing_request.exists():
|
|
return Response(status=status.HTTP_208_ALREADY_REPORTED, data={'status': "exists"})
|
|
FriendRequestIncoming.objects.create(
|
|
befriender_username=befriender_username,
|
|
befriender_domain=befriender_domain,
|
|
befriender_public_key=user.public_identity.public_key,
|
|
secret=secret,
|
|
befriendee_user=befriendee_user.get(),
|
|
)
|
|
return Response(status=status.HTTP_201_CREATED, data={'secret': secret, 'status': "pending"})
|
|
else:
|
|
FriendRequestOutgoing.objects.create(
|
|
befriender_user=user,
|
|
befriendee_username=befriendee_username,
|
|
befriendee_domain=befriendee_domain,
|
|
secret=secret,
|
|
)
|
|
return Response(status=status.HTTP_201_CREATED, data={'secret': secret, 'status': "pending"})
|
|
elif verify_incoming_friend_request(request, raw_request):
|
|
try:
|
|
befriendee = ToolshedUser.objects.get(username=befriendee_username, domain=befriendee_domain)
|
|
outgoing = FriendRequestOutgoing.objects.filter(
|
|
secret=request.data['secret'],
|
|
befriender_user=befriendee, # both sides match
|
|
befriendee_username=befriender_username,
|
|
befriendee_domain=befriender_domain)
|
|
if outgoing.exists():
|
|
befriender, _ = KnownIdentity.objects.get_or_create(
|
|
username=befriender_username,
|
|
domain=befriender_domain,
|
|
public_key=request.data['befriender_key']
|
|
)
|
|
befriender.save()
|
|
befriendee.friends.add(befriender)
|
|
befriendee.save()
|
|
outgoing.delete()
|
|
return Response(status=status.HTTP_201_CREATED, data={'status': "accepted"})
|
|
else:
|
|
FriendRequestIncoming.objects.create(
|
|
befriender_username=befriender_username,
|
|
befriender_domain=befriender_domain,
|
|
befriender_public_key=request.data['befriender_key'],
|
|
befriendee_user=befriendee,
|
|
secret=request.data['secret']
|
|
)
|
|
return Response(status=status.HTTP_201_CREATED, data={'status': "pending"})
|
|
except ToolshedUser.DoesNotExist:
|
|
return Response(status=status.HTTP_400_BAD_REQUEST)
|
|
except KeyError:
|
|
return Response(status=status.HTTP_400_BAD_REQUEST)
|
|
else:
|
|
return Response(status=status.HTTP_400_BAD_REQUEST)
|
|
|
|
|
|
@api_view(['DELETE'])
|
|
@authentication_classes([SignatureAuthenticationLocal])
|
|
@permission_classes([IsAuthenticated])
|
|
def dropFriend(request, pk, format=None):
|
|
user = request.user
|
|
friend = get_object_or_404(user.friends, pk=pk)
|
|
user.friends.remove(friend)
|
|
user.save()
|
|
return Response(status=status.HTTP_204_NO_CONTENT)
|
|
|
|
|
|
@api_view(['DELETE'])
|
|
@authentication_classes([SignatureAuthenticationLocal])
|
|
@permission_classes([IsAuthenticated])
|
|
def deleteFriendRequest(request, pk, format=None):
|
|
user = request.user
|
|
get_object_or_404(user.friend_requests_incoming, pk=pk).delete()
|
|
user.save()
|
|
return Response(status=status.HTTP_204_NO_CONTENT)
|
|
|
|
|
|
urlpatterns = [
|
|
path('friends/', Friends.as_view(), name='friends'),
|
|
path('friends/<int:pk>/', dropFriend),
|
|
path('friendrequests/', FriendsRequests.as_view(), name='friendrequests'),
|
|
path('friendrequests/<int:pk>/', deleteFriendRequest),
|
|
]
|