Home Assistant Unofficial Reference 2024.12.1
diagnostics.py
Go to the documentation of this file.
1 """Diagnostics support for UniFi Network."""
2 
3 from __future__ import annotations
4 
5 from collections.abc import Mapping
6 from itertools import chain
7 from typing import Any
8 
9 from homeassistant.components.diagnostics import REDACTED, async_redact_data
10 from homeassistant.const import CONF_HOST, CONF_PASSWORD, CONF_USERNAME
11 from homeassistant.core import HomeAssistant, callback
12 from homeassistant.helpers.device_registry import format_mac
13 
14 from . import UnifiConfigEntry
15 
16 TO_REDACT = {CONF_PASSWORD}
17 REDACT_CONFIG = {CONF_HOST, CONF_PASSWORD, CONF_USERNAME}
18 REDACT_CLIENTS = {"bssid", "essid"}
19 REDACT_DEVICES = {
20  "anon_id",
21  "gateway_mac",
22  "geo_info",
23  "serial",
24  "x_authkey",
25  "x_fingerprint",
26  "x_iapp_key",
27  "x_ssh_hostkey_fingerprint",
28  "x_vwirekey",
29 }
30 REDACT_WLANS = {"bc_filter_list", "x_passphrase"}
31 
32 
33 @callback
35  data: Mapping, to_replace: dict[str, str]
36 ) -> dict[str, Any]:
37  """Redact sensitive data in a dict."""
38  redacted = {**data}
39  for key, value in data.items():
40  if isinstance(value, dict):
41  redacted[key] = async_replace_dict_data(value, to_replace)
42  elif isinstance(value, (list, set, tuple)):
43  redacted[key] = async_replace_list_data(value, to_replace)
44  elif isinstance(value, str):
45  if value in to_replace:
46  redacted[key] = to_replace[value]
47  elif value.count(":") == 5:
48  redacted[key] = REDACTED
49  return redacted
50 
51 
52 @callback
54  data: list | set | tuple, to_replace: dict[str, str]
55 ) -> list[Any]:
56  """Redact sensitive data in a list."""
57  redacted = []
58  for item in data:
59  new_value: Any | None = None
60  if isinstance(item, (list, set, tuple)):
61  new_value = async_replace_list_data(item, to_replace)
62  elif isinstance(item, Mapping):
63  new_value = async_replace_dict_data(item, to_replace)
64  elif isinstance(item, str):
65  if item in to_replace:
66  new_value = to_replace[item]
67  elif item.count(":") == 5:
68  new_value = REDACTED
69  redacted.append(new_value or item)
70  return redacted
71 
72 
74  hass: HomeAssistant, config_entry: UnifiConfigEntry
75 ) -> dict[str, Any]:
76  """Return diagnostics for a config entry."""
77  hub = config_entry.runtime_data
78  diag: dict[str, Any] = {}
79  macs_to_redact: dict[str, str] = {}
80 
81  counter = 0
82  for mac in chain(hub.api.clients, hub.api.devices):
83  macs_to_redact[mac] = format_mac(str(counter).zfill(12))
84  counter += 1
85 
86  for device in hub.api.devices.values():
87  for entry in device.raw.get("ethernet_table", []):
88  mac = entry.get("mac", "")
89  if mac not in macs_to_redact:
90  macs_to_redact[mac] = format_mac(str(counter).zfill(12))
91  counter += 1
92 
93  diag["config"] = async_redact_data(
94  async_replace_dict_data(config_entry.as_dict(), macs_to_redact), REDACT_CONFIG
95  )
96  diag["role_is_admin"] = hub.is_admin
97  diag["clients"] = {
98  macs_to_redact[k]: async_redact_data(
99  async_replace_dict_data(v.raw, macs_to_redact), REDACT_CLIENTS
100  )
101  for k, v in hub.api.clients.items()
102  }
103  diag["devices"] = {
104  macs_to_redact[k]: async_redact_data(
105  async_replace_dict_data(v.raw, macs_to_redact), REDACT_DEVICES
106  )
107  for k, v in hub.api.devices.items()
108  }
109  diag["dpi_apps"] = {k: v.raw for k, v in hub.api.dpi_apps.items()}
110  diag["dpi_groups"] = {k: v.raw for k, v in hub.api.dpi_groups.items()}
111  diag["wlans"] = {
113  async_replace_dict_data(v.raw, macs_to_redact), REDACT_WLANS
114  )
115  for k, v in hub.api.wlans.items()
116  }
117 
118  return diag
dict async_redact_data(Mapping data, Iterable[Any] to_redact)
Definition: util.py:14
dict[str, Any] async_replace_dict_data(Mapping data, dict[str, str] to_replace)
Definition: diagnostics.py:36
list[Any] async_replace_list_data(list|set|tuple data, dict[str, str] to_replace)
Definition: diagnostics.py:55
dict[str, Any] async_get_config_entry_diagnostics(HomeAssistant hass, UnifiConfigEntry config_entry)
Definition: diagnostics.py:75