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

1"""Keeps the alarm panel code out of plain sight in the config entry 

2 

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""" 

7 

8import base64 

9import hashlib 

10import logging 

11 

12from cryptography.fernet import Fernet, InvalidToken 

13from homeassistant.core import HomeAssistant 

14from homeassistant.helpers import instance_id 

15 

16from .const import DOMAIN 

17 

18_LOGGER = logging.getLogger(__name__) 

19 

20 

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)) 

24 

25 

26async def async_encrypt(hass: HomeAssistant, text: str) -> str: 

27 return (await _cipher(hass)).encrypt(text.encode()).decode() 

28 

29 

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