This commit is contained in:
parent
b1a221a8e8
commit
b6f1da1580
5 changed files with 407 additions and 4 deletions
|
@ -102,6 +102,9 @@ class ToolshedUser(AbstractUser):
|
||||||
private_key = SigningKey(self.private_key.encode(), encoder=HexEncoder)
|
private_key = SigningKey(self.private_key.encode(), encoder=HexEncoder)
|
||||||
return private_key.sign(message.encode('utf-8'), encoder=HexEncoder).signature.decode('utf-8')
|
return private_key.sign(message.encode('utf-8'), encoder=HexEncoder).signature.decode('utf-8')
|
||||||
|
|
||||||
|
def public_key(self):
|
||||||
|
return self.public_identity.public_key
|
||||||
|
|
||||||
|
|
||||||
class FriendRequestOutgoing(models.Model):
|
class FriendRequestOutgoing(models.Model):
|
||||||
secret = models.CharField(max_length=255)
|
secret = models.CharField(max_length=255)
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
from nacl.exceptions import BadSignatureError
|
||||||
|
from nacl.signing import VerifyKey
|
||||||
from rest_framework import authentication
|
from rest_framework import authentication
|
||||||
|
|
||||||
from authentication.models import KnownIdentity, ToolshedUser
|
from authentication.models import KnownIdentity, ToolshedUser
|
||||||
|
@ -48,6 +50,28 @@ def verify_request(request, raw_request_body):
|
||||||
return username, domain, signed_data, signature_bytes_hex
|
return username, domain, signed_data, signature_bytes_hex
|
||||||
|
|
||||||
|
|
||||||
|
def verify_incoming_friend_request(request, raw_request_body):
|
||||||
|
try:
|
||||||
|
username, domain, signed_data, signature_bytes_hex = verify_request(request, raw_request_body)
|
||||||
|
except ValueError:
|
||||||
|
return False
|
||||||
|
try:
|
||||||
|
befriender = request.data['befriender']
|
||||||
|
befriender_key = request.data['befriender_key']
|
||||||
|
except KeyError:
|
||||||
|
return False
|
||||||
|
if username + "@" + domain != befriender:
|
||||||
|
return False
|
||||||
|
if len(befriender_key) != 64:
|
||||||
|
return False
|
||||||
|
verify_key = VerifyKey(bytes.fromhex(befriender_key))
|
||||||
|
try:
|
||||||
|
verify_key.verify(signed_data.encode('utf-8'), bytes.fromhex(signature_bytes_hex))
|
||||||
|
return True
|
||||||
|
except BadSignatureError:
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
def authenticate_request_against_known_identities(request, raw_request_body):
|
def authenticate_request_against_known_identities(request, raw_request_body):
|
||||||
try:
|
try:
|
||||||
username, domain, signed_data, signature_bytes_hex = verify_request(request, raw_request_body)
|
username, domain, signed_data, signature_bytes_hex = verify_request(request, raw_request_body)
|
||||||
|
|
|
@ -1,11 +1,18 @@
|
||||||
|
import secrets
|
||||||
|
|
||||||
from django.urls import path
|
from django.urls import path
|
||||||
|
from rest_framework import status
|
||||||
|
from rest_framework.decorators import api_view
|
||||||
|
from rest_framework.generics import get_object_or_404
|
||||||
from rest_framework.permissions import IsAuthenticated
|
from rest_framework.permissions import IsAuthenticated
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
from rest_framework.views import APIView
|
from rest_framework.views import APIView
|
||||||
from rest_framework.viewsets import ViewSetMixin
|
from rest_framework.viewsets import ViewSetMixin
|
||||||
|
|
||||||
from authentication.signature_auth import SignatureAuthentication
|
from authentication.models import KnownIdentity, FriendRequestIncoming, FriendRequestOutgoing, ToolshedUser
|
||||||
from toolshed.serializers import FriendSerializer
|
from authentication.signature_auth import verify_incoming_friend_request, split_userhandle_or_throw, \
|
||||||
|
authenticate_request_against_local_users, SignatureAuthentication
|
||||||
|
from toolshed.serializers import FriendSerializer, FriendRequestSerializer
|
||||||
|
|
||||||
|
|
||||||
class Friends(APIView, ViewSetMixin):
|
class Friends(APIView, ViewSetMixin):
|
||||||
|
@ -18,7 +25,102 @@ class Friends(APIView, ViewSetMixin):
|
||||||
serializer = FriendSerializer(friends, many=True)
|
serializer = FriendSerializer(friends, many=True)
|
||||||
return Response(serializer.data)
|
return Response(serializer.data)
|
||||||
|
|
||||||
|
def post(self, request, format=None): # /api/friends/
|
||||||
|
# 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): # /api/friendrequests/
|
||||||
|
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): # /api/friendrequests/
|
||||||
|
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):
|
||||||
|
secret = secrets.token_hex(64)
|
||||||
|
befriendee_user = ToolshedUser.objects.filter(username=befriendee_username, domain=befriendee_domain)
|
||||||
|
if befriendee_user.exists():
|
||||||
|
FriendRequestIncoming.objects.create(
|
||||||
|
befriender_username=befriender_username,
|
||||||
|
befriender_domain=befriender_domain,
|
||||||
|
befriender_public_key=user.public_identity.public_key,
|
||||||
|
secret=secret, # request.data['secret'] # TODO ??
|
||||||
|
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, # request.data['secret'] # TODO ??
|
||||||
|
)
|
||||||
|
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)
|
||||||
|
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path('friends/', Friends.as_view(), name='friends'),
|
path('friends/', Friends.as_view(), name='friends'),
|
||||||
|
path('friendrequests/', FriendsRequests.as_view(), name='friendrequests'),
|
||||||
]
|
]
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
|
from authentication.models import KnownIdentity, ToolshedUser, FriendRequestIncoming
|
||||||
from authentication.models import KnownIdentity, ToolshedUser
|
|
||||||
from authentication.serializers import OwnerSerializer
|
from authentication.serializers import OwnerSerializer
|
||||||
from files.models import File
|
from files.models import File
|
||||||
from files.serializers import FileSerializer
|
from files.serializers import FileSerializer
|
||||||
|
@ -18,6 +17,17 @@ class FriendSerializer(serializers.ModelSerializer):
|
||||||
return obj.username + '@' + obj.domain
|
return obj.username + '@' + obj.domain
|
||||||
|
|
||||||
|
|
||||||
|
class FriendRequestSerializer(serializers.ModelSerializer):
|
||||||
|
befriender = serializers.SerializerMethodField()
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = FriendRequestIncoming
|
||||||
|
fields = ['befriender', 'befriender_public_key', 'secret', 'id']
|
||||||
|
|
||||||
|
def get_befriender(self, obj):
|
||||||
|
return obj.befriender_username + '@' + obj.befriender_domain
|
||||||
|
|
||||||
|
|
||||||
class PropertySerializer(serializers.ModelSerializer):
|
class PropertySerializer(serializers.ModelSerializer):
|
||||||
category = serializers.SlugRelatedField(queryset=Category.objects.all(), slug_field='name')
|
category = serializers.SlugRelatedField(queryset=Category.objects.all(), slug_field='name')
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
|
from django.test import Client
|
||||||
from authentication.tests import SignatureAuthClient, UserTestMixin, ToolshedTestCase
|
from authentication.tests import SignatureAuthClient, UserTestMixin, ToolshedTestCase
|
||||||
|
from authentication.models import FriendRequestIncoming, FriendRequestOutgoing
|
||||||
|
|
||||||
client = SignatureAuthClient()
|
client = SignatureAuthClient()
|
||||||
|
|
||||||
|
@ -75,3 +77,265 @@ class FriendApiTestCase(UserTestMixin, ToolshedTestCase):
|
||||||
self.assertEqual(reply.status_code, 200)
|
self.assertEqual(reply.status_code, 200)
|
||||||
self.assertEqual(len(reply.json()), 1)
|
self.assertEqual(len(reply.json()), 1)
|
||||||
self.assertEqual(reply.json()[0]['username'], str(self.f['local_user1']))
|
self.assertEqual(reply.json()[0]['username'], str(self.f['local_user1']))
|
||||||
|
|
||||||
|
|
||||||
|
# what ~should~ happen:
|
||||||
|
# 1. user x@A sends a friend request to user y@B
|
||||||
|
# 1.1. x@A's client sends a POST request to A/api/friendrequests/ with body {from: x@A, to: y@B}
|
||||||
|
# 1.2. A's backend creates a FriendRequestOutgoing object, containing x@A's identity and y@B's name
|
||||||
|
# 1.3. x@A's client sends a POST request to B/api/friendrequests/ with body
|
||||||
|
# {from: x@A, to: y@B, public_key: x@A's public key}
|
||||||
|
# 1.4. B's backend creates a FriendRequestIncoming object, containing y@B's and x@A's identities
|
||||||
|
# 2. user y@B accepts the friend request
|
||||||
|
# 2.1. y@B's client sends a POST request to A/api/friendsrequests/ with body
|
||||||
|
# {from: x@A, to: y@B, public_key: y@B's public key}
|
||||||
|
# 2.2. A's backend matches the data to the FriendRequestOutgoing object, deletes both and creates a Friend object,
|
||||||
|
# containing x@A's and y@B's identities
|
||||||
|
# 2.3. y@B's client sends a POST request to B/api/friends/ containing the id of the FriendRequestIncoming object
|
||||||
|
# 2.4. B's backend creates a Friend object, using the identities from the FriendRequestIncoming object
|
||||||
|
|
||||||
|
|
||||||
|
class FriendRequestListTestCase(UserTestMixin, ToolshedTestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super().setUp()
|
||||||
|
self.prepare_users()
|
||||||
|
FriendRequestIncoming.objects.create(
|
||||||
|
befriender_username=self.f['ext_user2'].username, befriender_domain=self.f['ext_user2'].domain,
|
||||||
|
befriender_public_key=self.f['ext_user2'].public_key(), befriendee_user=self.f['local_user1'],
|
||||||
|
secret='secret1').save()
|
||||||
|
|
||||||
|
def test_friend_request_withouth_auth(self):
|
||||||
|
reply = Client().get('/api/friendrequests/')
|
||||||
|
self.assertEqual(reply.status_code, 401)
|
||||||
|
|
||||||
|
def test_friend_request_empty(self):
|
||||||
|
reply = client.get('/api/friendrequests/', self.f['local_user2'])
|
||||||
|
self.assertEqual(reply.status_code, 200)
|
||||||
|
self.assertEqual(reply.json(), [])
|
||||||
|
|
||||||
|
def test_friend_request_list(self):
|
||||||
|
reply = client.get('/api/friendrequests/', self.f['local_user1'])
|
||||||
|
self.assertEqual(reply.status_code, 200)
|
||||||
|
self.assertEqual(len(reply.json()), 1)
|
||||||
|
self.assertEqual(reply.json()[0]['befriender'], str(self.f['ext_user2']))
|
||||||
|
self.assertEqual(reply.json()[0]['befriender_public_key'], self.f['ext_user2'].public_key())
|
||||||
|
|
||||||
|
|
||||||
|
class FriendRequestIncomingTestCase(UserTestMixin, ToolshedTestCase):
|
||||||
|
def setUp(self):
|
||||||
|
super().setUp()
|
||||||
|
self.prepare_users()
|
||||||
|
FriendRequestIncoming.objects.create(
|
||||||
|
befriender_username=self.f['ext_user2'].username, befriender_domain=self.f['ext_user2'].domain,
|
||||||
|
befriender_public_key=self.f['ext_user2'].public_key(), befriendee_user=self.f['local_user1'],
|
||||||
|
secret='secret1').save()
|
||||||
|
|
||||||
|
def test_post_request(self):
|
||||||
|
befriender = self.f['ext_user1']
|
||||||
|
befriendee = self.f['local_user1']
|
||||||
|
reply = client.post('/api/friendrequests/', befriender, {
|
||||||
|
'befriender': str(befriender),
|
||||||
|
'befriender_key': befriender.public_key(),
|
||||||
|
'befriendee': str(befriendee),
|
||||||
|
'secret': 'secret2'
|
||||||
|
})
|
||||||
|
self.assertEqual(reply.status_code, 201)
|
||||||
|
self.assertEqual(reply.json()['status'], 'pending')
|
||||||
|
self.assertEqual(FriendRequestIncoming.objects.count(), 2)
|
||||||
|
incoming = FriendRequestIncoming.objects.get(befriender_username=befriender.username,
|
||||||
|
befriender_domain=befriender.domain)
|
||||||
|
self.assertEqual(incoming.befriendee_user, befriendee)
|
||||||
|
self.assertEqual(incoming.befriender_public_key, befriender.public_key())
|
||||||
|
self.assertEqual(incoming.secret, 'secret2')
|
||||||
|
|
||||||
|
def test_post_request_local(self):
|
||||||
|
befriender = self.f['local_user2']
|
||||||
|
befriendee = self.f['local_user1']
|
||||||
|
reply = client.post('/api/friendrequests/', befriender, {
|
||||||
|
'befriender': str(befriender),
|
||||||
|
'befriendee': str(befriendee),
|
||||||
|
# 'secret': 'secret2'
|
||||||
|
})
|
||||||
|
self.assertEqual(reply.status_code, 201)
|
||||||
|
self.assertEqual(reply.json()['status'], 'pending')
|
||||||
|
self.assertEqual(FriendRequestIncoming.objects.count(), 2)
|
||||||
|
incoming = FriendRequestIncoming.objects.get(befriender_username=befriender.username,
|
||||||
|
befriender_domain=befriender.domain)
|
||||||
|
self.assertEqual(incoming.befriendee_user, befriendee)
|
||||||
|
self.assertEqual(incoming.befriender_public_key, befriender.public_key())
|
||||||
|
# self.assertEqual(incoming.secret, 'secret2')
|
||||||
|
|
||||||
|
def test_post_request_withouth_auth(self):
|
||||||
|
reply = Client().post('/api/friendrequests/')
|
||||||
|
self.assertEqual(reply.status_code, 400)
|
||||||
|
|
||||||
|
def test_post_request_broken_header(self):
|
||||||
|
befriender = self.f['ext_user1']
|
||||||
|
befriendee = self.f['local_user1']
|
||||||
|
broken_client = SignatureAuthClient(header_prefix='broken ')
|
||||||
|
reply = broken_client.post('/api/friendrequests/', befriender, {
|
||||||
|
'befriender': str(befriender),
|
||||||
|
'befriender_key': befriender.public_key(),
|
||||||
|
'befriendee': str(befriendee),
|
||||||
|
'secret': 'secret2'
|
||||||
|
})
|
||||||
|
self.assertEqual(reply.status_code, 400)
|
||||||
|
|
||||||
|
def test_post_request_missing_key(self):
|
||||||
|
befriender = self.f['ext_user1']
|
||||||
|
befriendee = self.f['local_user1']
|
||||||
|
reply = client.post('/api/friendrequests/', befriender, {
|
||||||
|
'befriender': str(befriender),
|
||||||
|
'befriendee': str(befriendee),
|
||||||
|
'secret': 'secret2'
|
||||||
|
})
|
||||||
|
self.assertEqual(reply.status_code, 400)
|
||||||
|
|
||||||
|
def test_post_request_breaking_key(self):
|
||||||
|
befriender = self.f['ext_user1']
|
||||||
|
befriendee = self.f['local_user1']
|
||||||
|
reply = client.post('/api/friendrequests/', befriender, {
|
||||||
|
'befriender': str(befriender),
|
||||||
|
'befriendee': str(befriendee),
|
||||||
|
'secret': 'secret2',
|
||||||
|
'befriender_key': 'broken'
|
||||||
|
})
|
||||||
|
self.assertEqual(reply.status_code, 400)
|
||||||
|
|
||||||
|
def test_post_request_wrong_befriender(self):
|
||||||
|
befriender = self.f['ext_user1']
|
||||||
|
befriendee = self.f['local_user1']
|
||||||
|
reply = client.post('/api/friendrequests/', befriender, {
|
||||||
|
'befriender': str(self.f['local_user2']),
|
||||||
|
'befriender_key': befriender.public_key(),
|
||||||
|
'befriendee': str(befriendee),
|
||||||
|
'secret': 'secret2'
|
||||||
|
})
|
||||||
|
self.assertEqual(reply.status_code, 400)
|
||||||
|
|
||||||
|
def test_post_request_bad_signature(self):
|
||||||
|
befriender = self.f['ext_user1']
|
||||||
|
befriendee = self.f['local_user1']
|
||||||
|
bad_signature = SignatureAuthClient(bad_signature=True)
|
||||||
|
reply = bad_signature.post('/api/friendrequests/', befriender, {
|
||||||
|
'befriender': str(befriender),
|
||||||
|
'befriender_key': befriender.public_key(),
|
||||||
|
'befriendee': str(befriendee),
|
||||||
|
'secret': 'secret2'
|
||||||
|
})
|
||||||
|
self.assertEqual(reply.status_code, 400)
|
||||||
|
|
||||||
|
def test_post_request_self(self):
|
||||||
|
befriender = self.f['local_user1']
|
||||||
|
befriendee = self.f['local_user1']
|
||||||
|
reply = client.post('/api/friendrequests/', befriender, {
|
||||||
|
'befriender': str(befriender),
|
||||||
|
'befriender_key': befriender.public_key(),
|
||||||
|
'befriendee': str(befriendee),
|
||||||
|
'secret': 'secret2'
|
||||||
|
})
|
||||||
|
self.assertEqual(reply.status_code, 400)
|
||||||
|
|
||||||
|
def test_post_request_befreindee_not_found(self):
|
||||||
|
befriender = self.f['ext_user1']
|
||||||
|
befriendee = self.f['local_user1']
|
||||||
|
reply = client.post('/api/friendrequests/', befriender, {
|
||||||
|
'befriender': str(befriender),
|
||||||
|
'befriender_key': befriender.public_key(),
|
||||||
|
'befriendee': 'nonexistent@' + befriendee.domain,
|
||||||
|
'secret': 'secret2'
|
||||||
|
})
|
||||||
|
self.assertEqual(reply.status_code, 400)
|
||||||
|
|
||||||
|
def test_post_request_missing_secret(self):
|
||||||
|
befriender = self.f['ext_user1']
|
||||||
|
befriendee = self.f['local_user1']
|
||||||
|
reply = client.post('/api/friendrequests/', befriender, {
|
||||||
|
'befriender': str(befriender),
|
||||||
|
'befriender_key': befriender.public_key(),
|
||||||
|
'befriendee': str(befriendee)
|
||||||
|
})
|
||||||
|
self.assertEqual(reply.status_code, 400)
|
||||||
|
|
||||||
|
def test_accept_request(self):
|
||||||
|
befriender = self.f['ext_user2']
|
||||||
|
befriendee = self.f['local_user1']
|
||||||
|
request = FriendRequestIncoming.objects.filter(befriender_username=befriender.username,
|
||||||
|
befriender_domain=befriender.domain,
|
||||||
|
befriendee_user=befriendee).first()
|
||||||
|
reply = client.post('/api/friends/', befriendee, {
|
||||||
|
'friend_request_id': request.id,
|
||||||
|
'secret': request.secret
|
||||||
|
})
|
||||||
|
self.assertEqual(reply.status_code, 201)
|
||||||
|
self.assertEqual(reply.json(), {'status': 'accepted'})
|
||||||
|
|
||||||
|
def test_accept_request(self):
|
||||||
|
befriender = self.f['ext_user2']
|
||||||
|
befriendee = self.f['local_user1']
|
||||||
|
request = FriendRequestIncoming.objects.filter(befriender_username=befriender.username,
|
||||||
|
befriender_domain=befriender.domain,
|
||||||
|
befriendee_user=befriendee).first()
|
||||||
|
reply = client.post('/api/friends/', befriendee, {
|
||||||
|
'friend_request_id': request.id,
|
||||||
|
'secret': request.secret
|
||||||
|
})
|
||||||
|
self.assertEqual(reply.status_code, 201)
|
||||||
|
self.assertEqual(reply.json(), {'status': 'accepted'})
|
||||||
|
|
||||||
|
def test_accept_request_not_found(self):
|
||||||
|
befriender = self.f['ext_user2']
|
||||||
|
befriendee = self.f['local_user1']
|
||||||
|
reply = client.post('/api/friends/', befriendee, {
|
||||||
|
'friend_request_id': 999,
|
||||||
|
'secret': 'secret1'
|
||||||
|
})
|
||||||
|
self.assertEqual(reply.status_code, 404)
|
||||||
|
|
||||||
|
|
||||||
|
class FriendRequestOutgoingTestCase(UserTestMixin, ToolshedTestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super().setUp()
|
||||||
|
self.prepare_users()
|
||||||
|
FriendRequestOutgoing.objects.create(
|
||||||
|
befriender_user=self.f['local_user2'],
|
||||||
|
befriendee_username=self.f['ext_user1'].username,
|
||||||
|
befriendee_domain=self.f['ext_user1'].domain,
|
||||||
|
secret='secret3'
|
||||||
|
).save()
|
||||||
|
|
||||||
|
def test_post_outgoing_friend_request(self):
|
||||||
|
befriender = self.f['local_user1']
|
||||||
|
befriendee = self.f['ext_user1']
|
||||||
|
reply = client.post('/api/friendrequests/', befriender, {
|
||||||
|
'befriender': str(befriender),
|
||||||
|
'befriendee': str(befriendee),
|
||||||
|
})
|
||||||
|
self.assertEqual(reply.status_code, 201)
|
||||||
|
self.assertTrue('status' in reply.json())
|
||||||
|
self.assertEqual(reply.json()['status'], 'pending')
|
||||||
|
self.assertEqual(FriendRequestOutgoing.objects.count(), 2)
|
||||||
|
outgoing = FriendRequestOutgoing.objects.get(befriender_user=befriender)
|
||||||
|
self.assertTrue('secret' in reply.json())
|
||||||
|
self.assertEqual(reply.json()['secret'], outgoing.secret)
|
||||||
|
self.assertEqual(outgoing.befriendee_username, befriendee.username)
|
||||||
|
self.assertEqual(outgoing.befriendee_domain, befriendee.domain)
|
||||||
|
|
||||||
|
def test_accept_request(self):
|
||||||
|
befriender = self.f['ext_user1']
|
||||||
|
befriendee = self.f['local_user2']
|
||||||
|
reply = client.post('/api/friendrequests/', befriender, {
|
||||||
|
'befriender': str(befriender),
|
||||||
|
'befriender_key': befriender.public_key(),
|
||||||
|
'befriendee': str(befriendee),
|
||||||
|
'secret': 'secret3'
|
||||||
|
})
|
||||||
|
self.assertEqual(reply.status_code, 201)
|
||||||
|
self.assertEqual(reply.json(), {'status': 'accepted'})
|
||||||
|
self.assertEqual(FriendRequestIncoming.objects.count(), 0)
|
||||||
|
self.assertEqual(FriendRequestOutgoing.objects.count(), 0)
|
||||||
|
self.assertEqual(befriendee.friends.count(), 1)
|
||||||
|
self.assertEqual(befriendee.friends.first().username, befriender.username)
|
||||||
|
self.assertEqual(befriendee.friends.first().domain, befriender.domain)
|
||||||
|
|
Loading…
Reference in a new issue