# -*- coding: utf-8 -*- import unicodedata import binascii from django.core.exceptions import ValidationError from django.utils.deconstruct import deconstructible from django.utils.encoding import force_str from django.utils.translation import gettext_lazy as _ @deconstructible class NoControlCharactersValidator: message = _("Control Characters like new lines or tabs are not allowed.") code = "no_control_characters" whitelist = None def __init__(self, message=None, code=None, whitelist=None): if message: self.message = message if code: self.code = code if whitelist: self.whitelist = whitelist def __call__(self, value): value = force_str(value) whitelist = self.whitelist category = unicodedata.category for character in value: if whitelist and character in whitelist: continue if category(character)[0] == "C": params = {'value': value, 'whitelist': whitelist} raise ValidationError(self.message, code=self.code, params=params) def __eq__(self, other): return ( isinstance(other, NoControlCharactersValidator) and (self.whitelist == other.whitelist) and (self.message == other.message) and (self.code == other.code) ) @deconstructible class NoWhitespaceValidator: message = _("Leading and Trailing whitespaces are not allowed.") code = "no_whitespace" def __init__(self, message=None, code=None, whitelist=None): if message: self.message = message if code: self.code = code def __call__(self, value): value = force_str(value) if value != value.strip(): params = {'value': value} raise ValidationError(self.message, code=self.code, params=params) def __eq__(self, other): return ( isinstance(other, NoWhitespaceValidator) and (self.message == other.message) and (self.code == other.code) ) @deconstructible class HexValidator: messages = { 'invalid': _("Only a hex string is allowed."), 'length': _("Invalid length. Must be %(length)d characters."), 'min_length': _("Ensure that there are more than %(min)s characters."), 'max_length': _("Ensure that there are no more than %(max)s characters."), } code = "hex_only" def __init__(self, length=None, min_length=None, max_length=None, message=None, code=None): self.length = length self.min_length = min_length self.max_length = max_length if message: self.message = message if code: self.code = code def __call__(self, value): value = force_str(value) if self.length and len(value) != self.length: raise ValidationError(self.messages['length'], code='hex_only_length', params={'length': self.length}) if self.min_length and len(value) < self.min_length: raise ValidationError(self.messages['min_length'], code='hex_only_min_length', params={'min': self.min_length}) if self.max_length and len(value) < self.max_length: raise ValidationError(self.messages['max_length'], code='hex_only_max_length', params={'max': self.max_length}) try: binascii.unhexlify(value) except (TypeError, binascii.Error): raise ValidationError(self.messages['invalid'], code='hex_only') def __eq__(self, other): return ( isinstance(other, HexValidator) and (self.message == other.message) and (self.code == other.code) )