Home Assistant Unofficial Reference 2024.12.1
redact.py
Go to the documentation of this file.
1 """Helpers to redact sensitive data."""
2 
3 from __future__ import annotations
4 
5 from collections.abc import Callable, Iterable, Mapping
6 from typing import Any, cast, overload
7 
8 from homeassistant.core import callback
9 
10 REDACTED = "**REDACTED**"
11 
12 
14  x: str | Any, unmasked_prefix: int = 4, unmasked_suffix: int = 4
15 ) -> str:
16  """Mask part of a string with *."""
17  if not isinstance(x, str):
18  return REDACTED
19 
20  unmasked = unmasked_prefix + unmasked_suffix
21  if len(x) < unmasked * 2:
22  return REDACTED
23 
24  if not unmasked_prefix and not unmasked_suffix:
25  return REDACTED
26 
27  suffix = x[-unmasked_suffix:] if unmasked_suffix else ""
28  return f"{x[:unmasked_prefix]}***{suffix}"
29 
30 
31 @overload
32 def async_redact_data[_ValueT](
33  data: Mapping, to_redact: Iterable[Any] | Mapping[Any, Callable[[_ValueT], _ValueT]]
34 ) -> dict: ...
35 
36 
37 @overload
38 def async_redact_data[_T, _ValueT](
39  data: _T, to_redact: Iterable[Any] | Mapping[Any, Callable[[_ValueT], _ValueT]]
40 ) -> _T: ...
41 
42 
43 @callback
44 def async_redact_data[_T, _ValueT](
45  data: _T, to_redact: Iterable[Any] | Mapping[Any, Callable[[_ValueT], _ValueT]]
46 ) -> _T:
47  """Redact sensitive data in a dict."""
48  if not isinstance(data, (Mapping, list)):
49  return data
50 
51  if isinstance(data, list):
52  return cast(_T, [async_redact_data(val, to_redact) for val in data])
53 
54  redacted = {**data}
55 
56  for key, value in redacted.items():
57  if value is None:
58  continue
59  if isinstance(value, str) and not value:
60  continue
61  if key in to_redact:
62  if isinstance(to_redact, Mapping):
63  redacted[key] = to_redact[key](value)
64  else:
65  redacted[key] = REDACTED
66  elif isinstance(value, Mapping):
67  redacted[key] = async_redact_data(value, to_redact)
68  elif isinstance(value, list):
69  redacted[key] = [async_redact_data(item, to_redact) for item in value]
70 
71  return cast(_T, redacted)
dict async_redact_data(Mapping data, Iterable[Any] to_redact)
Definition: util.py:14
str partial_redact(str|Any x, int unmasked_prefix=4, int unmasked_suffix=4)
Definition: redact.py:15