|
@@ -1,6 +1,7 @@
|
|
|
from rest_framework import status, viewsets
|
|
|
from rest_framework.decorators import action
|
|
|
-from rest_framework.permissions import IsAuthenticated
|
|
|
+from rest_framework.exceptions import NotAuthenticated
|
|
|
+from rest_framework.permissions import AllowAny, IsAuthenticated
|
|
|
from rest_framework.response import Response
|
|
|
|
|
|
from desecapi import permissions
|
|
@@ -14,15 +15,21 @@ from .base import IdempotentDestroyMixin
|
|
|
|
|
|
|
|
|
class TOTPViewSet(IdempotentDestroyMixin, viewsets.ModelViewSet):
|
|
|
- permission_classes = (
|
|
|
- IsAuthenticated,
|
|
|
- permissions.HasManageTokensPermission,
|
|
|
- )
|
|
|
serializer_class = TOTPFactorSerializer
|
|
|
throttle_scope = "account_management_passive"
|
|
|
|
|
|
+ @property
|
|
|
+ def permission_classes(self):
|
|
|
+ if self.action == "verify":
|
|
|
+ return [AllowAny] # temporary for anonymous activation
|
|
|
+ return [IsAuthenticated, permissions.HasManageTokensPermission]
|
|
|
+
|
|
|
def get_queryset(self):
|
|
|
- return self.serializer_class.Meta.model.objects.filter(user=self.request.user)
|
|
|
+ qs = self.serializer_class.Meta.model.objects
|
|
|
+ if self.action == "verify" and self.request.method == "POST":
|
|
|
+ return qs
|
|
|
+ else:
|
|
|
+ return qs.filter(user=self.request.user)
|
|
|
|
|
|
def create(self, request, *args, **kwargs):
|
|
|
super().create(request, *args, **kwargs)
|
|
@@ -36,8 +43,17 @@ class TOTPViewSet(IdempotentDestroyMixin, viewsets.ModelViewSet):
|
|
|
|
|
|
@action(detail=True, methods=["post"])
|
|
|
def verify(self, request, pk=None):
|
|
|
+ new = self.get_object().last_used is None
|
|
|
+ authenticated = bool(request.user and request.user.is_authenticated)
|
|
|
+ if not new and not authenticated:
|
|
|
+ raise NotAuthenticated
|
|
|
+
|
|
|
serializer = TOTPCodeSerializer(
|
|
|
data=request.data, context=self.get_serializer_context()
|
|
|
)
|
|
|
serializer.is_valid(raise_exception=True)
|
|
|
- return Response({"detail": "The code was correct."})
|
|
|
+
|
|
|
+ message = (
|
|
|
+ "Your TOTP token has been activated!" if new else "The code was correct."
|
|
|
+ )
|
|
|
+ return Response({"detail": message})
|