text_validate_fields()   A
last analyzed

Complexity

Conditions 2

Size

Total Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
dl 0
loc 6
c 1
b 0
f 0
rs 9.4285
cc 2
1
import timeout_decorator
2
3
from django.db import models
4
5
from django.core.exceptions import ValidationError
6
from django.core.validators import RegexValidator
7
from jsonfield import JSONField
8
9
import re # regex
10
11
from django.core.validators import validate_email
12
13
14
def get_validator_by_name(name):
15
    """
16
    For given validator name, returns associated functions array:
17
    validator = { validate_fields: vf, validate_input: vi }
18
    Where:
19
        - vf(fields)
20
            Raises a ValidationError if given fields are not valid for this validator
21
        - vi(fields, user_input)
22
            Throws a ValidationError if given input is not valid for this validator
23
24
    Returns None if there is no validator matching that name.
25
    """
26
27
    # Validators functions
28
    def text_validate_fields(fields):
29
        # TODO: Is it safe to call re.compile with user input ? Possible infinite loops ... ?
30
        try:
31
            re.compile(fields['regex'])
32
        except re.error:
33
            raise ValidationError(fields['message'] + " (invalid Regex syntax)")
34
35
    # Protection against Evil Regex. Only 50ms to evaluate regex - should be enough.
36
    @timeout_decorator.timeout(0.05, use_signals=False)
37
    def regex_check_timeout(regex, error_message, input):
38
        try:
39
            RegexValidator(regex, error_message)(input)
40
        except re.error: # Should not happen ...
41
            raise ValidationError("Invalid validator for this field.")
42
43
    def text_validate_input(fields, input):
44
        if (fields['regex']):
45
            try:
46
                regex_check_timeout(fields['regex'], fields['message'], input)
47
            except timeout_decorator.TimeoutError:
48
                raise ValidationError(fields['message'])
49
50
    # Validators map
51
    validators_map = {
52
        Validator.VALIDATOR_NONE: {
53
            'validate_fields':    lambda f: True,
54
            'validate_input':     lambda f,i: True,
55
        },
56
        Validator.VALIDATOR_TEXT: {
57
            'validate_fields':    text_validate_fields,
58
            'validate_input':     text_validate_input
59
        },
60
        # TODO: Register validators here
61
    }
62
63
    # Find matching validator
64
    try:
65
        return validators_map[name]
66
    except KeyError:
67
        return None
68
69
70
def validate_validator_fields(validator, fields):
71
    v = get_validator_by_name(validator)
72
    v['validate_fields'](fields)
73
74
def are_validator_fields_valid(validator, fields):
75
    try:
76
        validate_validator_fields(validator, fields)
77
        return True
78
    except ValidationError:
79
        return False
80
81
def validate_validator_input(validator, validator_values, value):
82
    v = get_validator_by_name(validator)
83
    v['validate_input'](validator_values, value)
84
85
def is_validator_input_valid(validator, validator_values, value):
86
    try:
87
        validate_validator_input(validator, validator_values, value)
88
        return True
89
    except ValidationError:
90
        return False
91
92
class Validator(models.Model):
93
    class Meta:
94
        pass
95
96
    VALIDATOR_TEXT = 'text'
97
    VALIDATOR_NONE = 'none'
98
    VALIDATOR_HTML_CHOICES = (
99
        (VALIDATOR_TEXT, 'Text'),
100
        (VALIDATOR_NONE, 'None')
101
    )
102
103
    # Displayed validator name
104
    display_name    = models.CharField(max_length=255)
105
    # HTML name (<input type="html_name">)
106
    html_name       = models.CharField(max_length=255,
107
                            choices=VALIDATOR_HTML_CHOICES,
108
                            default=VALIDATOR_NONE,
109
                            primary_key=True)
110
    # Serialized JSON array (fieldName => fieldDescription)
111
    values          = JSONField()
112
113
    def __str__(self):
114
        return "Validator \"%s\" (\"%s\" with values=\"%s\")" % (self.display_name, self.html_name, self.values)
115
116
    def validate_fields(self, fields):
117
        return validate_validator_fields(self.html_name, fields)
118
119
    def validate_input(self, validator_values, client_input):
120
        return validate_validator_input(self.html_name, validator_values, client_input)
121