Przeglądaj źródła

feat(api): expose tokens only at creation time

Peter Thomassen 5 lat temu
rodzic
commit
2a306dbb54

+ 10 - 0
api/desecapi/serializers.py

@@ -54,6 +54,16 @@ class TokenSerializer(serializers.ModelSerializer):
         fields = ('id', 'created', 'name', 'token',)
         fields = ('id', 'created', 'name', 'token',)
         read_only_fields = ('created', 'token', 'id')
         read_only_fields = ('created', 'token', 'id')
 
 
+    def __init__(self, *args, include_plain=False, **kwargs):
+        self.include_plain = include_plain
+        return super().__init__(*args, **kwargs)
+
+    def get_fields(self):
+        fields = super().get_fields()
+        if not self.include_plain:
+            fields.pop('token')
+        return fields
+
 
 
 class RequiredOnPartialUpdateCharField(serializers.CharField):
 class RequiredOnPartialUpdateCharField(serializers.CharField):
     """
     """

+ 8 - 2
api/desecapi/views.py

@@ -60,6 +60,12 @@ class TokenViewSet(IdempotentDestroy,
     def get_queryset(self):
     def get_queryset(self):
         return self.request.user.auth_tokens.all()
         return self.request.user.auth_tokens.all()
 
 
+    def get_serializer(self, *args, **kwargs):
+        # When creating a new token, return the plaintext representation
+        if self.request.method == 'POST':
+            kwargs.setdefault('include_plain', True)
+        return super().get_serializer(*args, **kwargs)
+
     def perform_create(self, serializer):
     def perform_create(self, serializer):
         serializer.save(user=self.request.user)
         serializer.save(user=self.request.user)
 
 
@@ -442,7 +448,7 @@ class AccountLoginView(generics.GenericAPIView):
         token = models.Token.objects.create(user=user, name="login")
         token = models.Token.objects.create(user=user, name="login")
         user_logged_in.send(sender=user.__class__, request=self.request, user=user)
         user_logged_in.send(sender=user.__class__, request=self.request, user=user)
 
 
-        data = serializers.TokenSerializer(token).data
+        data = serializers.TokenSerializer(token, include_plain=True).data
         return Response(data)
         return Response(data)
 
 
 
 
@@ -585,7 +591,7 @@ class AuthenticatedActivateUserActionView(AuthenticatedActionView):
                           "configuring a router (or other DNS client), place it into the password field of the "
                           "configuring a router (or other DNS client), place it into the password field of the "
                           "configuration. Do not confuse the secret token with your account password! Your password is "
                           "configuration. Do not confuse the secret token with your account password! Your password is "
                           "not needed for DNS configuration, and you should not store it anywhere in plain text.",
                           "not needed for DNS configuration, and you should not store it anywhere in plain text.",
-                **serializers.TokenSerializer(token).data,
+                **serializers.TokenSerializer(token, include_plain=True).data,
             })
             })
         else:
         else:
             return Response({
             return Response({

+ 5 - 4
docs/authentication.rst

@@ -378,10 +378,11 @@ To retrieve a list of currently valid tokens, issue a ``GET`` request::
 
 
 The server will respond with a list of token objects, each containing a
 The server will respond with a list of token objects, each containing a
 timestamp when the token was created (note the ``Z`` indicating the UTC
 timestamp when the token was created (note the ``Z`` indicating the UTC
-timezone), an ID to identify that token, as well as the secret token value
-itself. Each token can carry a name that has no operational
-relevance to the API and is for user reference only. All tokens created
-by the log in endpoint will have "login" as name.
+timezone) and an ID to identify that token. Furthermore, each token can
+carry a name that is of no operational relevance to the API (it is meant
+for user reference only). Certain API operations (such as login) will
+automatically populate the ``name`` field with values such as "login" or
+"dyndns".
 
 
 ::
 ::
 
 

+ 1 - 2
test/e2e/schemas.js

@@ -87,12 +87,11 @@ exports.rrsets = {
 
 
 exports.token = {
 exports.token = {
     properties: {
     properties: {
-        token: { type: "string" },
         name: { type: "string" },
         name: { type: "string" },
         created: { type: "string" },
         created: { type: "string" },
         id: { type: "integer" },
         id: { type: "integer" },
     },
     },
-    required: ["token", "name", "created", "id"]
+    required: ["name", "created", "id"]
 };
 };
 
 
 exports.tokens = {
 exports.tokens = {