Skip to content

Commit 34714d0

Browse files
committed
Merge pull request defrex#8 from coldmind/master
Fix defrex#7
2 parents 4a765ce + f5b03fb commit 34714d0

File tree

2 files changed

+56
-15
lines changed

2 files changed

+56
-15
lines changed

encrypted_fields/fields.py

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
from django.db import models
66
from django.conf import settings
77
from django.core.exceptions import ImproperlyConfigured
8+
from django.utils.functional import cached_property
89

910
try:
1011
from django.utils.encoding import smart_text
@@ -14,7 +15,9 @@
1415
from keyczar import keyczar
1516

1617

17-
class EncryptedFieldException(Exception): pass
18+
class EncryptedFieldException(Exception):
19+
pass
20+
1821

1922
# Simple wrapper around keyczar to standardize the initialization
2023
# of the crypter object and allow for others to extend as needed.
@@ -28,6 +31,7 @@ def encrypt(self, cleartext):
2831
def decrypt(self, ciphertext):
2932
return self.crypter.Decrypt(ciphertext)
3033

34+
3135
class EncryptedFieldMixin(object):
3236
"""
3337
EncryptedFieldMixin will use keyczar to encrypt/decrypt data that is being
@@ -210,7 +214,15 @@ class EncryptedDateTimeField(EncryptedFieldMixin, models.DateTimeField):
210214

211215

212216
class EncryptedIntegerField(EncryptedFieldMixin, models.IntegerField):
213-
pass
217+
@cached_property
218+
def validators(self):
219+
"""
220+
See issue https://github.com/defrex/django-encrypted-fields/issues/7
221+
Need to keep all field validators, but need to change `get_internal_type` on the fly
222+
to prevent fail in django 1.7.
223+
"""
224+
self.get_internal_type = lambda: 'IntegerField'
225+
return models.IntegerField.validators.__get__(self)
214226

215227

216228
class EncryptedDateField(EncryptedFieldMixin, models.DateField):
@@ -224,6 +236,7 @@ class EncryptedFloatField(EncryptedFieldMixin, models.FloatField):
224236
class EncryptedEmailField(EncryptedFieldMixin, models.EmailField):
225237
pass
226238

239+
227240
class EncryptedBooleanField(EncryptedFieldMixin, models.BooleanField):
228241
pass
229242

encrypted_fields/tests.py

Lines changed: 41 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
# -*- coding: utf-8 -*-
22

33
import re
4+
import unittest
45

6+
import django
7+
from django.conf import settings
58
from django.db import models, connection
69
from django.test import TestCase
710
from django.utils import timezone
@@ -19,6 +22,7 @@
1922

2023
from keyczar import keyczar, readers
2124

25+
2226
# Test class that encapsulates some Keyczar functions.
2327
# Requirements are to implement __init__, decrypt(), encrypt()
2428
class TestCrypter(object):
@@ -32,24 +36,28 @@ def encrypt(self, cleartext):
3236
def decrypt(self, ciphertext):
3337
return self.crypter.Decrypt(ciphertext)
3438

39+
3540
class TestModel(models.Model):
36-
char = EncryptedCharField(max_length=255, null=True)
37-
prefix_char = EncryptedCharField(max_length=255, prefix='ENCRYPTED:::')
38-
decrypt_only = EncryptedCharField(max_length=255, decrypt_only=True)
39-
short_char = EncryptedCharField(max_length=50, null=True, enforce_max_length=True)
41+
char = EncryptedCharField(max_length=255, null=True, blank=True)
42+
prefix_char = EncryptedCharField(max_length=255, prefix='ENCRYPTED:::', blank=True)
43+
decrypt_only = EncryptedCharField(max_length=255, decrypt_only=True, blank=True)
44+
short_char = EncryptedCharField(
45+
max_length=50, null=True, enforce_max_length=True, blank=True)
4046

41-
text = EncryptedTextField(null=True)
42-
datetime = EncryptedDateTimeField(null=True)
43-
integer = EncryptedIntegerField(null=True)
44-
date = EncryptedDateField(null=True)
45-
floating = EncryptedFloatField(null=True)
46-
email = EncryptedEmailField(null=True)
47-
boolean = EncryptedBooleanField(default=False)
47+
text = EncryptedTextField(null=True, blank=True)
48+
datetime = EncryptedDateTimeField(null=True, blank=True)
49+
integer = EncryptedIntegerField(null=True, blank=True)
50+
date = EncryptedDateField(null=True, blank=True)
51+
floating = EncryptedFloatField(null=True, blank=True)
52+
email = EncryptedEmailField(null=True, blank=True)
53+
boolean = EncryptedBooleanField(default=False, blank=True)
4854

49-
char_custom_crypter = EncryptedCharField(max_length=255, null=True, crypter_klass=TestCrypter)
55+
char_custom_crypter = EncryptedCharField(
56+
max_length=255, null=True,crypter_klass=TestCrypter, blank=True)
5057

5158

5259
class FieldTest(TestCase):
60+
IS_POSTGRES = settings.DATABASES['default']['ENGINE'] == 'django.db.backends.postgresql_psycopg2'
5361

5462
def get_db_value(self, field, model_id):
5563
cursor = connection.cursor()
@@ -222,7 +230,7 @@ def test_float_field_encrypted(self):
222230
self.assertEqual(fresh_model.floating, plaintext)
223231

224232
def test_email_field_encrypted(self):
225-
plaintext = '[email protected]' # my email address, btw
233+
plaintext = '[email protected]' # my email address, btw
226234

227235
model = TestModel()
228236
model.email = plaintext
@@ -255,3 +263,23 @@ def test_boolean_field_encrypted(self):
255263

256264
fresh_model = TestModel.objects.get(id=model.id)
257265
self.assertEqual(fresh_model.boolean, plaintext)
266+
267+
@unittest.skipIf(django.VERSION < (1, 7), "Issue exists in django 1.7+")
268+
@unittest.skipIf(not IS_POSTGRES, "Issue exists for postgresql")
269+
def test_integerfield_validation_in_django_1_7_passes_successfully(self):
270+
plainint = 1111
271+
272+
obj = TestModel()
273+
obj.integer = plainint
274+
275+
# see https://github.com/defrex/django-encrypted-fields/issues/7
276+
obj.full_clean()
277+
obj.save()
278+
279+
ciphertext = self.get_db_value('integer', obj.id)
280+
281+
self.assertNotEqual(plainint, ciphertext)
282+
self.assertNotEqual(plainint, str(ciphertext))
283+
284+
fresh_model = TestModel.objects.get(id=obj.id)
285+
self.assertEqual(fresh_model.integer, plainint)

0 commit comments

Comments
 (0)