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
|
import re
import string
from moto.moto_api._internal import mock_random as random
from moto.utilities.id_generator import (
ExistingIds,
ResourceIdentifier,
Tags,
generate_str_id,
)
from moto.utilities.utils import ARN_PARTITION_REGEX, get_partition
def random_password(
password_length: int,
exclude_characters: str,
exclude_numbers: bool,
exclude_punctuation: bool,
exclude_uppercase: bool,
exclude_lowercase: bool,
include_space: bool,
require_each_included_type: bool,
) -> str:
password = ""
required_characters = ""
if not exclude_lowercase and not exclude_uppercase:
password += string.ascii_letters
required_characters += random.choice(
_exclude_characters(string.ascii_lowercase, exclude_characters)
)
required_characters += random.choice(
_exclude_characters(string.ascii_uppercase, exclude_characters)
)
elif not exclude_lowercase:
password += string.ascii_lowercase
required_characters += random.choice(
_exclude_characters(string.ascii_lowercase, exclude_characters)
)
elif not exclude_uppercase:
password += string.ascii_uppercase
required_characters += random.choice(
_exclude_characters(string.ascii_uppercase, exclude_characters)
)
if not exclude_numbers:
password += string.digits
required_characters += random.choice(
_exclude_characters(string.digits, exclude_characters)
)
if not exclude_punctuation:
password += string.punctuation
required_characters += random.choice(
_exclude_characters(string.punctuation, exclude_characters)
)
if include_space:
password += " "
required_characters += " "
if exclude_characters:
password = _exclude_characters(password, exclude_characters)
password = "".join(str(random.choice(password)) for x in range(password_length))
if require_each_included_type:
password = _add_password_require_each_included_type(
password, required_characters
)
return password
def get_secret_name_from_partial_arn(partial_arn: str) -> str:
# We can retrieve a secret either using a full ARN, or using a partial ARN
# name: testsecret
# full ARN: arn:aws:secretsmanager:us-west-2:123456789012:secret:testsecret-xxxxxx
# partial ARN: arn:aws:secretsmanager:us-west-2:123456789012:secret:testsecret
#
# This method only deals with partial ARN's, and will return the name: testsecret
#
# If you were to pass in full url, this method will return 'testsecret-xxxxxx' - which has no meaning on it's own
if re.match(ARN_PARTITION_REGEX + ":secretsmanager:", partial_arn):
# split the arn by colon
# then get the last value which is the name appended with a random string
return partial_arn.split(":")[-1]
return partial_arn
def _exclude_characters(password: str, exclude_characters: str) -> str:
for c in exclude_characters:
if c in string.punctuation:
# Escape punctuation regex usage
c = rf"\{c}"
password = re.sub(c, "", str(password))
return password
def _add_password_require_each_included_type(
password: str, required_characters: str
) -> str:
password_with_required_char = password[: -len(required_characters)]
password_with_required_char += required_characters
return password_with_required_char
class SecretsManagerSecretIdentifier(ResourceIdentifier):
service = "secretsmanager"
resource = "secret"
def __init__(self, account_id: str, region: str, secret_id: str):
super().__init__(account_id, region, name=secret_id)
def generate(self, existing_ids: ExistingIds = None, tags: Tags = None) -> str:
id_string = generate_str_id(
resource_identifier=self,
existing_ids=existing_ids,
tags=tags,
length=6,
include_digits=False,
)
return (
f"arn:{get_partition(self.region)}:secretsmanager:{self.region}:"
f"{self.account_id}:secret:{self.name}-{id_string}"
)
|