Added support for private storage. (#16878)
* Addded support for private storage. Include 'private' flag parameters to the Store class and save_json function. Updated various authentication and onboarding classes to use private stores. Fixed unit test for emulated_hue which used a mock patch on save_json(). * Fixed Hound formatting issues not detected by local linting.
This commit is contained in:
parent
e205092693
commit
e5861241c7
8 changed files with 64 additions and 53 deletions
|
@ -28,7 +28,8 @@ class AuthStore:
|
|||
"""Initialize the auth store."""
|
||||
self.hass = hass
|
||||
self._users = None # type: Optional[Dict[str, models.User]]
|
||||
self._store = hass.helpers.storage.Store(STORAGE_VERSION, STORAGE_KEY)
|
||||
self._store = hass.helpers.storage.Store(STORAGE_VERSION, STORAGE_KEY,
|
||||
private=True)
|
||||
|
||||
async def async_get_users(self) -> List[models.User]:
|
||||
"""Retrieve all users."""
|
||||
|
|
|
@ -85,7 +85,7 @@ class NotifyAuthModule(MultiFactorAuthModule):
|
|||
super().__init__(hass, config)
|
||||
self._user_settings = None # type: Optional[_UsersDict]
|
||||
self._user_store = hass.helpers.storage.Store(
|
||||
STORAGE_VERSION, STORAGE_KEY)
|
||||
STORAGE_VERSION, STORAGE_KEY, private=True)
|
||||
self._include = config.get(CONF_INCLUDE, [])
|
||||
self._exclude = config.get(CONF_EXCLUDE, [])
|
||||
self._message_template = config[CONF_MESSAGE]
|
||||
|
|
|
@ -67,7 +67,7 @@ class TotpAuthModule(MultiFactorAuthModule):
|
|||
super().__init__(hass, config)
|
||||
self._users = None # type: Optional[Dict[str, str]]
|
||||
self._user_store = hass.helpers.storage.Store(
|
||||
STORAGE_VERSION, STORAGE_KEY)
|
||||
STORAGE_VERSION, STORAGE_KEY, private=True)
|
||||
|
||||
@property
|
||||
def input_schema(self) -> vol.Schema:
|
||||
|
|
|
@ -52,7 +52,8 @@ class Data:
|
|||
def __init__(self, hass: HomeAssistant) -> None:
|
||||
"""Initialize the user data store."""
|
||||
self.hass = hass
|
||||
self._store = hass.helpers.storage.Store(STORAGE_VERSION, STORAGE_KEY)
|
||||
self._store = hass.helpers.storage.Store(STORAGE_VERSION, STORAGE_KEY,
|
||||
private=True)
|
||||
self._data = None # type: Optional[Dict[str, Any]]
|
||||
|
||||
async def async_load(self) -> None:
|
||||
|
|
|
@ -23,7 +23,8 @@ def async_is_onboarded(hass):
|
|||
|
||||
async def async_setup(hass, config):
|
||||
"""Set up the onboarding component."""
|
||||
store = hass.helpers.storage.Store(STORAGE_VERSION, STORAGE_KEY)
|
||||
store = hass.helpers.storage.Store(STORAGE_VERSION, STORAGE_KEY,
|
||||
private=True)
|
||||
data = await store.async_load()
|
||||
|
||||
if data is None:
|
||||
|
|
|
@ -46,11 +46,12 @@ async def async_migrator(hass, old_path, store, *,
|
|||
class Store:
|
||||
"""Class to help storing data."""
|
||||
|
||||
def __init__(self, hass, version: int, key: str):
|
||||
def __init__(self, hass, version: int, key: str, private: bool = False):
|
||||
"""Initialize storage class."""
|
||||
self.version = version
|
||||
self.key = key
|
||||
self.hass = hass
|
||||
self._private = private
|
||||
self._data = None
|
||||
self._unsub_delay_listener = None
|
||||
self._unsub_stop_listener = None
|
||||
|
@ -186,7 +187,7 @@ class Store:
|
|||
os.makedirs(os.path.dirname(path))
|
||||
|
||||
_LOGGER.debug('Writing data for %s', self.key)
|
||||
json.save_json(path, data)
|
||||
json.save_json(path, data, self._private)
|
||||
|
||||
async def _async_migrate_func(self, old_version, old_data):
|
||||
"""Migrate to the new version."""
|
||||
|
|
|
@ -3,6 +3,7 @@ import logging
|
|||
from typing import Union, List, Dict
|
||||
|
||||
import json
|
||||
import os
|
||||
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
|
||||
|
@ -38,14 +39,17 @@ def load_json(filename: str, default: Union[List, Dict, None] = None) \
|
|||
return {} if default is None else default
|
||||
|
||||
|
||||
def save_json(filename: str, data: Union[List, Dict]) -> None:
|
||||
def save_json(filename: str, data: Union[List, Dict],
|
||||
private: bool = False) -> None:
|
||||
"""Save JSON data to a file.
|
||||
|
||||
Returns True on success.
|
||||
"""
|
||||
try:
|
||||
json_data = json.dumps(data, sort_keys=True, indent=4)
|
||||
with open(filename, 'w', encoding='utf-8') as fdesc:
|
||||
mode = 0o600 if private else 0o644
|
||||
with open(os.open(filename, os.O_WRONLY | os.O_CREAT, mode),
|
||||
'w', encoding='utf-8') as fdesc:
|
||||
fdesc.write(json_data)
|
||||
except TypeError as error:
|
||||
_LOGGER.exception('Failed to serialize to JSON: %s',
|
||||
|
|
|
@ -16,24 +16,25 @@ def test_config_google_home_entity_id_to_number():
|
|||
handle = mop()
|
||||
|
||||
with patch('homeassistant.util.json.open', mop, create=True):
|
||||
number = conf.entity_id_to_number('light.test')
|
||||
assert number == '2'
|
||||
assert handle.write.call_count == 1
|
||||
assert json.loads(handle.write.mock_calls[0][1][0]) == {
|
||||
'1': 'light.test2',
|
||||
'2': 'light.test',
|
||||
}
|
||||
with patch('homeassistant.util.json.os.open', return_value=0):
|
||||
number = conf.entity_id_to_number('light.test')
|
||||
assert number == '2'
|
||||
assert handle.write.call_count == 1
|
||||
assert json.loads(handle.write.mock_calls[0][1][0]) == {
|
||||
'1': 'light.test2',
|
||||
'2': 'light.test',
|
||||
}
|
||||
|
||||
number = conf.entity_id_to_number('light.test')
|
||||
assert number == '2'
|
||||
assert handle.write.call_count == 1
|
||||
number = conf.entity_id_to_number('light.test')
|
||||
assert number == '2'
|
||||
assert handle.write.call_count == 1
|
||||
|
||||
number = conf.entity_id_to_number('light.test2')
|
||||
assert number == '1'
|
||||
assert handle.write.call_count == 1
|
||||
number = conf.entity_id_to_number('light.test2')
|
||||
assert number == '1'
|
||||
assert handle.write.call_count == 1
|
||||
|
||||
entity_id = conf.number_to_entity_id('1')
|
||||
assert entity_id == 'light.test2'
|
||||
entity_id = conf.number_to_entity_id('1')
|
||||
assert entity_id == 'light.test2'
|
||||
|
||||
|
||||
def test_config_google_home_entity_id_to_number_altered():
|
||||
|
@ -46,24 +47,25 @@ def test_config_google_home_entity_id_to_number_altered():
|
|||
handle = mop()
|
||||
|
||||
with patch('homeassistant.util.json.open', mop, create=True):
|
||||
number = conf.entity_id_to_number('light.test')
|
||||
assert number == '22'
|
||||
assert handle.write.call_count == 1
|
||||
assert json.loads(handle.write.mock_calls[0][1][0]) == {
|
||||
'21': 'light.test2',
|
||||
'22': 'light.test',
|
||||
}
|
||||
with patch('homeassistant.util.json.os.open', return_value=0):
|
||||
number = conf.entity_id_to_number('light.test')
|
||||
assert number == '22'
|
||||
assert handle.write.call_count == 1
|
||||
assert json.loads(handle.write.mock_calls[0][1][0]) == {
|
||||
'21': 'light.test2',
|
||||
'22': 'light.test',
|
||||
}
|
||||
|
||||
number = conf.entity_id_to_number('light.test')
|
||||
assert number == '22'
|
||||
assert handle.write.call_count == 1
|
||||
number = conf.entity_id_to_number('light.test')
|
||||
assert number == '22'
|
||||
assert handle.write.call_count == 1
|
||||
|
||||
number = conf.entity_id_to_number('light.test2')
|
||||
assert number == '21'
|
||||
assert handle.write.call_count == 1
|
||||
number = conf.entity_id_to_number('light.test2')
|
||||
assert number == '21'
|
||||
assert handle.write.call_count == 1
|
||||
|
||||
entity_id = conf.number_to_entity_id('21')
|
||||
assert entity_id == 'light.test2'
|
||||
entity_id = conf.number_to_entity_id('21')
|
||||
assert entity_id == 'light.test2'
|
||||
|
||||
|
||||
def test_config_google_home_entity_id_to_number_empty():
|
||||
|
@ -76,23 +78,24 @@ def test_config_google_home_entity_id_to_number_empty():
|
|||
handle = mop()
|
||||
|
||||
with patch('homeassistant.util.json.open', mop, create=True):
|
||||
number = conf.entity_id_to_number('light.test')
|
||||
assert number == '1'
|
||||
assert handle.write.call_count == 1
|
||||
assert json.loads(handle.write.mock_calls[0][1][0]) == {
|
||||
'1': 'light.test',
|
||||
}
|
||||
with patch('homeassistant.util.json.os.open', return_value=0):
|
||||
number = conf.entity_id_to_number('light.test')
|
||||
assert number == '1'
|
||||
assert handle.write.call_count == 1
|
||||
assert json.loads(handle.write.mock_calls[0][1][0]) == {
|
||||
'1': 'light.test',
|
||||
}
|
||||
|
||||
number = conf.entity_id_to_number('light.test')
|
||||
assert number == '1'
|
||||
assert handle.write.call_count == 1
|
||||
number = conf.entity_id_to_number('light.test')
|
||||
assert number == '1'
|
||||
assert handle.write.call_count == 1
|
||||
|
||||
number = conf.entity_id_to_number('light.test2')
|
||||
assert number == '2'
|
||||
assert handle.write.call_count == 2
|
||||
number = conf.entity_id_to_number('light.test2')
|
||||
assert number == '2'
|
||||
assert handle.write.call_count == 2
|
||||
|
||||
entity_id = conf.number_to_entity_id('2')
|
||||
assert entity_id == 'light.test2'
|
||||
entity_id = conf.number_to_entity_id('2')
|
||||
assert entity_id == 'light.test2'
|
||||
|
||||
|
||||
def test_config_alexa_entity_id_to_number():
|
||||
|
|
Loading…
Add table
Reference in a new issue