|
5 | 5 | import re |
6 | 6 | from typing import Any, Callable |
7 | 7 |
|
8 | | -# , Iterable |
9 | 8 | from aws_lambda_powertools.utilities.data_masking.constants import DATA_MASKING_STRING |
10 | 9 |
|
11 | 10 | PRESERVE_CHARS = set("-_. ") |
@@ -77,72 +76,105 @@ def erase( |
77 | 76 | mask_format: str | None = None, |
78 | 77 | masking_rules: dict | None = None, |
79 | 78 | **kwargs, |
80 | | - ) -> str | dict | list | tuple | set: |
81 | | - """ |
82 | | - This method irreversibly erases data. |
83 | | -
|
84 | | - If the data to be erased is of type `str`, `dict`, or `bytes`, |
85 | | - this method will return an erased string, i.e. "*****". |
86 | | -
|
87 | | - If the data to be erased is of an iterable type like `list`, `tuple`, |
88 | | - or `set`, this method will return a new object of the same type as the |
89 | | - input data but with each element masked according to the specified rules. |
90 | | - """ |
91 | | - result = None |
92 | | - |
| 79 | + ) -> Any: |
93 | 80 | # Handle empty or None data |
94 | 81 | if data is None or (isinstance(data, (str, list, dict)) and not data): |
95 | 82 | return data |
96 | 83 |
|
97 | | - # Handle string data |
98 | | - if isinstance(data, str): |
99 | | - if regex_pattern and mask_format: |
100 | | - result = self._regex_mask(data, regex_pattern, mask_format) |
101 | | - elif custom_mask: |
102 | | - result = self._pattern_mask(data, custom_mask) |
103 | | - elif dynamic_mask: |
104 | | - result = self._custom_erase(data, **kwargs) |
105 | | - else: |
106 | | - result = DATA_MASKING_STRING |
107 | | - |
108 | | - # Handle dictionary data |
| 84 | + result = data # Default to returning the original data |
| 85 | + |
| 86 | + if isinstance(data, (str, int, float)): |
| 87 | + result = self._mask_primitive(str(data), dynamic_mask, custom_mask, regex_pattern, mask_format, **kwargs) |
109 | 88 | elif isinstance(data, dict): |
110 | | - if masking_rules: |
111 | | - result = self._apply_masking_rules(data, masking_rules) |
112 | | - else: |
113 | | - result = {} |
114 | | - for k, v in data.items(): |
115 | | - result[str(k)] = self.erase( |
116 | | - str(v), |
117 | | - dynamic_mask=dynamic_mask, |
118 | | - custom_mask=custom_mask, |
119 | | - regex_pattern=regex_pattern, |
120 | | - mask_format=mask_format, |
121 | | - masking_rules=masking_rules, |
122 | | - **kwargs, |
123 | | - ) |
124 | | - |
125 | | - # Handle iterable data (list, tuple, set) |
| 89 | + result = self._mask_dict( |
| 90 | + data, |
| 91 | + dynamic_mask, |
| 92 | + custom_mask, |
| 93 | + regex_pattern, |
| 94 | + mask_format, |
| 95 | + masking_rules, |
| 96 | + **kwargs, |
| 97 | + ) |
126 | 98 | elif isinstance(data, (list, tuple, set)): |
127 | | - masked_data = [ |
128 | | - self.erase( |
129 | | - item, |
| 99 | + result = self._mask_iterable( |
| 100 | + data, |
| 101 | + dynamic_mask, |
| 102 | + custom_mask, |
| 103 | + regex_pattern, |
| 104 | + mask_format, |
| 105 | + masking_rules, |
| 106 | + **kwargs, |
| 107 | + ) |
| 108 | + |
| 109 | + return result |
| 110 | + |
| 111 | + def _mask_primitive( |
| 112 | + self, |
| 113 | + data: str, |
| 114 | + dynamic_mask: bool | None, |
| 115 | + custom_mask: str | None, |
| 116 | + regex_pattern: str | None, |
| 117 | + mask_format: str | None, |
| 118 | + **kwargs, |
| 119 | + ) -> str: |
| 120 | + if regex_pattern and mask_format: |
| 121 | + return self._regex_mask(data, regex_pattern, mask_format) |
| 122 | + elif custom_mask: |
| 123 | + return self._pattern_mask(data, custom_mask) |
| 124 | + elif dynamic_mask: |
| 125 | + return self._custom_erase(data, **kwargs) |
| 126 | + else: |
| 127 | + return DATA_MASKING_STRING |
| 128 | + |
| 129 | + def _mask_dict( |
| 130 | + self, |
| 131 | + data: dict, |
| 132 | + dynamic_mask: bool | None, |
| 133 | + custom_mask: str | None, |
| 134 | + regex_pattern: str | None, |
| 135 | + mask_format: str | None, |
| 136 | + masking_rules: dict | None, |
| 137 | + **kwargs, |
| 138 | + ) -> dict: |
| 139 | + if masking_rules: |
| 140 | + return self._apply_masking_rules(data, masking_rules) |
| 141 | + else: |
| 142 | + return { |
| 143 | + k: self.erase( |
| 144 | + v, |
130 | 145 | dynamic_mask=dynamic_mask, |
131 | 146 | custom_mask=custom_mask, |
132 | 147 | regex_pattern=regex_pattern, |
133 | 148 | mask_format=mask_format, |
134 | 149 | masking_rules=masking_rules, |
135 | 150 | **kwargs, |
136 | 151 | ) |
137 | | - for item in data |
138 | | - ] |
139 | | - result = type(data)(masked_data) |
| 152 | + for k, v in data.items() |
| 153 | + } |
140 | 154 |
|
141 | | - # Handle other types (int, float, bool, etc.) |
142 | | - else: |
143 | | - result = str(data) |
144 | | - |
145 | | - return result |
| 155 | + def _mask_iterable( |
| 156 | + self, |
| 157 | + data: list | tuple | set, |
| 158 | + dynamic_mask: bool | None, |
| 159 | + custom_mask: str | None, |
| 160 | + regex_pattern: str | None, |
| 161 | + mask_format: str | None, |
| 162 | + masking_rules: dict | None, |
| 163 | + **kwargs, |
| 164 | + ) -> list | tuple | set: |
| 165 | + masked_data = [ |
| 166 | + self.erase( |
| 167 | + item, |
| 168 | + dynamic_mask=dynamic_mask, |
| 169 | + custom_mask=custom_mask, |
| 170 | + regex_pattern=regex_pattern, |
| 171 | + mask_format=mask_format, |
| 172 | + masking_rules=masking_rules, |
| 173 | + **kwargs, |
| 174 | + ) |
| 175 | + for item in data |
| 176 | + ] |
| 177 | + return type(data)(masked_data) |
146 | 178 |
|
147 | 179 | def _apply_masking_rules(self, data: dict, masking_rules: dict) -> Any: |
148 | 180 | """Apply masking rules to dictionary data.""" |
|
0 commit comments