mirror of https://github.com/home-assistant/core
72 lines
2.0 KiB
Python
72 lines
2.0 KiB
Python
"""Helpers to redact sensitive data."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from collections.abc import Callable, Iterable, Mapping
|
|
from typing import Any, cast, overload
|
|
|
|
from homeassistant.core import callback
|
|
|
|
REDACTED = "**REDACTED**"
|
|
|
|
|
|
def partial_redact(
|
|
x: str | Any, unmasked_prefix: int = 4, unmasked_suffix: int = 4
|
|
) -> str:
|
|
"""Mask part of a string with *."""
|
|
if not isinstance(x, str):
|
|
return REDACTED
|
|
|
|
unmasked = unmasked_prefix + unmasked_suffix
|
|
if len(x) < unmasked * 2:
|
|
return REDACTED
|
|
|
|
if not unmasked_prefix and not unmasked_suffix:
|
|
return REDACTED
|
|
|
|
suffix = x[-unmasked_suffix:] if unmasked_suffix else ""
|
|
return f"{x[:unmasked_prefix]}***{suffix}"
|
|
|
|
|
|
@overload
|
|
def async_redact_data[_ValueT](
|
|
data: Mapping, to_redact: Iterable[Any] | Mapping[Any, Callable[[_ValueT], _ValueT]]
|
|
) -> dict: ...
|
|
|
|
|
|
@overload
|
|
def async_redact_data[_T, _ValueT](
|
|
data: _T, to_redact: Iterable[Any] | Mapping[Any, Callable[[_ValueT], _ValueT]]
|
|
) -> _T: ...
|
|
|
|
|
|
@callback
|
|
def async_redact_data[_T, _ValueT](
|
|
data: _T, to_redact: Iterable[Any] | Mapping[Any, Callable[[_ValueT], _ValueT]]
|
|
) -> _T:
|
|
"""Redact sensitive data in a dict."""
|
|
if not isinstance(data, (Mapping, list)):
|
|
return data
|
|
|
|
if isinstance(data, list):
|
|
return cast(_T, [async_redact_data(val, to_redact) for val in data])
|
|
|
|
redacted = {**data}
|
|
|
|
for key, value in redacted.items():
|
|
if value is None:
|
|
continue
|
|
if isinstance(value, str) and not value:
|
|
continue
|
|
if key in to_redact:
|
|
if isinstance(to_redact, Mapping):
|
|
redacted[key] = to_redact[key](value)
|
|
else:
|
|
redacted[key] = REDACTED
|
|
elif isinstance(value, Mapping):
|
|
redacted[key] = async_redact_data(value, to_redact)
|
|
elif isinstance(value, list):
|
|
redacted[key] = [async_redact_data(item, to_redact) for item in value]
|
|
|
|
return cast(_T, redacted)
|