Source code for CryptographicFields.fields

from typing import Any
from django.db import models
from .utils import StartsWith
from django.core import exceptions, validators
from django.db.models.fields import PositiveIntegerRelDbTypeMixin
from .cryptography import encrypt,decrypt
from ast import literal_eval
import datetime
from django import forms
from django.utils import timezone
from timestring import Date
from decimal import Decimal
from uuid import UUID
from django.utils.translation import gettext_lazy as _
"""
to_python() make validations & checks type of the data
get_db_prep_value() encrypts the data
from_db_value() decrypts the data returned from the db
pre_save() generates date ,datetime,time for the respestive fields
get_db_prep_save() saves the value into db
"""
[docs]class CharField(models.CharField):
[docs] def get_internal_type(self)-> str: return "TextField"
[docs] def to_python(self, value: Any) -> Any: return self.clean(super().to_python(value),None)
[docs] def get_prep_value(self, value: Any) -> Any: return self.to_python(value)
[docs] def from_db_value(self, value:Any, expression:Any, connection:Any)-> Any: return decrypt(value).decode()
[docs] def get_db_prep_value(self, value, connection, prepared=False): if not prepared: value = self.get_prep_value(value) return encrypt(value)
[docs] def clean(self, value, model_instance): """ Convert the value's type and run validation. Validation errors from to_python() and validate() are propagated. Return the correct value if no error is raised. """ self.validate(value, model_instance) self.run_validators(value) return value
[docs]class BooleanField(models.BooleanField):
[docs] def get_internal_type(self)-> str: return "TextField"
[docs] def to_python(self, value: Any) -> Any: return self.clean(super().to_python(value),None)
[docs] def get_prep_value(self, value: Any) -> Any: return self.to_python(value)
[docs] def get_db_prep_value(self, value, connection, prepared=False): if not prepared: value = self.get_prep_value(value) return encrypt(value)
[docs] def from_db_value(self, value:Any, expression:Any, connection:Any)-> Any: return literal_eval(decrypt(value).decode())
[docs] def clean(self, value, model_instance): """ Convert the value's type and run validation. Validation errors from to_python() and validate() are propagated. Return the correct value if no error is raised. """ self.validate(value, model_instance) self.run_validators(value) return value
[docs]class DateField(models.DateField):
[docs] def get_internal_type(self)-> str: return "TextField"
[docs] def to_python(self, value: Any) -> Any: return self.clean(super().to_python(value),None)
[docs] def get_prep_value(self, value: Any) -> Any: return self.to_python(value)
[docs] def get_db_prep_value(self, value, connection, prepared=False): # Casts dates into the format expected by the backend if not prepared: value = self.get_prep_value(value) return encrypt(connection.ops.adapt_datefield_value(value))
[docs] def from_db_value(self, value:Any, expression:Any, connection:Any)-> Any: return Date(decrypt(value).decode()).date.date()
[docs] def pre_save(self, model_instance, add): if self.auto_now or (self.auto_now_add and add): value = datetime.date.today() setattr(model_instance, self.attname, value) return value else: return super().pre_save(model_instance, add)
[docs] def clean(self, value, model_instance): """ Convert the value's type and run validation. Validation errors from to_python() and validate() are propagated. Return the correct value if no error is raised. """ self.validate(value, model_instance) self.run_validators(value) return value
[docs]class DateTimeField(models.DateTimeField):
[docs] def get_internal_type(self)-> str: return "TextField"
[docs] def to_python(self, value: Any) -> Any: return self.clean(super().to_python(value),None)
[docs] def get_prep_value(self, value: Any) -> Any: return super().get_prep_value(value)
[docs] def get_db_prep_value(self, value, connection, prepared=False): # Casts dates into the format expected by the backend if not prepared: value = self.get_prep_value(value) return encrypt(connection.ops.adapt_datetimefield_value(value))
[docs] def from_db_value(self, value:Any, expression:Any, connection:Any)-> Any: return Date(decrypt(value).decode()).date
[docs] def pre_save(self, model_instance, add): if self.auto_now or (self.auto_now_add and add): value = timezone.now() setattr(model_instance, self.attname, value) return value else: return super().pre_save(model_instance, add)
[docs] def clean(self, value, model_instance): """ Convert the value's type and run validation. Validation errors from to_python() and validate() are propagated. Return the correct value if no error is raised. """ self.validate(value, model_instance) self.run_validators(value) return value
[docs]class TimeField(models.TimeField):
[docs] def get_internal_type(self)-> str: return "TextField"
[docs] def to_python(self, value: Any) -> Any: return self.clean(super().to_python(value),None)
[docs] def get_prep_value(self, value: Any) -> Any: return self.to_python(value)
[docs] def get_db_prep_value(self, value, connection, prepared=False): # Casts dates into the format expected by the backend if not prepared: value = self.get_prep_value(value) return encrypt(connection.ops.adapt_timefield_value(value))
[docs] def from_db_value(self, value:Any, expression:Any, connection:Any)-> Any: return Date(decrypt(value).decode()).date.time()
[docs] def pre_save(self, model_instance, add): if self.auto_now or (self.auto_now_add and add): value = datetime.datetime.now().time() setattr(model_instance, self.attname, value) return value else: return super().pre_save(model_instance, add)
[docs] def clean(self, value, model_instance): """ Convert the value's type and run validation. Validation errors from to_python() and validate() are propagated. Return the correct value if no error is raised. """ self.validate(value, model_instance) self.run_validators(value) return value
[docs]class DecimalField(models.DecimalField):
[docs] def get_internal_type(self)-> str: return "TextField"
[docs] def to_python(self, value: Any) -> Any: return super().to_python(value)
[docs] def get_prep_value(self, value: Any) -> Any: return self.to_python(value)
[docs] def get_db_prep_save(self, value, connection,): return encrypt(connection.ops.adapt_decimalfield_value(self.get_prep_value(value), self.max_digits, self.decimal_places))
[docs] def from_db_value(self, value:Any, expression:Any, connection:Any)-> Any: return float(decrypt(value).decode())
#return value
[docs] def clean(self, value, model_instance): """ Convert the value's type and run validation. Validation errors from to_python() and validate() are propagated. Return the correct value if no error is raised. """ self.validate(value, model_instance) self.run_validators(value) return value
[docs]class EmailField(CharField): default_validators = [validators.validate_email] description = _("Email address") def __init__(self, *args, **kwargs): # max_length=254 to be compliant with RFCs 3696 and 5321 kwargs.setdefault('max_length', 254) super().__init__(*args, **kwargs)
[docs] def formfield(self, **kwargs): # As with CharField, this will cause email validation to be performed # twice. return super().formfield(**{ 'form_class': forms.EmailField, **kwargs, })
[docs]class FloatField(models.FloatField):
[docs] def get_internal_type(self)-> str: return "TextField"
[docs] def to_python(self, value: Any) -> Any: return self.clean(super().to_python(value),None)
[docs] def get_prep_value(self, value: Any) -> Any: return self.to_python(value)
[docs] def from_db_value(self, value:Any, expression:Any, connection:Any)-> Any: return float(decrypt(value).decode())
[docs] def get_db_prep_value(self, value, connection, prepared=False): if not prepared: value = self.get_prep_value(value) return encrypt(value)
[docs] def clean(self, value, model_instance): """ Convert the value's type and run validation. Validation errors from to_python() and validate() are propagated. Return the correct value if no error is raised. """ self.validate(value, model_instance) self.run_validators(value) return value
[docs]class IntegerField(models.IntegerField):
[docs] def get_internal_type(self)-> str: return "TextField"
[docs] def to_python(self, value: Any) -> Any: return self.clean(super().to_python(value),None)
[docs] def get_prep_value(self, value: Any) -> Any: return self.to_python(value)
[docs] def from_db_value(self, value:Any, expression:Any, connection:Any)-> Any: return int(decrypt(value).decode())
[docs] def get_db_prep_value(self, value, connection, prepared=False): if not prepared: value = self.get_prep_value(value) return encrypt(value)
[docs] def clean(self, value, model_instance): """ Convert the value's type and run validation. Validation errors from to_python() and validate() are propagated. Return the correct value if no error is raised. """ self.validate(value, model_instance) self.run_validators(value) return value
[docs]class BigIntegerField(IntegerField): error_messages = { 'invalid': _('“%(value)s” value must be less than %(max) & greater than %(min).'), } description = _("Big (8 byte) integer") MAX_BIGINT = 9223372036854775807
[docs] def to_python(self, value: Any) -> Any: value=self.clean(super().to_python(value),None) if value < (-self.MAX_BIGINT-1) or value > self.MAX_BIGINT: raise exceptions.ValidationError(self.error_messages['invalid'],code='invalid', params={'value': value,'max':self.MAX_BIGINT,'min':(-self.MAX_BIGINT-1)}) return value
[docs] def formfield(self, **kwargs): return super().formfield(**{ 'min_value': -self.MAX_BIGINT - 1, 'max_value': self.MAX_BIGINT, **kwargs, })
[docs]class GenericIPAddressField(models.GenericIPAddressField):
[docs] def get_internal_type(self)-> str: return "TextField"
[docs] def to_python(self, value: Any) -> Any: return self.clean(super().to_python(value),None)
[docs] def get_prep_value(self, value: Any) -> Any: return self.to_python(value)
[docs] def get_db_prep_value(self, value, connection, prepared=False): if not prepared: value=self.get_prep_value(value) return encrypt(connection.ops.adapt_ipaddressfield_value(value))
[docs] def from_db_value(self, value:Any, expression:Any, connection:Any)-> Any: return decrypt(value).decode()
[docs] def clean(self, value, model_instance): """ Convert the value's type and run validation. Validation errors from to_python() and validate() are propagated. Return the correct value if no error is raised. """ self.validate(value, model_instance) self.run_validators(value) return value
[docs]class PositiveBigIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField): description = _('Positive big integer') error_messages = { 'invalid': _('“%(value)s” value must be less than greater than %(min).'), }
[docs] def to_python(self, value: Any) -> Any: value=self.clean(super().to_python(value),None) if value < 0: raise exceptions.ValidationError(self.error_messages['invalid'],code='invalid', params={'value': value,'min':0}) return value
[docs] def formfield(self, **kwargs): return super().formfield(**{ 'min_value': 0, **kwargs, })
[docs]class PositiveIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField): description = _("Positive integer") error_messages = { 'invalid': _('“%(value)s” value must be less than greater than %(min).'), }
[docs] def to_python(self, value: Any) -> Any: value=self.clean(super().to_python(value),None) if value < 0: raise exceptions.ValidationError(self.error_messages['invalid'],code='invalid', params={'value': value,'min':0}) return value
[docs] def formfield(self, **kwargs): return super().formfield(**{ 'min_value': 0, **kwargs, })
[docs]class PositiveSmallIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField): description = _("Positive small integer") error_messages = { 'invalid': _('“%(value)s” value must be less than greater than %(min).'), }
[docs] def to_python(self, value: Any) -> Any: value=self.clean(super().to_python(value),None) if value < 0: raise exceptions.ValidationError(self.error_messages['invalid'],code='invalid', params={'value': value,'min':0}) return value
[docs] def formfield(self, **kwargs): return super().formfield(**{ 'min_value': 0, **kwargs, })
[docs]class SlugField(CharField): default_validators = [validators.validate_slug] description = _("Slug (up to %(max_length)s)") def __init__(self, *args, max_length=50, db_index=True, allow_unicode=False, **kwargs): self.allow_unicode = allow_unicode if self.allow_unicode: self.default_validators = [validators.validate_unicode_slug] super().__init__(*args, max_length=max_length, db_index=db_index, **kwargs)
[docs] def deconstruct(self): name, path, args, kwargs = super().deconstruct() if kwargs.get("max_length") == 50: del kwargs['max_length'] if self.db_index is False: kwargs['db_index'] = False else: del kwargs['db_index'] if self.allow_unicode is not False: kwargs['allow_unicode'] = self.allow_unicode return name, path, args, kwargs
[docs] def get_internal_type(self): return "SlugField"
[docs] def formfield(self, **kwargs): return super().formfield(**{ 'form_class': forms.SlugField, 'allow_unicode': self.allow_unicode, **kwargs, })
[docs]class SmallIntegerField(IntegerField): description = _("Small integer")
[docs]class TextField(models.TextField):
[docs] def get_internal_type(self)-> str: return "TextField"
[docs] def to_python(self, value: Any) -> Any: return self.clean(super().to_python(value),None)
[docs] def get_prep_value(self, value: Any) -> Any: return self.to_python(value)
[docs] def from_db_value(self, value:Any, expression:Any, connection:Any)-> Any: return decrypt(value).decode()
[docs] def get_db_prep_value(self, value, connection, prepared=False): if not prepared: value = self.get_prep_value(value) return encrypt(value)
[docs] def clean(self, value, model_instance): """ Convert the value's type and run validation. Validation errors from to_python() and validate() are propagated. Return the correct value if no error is raised. """ self.validate(value, model_instance) self.run_validators(value) return value
[docs]class URLField(CharField): default_validators = [validators.URLValidator()] description = _("URL") def __init__(self, verbose_name=None, name=None, **kwargs): kwargs.setdefault('max_length', 200) super().__init__(verbose_name, name, **kwargs)
[docs] def deconstruct(self): name, path, args, kwargs = super().deconstruct() if kwargs.get("max_length") == 200: del kwargs['max_length'] return name, path, args, kwargs
[docs] def formfield(self, **kwargs): # As with CharField, this will cause URL validation to be performed # twice. return super().formfield(**{ 'form_class': forms.URLField, **kwargs, })
[docs]class BinaryField(models.BinaryField):
[docs] def get_internal_type(self)-> str: return "TextField"
[docs] def to_python(self, value: Any) -> Any: value=self.clean(value,None) if isinstance(value ,str): value=bytes(value,"UTF-8").hex() elif isinstance(value,memoryview): value=value.bytes.hex() return value
[docs] def get_prep_value(self, value: Any) -> Any: return self.to_python(value)
[docs] def from_db_value(self, value:Any, expression:Any, connection:Any)-> Any: return decrypt(value)
[docs] def get_db_prep_value(self, value, connection, prepared=False): if not prepared: value = self.get_prep_value(value) return encrypt(connection.Database.Binary(value))
[docs] def clean(self, value, model_instance): """ Convert the value's type and run validation. Validation errors from to_python() and validate() are propagated. Return the correct value if no error is raised. """ self.validate(value, model_instance) self.run_validators(value) return value
[docs]class UUIDField(models.UUIDField):
[docs] def get_internal_type(self)-> str: return "TextField"
[docs] def to_python(self, value: Any) -> Any: return self.clean(super().to_python(value),None)
[docs] def get_prep_value(self, value: Any) -> Any: return self.to_python(value)
[docs] def from_db_value(self, value:Any, expression:Any, connection:Any)-> Any: #return UUID.hex(decrypt(value).decode()) return UUID(hex=decrypt(value).decode())
[docs] def get_db_prep_value(self, value, connection, prepared=False): if not prepared: value = self.get_prep_value(value) return encrypt(value.hex)
[docs] def clean(self, value, model_instance): """ Convert the value's type and run validation. Validation errors from to_python() and validate() are propagated. Return the correct value if no error is raised. """ self.validate(value, model_instance) self.run_validators(value) return value
[docs]class FilePathField(models.FilePathField):
[docs] def get_internal_type(self)-> str: return "TextField"
[docs] def to_python(self, value: Any) -> Any: return self.clean(super().to_python(value),None)
[docs] def get_prep_value(self, value: Any) -> Any: return self.to_python(value)
[docs] def from_db_value(self, value:Any, expression:Any, connection:Any)-> Any: return decrypt(value).decode()
[docs] def get_db_prep_value(self, value, connection, prepared=False): if not prepared: value = self.get_prep_value(value) return encrypt(value)
CharField.register_lookup(StartsWith) BooleanField.register_lookup(StartsWith) DateField.register_lookup(StartsWith) DateTimeField.register_lookup(StartsWith) EmailField.register_lookup(StartsWith) GenericIPAddressField.register_lookup(StartsWith) SlugField.register_lookup(StartsWith) TextField.register_lookup(StartsWith) URLField.register_lookup(StartsWith) BinaryField.register_lookup(StartsWith) UUIDField.register_lookup(StartsWith) FilePathField.register_lookup(StartsWith) DateField.register_lookup(StartsWith,lookup_name="date") DateTimeField.register_lookup(StartsWith,lookup_name="date") TimeField.register_lookup(StartsWith,lookup_name="time")