45 lines
1.1 KiB
Python
45 lines
1.1 KiB
Python
"""敏感信息脱敏工具。"""
|
|
|
|
import re
|
|
from collections.abc import Mapping
|
|
from typing import Any
|
|
|
|
SENSITIVE_KEYS = {
|
|
"api_key",
|
|
"apikey",
|
|
"authorization",
|
|
"password",
|
|
"secret",
|
|
"token",
|
|
"access_token",
|
|
"refresh_token",
|
|
"private_key",
|
|
}
|
|
_REDACTED = "[REDACTED]"
|
|
_BEARER_RE = re.compile(r"Bearer\s+[A-Za-z0-9._~+/-]+=*", re.IGNORECASE)
|
|
|
|
|
|
def redact_text(value: str) -> str:
|
|
return _BEARER_RE.sub("Bearer [REDACTED]", value)
|
|
|
|
|
|
def redact_mapping(data: Mapping[str, Any]) -> dict[str, Any]:
|
|
redacted: dict[str, Any] = {}
|
|
for key, value in data.items():
|
|
normalized = key.lower().replace("-", "_")
|
|
if normalized in SENSITIVE_KEYS or any(part in normalized for part in SENSITIVE_KEYS):
|
|
redacted[key] = _REDACTED
|
|
else:
|
|
redacted[key] = redact_value(value)
|
|
return redacted
|
|
|
|
|
|
def redact_value(value: Any) -> Any:
|
|
if isinstance(value, str):
|
|
return redact_text(value)
|
|
if isinstance(value, Mapping):
|
|
return redact_mapping(value)
|
|
if isinstance(value, list):
|
|
return [redact_value(item) for item in value]
|
|
return value
|