Skip to content

Commit

Permalink
Fix defrex#7
Browse files Browse the repository at this point in the history
  • Loading branch information
Andriy Sokolovskiy committed Nov 26, 2014
1 parent 4a765ce commit f5b03fb
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 15 deletions.
17 changes: 15 additions & 2 deletions encrypted_fields/fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from django.db import models
from django.conf import settings
from django.core.exceptions import ImproperlyConfigured
from django.utils.functional import cached_property

try:
from django.utils.encoding import smart_text
Expand All @@ -14,7 +15,9 @@
from keyczar import keyczar


class EncryptedFieldException(Exception): pass
class EncryptedFieldException(Exception):
pass


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


class EncryptedFieldMixin(object):
"""
EncryptedFieldMixin will use keyczar to encrypt/decrypt data that is being
Expand Down Expand Up @@ -210,7 +214,15 @@ class EncryptedDateTimeField(EncryptedFieldMixin, models.DateTimeField):


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


class EncryptedDateField(EncryptedFieldMixin, models.DateField):
Expand All @@ -224,6 +236,7 @@ class EncryptedFloatField(EncryptedFieldMixin, models.FloatField):
class EncryptedEmailField(EncryptedFieldMixin, models.EmailField):
pass


class EncryptedBooleanField(EncryptedFieldMixin, models.BooleanField):
pass

Expand Down
54 changes: 41 additions & 13 deletions encrypted_fields/tests.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
# -*- coding: utf-8 -*-

import re
import unittest

import django
from django.conf import settings
from django.db import models, connection
from django.test import TestCase
from django.utils import timezone
Expand All @@ -19,6 +22,7 @@

from keyczar import keyczar, readers


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


class TestModel(models.Model):
char = EncryptedCharField(max_length=255, null=True)
prefix_char = EncryptedCharField(max_length=255, prefix='ENCRYPTED:::')
decrypt_only = EncryptedCharField(max_length=255, decrypt_only=True)
short_char = EncryptedCharField(max_length=50, null=True, enforce_max_length=True)
char = EncryptedCharField(max_length=255, null=True, blank=True)
prefix_char = EncryptedCharField(max_length=255, prefix='ENCRYPTED:::', blank=True)
decrypt_only = EncryptedCharField(max_length=255, decrypt_only=True, blank=True)
short_char = EncryptedCharField(
max_length=50, null=True, enforce_max_length=True, blank=True)

text = EncryptedTextField(null=True)
datetime = EncryptedDateTimeField(null=True)
integer = EncryptedIntegerField(null=True)
date = EncryptedDateField(null=True)
floating = EncryptedFloatField(null=True)
email = EncryptedEmailField(null=True)
boolean = EncryptedBooleanField(default=False)
text = EncryptedTextField(null=True, blank=True)
datetime = EncryptedDateTimeField(null=True, blank=True)
integer = EncryptedIntegerField(null=True, blank=True)
date = EncryptedDateField(null=True, blank=True)
floating = EncryptedFloatField(null=True, blank=True)
email = EncryptedEmailField(null=True, blank=True)
boolean = EncryptedBooleanField(default=False, blank=True)

char_custom_crypter = EncryptedCharField(max_length=255, null=True, crypter_klass=TestCrypter)
char_custom_crypter = EncryptedCharField(
max_length=255, null=True,crypter_klass=TestCrypter, blank=True)


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

def get_db_value(self, field, model_id):
cursor = connection.cursor()
Expand Down Expand Up @@ -222,7 +230,7 @@ def test_float_field_encrypted(self):
self.assertEqual(fresh_model.floating, plaintext)

def test_email_field_encrypted(self):
plaintext = '[email protected]' # my email address, btw
plaintext = '[email protected]' # my email address, btw

model = TestModel()
model.email = plaintext
Expand Down Expand Up @@ -255,3 +263,23 @@ def test_boolean_field_encrypted(self):

fresh_model = TestModel.objects.get(id=model.id)
self.assertEqual(fresh_model.boolean, plaintext)

@unittest.skipIf(django.VERSION < (1, 7), "Issue exists in django 1.7+")
@unittest.skipIf(not IS_POSTGRES, "Issue exists for postgresql")
def test_integerfield_validation_in_django_1_7_passes_successfully(self):
plainint = 1111

obj = TestModel()
obj.integer = plainint

# see https://github.com/defrex/django-encrypted-fields/issues/7
obj.full_clean()
obj.save()

ciphertext = self.get_db_value('integer', obj.id)

self.assertNotEqual(plainint, ciphertext)
self.assertNotEqual(plainint, str(ciphertext))

fresh_model = TestModel.objects.get(id=obj.id)
self.assertEqual(fresh_model.integer, plainint)

0 comments on commit f5b03fb

Please sign in to comment.