File: validations.py

package info (click to toggle)
python-moto 5.1.18-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 116,520 kB
  • sloc: python: 636,725; javascript: 181; makefile: 39; sh: 3
file content (168 lines) | stat: -rw-r--r-- 6,071 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
"""DirectoryServiceBackend checks that result in ValidationException.

Note that ValidationExceptions are accumulative.
"""

import re
from typing import Any

from moto.ds.exceptions import DsValidationException


def validate_args(validators: Any) -> None:
    """Raise exception if any of the validations fails.

    validators is a list of tuples each containing the following:
        (printable field name, field value)

    The error messages are accumulated before the exception is raised.
    """
    validation_map = {
        "alias": validate_alias,
        "description": validate_description,
        "directoryId": validate_directory_id,
        "connectSettings.customerDnsIps": validate_dns_ips,
        "edition": validate_edition,
        "name": validate_name,
        "password": validate_password,
        "shortName": validate_short_name,
        "size": validate_size,
        "ssoPassword": validate_sso_password,
        "connectSettings.vpcSettings.subnetIds": validate_subnet_ids,
        "connectSettings.customerUserName": validate_user_name,
        "userName": validate_user_name,
        "vpcSettings.subnetIds": validate_subnet_ids,
        "trustDirection": validate_trust_direction,
        "remoteDomainName": validate_remote_domain_name,
    }
    err_msgs = []
    # This eventually could be a switch (python 3.10), elminating the need
    # for the above map and individual functions.
    for fieldname, value in validators:
        msg = validation_map[fieldname](value)
        if msg:
            err_msgs.append((fieldname, value, msg))
    if err_msgs:
        raise DsValidationException(err_msgs)


def validate_alias(value: str) -> str:
    """Raise exception if alias fails to conform to length and constraints."""
    if len(value) > 62:
        return "have length less than or equal to 62"

    alias_pattern = r"^(?!D-|d-)([\da-zA-Z]+)([-]*[\da-zA-Z])*$"
    if not re.match(alias_pattern, value):
        return rf"satisfy regular expression pattern: {alias_pattern}"
    return ""


def validate_description(value: str) -> str:
    """Raise exception if description exceeds length."""
    if value and len(value) > 128:
        return "have length less than or equal to 128"
    return ""


def validate_directory_id(value: str) -> str:
    """Raise exception if the directory id is invalid."""
    id_pattern = r"^d-[0-9a-f]{10}$"
    if not re.match(id_pattern, value):
        return rf"satisfy regular expression pattern: {id_pattern}"
    return ""


def validate_dns_ips(value: str) -> str:
    """Raise exception if DNS IPs fail to match constraints."""
    dnsip_pattern = (
        r"^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}"
        r"(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$"
    )
    for dnsip in value:
        if not re.match(dnsip_pattern, dnsip):
            return rf"satisfy regular expression pattern: {dnsip_pattern}"
    return ""


def validate_edition(value: str) -> str:
    """Raise exception if edition not one of the allowed values."""
    if value and value not in ["Enterprise", "Standard"]:
        return "satisfy enum value set: [Enterprise, Standard]"
    return ""


def validate_name(value: str) -> str:
    """Raise exception if name fails to match constraints."""
    name_pattern = r"^([a-zA-Z0-9]+[\.-])+([a-zA-Z0-9])+$"
    if not re.match(name_pattern, value):
        return rf"satisfy regular expression pattern: {name_pattern}"
    return ""


def validate_password(value: str) -> str:
    """Raise exception if password fails to match constraints."""
    passwd_pattern = (
        r"^(?=^.{8,64}$)((?=.*\d)(?=.*[A-Z])(?=.*[a-z])|"
        r"(?=.*\d)(?=.*[^A-Za-z0-9\s])(?=.*[a-z])|"
        r"(?=.*[^A-Za-z0-9\s])(?=.*[A-Z])(?=.*[a-z])|"
        r"(?=.*\d)(?=.*[A-Z])(?=.*[^A-Za-z0-9\s]))^.*$"
    )
    if not re.match(passwd_pattern, value):
        return rf"satisfy regular expression pattern: {passwd_pattern}"
    return ""


def validate_short_name(value: str) -> str:
    """Raise exception if short name fails to match constraints."""
    short_name_pattern = r'^[^\/:*?"<>|.]+[^\/:*?"<>|]*$'
    if value and not re.match(short_name_pattern, value):
        return rf"satisfy regular expression pattern: {short_name_pattern}"
    return ""


def validate_size(value: str) -> str:
    """Raise exception if size fails to match constraints."""
    if value.lower() not in ["small", "large"]:
        return "satisfy enum value set: [Small, Large]"
    return ""


def validate_sso_password(value: str) -> str:
    """Raise exception is SSO password exceeds length."""
    if value and len(value) > 128:
        return "have length less than or equal to 128"
    return ""


def validate_subnet_ids(value: str) -> str:
    """Raise exception is subnet IDs fail to match constraints."""
    subnet_id_pattern = r"^(subnet-[0-9a-f]{8}|subnet-[0-9a-f]{17})$"
    for subnet in value:
        if not re.match(subnet_id_pattern, subnet):
            return rf"satisfy regular expression pattern: {subnet_id_pattern}"
    return ""


def validate_user_name(value: str) -> str:
    """Raise exception is username fails to match constraints."""
    username_pattern = r"^[a-zA-Z0-9._-]+$"
    if value and not re.match(username_pattern, value):
        return rf"satisfy regular expression pattern: {username_pattern}"
    return ""


def validate_trust_direction(value: str) -> str:
    """Raise exception if trust direction fails to match constraints."""
    if value not in ["One-Way: Outgoing", "One-Way: Incoming", "Two-Way"]:
        return "satisfy enum value set: [One-Way: Outgoing, One-Way: Incoming, Two-Way]"
    return ""


def validate_remote_domain_name(value: str) -> str:
    """Raise exception if remote domain name fails to match constraints."""
    domain_name_pattern = r"^([a-zA-Z0-9]+[\\.-])+([a-zA-Z0-9])+[.]?$"
    if not re.match(domain_name_pattern, value):
        return rf"satisfy regular expression pattern: {domain_name_pattern}"
    elif len(value) > 1024:
        return "have length less than or equal to 1024"
    return ""