from __future__ import annotations import re from collections.abc import Mapping, MutableMapping from typing import Any REDACTED = "[REDACTED]" _SENSITIVE_KEY = re.compile( r"(authorization|cookie|password|passwd|secret|token|api[_-]?key|" r"database[_-]?url|redis[_-]?url|dsn|callback[_-]?url)", re.IGNORECASE, ) _URI_USERINFO = re.compile(r"(?P[a-z][a-z0-9+.-]*://)[^/@\s]+@", re.IGNORECASE) _QUERY_SECRET = re.compile( r"(?P[?&](?:token|access_token|api_key|key|secret|password)=)[^&#\s]+", re.IGNORECASE, ) _AUTH_VALUE = re.compile(r"\b(Bearer|Basic)\s+[A-Za-z0-9._~+/=-]+", re.IGNORECASE) def sanitize_text(value: str) -> str: value = _URI_USERINFO.sub(r"\g[REDACTED]@", value) value = _QUERY_SECRET.sub(r"\g[REDACTED]", value) return _AUTH_VALUE.sub(r"\1 [REDACTED]", value) def sanitize_value(value: Any) -> Any: if isinstance(value, str): return sanitize_text(value) if isinstance(value, Mapping): return { str(key): REDACTED if _SENSITIVE_KEY.search(str(key)) else sanitize_value(item) for key, item in value.items() } if isinstance(value, list): return [sanitize_value(item) for item in value] if isinstance(value, tuple): return tuple(sanitize_value(item) for item in value) return value def redact_event( _logger: Any, _method_name: str, event_dict: MutableMapping[str, Any], ) -> MutableMapping[str, Any]: return sanitize_value(event_dict)