<commit_before>from __future__ import unicode_literals

import binascii

from django.conf import settings
from django.db import models

from .compat import smart_bytes, force_text, six

try:
    import Crypto.Cipher.AES
except ImportError: # pragma: no cover
    raise ImportError('PyCrypto is required to use django-all-access.')


class EncryptedField(six.with_metaclass(models.SubfieldBase, models.TextField)):
    """
    This code is based on http://www.djangosnippets.org/snippets/1095/
    and django-fields https://github.com/svetlyak40wt/django-fields
    """

    cipher_class = Crypto.Cipher.AES
    prefix = b'$AES$'

    def __init__(self, *args, **kwargs):
        self.cipher = self.cipher_class.new(smart_bytes(settings.SECRET_KEY)[:32])
        super(EncryptedField, self).__init__(*args, **kwargs)

    def _is_encrypted(self, value):

        return value.startswith(self.prefix)

    def _get_padding(self, value):
        # We always want at least 2 chars of padding (including zero byte),
        # so we could have up to block_size + 1 chars.
        mod = (len(value) + 2) % self.cipher.block_size
        return self.cipher.block_size - mod + 2

    def to_python(self, value):
        if value is None:
            return value
        value = smart_bytes(value)
        if self._is_encrypted(value):
            return force_text(
                self.cipher.decrypt(
                    binascii.a2b_hex(value[len(self.prefix):])
                )
            ).split('\0')[0]
        return value

    def get_db_prep_value(self, value, connection=None, prepared=False):
        if self.null:
            # Normalize empty values to None
            value = value or None
        if value is None:
            return None
        value = smart_bytes(value)
        if not self._is_encrypted(value):
            padding  = self._get_padding(value)
            if padding > 0:
                value = value + b'\0' + b'*' * (padding - 1)
            value = self.prefix + binascii.b2a_hex(self.cipher.encrypt(value))
        return value


# pragma: no cover
try:
    from south.modelsinspector import add_introspection_rules
except ImportError: # pragma: no cover
    # South not installed
    pass
else:
    add_introspection_rules([], ["^allaccess\.fields\.EncryptedField"])<commit_msg>Convert decrypted value to unicode.<commit_after>from __future__ import unicode_literals

import binascii

from django.conf import settings
from django.db import models

from .compat import smart_bytes, force_text, six

try:
    import Crypto.Cipher.AES
except ImportError: # pragma: no cover
    raise ImportError('PyCrypto is required to use django-all-access.')


class EncryptedField(six.with_metaclass(models.SubfieldBase, models.TextField)):
    """
    This code is based on http://www.djangosnippets.org/snippets/1095/
    and django-fields https://github.com/svetlyak40wt/django-fields
    """

    cipher_class = Crypto.Cipher.AES
    prefix = b'$AES$'

    def __init__(self, *args, **kwargs):
        self.cipher = self.cipher_class.new(smart_bytes(settings.SECRET_KEY)[:32])
        super(EncryptedField, self).__init__(*args, **kwargs)

    def _is_encrypted(self, value):

        return value.startswith(self.prefix)

    def _get_padding(self, value):
        # We always want at least 2 chars of padding (including zero byte),
        # so we could have up to block_size + 1 chars.
        mod = (len(value) + 2) % self.cipher.block_size
        return self.cipher.block_size - mod + 2

    def to_python(self, value):
        if value is None:
            return value
        value = smart_bytes(value)
        if self._is_encrypted(value):
            return force_text(
                self.cipher.decrypt(
                    binascii.a2b_hex(value[len(self.prefix):])
                )
            ).split('\0')[0]
        return force_text(value)

    def get_db_prep_value(self, value, connection=None, prepared=False):
        if self.null:
            # Normalize empty values to None
            value = value or None
        if value is None:
            return None
        value = smart_bytes(value)
        if not self._is_encrypted(value):
            padding  = self._get_padding(value)
            if padding > 0:
                value = value + b'\0' + b'*' * (padding - 1)
            value = self.prefix + binascii.b2a_hex(self.cipher.encrypt(value))
        return value


# pragma: no cover
try:
    from south.modelsinspector import add_introspection_rules
except ImportError: # pragma: no cover
    # South not installed
    pass
else:
    add_introspection_rules([], ["^allaccess\.fields\.EncryptedField"])
{'fraction_non_alphanumeric': 0.09879982854693528, 'fraction_numerical': 0.008144020574367767, 'mean_word_length': 2.5249244712990935, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 5, 'https://': 2, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4076154', 'n_tokens_mistral': 1470, 'n_tokens_neox': 1380, 'n_words': 363}