from aspen_crypto.keys import Ed25519PrivateKey
from lcrequests.tokens import V4PasetoToken

from django.contrib.auth import get_user_model
from django.test import TestCase
from rest_framework import status
from rest_framework.test import APIClient

from ..models import EncryptionKey

User = get_user_model()


class RestFrameworkPasetoTokenAuthenticationTest(TestCase):
    def setUp(self):
        self.api_client = APIClient(enforce_csrf_checks=True)
        self.user = User.objects.create_user(username="foo", is_superuser=True)

        self.key_ed25519 = Ed25519PrivateKey.generate()
        self.key_ed25519_orphan = Ed25519PrivateKey.generate()

        self.user_key_ed25519 = EncryptionKey.objects.create(
            name='ed255919-drf',
            user=self.user,
            key=self.key_ed25519.public_key.as_pem.decode(),
        )
        self.user_key_ed25519.refresh_from_db()

    def test_no_auth_unauthenticated_user(self):
        response = self.api_client.get(
            f'/api/encipher/encryptionkey/{self.user_key_ed25519.cid}/',
        )
        self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)

    def test_invalid_auth_unauthenticated_user(self):
        auth = 'Paseto what-a-crazy-token'
        response = self.api_client.get(
            f'/api/encipher/encryptionkey/{self.user_key_ed25519.cid}/',
            HTTP_AUTHORIZATION=auth,
        )
        self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)

    def test_unverifiable_key_unauthenticated_user(self):
        auth = 'Paseto eyJ0eXAiOiJKV1QiLCJhbGciOiJFZERTQSIsImtpZCI6IjJiNDIyZWNkZjM3YTYxNjVkOGRiMTY0MzE2N2UxNjEyYmZlNjE0ZmJmYWQwYmRiY2E2NjJkMGIyMDVlN2UxNGIifQ.eyJ1c2VybmFtZSI6ImZvbyIsInRpbWUiOjE2NDczNjg2MzksIm5vbmNlIjoibmNYTlpTaHlrWUkifQ.hNUay432cUdfUDYAfcRAvIpnWHPpmJK2saLdLvQAyllTDnzL9dpzehjv6uULOabTnzL_9YzulOnS4jXPh-tpCg'  # noqa
        response = self.api_client.get(
            f'/api/encipher/encryptionkey/{self.user_key_ed25519.cid}/',
            HTTP_AUTHORIZATION=auth,
        )
        self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)

    def test_signed_token_authenticates_user(self):
        auth = V4PasetoToken(
            user_cid=self.user.cid,
            private_key=self.key_ed25519,
        ).auth_header()
        self.assertTrue(self.user.has_perm('encipher.view_encryptionkey'))

        response = self.api_client.get(
            f'/api/encipher/encryptionkey/{self.user_key_ed25519.cid}/',
            HTTP_AUTHORIZATION=auth,
        )
        self.assertEqual(response.status_code, status.HTTP_200_OK)

    def test_auth_requesting_correct_public_key_succeeds(self):
        auth = V4PasetoToken(
            user_cid=self.user.cid,
            private_key=self.key_ed25519,
        ).auth_header()

        response = self.api_client.get(
            f'/api/encipher/encryptionkey/{self.user_key_ed25519.cid}/',
            HTTP_AUTHORIZATION=auth,
        )
        self.assertEqual(response.status_code, status.HTTP_200_OK, response.json())

    def test_auth_requesting_nonexistent_public_key_fails(self):
        auth = V4PasetoToken(
            user_cid=self.user.cid,
            private_key=self.key_ed25519_orphan,
        ).auth_header()

        response = self.api_client.get(
            f'/api/encipher/encryptionkey/{self.user_key_ed25519.cid}/',
            HTTP_AUTHORIZATION=auth,
        )
        self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED, response.json())
