From 3e5f8a3269d58346a6126ed1c2950e79f88f9421 Mon Sep 17 00:00:00 2001 From: yelinz Date: Mon, 15 Jan 2024 10:47:59 +0100 Subject: [PATCH] fix: enable cleanup for storage attribute add checks to prevent misconfigured usage complete coverage --- alexandria/core/factories.py | 2 +- .../core/management/commands/encrypt_files.py | 11 +++ alexandria/core/presign_urls.py | 9 +- alexandria/core/storage_clients.py | 86 ------------------- .../core/tests/snapshots/snap_test_api.py | 36 ++++---- alexandria/core/tests/test_views.py | 19 +++- alexandria/core/views.py | 29 ++----- alexandria/storages/fields.py | 11 ++- .../storages/tests/test_dynamic_field.py | 4 + 9 files changed, 72 insertions(+), 135 deletions(-) delete mode 100644 alexandria/core/storage_clients.py diff --git a/alexandria/core/factories.py b/alexandria/core/factories.py index dbeb8861..7843e9cd 100644 --- a/alexandria/core/factories.py +++ b/alexandria/core/factories.py @@ -107,7 +107,7 @@ class FileFactory(BaseFactory): name = factory.Maybe( factory.LazyAttribute(lambda o: o.variant == models.File.Variant.ORIGINAL), - yes_declaration=factory.Sequence(lambda n: "Version #%i" % ((int(n) + 1) / 2)), + yes_declaration=Faker("name"), no_declaration=factory.LazyAttribute( lambda o: f"{o.original.name}_preview.jpg" ), diff --git a/alexandria/core/management/commands/encrypt_files.py b/alexandria/core/management/commands/encrypt_files.py index a8686af3..8c29f5d5 100644 --- a/alexandria/core/management/commands/encrypt_files.py +++ b/alexandria/core/management/commands/encrypt_files.py @@ -12,6 +12,17 @@ def add_arguments(self, parser): parser.add_argument("--dry", dest="dry", action="store_true", default=False) def handle(self, *args, **options): + if ( + not settings.ALEXANDRIA_ENABLE_AT_REST_ENCRYPTION + or settings.ALEXANDRIA_ENCRYPTION_METHOD + == File.EncryptionStatus.NOT_ENCRYPTED + ): + return self.stdout.write( + self.style.WARNING( + "Encryption is not enabled. Skipping encryption of files." + ) + ) + for file in tqdm( File.objects.filter(encryption_status=File.EncryptionStatus.NOT_ENCRYPTED) ): diff --git a/alexandria/core/presign_urls.py b/alexandria/core/presign_urls.py index 7376fa85..fffba021 100644 --- a/alexandria/core/presign_urls.py +++ b/alexandria/core/presign_urls.py @@ -4,6 +4,7 @@ from django.conf import settings from django.utils import timezone from django.utils.http import urlsafe_base64_encode +from rest_framework.exceptions import ValidationError from rest_framework_json_api.relations import reverse @@ -45,10 +46,8 @@ def verify_signed_components(pk, hostname, expires, scheme, token_sig): host, expires, signature = make_signature_components(pk, hostname, expires, scheme) if int(now.timestamp()) > expires: - raise TimeoutError() - try: - assert token_sig == signature - except AssertionError: - raise + raise ValidationError("Download URL expired.") + if not token_sig == signature: + raise ValidationError("Invalid signature.") return True diff --git a/alexandria/core/storage_clients.py b/alexandria/core/storage_clients.py deleted file mode 100644 index 5253c0bb..00000000 --- a/alexandria/core/storage_clients.py +++ /dev/null @@ -1,86 +0,0 @@ -from datetime import timedelta -from functools import wraps -from logging import getLogger - -import minio -from django.conf import settings -from minio.commonconfig import CopySource - -log = getLogger(__name__) - - -def _retry_on_missing_bucket(fn): - """Create missing bucket if needed (decorator). - - If enabled in the settings, try to create the bucket if it - doesn't exist yet, then retry. - """ - - @wraps(fn) - def wrapper(self, *args, **kwargs): - try: - return fn(self, *args, **kwargs) - except minio.error.S3Error as exc: # pragma: todo cover - if ( - exc.code == "NoSuchBucket" - and settings.ALEXANDRIA_MINIO_STORAGE_AUTO_CREATE_MEDIA_BUCKET - ): - log.warning( - f"Minio bucket '{self.bucket}' missing, trying to create it" - ) - self.client.make_bucket(self.bucket) - return fn(self, *args, **kwargs) - raise - - return wrapper - - -class Minio: - def __init__(self): - endpoint = settings.ALEXANDRIA_MINIO_STORAGE_ENDPOINT - access_key = settings.ALEXANDRIA_MINIO_STORAGE_ACCESS_KEY - secret_key = settings.ALEXANDRIA_MINIO_STORAGE_SECRET_KEY - secure = settings.ALEXANDRIA_MINIO_STORAGE_USE_HTTPS - self.client = minio.Minio( - endpoint, access_key=access_key, secret_key=secret_key, secure=secure - ) - self.bucket = settings.ALEXANDRIA_MINIO_STORAGE_MEDIA_BUCKET_NAME - - @_retry_on_missing_bucket - def download_url(self, object_name): - return self.client.presigned_get_object( - self.bucket, - object_name, - timedelta(minutes=settings.ALEXANDRIA_MINIO_PRESIGNED_TTL_MINUTES), - ) - - @_retry_on_missing_bucket - def upload_url(self, object_name): - return self.client.presigned_put_object( - self.bucket, - object_name, - timedelta(minutes=settings.ALEXANDRIA_MINIO_PRESIGNED_TTL_MINUTES), - ) - - @_retry_on_missing_bucket - def remove_object(self, object_name): - self.client.remove_object(self.bucket, object_name) - - @_retry_on_missing_bucket - def get_object(self, object_name): - data = self.client.get_object(self.bucket, object_name) - return data - - def copy_object(self, source_name, target_name): - self.client.copy_object( - self.bucket, target_name, CopySource(self.bucket, source_name) - ) - - -if settings.ALEXANDRIA_MEDIA_STORAGE_SERVICE == "minio": - client = Minio() -else: # pragma: no cover - client = None - raise NotImplementedError( - f"Storage service {settings.ALEXANDRIA_MEDIA_STORAGE_SERVICE} is not implemented!" - ) diff --git a/alexandria/core/tests/snapshots/snap_test_api.py b/alexandria/core/tests/snapshots/snap_test_api.py index 8edb65e6..554696df 100644 --- a/alexandria/core/tests/snapshots/snap_test_api.py +++ b/alexandria/core/tests/snapshots/snap_test_api.py @@ -112,10 +112,10 @@ snapshots["test_api_create[FileViewSet] 1"] = { "queries": [ 'SELECT "alexandria_core_document"."created_at", "alexandria_core_document"."created_by_user", "alexandria_core_document"."created_by_group", "alexandria_core_document"."modified_at", "alexandria_core_document"."modified_by_user", "alexandria_core_document"."modified_by_group", "alexandria_core_document"."metainfo", "alexandria_core_document"."id", "alexandria_core_document"."title", "alexandria_core_document"."description", "alexandria_core_document"."category_id", "alexandria_core_document"."date" FROM "alexandria_core_document" WHERE "alexandria_core_document"."id" = \'9dd4e461-268c-8034-f5c8-564e155c67a6\'::uuid LIMIT 21', - 'INSERT INTO "alexandria_core_file" ("created_at", "created_by_user", "created_by_group", "modified_at", "modified_by_user", "modified_by_group", "metainfo", "id", "variant", "original_id", "name", "document_id", "checksum", "encryption_status", "content") VALUES (\'2017-05-21T00:00:00+00:00\'::timestamptz, \'admin\', \'admin\', \'2017-05-21T00:00:00+00:00\'::timestamptz, \'admin\', \'admin\', \'{}\', \'f561aaf6-ef0b-f14d-4208-bb46a4ccb3ad\'::uuid, \'original\', NULL, \'Version #33\', \'9dd4e461-268c-8034-f5c8-564e155c67a6\'::uuid, \'sha256:945db0f84bf4ec45cf1c4835cb61848210d64c3867f5a3d78f55ca18e4a98879\', NULL, \'f561aaf6-ef0b-f14d-4208-bb46a4ccb3ad_Version_33\')', + 'INSERT INTO "alexandria_core_file" ("created_at", "created_by_user", "created_by_group", "modified_at", "modified_by_user", "modified_by_group", "metainfo", "id", "variant", "original_id", "name", "document_id", "checksum", "encryption_status", "content") VALUES (\'2017-05-21T00:00:00+00:00\'::timestamptz, \'admin\', \'admin\', \'2017-05-21T00:00:00+00:00\'::timestamptz, \'admin\', \'admin\', \'{}\', \'f561aaf6-ef0b-f14d-4208-bb46a4ccb3ad\'::uuid, \'original\', NULL, \'Jason Lopez\', \'9dd4e461-268c-8034-f5c8-564e155c67a6\'::uuid, \'sha256:945db0f84bf4ec45cf1c4835cb61848210d64c3867f5a3d78f55ca18e4a98879\', NULL, \'f561aaf6-ef0b-f14d-4208-bb46a4ccb3ad_Jason_Lopez\')', """UPDATE "alexandria_core_document" SET "created_at" = \'2017-05-21T00:00:00+00:00\'::timestamptz, "created_by_user" = \'admin\', "created_by_group" = \'admin\', "modified_at" = \'2017-05-21T00:00:00+00:00\'::timestamptz, "modified_by_user" = \'admin\', "modified_by_group" = \'admin\', "metainfo" = \'{}\', "title" = hstore(ARRAY[\'en\',\'de\',\'fr\'], ARRAY[\'Michael Edwards\',\'\',\'\']), "description" = hstore(ARRAY[\'en\',\'de\',\'fr\'], ARRAY[\'Open else look tree arm responsibility week. Environmental statement bag someone them style. Public these health team change. Tax final upon stay sing middle suggest.\',\'\',\'\']), "category_id" = \'note-act-source\', "date" = \'1999-11-26\'::date WHERE "alexandria_core_document"."id" = \'9dd4e461-268c-8034-f5c8-564e155c67a6\'::uuid""", - 'INSERT INTO "alexandria_core_file" ("created_at", "created_by_user", "created_by_group", "modified_at", "modified_by_user", "modified_by_group", "metainfo", "id", "variant", "original_id", "name", "document_id", "checksum", "encryption_status", "content") VALUES (\'2017-05-21T00:00:00+00:00\'::timestamptz, NULL, NULL, \'2017-05-21T00:00:00+00:00\'::timestamptz, NULL, NULL, \'{}\', \'ea416ed0-759d-46a8-de58-f63a59077499\'::uuid, \'thumbnail\', \'f561aaf6-ef0b-f14d-4208-bb46a4ccb3ad\'::uuid, \'Version #33_preview.jpg\', \'9dd4e461-268c-8034-f5c8-564e155c67a6\'::uuid, \'sha256:0b5121c3edeb9ac0ac4d2f2cfa34773e43b68017bba0dfc859bdfdeae4392cc2\', NULL, \'ea416ed0-759d-46a8-de58-f63a59077499_Version_33_preview.jpg\')', + 'INSERT INTO "alexandria_core_file" ("created_at", "created_by_user", "created_by_group", "modified_at", "modified_by_user", "modified_by_group", "metainfo", "id", "variant", "original_id", "name", "document_id", "checksum", "encryption_status", "content") VALUES (\'2017-05-21T00:00:00+00:00\'::timestamptz, NULL, NULL, \'2017-05-21T00:00:00+00:00\'::timestamptz, NULL, NULL, \'{}\', \'ea416ed0-759d-46a8-de58-f63a59077499\'::uuid, \'thumbnail\', \'f561aaf6-ef0b-f14d-4208-bb46a4ccb3ad\'::uuid, \'Jason Lopez_preview.jpg\', \'9dd4e461-268c-8034-f5c8-564e155c67a6\'::uuid, \'sha256:0b5121c3edeb9ac0ac4d2f2cfa34773e43b68017bba0dfc859bdfdeae4392cc2\', NULL, \'ea416ed0-759d-46a8-de58-f63a59077499_Jason_Lopez_preview.jpg\')', 'SELECT "alexandria_core_file"."created_at", "alexandria_core_file"."created_by_user", "alexandria_core_file"."created_by_group", "alexandria_core_file"."modified_at", "alexandria_core_file"."modified_by_user", "alexandria_core_file"."modified_by_group", "alexandria_core_file"."metainfo", "alexandria_core_file"."id", "alexandria_core_file"."variant", "alexandria_core_file"."original_id", "alexandria_core_file"."name", "alexandria_core_file"."document_id", "alexandria_core_file"."checksum", "alexandria_core_file"."encryption_status", "alexandria_core_file"."content" FROM "alexandria_core_file" WHERE "alexandria_core_file"."original_id" = \'f561aaf6-ef0b-f14d-4208-bb46a4ccb3ad\'::uuid ORDER BY "alexandria_core_file"."created_at" DESC', 'SELECT (1) AS "a" FROM "alexandria_core_document" WHERE ("alexandria_core_document"."id" = \'9dd4e461-268c-8034-f5c8-564e155c67a6\'::uuid AND "alexandria_core_document"."id" = \'9dd4e461-268c-8034-f5c8-564e155c67a6\'::uuid) LIMIT 1', ], @@ -131,7 +131,7 @@ "request_payload": { "content": GenericRepr("<_io.BytesIO object at 0x100000000>"), "document": "9dd4e461-268c-8034-f5c8-564e155c67a6", - "name": "Version #33", + "name": "Jason Lopez", "variant": "original", }, "response": { @@ -146,7 +146,7 @@ "modified-at": "2017-05-21T00:00:00Z", "modified-by-group": "admin", "modified-by-user": "admin", - "name": "Version #33", + "name": "Jason Lopez", "variant": "original", }, "id": "f561aaf6-ef0b-f14d-4208-bb46a4ccb3ad", @@ -569,7 +569,7 @@ "modified-at": "2017-05-21T00:00:00Z", "modified-by-group": "admin", "modified-by-user": "admin", - "name": "Version #32", + "name": "Jason Lopez", "variant": "original", }, "id": "9336ebf2-5087-d91c-818e-e6e9ec29f8c1", @@ -1065,7 +1065,7 @@ 'SELECT "alexandria_core_mark"."created_at", "alexandria_core_mark"."created_by_user", "alexandria_core_mark"."created_by_group", "alexandria_core_mark"."modified_at", "alexandria_core_mark"."modified_by_user", "alexandria_core_mark"."modified_by_group", "alexandria_core_mark"."metainfo", "alexandria_core_mark"."slug", "alexandria_core_mark"."name", "alexandria_core_mark"."description" FROM "alexandria_core_mark" INNER JOIN "alexandria_core_document_marks" ON ("alexandria_core_mark"."slug" = "alexandria_core_document_marks"."mark_id") WHERE "alexandria_core_document_marks"."document_id" = \'f561aaf6-ef0b-f14d-4208-bb46a4ccb3ad\'::uuid', 'SELECT (1) AS "a" FROM "alexandria_core_document" WHERE ("alexandria_core_document"."id" = \'fb0e22c7-9ac7-5679-e988-1e6ba183b354\'::uuid AND "alexandria_core_document"."id" = \'fb0e22c7-9ac7-5679-e988-1e6ba183b354\'::uuid) LIMIT 1', 'SELECT "alexandria_core_file"."created_at", "alexandria_core_file"."created_by_user", "alexandria_core_file"."created_by_group", "alexandria_core_file"."modified_at", "alexandria_core_file"."modified_by_user", "alexandria_core_file"."modified_by_group", "alexandria_core_file"."metainfo", "alexandria_core_file"."id", "alexandria_core_file"."variant", "alexandria_core_file"."original_id", "alexandria_core_file"."name", "alexandria_core_file"."document_id", "alexandria_core_file"."checksum", "alexandria_core_file"."encryption_status", "alexandria_core_file"."content" FROM "alexandria_core_file" WHERE "alexandria_core_file"."document_id" = \'fb0e22c7-9ac7-5679-e988-1e6ba183b354\'::uuid ORDER BY "alexandria_core_file"."created_at" DESC', - 'SELECT (1) AS "a" FROM "alexandria_core_category" WHERE ("alexandria_core_category"."slug" = \'moment-poor\' AND "alexandria_core_category"."slug" = \'moment-poor\') LIMIT 1', + 'SELECT (1) AS "a" FROM "alexandria_core_category" WHERE ("alexandria_core_category"."slug" = \'party-coach-note\' AND "alexandria_core_category"."slug" = \'party-coach-note\') LIMIT 1', 'SELECT "alexandria_core_tag"."created_at", "alexandria_core_tag"."created_by_user", "alexandria_core_tag"."created_by_group", "alexandria_core_tag"."modified_at", "alexandria_core_tag"."modified_by_user", "alexandria_core_tag"."modified_by_group", "alexandria_core_tag"."metainfo", "alexandria_core_tag"."id", "alexandria_core_tag"."name", "alexandria_core_tag"."description", "alexandria_core_tag"."tag_synonym_group_id" FROM "alexandria_core_tag" INNER JOIN "alexandria_core_document_tags" ON ("alexandria_core_tag"."id" = "alexandria_core_document_tags"."tag_id") WHERE "alexandria_core_document_tags"."document_id" = \'fb0e22c7-9ac7-5679-e988-1e6ba183b354\'::uuid', 'SELECT "alexandria_core_mark"."created_at", "alexandria_core_mark"."created_by_user", "alexandria_core_mark"."created_by_group", "alexandria_core_mark"."modified_at", "alexandria_core_mark"."modified_by_user", "alexandria_core_mark"."modified_by_group", "alexandria_core_mark"."metainfo", "alexandria_core_mark"."slug", "alexandria_core_mark"."name", "alexandria_core_mark"."description" FROM "alexandria_core_mark" INNER JOIN "alexandria_core_document_marks" ON ("alexandria_core_mark"."slug" = "alexandria_core_document_marks"."mark_id") WHERE "alexandria_core_document_marks"."document_id" = \'fb0e22c7-9ac7-5679-e988-1e6ba183b354\'::uuid', ], @@ -1091,7 +1091,7 @@ "modified-at": "2017-05-21T00:00:00Z", "modified-by-group": "admin", "modified-by-user": "admin", - "name": "Version #34", + "name": "Jason Lopez", "variant": "original", }, "id": "9336ebf2-5087-d91c-818e-e6e9ec29f8c1", @@ -1118,7 +1118,7 @@ "modified-at": "2017-05-21T00:00:00Z", "modified-by-group": "admin", "modified-by-user": "admin", - "name": "Version #35", + "name": "Rebecca Gonzalez", "variant": "original", }, "id": "ea416ed0-759d-46a8-de58-f63a59077499", @@ -1145,7 +1145,7 @@ "modified-at": "2017-05-21T00:00:00Z", "modified-by-group": "admin", "modified-by-user": "admin", - "name": "Version #35", + "name": "William Kennedy", "variant": "original", }, "id": "dad3a37a-a9d5-0688-b515-7698acfd7aee", @@ -1208,15 +1208,15 @@ "date": "2005-06-14", "description": { "de": "", - "en": """Bank arm serious live by itself. Project find white continue none president. Idea eye plan third program. -Son success provide beyond. Officer player possible issue ahead suffer.""", + "en": """Serious live by. Run then project find white continue. +Effort partner area media increase meeting. Son success provide beyond. Officer player possible issue ahead suffer.""", "fr": "", }, "metainfo": {}, "modified-at": "2017-05-21T00:00:00Z", "modified-by-group": "admin", "modified-by-user": "admin", - "title": {"de": "", "en": "Rebecca Gonzalez", "fr": ""}, + "title": {"de": "", "en": "Olivia Miller", "fr": ""}, }, "id": "f561aaf6-ef0b-f14d-4208-bb46a4ccb3ad", "relationships": { @@ -1242,22 +1242,24 @@ "created-at": "2017-05-21T00:00:00Z", "created-by-group": "admin", "created-by-user": "admin", - "date": "1973-06-29", + "date": "1977-12-09", "description": { "de": "", - "en": """Cell series star. Agency season worry take value eye sell. -Human less power relate fine religious. Loss increase firm friend ability. Their office though television return main.""", + "en": """Star Republican agency season. Take value eye sell them he. +Same season natural think Mr course tree. Within never whose five hold food.""", "fr": "", }, "metainfo": {}, "modified-at": "2017-05-21T00:00:00Z", "modified-by-group": "admin", "modified-by-user": "admin", - "title": {"de": "", "en": "William Kennedy", "fr": ""}, + "title": {"de": "", "en": "Carol Mata", "fr": ""}, }, "id": "fb0e22c7-9ac7-5679-e988-1e6ba183b354", "relationships": { - "category": {"data": {"id": "moment-poor", "type": "categories"}}, + "category": { + "data": {"id": "party-coach-note", "type": "categories"} + }, "files": { "data": [ { diff --git a/alexandria/core/tests/test_views.py b/alexandria/core/tests/test_views.py index cfb367dc..74d36aae 100644 --- a/alexandria/core/tests/test_views.py +++ b/alexandria/core/tests/test_views.py @@ -384,7 +384,8 @@ def test_document_delete_some_tags(admin_client, tag_factory, document_factory): @pytest.mark.parametrize( - "presigned, expected_status", [(True, HTTP_200_OK), (False, HTTP_403_FORBIDDEN)] + "presigned, expected_status", + [(True, HTTP_200_OK), (False, HTTP_403_FORBIDDEN)], ) def test_download_file(admin_client, file, presigned, expected_status): if not presigned: @@ -392,6 +393,7 @@ def test_download_file(admin_client, file, presigned, expected_status): else: response = admin_client.get(reverse("file-detail", args=(file.pk,))) url = response.json()["data"]["attributes"]["download-url"] + result = admin_client.get(url) assert result.status_code == expected_status @@ -404,7 +406,7 @@ def test_presigned_url_expired(admin_client, client, file, freezer, settings): delta=timezone.timedelta(seconds=settings.ALEXANDRIA_DOWNLOAD_URL_LIFETIME + 5) ) response = client.get(url) - assert response.status_code == HTTP_403_FORBIDDEN + assert response.status_code == HTTP_400_BAD_REQUEST def test_presigned_url_tempered_signature(admin_client, client, file): @@ -416,4 +418,15 @@ def test_presigned_url_tempered_signature(admin_client, client, file): val = str(int(val) + 1000) url = f"{without_params}?{signature}&{key}={val}" response = client.get(url) - assert response.status_code == HTTP_403_FORBIDDEN + assert response.status_code == HTTP_400_BAD_REQUEST + + +def test_presigned_url_different_file(admin_client, file, file_factory): + response = admin_client.get(reverse("file-detail", args=(file.pk,))) + url = response.json()["data"]["attributes"]["download-url"] + + other_file = file_factory() + url = url.replace(str(file.pk), str(other_file.pk)) + + response = admin_client.get(url) + assert response.status_code == HTTP_400_BAD_REQUEST diff --git a/alexandria/core/views.py b/alexandria/core/views.py index 76ce34d3..c9b77c91 100644 --- a/alexandria/core/views.py +++ b/alexandria/core/views.py @@ -5,10 +5,7 @@ from tempfile import NamedTemporaryFile from django.conf import settings -from django.core.exceptions import ( - ObjectDoesNotExist, - ValidationError as DjangoCoreValidationError, -) +from django.core.exceptions import ValidationError as DjangoCoreValidationError from django.http import FileResponse from django.utils.translation import gettext as _ from generic_permissions.permissions import AllowAny, PermissionViewMixin @@ -223,22 +220,14 @@ def create(self, request, *args, **kwargs): @action(methods=["get"], detail=True) def download(self, request, pk=None): if token_sig := request.query_params.get("signature"): - try: - verify_signed_components( - pk, - request.get_host(), - expires=int(request.query_params.get("expires")), - scheme=request.META.get("wsgi.url_scheme", "http"), - token_sig=token_sig, - ) - except TimeoutError: - raise PermissionDenied("Download URL expired.") - except AssertionError: - raise PermissionDenied("Invalid signature.") - try: - obj = models.File.objects.get(pk=pk) - except ObjectDoesNotExist: - raise NotFound() + verify_signed_components( + pk, + request.get_host(), + expires=int(request.query_params.get("expires")), + scheme=request.META.get("wsgi.url_scheme", "http"), + token_sig=token_sig, + ) + obj = models.File.objects.get(pk=pk) return FileResponse( obj.content.file.file, as_attachment=False, filename=obj.name diff --git a/alexandria/storages/fields.py b/alexandria/storages/fields.py index cafe3860..70111ca5 100644 --- a/alexandria/storages/fields.py +++ b/alexandria/storages/fields.py @@ -10,6 +10,8 @@ class DynamicStorageFieldFile(FieldFile): def __init__(self, instance, field, name): super().__init__(instance, field, name) + DefaultStorage = get_storage_class() + self.storage = DefaultStorage() if settings.ALEXANDRIA_ENABLE_AT_REST_ENCRYPTION: from alexandria.core.models import File @@ -27,14 +29,17 @@ def pre_save(self, instance, add): if settings.ALEXANDRIA_ENABLE_AT_REST_ENCRYPTION: from alexandria.core.models import File - if ( - method := settings.ALEXANDRIA_ENCRYPTION_METHOD - ) not in File.EncryptionStatus.values: + method = settings.ALEXANDRIA_ENCRYPTION_METHOD + if method not in File.EncryptionStatus.values: msg = ( f"ALEXANDRIA_ENCRYPTION_METHOD must be one of " f"{File.EncryptionStatus.values}. {method} is not valid" ) raise ImproperlyConfigured(msg) + elif method == File.EncryptionStatus.NOT_ENCRYPTED: + raise ImproperlyConfigured( + "ALEXANDRIA_ENCRYPTION_METHOD is set to NOT_ENCRYPTED while ALEXANDRIA_ENABLE_AT_REST_ENCRYPTION is enabled." + ) if not isinstance(self.storage, S3Storage): msg = ( "At-rest object encryption is currently only available for S3 compatible storage backends. " diff --git a/alexandria/storages/tests/test_dynamic_field.py b/alexandria/storages/tests/test_dynamic_field.py index 37dcbeec..6983b62f 100644 --- a/alexandria/storages/tests/test_dynamic_field.py +++ b/alexandria/storages/tests/test_dynamic_field.py @@ -37,6 +37,10 @@ def test_dynamic_storage_select_global_ssec( "invalid-encryption-mode", "alexandria.storages.backends.s3.S3Storage", ), + ( + "none", + "alexandria.storages.backends.s3.S3Storage", + ), ( File.EncryptionStatus.SSEC_GLOBAL_KEY.value, "django.core.files.storage.FileSystemStorage",