So I want to encrypt files before storage in django and decrypt them upon retrieval.
I am using a custom storage class for the same and the cryptography module.
import hashlib
import os
import uuid
import django.core.files.storage as storage
from cryptography.fernet import Fernet
from django.conf import settings
from django.core.files import File
class DefaultStorage(storage.FileSystemStorage):
def __init__(self):
super(DefaultStorage, self).__init__()
self.encryptor = Fernet(settings.ENCRYPTION_KEY)
def _save(self, name, content):
encrypted = self.encryptor.encrypt(content.file.read())
content.file.write(encrypted)
print(content.file.read() == encrypted)
return super(DefaultStorage, self)._save(name, content)
def _open(self, name, mode='rb'):
encrypted = open(self.path(name), mode).read()
return File(self.encryptor.decrypt(encrypted))
def get_available_name(self, name, max_length=None):
# we return a hash of the file given,
# in case we miss out on uniqueness, django calls
# the get_alternative_name method
dir_name, file_name = os.path.split(name)
file_root, file_ext = os.path.splitext(file_name)
file_root = hashlib.md5(file_root.encode()).hexdigest()
name = os.path.join(dir_name, file_root + file_ext)
return super(DefaultStorage, self).get_available_name(name, max_length)
def get_alternative_name(self, file_root, file_ext):
# we insert a random uuid hex string into the given
# file name before returning the same back
return '%s%s%s' % (file_root, uuid.uuid4().hex, file_ext)
I am overwriting the _save
and _open
methods here, but the class doesn't work as expected.
Under the save method, I want to encrypt the contents of the file, but when I print this:
print(content.file.read() == encrypted)
It returns false.
This means that the file isnt even being encrypted in the firs place. What am I doing wrong here?
Same for _open
method? Can someone please help me? thanks a lot!
EDIT
def _save(self, name, content):
initial = content.file
encrypted = self.encryptor.encrypt(content.file.read())
content.file.write(encrypted)
# the temporary file is already stored in the path
# content.file.name
# we need to write to this directory
print(content.file.seek(0) == encrypted)
return super(DefaultStorage, self)._save(name, content)
this print statement also returns False
EDIT 2
When I removed the existing _open
method, I found out that the file could still be retrieved (without decryption). This means that the file isn't even being encrypted. Any idea why? Can someone please help me?
The _save method:
def _save(self, name, content):
encrypted = self.encryptor.encrypt(content.file.read())
content.file.write(encrypted)
return super(DefaultStorage, self)._save(name, content)
Usually, content.file.read()
leaves the cursor at the end of the file.
If you want to read the file again, you need to move the cursor to the start; otherwise, .read()
will just return empty, because there is nothing after the end of the file.
content.file.seek(0) # places cursor at the start
print(content.file.read() == encrypted) # reads file again
This can be done using content.file.seek(0)
(place cursor at position 0), or by closing and opening the file again.
But careful, reading and writing the same file can be tricky and cause problems. Rather write to an aux file and replace the original file with the new file afterwards.