Skip to content

Commit 20ddefd

Browse files
committed
add LogSanitizer to filter out sensitive values from logs
usage example: import logging from mistapi.__logger import LogSanitizer LOG_FILE = "./log.txt" logging.basicConfig(filename=LOG_FILE, filemode="w") LOGGER = logging.getLogger(__name__) LOGGER.setLevel(logging.DEBUG) LOGGER.addFilter(LogSanitizer()) LOGGER.debug(var_with_sensitive_data)
1 parent 73c3330 commit 20ddefd

1 file changed

Lines changed: 162 additions & 10 deletions

File tree

src/mistapi/__logger.py

Lines changed: 162 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,63 +10,200 @@
1010
--------------------------------------------------------------------------------
1111
"""
1212

13+
import json
1314
import logging
1415
import os
16+
import re
1517

1618
os.system("") # nosec bandit B605 B607
1719

20+
SENSITIVE_FIELDS = [
21+
"secret",
22+
"mesh_psk",
23+
"psk",
24+
"default_psk",
25+
"broadnet_password",
26+
"gupshup_password",
27+
"lte_password",
28+
"password",
29+
"poser_password",
30+
"puzzel_password",
31+
"authentication_password",
32+
"encryption_password",
33+
"root_password",
34+
"mist_password",
35+
"apitoken",
36+
"cp_api_key",
37+
"ecm_api_key",
38+
"key",
39+
"fips_zeroize_password",
40+
"passphrase",
41+
"old_passphrase",
42+
"oauth2_client_secret",
43+
"oauth2_password",
44+
"splunk_token",
45+
"conductor_token",
46+
]
47+
1848

1949
def magenta(text):
50+
"""
51+
Docstring for magenta
52+
53+
:param text: Description
54+
"""
2055
return "\033[0;35m" + text + "\033[0m"
2156

2257

2358
def red(text):
59+
"""
60+
Docstring for red
61+
62+
:param text: Description
63+
"""
2464
return "\033[0;31m" + text + "\033[0m"
2565

2666

2767
def yellow(text):
68+
"""
69+
Docstring for yellow
70+
71+
:param text: Description
72+
"""
2873
return "\033[0;33m" + text + "\033[0m"
2974

3075

3176
def green(text):
77+
"""
78+
Docstring for green
79+
80+
:param text: Description
81+
"""
3282
return "\033[0;32m" + text + "\033[0m"
3383

3484

3585
def white(text):
86+
"""
87+
Docstring for white
88+
89+
:param text: Description
90+
"""
3691
return "\033[0;37m" + text + "\033[0m"
3792

3893

3994
def cyan(text):
95+
"""
96+
Docstring for cyan
97+
98+
:param text: Description
99+
"""
40100
return "\033[0;36m" + text + "\033[0m"
41101

42102

43103
def blue(text):
104+
"""
105+
Docstring for blue
106+
107+
:param text: Description
108+
"""
44109
return "\033[0;34m" + text + "\033[0m"
45110

46111

47112
class Console:
113+
"""
114+
Console class for logging messages to the console with different log levels
115+
and sanitizing sensitive fields in the messages.
116+
"""
117+
48118
def __init__(self, level: int = 20) -> None:
49119
self.level: int = level
120+
self.sensitive_fields = SENSITIVE_FIELDS
121+
# compile regex pattern to match sensitive fields
122+
# example pattern: r'("password"\s*:\s*)"(.*?)"'
123+
# matches "password": "value"
124+
# and captures "password": and "value" separately
125+
# to replace "value" with "******"
126+
# case insensitive
127+
self.sensitive_pattern = re.compile(
128+
r'(["\']('
129+
+ "|".join(self.sensitive_fields)
130+
+ r')["\']?\s*:\s*)["\']([^"\']*)["\']',
131+
re.IGNORECASE,
132+
)
133+
134+
def sanitize(self, data) -> str:
135+
"""
136+
sanitize sensitive fields in a dictionary or string
137+
138+
PARAMS
139+
-----------
140+
data : str
141+
142+
RETURNS
143+
-----------
144+
sanitized data : str
145+
"""
146+
if not isinstance(data, str):
147+
data_str = json.dumps(data)
148+
else:
149+
data_str = str(data)
150+
sanitized_data = self.sensitive_pattern.sub(r'\1"******"', data_str)
151+
return sanitized_data
152+
153+
def critical(self, message) -> None:
154+
"""
155+
Docstring for critical
50156
51-
def critical(self, message: str) -> None:
157+
:param self: Description
158+
:param message: Description
159+
:type message: str
160+
"""
52161
if self.level <= 50 and self.level > 0:
53-
print(f"[{magenta('CRITICAL ')}] {message}")
162+
print(f"[{magenta('CRITICAL ')}] {self.sanitize(message)}")
163+
164+
def error(self, message) -> None:
165+
"""
166+
Docstring for error
54167
55-
def error(self, message: str) -> None:
168+
:param self: Description
169+
:param message: Description
170+
:type message: str
171+
"""
56172
if self.level <= 40 and self.level > 0:
57-
print(f"[{red(' ERROR ')}] {message}")
173+
print(f"[{red(' ERROR ')}] {self.sanitize(message)}")
58174

59-
def warning(self, message: str) -> None:
175+
def warning(self, message) -> None:
176+
"""
177+
Docstring for warning
178+
179+
:param self: Description
180+
:param message: Description
181+
:type message: str
182+
"""
60183
if self.level <= 30 and self.level > 0:
61-
print(f"[{yellow(' WARNING ')}] {message}")
184+
print(f"[{yellow(' WARNING ')}] {self.sanitize(message)}")
185+
186+
def info(self, message) -> None:
187+
"""
188+
Docstring for info
62189
63-
def info(self, message: str) -> None:
190+
:param self: Description
191+
:param message: Description
192+
:type message: str
193+
"""
64194
if self.level <= 20 and self.level > 0:
65-
print(f"[{green(' INFO ')}] {message}")
195+
print(f"[{green(' INFO ')}] {self.sanitize(message)}")
196+
197+
def debug(self, message) -> None:
198+
"""
199+
Docstring for debug
66200
67-
def debug(self, message: str) -> None:
201+
:param self: Description
202+
:param message: Description
203+
:type message: str
204+
"""
68205
if self.level <= 10 and self.level > 0:
69-
print(f"[{white('DEBUG ')}] {message}")
206+
print(f"[{white('DEBUG ')}] {self.sanitize(message)}")
70207

71208
def _set_log_level(
72209
self, console_log_level: int = 20, logging_log_level: int = 10
@@ -91,6 +228,21 @@ def _set_log_level(
91228
logger.setLevel(logging_log_level)
92229

93230

231+
class LogSanitizer(logging.Filter):
232+
"""
233+
Logging filter that sanitizes sensitive fields in log messages
234+
"""
235+
236+
def __init__(self):
237+
super().__init__()
238+
self.console = Console()
239+
240+
def filter(self, record):
241+
record.msg = self.console.sanitize(record.msg)
242+
return True
243+
244+
94245
console = Console()
95246
logger = logging.getLogger("mistapi")
96247
logger.setLevel(logging.DEBUG)
248+
logger.addFilter(LogSanitizer())

0 commit comments

Comments
 (0)