From 3dfceb63b139efbf5d7196bf77e5a78d65761fac Mon Sep 17 00:00:00 2001 From: Tom Hacohen Date: Mon, 29 Jun 2020 14:50:06 +0300 Subject: [PATCH] Views: move the base64 encoding to the renderers. Hard-coding the serialization encoding in the serializers is wrong. This fix now enables us to change to easily change to msgpack as the transport layer. --- django_etebase/renderers.py | 18 ++++++++++++++++++ django_etebase/serializers.py | 21 +++++++++++---------- django_etebase/views.py | 12 ++++++------ 3 files changed, 35 insertions(+), 16 deletions(-) create mode 100644 django_etebase/renderers.py diff --git a/django_etebase/renderers.py b/django_etebase/renderers.py new file mode 100644 index 0000000..43c1a0d --- /dev/null +++ b/django_etebase/renderers.py @@ -0,0 +1,18 @@ +from rest_framework.utils.encoders import JSONEncoder as DRFJSONEncoder +from rest_framework.renderers import JSONRenderer as DRFJSONRenderer + +from .serializers import b64encode + + +class JSONEncoder(DRFJSONEncoder): + def default(self, obj): + if isinstance(obj, bytes) or isinstance(obj, memoryview): + return b64encode(obj) + return super().default(obj) + + +class JSONRenderer(DRFJSONRenderer): + """ + Renderer which serializes to JSON with support for our base64 + """ + encoder_class = JSONEncoder diff --git a/django_etebase/serializers.py b/django_etebase/serializers.py index 1876572..f78cd6b 100644 --- a/django_etebase/serializers.py +++ b/django_etebase/serializers.py @@ -56,18 +56,19 @@ def b64decode(data): return base64.urlsafe_b64decode(data) +def b64decode_or_bytes(data): + if isinstance(data, bytes): + return data + else: + return b64decode(data) + + class BinaryBase64Field(serializers.Field): def to_representation(self, value): - if self.context.get('supports_binary', False): - return value - else: - return b64encode(value) + return value def to_internal_value(self, data): - if isinstance(data, bytes): - return data - else: - return b64decode(data) + return b64decode_or_bytes(data) class CollectionEncryptionKeyField(BinaryBase64Field): @@ -91,14 +92,14 @@ class ChunksField(serializers.RelatedField): obj = obj.chunk if self.context.get('prefetch'): with open(obj.chunkFile.path, 'rb') as f: - return (obj.uid, b64encode(f.read())) + return (obj.uid, f.read()) else: return (obj.uid, ) def to_internal_value(self, data): if data[0] is None or data[1] is None: raise serializers.ValidationError('null is not allowed') - return (data[0], b64decode(data[1])) + return (data[0], b64decode_or_bytes(data[1])) class CollectionItemChunkSerializer(serializers.ModelSerializer): diff --git a/django_etebase/views.py b/django_etebase/views.py index 93a7645..970ad8c 100644 --- a/django_etebase/views.py +++ b/django_etebase/views.py @@ -29,7 +29,7 @@ from rest_framework import viewsets from rest_framework.decorators import action as action_decorator from rest_framework.response import Response from rest_framework.parsers import JSONParser, FormParser, MultiPartParser -from rest_framework.renderers import JSONRenderer, BrowsableAPIRenderer +from rest_framework.renderers import BrowsableAPIRenderer import nacl.encoding import nacl.signing @@ -42,6 +42,7 @@ from .drf_msgpack.parsers import MessagePackParser from .drf_msgpack.renderers import MessagePackRenderer from . import app_settings, permissions +from .renderers import JSONRenderer from .models import ( Collection, CollectionItem, @@ -53,7 +54,6 @@ from .models import ( UserInfo, ) from .serializers import ( - b64encode, AuthenticationChangePasswordInnerSerializer, AuthenticationSignupSerializer, AuthenticationLoginChallengeSerializer, @@ -700,8 +700,8 @@ class AuthenticationViewSet(viewsets.ViewSet): challenge = box.encrypt(msgpack_encode(challenge_data), encoder=nacl.encoding.RawEncoder) ret = { - "salt": b64encode(salt), - "challenge": b64encode(challenge), + "salt": salt, + "challenge": challenge, "version": user.userinfo.version, } return Response(ret, status=status.HTTP_200_OK) @@ -717,7 +717,7 @@ class AuthenticationViewSet(viewsets.ViewSet): response = msgpack_decode(response_raw) signature = outer_serializer.validated_data['signature'] - context = {'host': request.get_host(), 'supports_binary': True} + context = {'host': request.get_host()} serializer = AuthenticationLoginInnerSerializer(data=response, context=context) serializer.is_valid(raise_exception=True) @@ -750,7 +750,7 @@ class AuthenticationViewSet(viewsets.ViewSet): response = msgpack_decode(response_raw) signature = outer_serializer.validated_data['signature'] - context = {'host': request.get_host(), 'supports_binary': True} + context = {'host': request.get_host()} serializer = AuthenticationChangePasswordInnerSerializer(request.user.userinfo, data=response, context=context) serializer.is_valid(raise_exception=True)