from django.conf import settings
from django.shortcuts import get_object_or_404
from rest_framework import viewsets
from rest_framework.response import Response
from rest_framework.views import APIView
from .serializers import MixnetSerializer
from .models import Auth, Mixnet, Key
from base.serializers import KeySerializer, AuthSerializer
[docs]class MixnetViewSet(viewsets.ModelViewSet):
    """
    API endpoint that allows mixnets to be viewed or edited.
    """
    queryset = Mixnet.objects.all()
    serializer_class = MixnetSerializer
[docs]    def create(self, request):
        """
        This create a new mixnet and public key
         * auths: [ {"name": str, "url": str} ]
         * voting: id
         * position: int / nullable
         * key: { "p": int, "g": int } / nullable
        """
        auths = request.data.get("auths")
        voting = request.data.get("voting")
        key = request.data.get("key", {"p": 0, "g": 0})
        position = request.data.get("position", 0)
        p, g = int(key["p"]), int(key["g"])
        dbauths = []
        for auth in auths:
            isme = auth["url"] == settings.BASEURL
            a, _ = Auth.objects.get_or_create(name=auth["name"],
                                              url=auth["url"],
                                              me=isme)
            dbauths.append(a)
        mn = Mixnet(voting_id=voting, auth_position=position)
        mn.save()
        for a in dbauths:
            mn.auths.add(a)
        mn.gen_key(p, g)
        data = {"key": {"p": mn.key.p, "g": mn.key.g}}
        # chained call to the next auth to gen the key
        resp = mn.chain_call("/", data)
        if resp:
            y = (resp["y"] * mn.key.y) % mn.key.p
        else:
            y = mn.key.y
        pubkey = Key(p=mn.key.p, g=mn.key.g, y=y)
        pubkey.save()
        mn.pubkey = pubkey
        mn.save()
        return Response(KeySerializer(pubkey, many=False).data)  
[docs]class Shuffle(APIView):
[docs]    def post(self, request, voting_id):
        """
         * voting_id: id
         * msgs: [ [int, int] ]
         * pk: { "p": int, "g": int, "y": int } / nullable
         * position: int / nullable
        """
        position = request.data.get("position", 0)
        mn = get_object_or_404(
            Mixnet,
            voting_id=voting_id,
            auth_position=position)
        msgs = request.data.get("msgs", [])
        pk = request.data.get("pk", None)
        if pk:
            p, g, y = pk["p"], pk["g"], pk["y"]
        else:
            p, g, y = mn.key.p, mn.key.g, mn.key.y
        msgs = mn.shuffle(msgs, (p, g, y))
        data = {
            "msgs": msgs,
            "pk": {"p": p, "g": g, "y": y},
        }
        # chained call to the next auth to gen the key
        resp = mn.chain_call("/shuffle/{}/".format(voting_id), data)
        if resp:
            msgs = resp
        return Response(msgs)  
[docs]class Decrypt(APIView):
[docs]    def post(self, request, voting_id):
        """
         * voting_id: id
         * msgs: [ [int, int] ]
         * pk: { "p": int, "g": int, "y": int } / nullable
         * position: int / nullable
        """
        position = request.data.get("position", 0)
        mn = get_object_or_404(
            Mixnet,
            voting_id=voting_id,
            auth_position=position)
        msgs = request.data.get("msgs", [])
        pk = request.data.get("pk", None)
        if pk:
            p, g, y = pk["p"], pk["g"], pk["y"]
        else:
            p, g, y = mn.key.p, mn.key.g, mn.key.y
        next_auths = mn.next_auths()
        last = next_auths.count() == 0
        # useful for tests only, to override the last value
        last = request.data.get("force-last", last)
        msgs = mn.decrypt(msgs, (p, g, y), last=last)
        data = {
            "msgs": msgs,
            "pk": {"p": p, "g": g, "y": y},
        }
        # chained call to the next auth to gen the key
        resp = mn.chain_call("/decrypt/{}/".format(voting_id), data)
        if resp:
            msgs = resp
        return Response(msgs)