iLO-manager first main commitgit status
This commit is contained in:
1 parent
e6f4cc04ca
commit
599d8da562
3271 files changed
+550655
No files matched your search
@@ -0,0 +1,678 @@
|
||||
###
|
||||
# Copyright 2025 Hewlett Packard Enterprise, Inc. All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
###
|
||||
|
||||
# -*- coding: utf-8 -*-
|
||||
"""Centralized security masking framework for iLORest"""
|
||||
|
||||
import json
|
||||
import re
|
||||
import copy
|
||||
from typing import Dict, List, Any, Union, Optional
|
||||
|
||||
|
||||
class SecurityMasker:
|
||||
"""Centralized framework for masking sensitive information in logs and outputs."""
|
||||
|
||||
# Default mask character
|
||||
MASK_VALUE = "******"
|
||||
|
||||
# Number of characters to show for partial masking
|
||||
PARTIAL_MASK_SHOW_CHARS = 4
|
||||
|
||||
# Sensitive command-line argument patterns
|
||||
SENSITIVE_CLI_KEYWORDS = {
|
||||
"--password",
|
||||
"--pass",
|
||||
"-p",
|
||||
"--pwd",
|
||||
"--token",
|
||||
"--auth-token",
|
||||
"--session-token",
|
||||
"--key",
|
||||
"--api-key",
|
||||
"--secret",
|
||||
"--credential",
|
||||
"--cert-key",
|
||||
"--private-key",
|
||||
"--passphrase",
|
||||
"--sessionkey",
|
||||
"--auth",
|
||||
"--authorization",
|
||||
"--filepass",
|
||||
"--backup-password",
|
||||
"--biospassword",
|
||||
}
|
||||
|
||||
# Fields requiring COMPLETE masking (no characters visible)
|
||||
COMPLETE_MASK_FIELDS = {
|
||||
"password",
|
||||
"oldpassword",
|
||||
"newpassword",
|
||||
"currentpassword",
|
||||
"passwd",
|
||||
"pwd",
|
||||
"pass",
|
||||
"passphrase",
|
||||
"secret",
|
||||
"client_secret",
|
||||
"private_key",
|
||||
"privatekey",
|
||||
"cert_key",
|
||||
"certkey",
|
||||
"pin",
|
||||
"otp",
|
||||
"totp",
|
||||
"mfa_token",
|
||||
"csrf_token",
|
||||
"csrftoken",
|
||||
}
|
||||
|
||||
# Fields allowing PARTIAL masking (last 4-6 chars visible for debugging)
|
||||
PARTIAL_MASK_FIELDS = {
|
||||
"token",
|
||||
"auth_token",
|
||||
"authtoken",
|
||||
"session_token",
|
||||
"sessiontoken",
|
||||
"access_token",
|
||||
"accesstoken",
|
||||
"refresh_token",
|
||||
"refreshtoken",
|
||||
"bearer_token",
|
||||
"api_key",
|
||||
"apikey",
|
||||
"sessionkey",
|
||||
"session_key",
|
||||
"credential",
|
||||
"credentials",
|
||||
"appid",
|
||||
"app_id",
|
||||
"applicationid",
|
||||
"application_id",
|
||||
}
|
||||
|
||||
# Headers requiring COMPLETE masking
|
||||
COMPLETE_MASK_HEADERS = {
|
||||
"authorization", # Often contains Basic auth with password
|
||||
"www-authenticate",
|
||||
"proxy-authorization",
|
||||
"cookie",
|
||||
"set-cookie", # May contain sensitive session data
|
||||
}
|
||||
|
||||
# Headers allowing PARTIAL masking (for debugging/correlation)
|
||||
PARTIAL_MASK_HEADERS = {
|
||||
"x-auth-token",
|
||||
"x-session-token",
|
||||
"x-api-key",
|
||||
"api-key",
|
||||
"bearer", # When separate from Authorization header
|
||||
"x-session-id",
|
||||
"session-id",
|
||||
}
|
||||
|
||||
# All sensitive headers (union of complete and partial)
|
||||
SENSITIVE_HEADERS = (
|
||||
COMPLETE_MASK_HEADERS
|
||||
| PARTIAL_MASK_HEADERS
|
||||
| {"authentication", "basic", "digest", "oauth", "jwt", "x-csrf-token", "x-request-id"}
|
||||
)
|
||||
|
||||
# All sensitive body fields (union of complete and partial)
|
||||
SENSITIVE_BODY_FIELDS = COMPLETE_MASK_FIELDS | PARTIAL_MASK_FIELDS | {"auth", "authorization"}
|
||||
|
||||
# URL parameter patterns that might contain sensitive data
|
||||
SENSITIVE_URL_PARAMS = {"password", "token", "key", "secret", "auth", "session", "credential", "pass", "pwd"}
|
||||
|
||||
@classmethod
|
||||
def mask_command_arguments(cls, args: List[str]) -> List[str]:
|
||||
"""
|
||||
Mask sensitive information in command-line arguments.
|
||||
|
||||
Args:
|
||||
args: List of command-line arguments
|
||||
|
||||
Returns:
|
||||
List of arguments with sensitive values masked
|
||||
|
||||
Example:
|
||||
>>> SecurityMasker.mask_command_arguments(['--user', 'admin', '--password', 'MyP@ss'])
|
||||
['--user', 'admin', '--password', '******']
|
||||
"""
|
||||
if not args:
|
||||
return args
|
||||
|
||||
masked_args = []
|
||||
i = 0
|
||||
|
||||
while i < len(args):
|
||||
arg = args[i]
|
||||
|
||||
# Check for inline sensitive arguments (--password=value)
|
||||
if cls._has_inline_sensitive_value(arg):
|
||||
masked_args.append(cls._mask_inline_argument(arg))
|
||||
i += 1
|
||||
continue
|
||||
|
||||
# Check if current arg is a sensitive flag
|
||||
if cls._is_sensitive_cli_flag(arg):
|
||||
masked_args.append(arg) # Keep the flag
|
||||
# Mask the next argument if it exists and isn't another flag
|
||||
if i + 1 < len(args) and not args[i + 1].startswith("-"):
|
||||
i += 1 # Move to the next argument
|
||||
masked_args.append(cls.MASK_VALUE) # Mask the value
|
||||
i += 1
|
||||
continue
|
||||
|
||||
# Keep non-sensitive arguments as-is
|
||||
masked_args.append(arg)
|
||||
i += 1
|
||||
|
||||
return masked_args
|
||||
|
||||
@classmethod
|
||||
def mask_http_headers(
|
||||
cls, headers: Union[Dict[str, str], List[tuple], Any]
|
||||
) -> Union[Dict[str, str], List[tuple], str]:
|
||||
"""
|
||||
Mask sensitive information in HTTP headers.
|
||||
|
||||
Args:
|
||||
headers: HTTP headers in various formats (dict, list of tuples, or other)
|
||||
|
||||
Returns:
|
||||
Headers with sensitive values masked
|
||||
|
||||
Examples:
|
||||
# dict format
|
||||
>>> SecurityMasker.mask_http_headers({'Authorization': 'Basic abc123', 'Accept': 'application/json'})
|
||||
{'Authorization': '******', 'Accept': 'application/json'}
|
||||
|
||||
# list-of-tuples format
|
||||
>>> SecurityMasker.mask_http_headers([('Authorization', 'Bearer abcd'), ('Host', 'example')])
|
||||
[('Authorization', '******'), ('Host', 'example')]
|
||||
"""
|
||||
if not headers:
|
||||
return headers
|
||||
|
||||
try:
|
||||
# Handle dictionary format
|
||||
if isinstance(headers, dict):
|
||||
return cls._mask_headers_dict(headers)
|
||||
|
||||
# Handle list of tuples format
|
||||
elif isinstance(headers, (list, tuple)):
|
||||
return cls._mask_headers_list(headers)
|
||||
|
||||
# Handle string representation of headers
|
||||
elif isinstance(headers, str):
|
||||
return cls._mask_headers_string(headers)
|
||||
|
||||
# Handle other object types (e.g., HTTPMessage)
|
||||
else:
|
||||
return cls._mask_headers_object(headers)
|
||||
|
||||
except Exception:
|
||||
# If masking fails, return a safe placeholder
|
||||
return "[HEADERS MASKED DUE TO PROCESSING ERROR]"
|
||||
|
||||
@classmethod
|
||||
def mask_simple_body(cls, body: Union[str, bytes, Dict[str, Any]]) -> Union[str, bytes, Dict[str, Any]]:
|
||||
"""
|
||||
Mask sensitive information in simple HTTP request/response bodies.
|
||||
|
||||
This method handles basic body masking for simple payloads.
|
||||
For complex bodies with advanced JSON parsing and error handling,
|
||||
use mask_complex_body() instead.
|
||||
|
||||
Args:
|
||||
body: Request/response body in various formats
|
||||
|
||||
Returns:
|
||||
Body with sensitive values masked
|
||||
|
||||
Examples:
|
||||
# JSON string
|
||||
>>> SecurityMasker.mask_simple_body('{"password":"secret"}')
|
||||
'{"password":"******"}'
|
||||
|
||||
# dict
|
||||
>>> SecurityMasker.mask_simple_body({"token": "abcd"})
|
||||
{"token": "******"}
|
||||
"""
|
||||
if not body:
|
||||
return body
|
||||
|
||||
try:
|
||||
# Handle string body (likely JSON)
|
||||
if isinstance(body, str):
|
||||
return cls._mask_string_body(body)
|
||||
|
||||
# Handle bytes body
|
||||
elif isinstance(body, bytes):
|
||||
return cls._mask_bytes_body(body)
|
||||
|
||||
# Handle dictionary body
|
||||
elif isinstance(body, dict):
|
||||
return cls._mask_dict_body(body)
|
||||
|
||||
# Handle other types
|
||||
else:
|
||||
return body
|
||||
|
||||
except Exception:
|
||||
# If masking fails, return original or safe placeholder
|
||||
if isinstance(body, (str, bytes)):
|
||||
return "[BODY MASKED DUE TO PROCESSING ERROR]"
|
||||
return body
|
||||
|
||||
@classmethod
|
||||
def mask_url_parameters(cls, url: str) -> str:
|
||||
"""
|
||||
Mask sensitive information in URL parameters.
|
||||
|
||||
Args:
|
||||
url: URL string that may contain parameters
|
||||
|
||||
Returns:
|
||||
URL with sensitive parameter values masked
|
||||
|
||||
Example:
|
||||
>>> SecurityMasker.mask_url_parameters('https://api.example.com/login?user=admin&password=1234')
|
||||
'https://api.example.com/login?user=admin&password=******'
|
||||
"""
|
||||
if not url or "?" not in url:
|
||||
return url
|
||||
|
||||
try:
|
||||
base_url, params = url.split("?", 1)
|
||||
param_pairs = params.split("&")
|
||||
masked_pairs = []
|
||||
|
||||
for pair in param_pairs:
|
||||
if "=" in pair:
|
||||
key, value = pair.split("=", 1)
|
||||
if any(sensitive in key.lower() for sensitive in cls.SENSITIVE_URL_PARAMS):
|
||||
masked_pairs.append(f"{key}={cls.MASK_VALUE}")
|
||||
else:
|
||||
masked_pairs.append(pair)
|
||||
else:
|
||||
masked_pairs.append(pair)
|
||||
|
||||
return f"{base_url}?{'&'.join(masked_pairs)}"
|
||||
|
||||
except Exception:
|
||||
return url
|
||||
|
||||
@classmethod
|
||||
def mask_complex_body(cls, body: Union[str, bytes, Dict[str, Any]]) -> Union[str, bytes]:
|
||||
"""
|
||||
Mask sensitive information in complex HTTP request/response bodies for logging.
|
||||
|
||||
This is a specialized method for complex body masking that handles:
|
||||
- Advanced JSON parsing with error recovery
|
||||
- Automatic encoding/decoding (str ↔ bytes)
|
||||
- Type preservation (returns same type as input)
|
||||
- Graceful error handling to ensure logging never fails
|
||||
|
||||
Use this method for complex request/response bodies. For simple bodies,
|
||||
mask_simple_body() may be sufficient.
|
||||
|
||||
Args:
|
||||
body: The request/response body in various formats (str, bytes, dict)
|
||||
|
||||
Returns:
|
||||
Masked body as string or bytes (matching input type)
|
||||
|
||||
Example:
|
||||
>>> SecurityMasker.mask_complex_body(b'{"users":[{"name":"u","password":"p"}]}')
|
||||
b'{"users": [{"name": "u", "password": "******"}]}'
|
||||
"""
|
||||
if not body:
|
||||
return body
|
||||
|
||||
original_type = type(body)
|
||||
|
||||
try:
|
||||
# Convert to string if bytes
|
||||
if isinstance(body, bytes):
|
||||
try:
|
||||
body = body.decode("utf-8")
|
||||
except UnicodeDecodeError:
|
||||
# If decode fails, return original bytes
|
||||
return body
|
||||
|
||||
# If already a dict, mask and return as JSON string
|
||||
if isinstance(body, dict):
|
||||
masked_dict = cls._mask_dict_body(body)
|
||||
return json.dumps(masked_dict)
|
||||
|
||||
# If string, check if it's JSON
|
||||
if isinstance(body, str):
|
||||
body = body.strip()
|
||||
if body.startswith(("{", "[")):
|
||||
try:
|
||||
# Parse JSON and mask
|
||||
body_json = json.loads(body)
|
||||
masked_json = cls._mask_dict_body(body_json)
|
||||
masked_string = json.dumps(masked_json)
|
||||
|
||||
# Return in original type
|
||||
if original_type == bytes:
|
||||
return masked_string.encode("utf-8")
|
||||
return masked_string
|
||||
except json.JSONDecodeError:
|
||||
# Not valid JSON, return as-is
|
||||
pass
|
||||
|
||||
# Return body as-is if not JSON or other type
|
||||
if original_type == bytes and isinstance(body, str):
|
||||
return body.encode("utf-8")
|
||||
return body
|
||||
|
||||
except Exception:
|
||||
# If anything fails, return original to ensure logging continues
|
||||
# Converting to string if needed for logging
|
||||
if isinstance(body, bytes):
|
||||
try:
|
||||
return body.decode("utf-8", errors="replace")
|
||||
except:
|
||||
return "[BODY - BINARY DATA]"
|
||||
return body if body else ""
|
||||
|
||||
@classmethod
|
||||
def mask_user_input(cls, user_input: str, command_context: Optional[str] = None) -> str:
|
||||
"""
|
||||
Mask sensitive information in user input based on context.
|
||||
|
||||
Args:
|
||||
user_input: Raw user input string
|
||||
command_context: Optional context about what command is being executed
|
||||
|
||||
Returns:
|
||||
User input with sensitive parts masked
|
||||
|
||||
Example:
|
||||
>>> SecurityMasker.mask_user_input('--login admin --password MyP@ss')
|
||||
'--login admin --password ******'
|
||||
"""
|
||||
if not user_input:
|
||||
return user_input
|
||||
|
||||
# Split input into tokens for analysis
|
||||
tokens = user_input.split()
|
||||
|
||||
# Apply command argument masking
|
||||
masked_tokens = cls.mask_command_arguments(tokens)
|
||||
|
||||
return " ".join(masked_tokens)
|
||||
|
||||
# Private helper methods
|
||||
@classmethod
|
||||
def _is_sensitive_cli_flag(cls, arg: str) -> bool:
|
||||
"""Check if an argument is a sensitive command-line flag."""
|
||||
return arg.lower() in {flag.lower() for flag in cls.SENSITIVE_CLI_KEYWORDS}
|
||||
|
||||
@classmethod
|
||||
def _has_inline_sensitive_value(cls, arg: str) -> bool:
|
||||
"""Check if an argument contains inline sensitive value (flag=value)."""
|
||||
if "=" not in arg:
|
||||
return False
|
||||
flag = arg.split("=")[0]
|
||||
return cls._is_sensitive_cli_flag(flag)
|
||||
|
||||
@classmethod
|
||||
def _mask_inline_argument(cls, arg: str) -> str:
|
||||
"""Mask the value part of an inline argument."""
|
||||
return re.sub(r"=(.*)", f"={cls.MASK_VALUE}", arg)
|
||||
|
||||
@classmethod
|
||||
def _mask_headers_dict(cls, headers: Dict[str, str]) -> Dict[str, str]:
|
||||
"""Mask sensitive headers in dictionary format."""
|
||||
masked = {}
|
||||
for key, value in headers.items():
|
||||
if cls._is_sensitive_header(key):
|
||||
# Determine if complete or partial masking
|
||||
masked[key] = cls._mask_value(value, key, is_header=True)
|
||||
else:
|
||||
masked[key] = value
|
||||
return masked
|
||||
|
||||
@classmethod
|
||||
def _mask_headers_list(cls, headers: List[tuple]) -> List[tuple]:
|
||||
"""Mask sensitive headers in list of tuples format."""
|
||||
masked = []
|
||||
for item in headers:
|
||||
if isinstance(item, (list, tuple)) and len(item) >= 2:
|
||||
key, value = item[0], item[1]
|
||||
if cls._is_sensitive_header(key):
|
||||
masked_value = cls._mask_value(value, key, is_header=True)
|
||||
masked.append((key, masked_value))
|
||||
else:
|
||||
masked.append(item)
|
||||
else:
|
||||
masked.append(item)
|
||||
return masked
|
||||
|
||||
@classmethod
|
||||
def _mask_headers_string(cls, headers: str) -> str:
|
||||
"""Mask sensitive headers in string format."""
|
||||
lines = headers.split("\n")
|
||||
masked_lines = []
|
||||
|
||||
for line in lines:
|
||||
if ":" in line:
|
||||
key, value = line.split(":", 1)
|
||||
if cls._is_sensitive_header(key.strip()):
|
||||
# Preserve leading whitespace (indentation) from original key
|
||||
leading_space = key[: len(key) - len(key.lstrip())]
|
||||
masked_value = cls._mask_value(value.strip(), key.strip(), is_header=True)
|
||||
masked_lines.append(f"{leading_space}{key.strip()}: {masked_value}")
|
||||
else:
|
||||
masked_lines.append(line)
|
||||
else:
|
||||
masked_lines.append(line)
|
||||
|
||||
return "\n".join(masked_lines)
|
||||
|
||||
@classmethod
|
||||
def _mask_headers_object(cls, headers: Any) -> str:
|
||||
"""Mask sensitive headers in object format (e.g., HTTPMessage)."""
|
||||
try:
|
||||
# Try to convert to dictionary first
|
||||
if hasattr(headers, "items"):
|
||||
header_dict = dict(headers.items())
|
||||
masked_dict = cls._mask_headers_dict(header_dict)
|
||||
return str(masked_dict)
|
||||
elif hasattr(headers, "__dict__"):
|
||||
return cls._mask_headers_dict(headers.__dict__)
|
||||
else:
|
||||
return "[HEADERS MASKED - UNKNOWN FORMAT]"
|
||||
except Exception:
|
||||
return "[HEADERS MASKED DUE TO PROCESSING ERROR]"
|
||||
|
||||
@classmethod
|
||||
def _is_sensitive_header(cls, header_name: str) -> bool:
|
||||
"""Check if a header name is considered sensitive."""
|
||||
header_lower = header_name.lower().strip()
|
||||
return any(sensitive in header_lower for sensitive in cls.SENSITIVE_HEADERS)
|
||||
|
||||
@classmethod
|
||||
def _mask_string_body(cls, body: str) -> str:
|
||||
"""Mask sensitive information in string body."""
|
||||
try:
|
||||
# Try to parse as JSON
|
||||
if body.strip().startswith(("{", "[")):
|
||||
json_body = json.loads(body)
|
||||
masked_body = cls._mask_dict_body(json_body)
|
||||
return json.dumps(masked_body)
|
||||
else:
|
||||
# Handle form data or other string formats
|
||||
return cls._mask_form_data(body)
|
||||
except json.JSONDecodeError:
|
||||
# Not JSON, treat as form data or plain text
|
||||
return cls._mask_form_data(body)
|
||||
|
||||
@classmethod
|
||||
def _mask_bytes_body(cls, body: bytes) -> bytes:
|
||||
"""Mask sensitive information in bytes body."""
|
||||
try:
|
||||
# Convert to string, mask, then back to bytes
|
||||
string_body = body.decode("utf-8")
|
||||
masked_string = cls._mask_string_body(string_body)
|
||||
return masked_string.encode("utf-8")
|
||||
except UnicodeDecodeError:
|
||||
# If can't decode, return as-is (likely binary data)
|
||||
return body
|
||||
|
||||
@classmethod
|
||||
def _mask_dict_body(cls, body: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""Mask sensitive information in dictionary body."""
|
||||
masked = copy.deepcopy(body)
|
||||
|
||||
def mask_recursive(obj):
|
||||
if isinstance(obj, dict):
|
||||
for key, value in obj.items():
|
||||
if cls._is_sensitive_body_field(key):
|
||||
# Apply appropriate masking based on field type
|
||||
obj[key] = cls._mask_value(str(value) if value else "", key, is_header=False)
|
||||
else:
|
||||
mask_recursive(value)
|
||||
elif isinstance(obj, list):
|
||||
for item in obj:
|
||||
mask_recursive(item)
|
||||
|
||||
mask_recursive(masked)
|
||||
return masked
|
||||
|
||||
@classmethod
|
||||
def _mask_form_data(cls, data: str) -> str:
|
||||
"""Mask sensitive information in form data."""
|
||||
# Handle URL-encoded form data
|
||||
if "&" in data and "=" in data:
|
||||
pairs = data.split("&")
|
||||
masked_pairs = []
|
||||
for pair in pairs:
|
||||
if "=" in pair:
|
||||
key, value = pair.split("=", 1)
|
||||
if cls._is_sensitive_body_field(key):
|
||||
masked_pairs.append(f"{key}={cls.MASK_VALUE}")
|
||||
else:
|
||||
masked_pairs.append(pair)
|
||||
else:
|
||||
masked_pairs.append(pair)
|
||||
return "&".join(masked_pairs)
|
||||
|
||||
# For other string formats, return as-is
|
||||
return data
|
||||
|
||||
@classmethod
|
||||
def _is_sensitive_body_field(cls, field_name: str) -> bool:
|
||||
"""Check if a body field name is considered sensitive."""
|
||||
field_lower = field_name.lower().strip()
|
||||
return field_lower in cls.SENSITIVE_BODY_FIELDS
|
||||
|
||||
@classmethod
|
||||
def _mask_value(cls, value: str, field_name: str, is_header: bool = False) -> str:
|
||||
"""
|
||||
Mask a sensitive value with either complete or partial masking.
|
||||
|
||||
Args:
|
||||
value: The value to mask
|
||||
field_name: The field/header name (for determining mask type)
|
||||
is_header: Whether this is a header (vs body field)
|
||||
|
||||
Returns:
|
||||
Masked value (either completely or partially)
|
||||
"""
|
||||
if not value:
|
||||
return cls.MASK_VALUE
|
||||
|
||||
field_lower = field_name.lower().strip()
|
||||
|
||||
# Determine if we should use complete or partial masking
|
||||
use_complete_mask = False
|
||||
|
||||
if is_header:
|
||||
# Check if header requires complete masking
|
||||
use_complete_mask = field_lower in {h.lower() for h in cls.COMPLETE_MASK_HEADERS}
|
||||
# Special case: Authorization header with "Basic" is password-based
|
||||
if field_lower == "authorization" and value.strip().lower().startswith("basic"):
|
||||
use_complete_mask = True
|
||||
else:
|
||||
# Check if body field requires complete masking
|
||||
use_complete_mask = field_lower in {f.lower() for f in cls.COMPLETE_MASK_FIELDS}
|
||||
|
||||
# Apply appropriate masking
|
||||
if use_complete_mask:
|
||||
return cls.MASK_VALUE
|
||||
else:
|
||||
# Partial masking: show last N characters
|
||||
return cls._partial_mask(value)
|
||||
|
||||
@classmethod
|
||||
def _partial_mask(cls, value: str, show_chars: int = None) -> str:
|
||||
"""
|
||||
Apply partial masking to a value, showing only the last N characters.
|
||||
|
||||
Args:
|
||||
value: The value to mask
|
||||
show_chars: Number of characters to show (default: PARTIAL_MASK_SHOW_CHARS)
|
||||
|
||||
Returns:
|
||||
Partially masked value like "******a0fb"
|
||||
"""
|
||||
if show_chars is None:
|
||||
show_chars = cls.PARTIAL_MASK_SHOW_CHARS
|
||||
|
||||
if not value or len(value) <= show_chars:
|
||||
# If value is too short, completely mask it
|
||||
return cls.MASK_VALUE
|
||||
|
||||
# Show last N characters
|
||||
visible_part = value[-show_chars:]
|
||||
return f"{cls.MASK_VALUE}{visible_part}"
|
||||
|
||||
|
||||
# Convenience functions for backward compatibility and easy usage
|
||||
def mask_passwords(args: List[str]) -> List[str]:
|
||||
"""Backward compatible function for masking passwords in command arguments."""
|
||||
return SecurityMasker.mask_command_arguments(args)
|
||||
|
||||
|
||||
def mask_http_request_data(method: str, path: str, headers: Any, body: Any) -> tuple:
|
||||
"""
|
||||
Mask all sensitive data in an HTTP request for logging.
|
||||
|
||||
Args:
|
||||
method: HTTP method
|
||||
path: Request path/URL
|
||||
headers: Request headers
|
||||
body: Request body
|
||||
|
||||
Returns:
|
||||
Tuple of (method, masked_path, masked_headers, masked_body)
|
||||
"""
|
||||
masked_path = SecurityMasker.mask_url_parameters(path)
|
||||
masked_headers = SecurityMasker.mask_http_headers(headers)
|
||||
masked_body = SecurityMasker.mask_simple_body(body)
|
||||
|
||||
return method, masked_path, masked_headers, masked_body
|
||||
|
||||
|
||||
def mask_user_input(user_input: str, command_context: Optional[str] = None) -> str:
|
||||
"""Convenience function for masking user input."""
|
||||
return SecurityMasker.mask_user_input(user_input, command_context)
|
||||
Reference in new issue
Block a user