Decrypting image fields for Django REST API responses

I am trying to implement a system in which pictures are encrypted on my database, but when they are sent as a response to a user, this data becomes decrypted. Here is how I am encrypting...

def encrypt_validated_data(obj, image_name):
  for data_key in obj.validated_data:
    if type(obj.validated_data[data_key]) is InMemoryUploadedFile:
      file_extension = obj.validated_data[data_key].image.format.lower()
      file_extension = "." + file_extension
      file_name = image_name + file_extension
      encrypted_file = obj.cipher.encrypt(
        obj.validated_data[data_key].read()
      ).decode("utf-8")
      
      obj.validated_data[data_key] = ContentFile(
        encrypted_file,
        name = file_name
      )
    else:
      obj.validated_data[data_key] = obj.cipher.encrypt(
        obj.validated_data[data_key].encode("utf-8")
      ).decode("utf-8")
  
  return obj

This code is called whenever an object is going to be saved to the database. It encrypts all the fields, and deals with the image case. Now, I need to decrypt this data for my response. My first thought was to manipulate the to_representation on the serializer such that I could decrypt each data part. This works great for text fields, but I haven't figured out a way to do it with image fields! This is the code so far...

class ProfileSerializer(serializers.ModelSerializer):
  cipher = Fernet(settings.ENCRYPTED_FIELDS_KEY)
  profile_picture = serializers.ImageField(required=False)
  
  class Meta:
    model = YearRepresentative
    fields = [
      "user_id",
      "name",
      "profile_picture",
      "pronouns"
    ]
  
  def to_representation(self, instance):
    encrypted_data = super().to_representation(instance)
    for key in encrypted_data:
      # We keep user ids encrypted
      if key == "user_id" or encrypted_data[key] is None:
        pass
      elif key == "profile_picture":
        encrypted_picture = instance.profile_picture
        
        encrypted_file_content = encrypted_picture.read()
        
        decrypted_file_content = self.cipher.decrypt(encrypted_file_content)
        
        decrypted_picture = ContentFile(
          decrypted_file_content,
          name = encrypted_picture.name
        )
        encrypted_data[key] = decrypted_picture 
      else:
        encrypted_field = encrypted_data[key]
        encrypted_data[key] = self.cipher.decrypt(encrypted_field).decode("utf-8")
        
    return encrypted_data

When I call encrypted_data[key] = decrypted_picture, I get the error message...

'utf-8' codec can't decode byte 0x89 in position 0: invalid start byte

Unicode error hint
The string that could not be encoded/decoded was: �PNG

This makes sense, but I'm not sure how to solve it exactly. What I am looking to ultimately achieve with this implementation too is that the decrypted image is only available on API calls - that is, it isn't saved to storage in a place where it can get accessed. Is that possible?

How should I go about decrypting an image and then getting it in a format in which it can be returned as a response? Thank you for any help!

Вернуться на верх