From 8c6563c0f3ce70ea1fbeb354f5f4b90fc732c034 Mon Sep 17 00:00:00 2001 From: naohide anahara <57.x.mas@gmail.com> Date: Sat, 7 May 2022 08:23:24 +0900 Subject: [PATCH] Fix EncryptedIntegerField and testcase --- encrypted_fields/fields.py | 37 ++++++++++++++++++++++++++++++++++--- package_test/tests.py | 29 ++++++++++++++++++++++++++--- 2 files changed, 60 insertions(+), 6 deletions(-) diff --git a/encrypted_fields/fields.py b/encrypted_fields/fields.py index 56acc52..53cec54 100644 --- a/encrypted_fields/fields.py +++ b/encrypted_fields/fields.py @@ -1,13 +1,13 @@ import base64 -from django.utils import timezone -import warnings from cryptography.fernet import Fernet, MultiFernet, InvalidToken from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC from django.conf import settings +from django.core import validators from django.db import models +from django.db.backends.base.operations import BaseDatabaseOperations from django.utils.functional import cached_property @@ -105,7 +105,38 @@ class EncryptedDateTimeField(EncryptedFieldMixin, models.DateTimeField): class EncryptedIntegerField(EncryptedFieldMixin, models.IntegerField): @cached_property def validators(self): - return [*self.default_validators, *self._validators] + # These validators can't be added at field initialization time since + # they're based on values retrieved from `connection`. + validators_ = [*self.default_validators, *self._validators] + internal_type = models.IntegerField().get_internal_type() + min_value, max_value = BaseDatabaseOperations.integer_field_ranges[internal_type] + if min_value is not None and not any( + ( + isinstance(validator, validators.MinValueValidator) + and ( + validator.limit_value() + if callable(validator.limit_value) + else validator.limit_value + ) + >= min_value + ) + for validator in validators_ + ): + validators_.append(validators.MinValueValidator(min_value)) + if max_value is not None and not any( + ( + isinstance(validator, validators.MaxValueValidator) + and ( + validator.limit_value() + if callable(validator.limit_value) + else validator.limit_value + ) + <= max_value + ) + for validator in validators_ + ): + validators_.append(validators.MaxValueValidator(max_value)) + return validators_ class EncryptedDateField(EncryptedFieldMixin, models.DateField): diff --git a/package_test/tests.py b/package_test/tests.py index 55ebc17..1bce167 100644 --- a/package_test/tests.py +++ b/package_test/tests.py @@ -23,6 +23,7 @@ class FieldTest(TestCase): model = TestModel() model.char = plaintext + model.full_clean() model.save() ciphertext = self.get_db_value("char", model.id) @@ -38,6 +39,7 @@ class FieldTest(TestCase): model = TestModel() model.text = plaintext + model.full_clean() model.save() ciphertext = self.get_db_value("text", model.id) @@ -53,6 +55,7 @@ class FieldTest(TestCase): model = TestModel() model.datetime = plaintext + model.full_clean() model.save() ciphertext = self.get_db_value("datetime", model.id) @@ -67,6 +70,7 @@ class FieldTest(TestCase): with self.assertRaises(ValidationError): model.datetime = plaintext + model.full_clean() model.save() def test_integer_field_encrypted(self): @@ -74,6 +78,7 @@ class FieldTest(TestCase): model = TestModel() model.integer = plaintext + model.full_clean() model.save() ciphertext = self.get_db_value("integer", model.id) @@ -84,10 +89,19 @@ class FieldTest(TestCase): fresh_model = TestModel.objects.get(id=model.id) self.assertEqual(fresh_model.integer, plaintext) + # "IntegerField": (-2147483648, 2147483647) + plaintext = 2147483648 + + with self.assertRaises(ValidationError): + model.integer = plaintext + model.full_clean() + model.save() + plaintext = "text" - with self.assertRaises(ValueError): + with self.assertRaises(TypeError): model.integer = plaintext + model.full_clean() model.save() def test_date_field_encrypted(self): @@ -95,6 +109,7 @@ class FieldTest(TestCase): model = TestModel() model.date = plaintext + model.full_clean() model.save() ciphertext = self.get_db_value("date", model.id) @@ -107,6 +122,7 @@ class FieldTest(TestCase): with self.assertRaises(ValidationError): model.date = plaintext + model.full_clean() model.save() def test_float_field_encrypted(self): @@ -114,6 +130,7 @@ class FieldTest(TestCase): model = TestModel() model.floating = plaintext + model.full_clean() model.save() ciphertext = self.get_db_value("floating", model.id) @@ -128,6 +145,7 @@ class FieldTest(TestCase): with self.assertRaises(ValueError): model.floating = plaintext + model.full_clean() model.save() def test_email_field_encrypted(self): @@ -135,6 +153,7 @@ class FieldTest(TestCase): model = TestModel() model.email = plaintext + model.full_clean() model.save() ciphertext = self.get_db_value("email", model.id) @@ -147,14 +166,17 @@ class FieldTest(TestCase): plaintext = "text" - model.email = plaintext - model.save() + with self.assertRaises(ValidationError): + model.email = plaintext + model.full_clean() + model.save() def test_boolean_field_encrypted(self): plaintext = True model = TestModel() model.boolean = plaintext + model.full_clean() model.save() ciphertext = self.get_db_value("boolean", model.id) @@ -174,6 +196,7 @@ class FieldTest(TestCase): with self.assertRaises(ValidationError): model.boolean = plaintext + model.full_clean() model.save()