Coverage for custom_components/autoarm/crypto.py: 100%
19 statements
« prev ^ index » next coverage.py v7.16.2, created at 2026-10-26 20:57 +0000
« prev ^ index » next coverage.py v7.16.2, created at 2026-10-26 20:57 +0000
1"""Keeps the alarm panel code out of plain sight in the config entry
3The key is derived from this Home Assistant's instance id, which is stored alongside the config entry, so this
4is obfuscation, to stop the code being read off a screen, a backup listing or a shared file, and no protection
5against someone with the whole of the `.storage` directory
6"""
8import base64
9import hashlib
10import logging
12from cryptography.fernet import Fernet, InvalidToken
13from homeassistant.core import HomeAssistant
14from homeassistant.helpers import instance_id
16from .const import DOMAIN
18_LOGGER = logging.getLogger(__name__)
21async def _cipher(hass: HomeAssistant) -> Fernet:
22 key: bytes = hashlib.sha256(f"{DOMAIN}:{await instance_id.async_get(hass)}".encode()).digest()
23 return Fernet(base64.urlsafe_b64encode(key))
26async def async_encrypt(hass: HomeAssistant, text: str) -> str:
27 return (await _cipher(hass)).encrypt(text.encode()).decode()
30async def async_decrypt(hass: HomeAssistant, token: str) -> str | None:
31 """None if it can't be read, as when the config entry has come from another Home Assistant"""
32 try:
33 return (await _cipher(hass)).decrypt(token.encode()).decode()
34 except InvalidToken:
35 _LOGGER.warning("AUTOARM Unable to read the stored alarm panel code, set it again in the options")
36 return None