1import random
2import string
3import re
4
5from moto.core import ACCOUNT_ID
6
7
8def random_password(
9    password_length,
10    exclude_characters,
11    exclude_numbers,
12    exclude_punctuation,
13    exclude_uppercase,
14    exclude_lowercase,
15    include_space,
16    require_each_included_type,
17):
18
19    password = ""
20    required_characters = ""
21
22    if not exclude_lowercase and not exclude_uppercase:
23        password += string.ascii_letters
24        required_characters += random.choice(
25            _exclude_characters(string.ascii_lowercase, exclude_characters)
26        )
27        required_characters += random.choice(
28            _exclude_characters(string.ascii_uppercase, exclude_characters)
29        )
30    elif not exclude_lowercase:
31        password += string.ascii_lowercase
32        required_characters += random.choice(
33            _exclude_characters(string.ascii_lowercase, exclude_characters)
34        )
35    elif not exclude_uppercase:
36        password += string.ascii_uppercase
37        required_characters += random.choice(
38            _exclude_characters(string.ascii_uppercase, exclude_characters)
39        )
40    if not exclude_numbers:
41        password += string.digits
42        required_characters += random.choice(
43            _exclude_characters(string.digits, exclude_characters)
44        )
45    if not exclude_punctuation:
46        password += string.punctuation
47        required_characters += random.choice(
48            _exclude_characters(string.punctuation, exclude_characters)
49        )
50    if include_space:
51        password += " "
52        required_characters += " "
53    if exclude_characters:
54        password = _exclude_characters(password, exclude_characters)
55
56    password = "".join(str(random.choice(password)) for x in range(password_length))
57
58    if require_each_included_type:
59        password = _add_password_require_each_included_type(
60            password, required_characters
61        )
62
63    return password
64
65
66def secret_arn(region, secret_id):
67    id_string = "".join(random.choice(string.ascii_letters) for _ in range(5))
68    return "arn:aws:secretsmanager:{0}:{1}:secret:{2}-{3}".format(
69        region, ACCOUNT_ID, secret_id, id_string
70    )
71
72
73def get_secret_name_from_arn(secret_id):
74    # can fetch by both arn and by name
75    # but we are storing via name
76    # so we need to change the arn to name
77    # if it starts with arn then the secret id is arn
78    if secret_id.startswith("arn:aws:secretsmanager:"):
79        # split the arn by colon
80        # then get the last value which is the name appended with a random string
81        # then remove the random string
82        secret_id = "-".join(secret_id.split(":")[-1].split("-")[:-1])
83    return secret_id
84
85
86def _exclude_characters(password, exclude_characters):
87    for c in exclude_characters:
88        if c in string.punctuation:
89            # Escape punctuation regex usage
90            c = r"\{0}".format(c)
91        password = re.sub(c, "", str(password))
92    return password
93
94
95def _add_password_require_each_included_type(password, required_characters):
96    password_with_required_char = password[: -len(required_characters)]
97    password_with_required_char += required_characters
98
99    return password_with_required_char
100