mirror of
https://github.com/home-assistant/core.git
synced 2025-04-24 09:17:53 +00:00
RFC: Create a secrets file and enable HTTP password by default (#9685)
* Create a secret and enable password by default * Comment out api password secret * Lint/fix tests
This commit is contained in:
parent
8db4641455
commit
75f902f57e
@ -23,7 +23,7 @@ from homeassistant.const import (
|
||||
from homeassistant.core import callback, DOMAIN as CONF_CORE
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
from homeassistant.loader import get_component, get_platform
|
||||
from homeassistant.util.yaml import load_yaml
|
||||
from homeassistant.util.yaml import load_yaml, SECRET_YAML
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
from homeassistant.util import dt as date_util, location as loc_util
|
||||
from homeassistant.util.unit_system import IMPERIAL_SYSTEM, METRIC_SYSTEM
|
||||
@ -70,8 +70,8 @@ frontend:
|
||||
config:
|
||||
|
||||
http:
|
||||
# Uncomment this to add a password (recommended!)
|
||||
# api_password: PASSWORD
|
||||
# Secrets are defined in the file secrets.yaml
|
||||
# api_password: !secret http_password
|
||||
# Uncomment this if you are using SSL/TLS, running in Docker container, etc.
|
||||
# base_url: example.duckdns.org:8123
|
||||
|
||||
@ -111,6 +111,11 @@ group: !include groups.yaml
|
||||
automation: !include automations.yaml
|
||||
script: !include scripts.yaml
|
||||
"""
|
||||
DEFAULT_SECRETS = """
|
||||
# Use this file to store secrets like usernames and passwords.
|
||||
# Learn more at https://home-assistant.io/docs/configuration/secrets/
|
||||
http_password: welcome
|
||||
"""
|
||||
|
||||
|
||||
PACKAGES_CONFIG_SCHEMA = vol.Schema({
|
||||
@ -181,6 +186,7 @@ def create_default_config(config_dir, detect_location=True):
|
||||
CONFIG_PATH as CUSTOMIZE_CONFIG_PATH)
|
||||
|
||||
config_path = os.path.join(config_dir, YAML_CONFIG_FILE)
|
||||
secret_path = os.path.join(config_dir, SECRET_YAML)
|
||||
version_path = os.path.join(config_dir, VERSION_FILE)
|
||||
group_yaml_path = os.path.join(config_dir, GROUP_CONFIG_PATH)
|
||||
automation_yaml_path = os.path.join(config_dir, AUTOMATION_CONFIG_PATH)
|
||||
@ -209,7 +215,7 @@ def create_default_config(config_dir, detect_location=True):
|
||||
# Writing files with YAML does not create the most human readable results
|
||||
# So we're hard coding a YAML template.
|
||||
try:
|
||||
with open(config_path, 'w') as config_file:
|
||||
with open(config_path, 'wt') as config_file:
|
||||
config_file.write("homeassistant:\n")
|
||||
|
||||
for attr, _, _, description in DEFAULT_CORE_CONFIG:
|
||||
@ -221,6 +227,9 @@ def create_default_config(config_dir, detect_location=True):
|
||||
|
||||
config_file.write(DEFAULT_CONFIG)
|
||||
|
||||
with open(secret_path, 'wt') as secret_file:
|
||||
secret_file.write(DEFAULT_SECRETS)
|
||||
|
||||
with open(version_path, 'wt') as version_file:
|
||||
version_file.write(__version__)
|
||||
|
||||
|
@ -21,7 +21,7 @@ from homeassistant.exceptions import HomeAssistantError
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
_SECRET_NAMESPACE = 'homeassistant'
|
||||
_SECRET_YAML = 'secrets.yaml'
|
||||
SECRET_YAML = 'secrets.yaml'
|
||||
__SECRET_CACHE = {} # type: Dict
|
||||
|
||||
|
||||
@ -133,7 +133,7 @@ def _include_dir_merge_named_yaml(loader: SafeLineLoader,
|
||||
mapping = OrderedDict() # type: OrderedDict
|
||||
loc = os.path.join(os.path.dirname(loader.name), node.value)
|
||||
for fname in _find_files(loc, '*.yaml'):
|
||||
if os.path.basename(fname) == _SECRET_YAML:
|
||||
if os.path.basename(fname) == SECRET_YAML:
|
||||
continue
|
||||
loaded_yaml = load_yaml(fname)
|
||||
if isinstance(loaded_yaml, dict):
|
||||
@ -146,7 +146,7 @@ def _include_dir_list_yaml(loader: SafeLineLoader,
|
||||
"""Load multiple files from directory as a list."""
|
||||
loc = os.path.join(os.path.dirname(loader.name), node.value)
|
||||
return [load_yaml(f) for f in _find_files(loc, '*.yaml')
|
||||
if os.path.basename(f) != _SECRET_YAML]
|
||||
if os.path.basename(f) != SECRET_YAML]
|
||||
|
||||
|
||||
def _include_dir_merge_list_yaml(loader: SafeLineLoader,
|
||||
@ -156,7 +156,7 @@ def _include_dir_merge_list_yaml(loader: SafeLineLoader,
|
||||
node.value) # type: str
|
||||
merged_list = [] # type: List
|
||||
for fname in _find_files(loc, '*.yaml'):
|
||||
if os.path.basename(fname) == _SECRET_YAML:
|
||||
if os.path.basename(fname) == SECRET_YAML:
|
||||
continue
|
||||
loaded_yaml = load_yaml(fname)
|
||||
if isinstance(loaded_yaml, list):
|
||||
@ -216,7 +216,7 @@ def _env_var_yaml(loader: SafeLineLoader,
|
||||
|
||||
def _load_secret_yaml(secret_path: str) -> Dict:
|
||||
"""Load the secrets yaml from path."""
|
||||
secret_path = os.path.join(secret_path, _SECRET_YAML)
|
||||
secret_path = os.path.join(secret_path, SECRET_YAML)
|
||||
if secret_path in __SECRET_CACHE:
|
||||
return __SECRET_CACHE[secret_path]
|
||||
|
||||
@ -264,6 +264,8 @@ def _secret_yaml(loader: SafeLineLoader,
|
||||
_LOGGER.debug("Secret %s retrieved from keyring", node.value)
|
||||
return pwd
|
||||
|
||||
global credstash # pylint: disable=invalid-name
|
||||
|
||||
if credstash:
|
||||
try:
|
||||
pwd = credstash.getSecret(node.value, table=_SECRET_NAMESPACE)
|
||||
@ -272,6 +274,9 @@ def _secret_yaml(loader: SafeLineLoader,
|
||||
return pwd
|
||||
except credstash.ItemNotFound:
|
||||
pass
|
||||
except Exception: # pylint: disable=broad-except
|
||||
# Catch if package installed and no config
|
||||
credstash = None
|
||||
|
||||
_LOGGER.error("Secret %s not defined", node.value)
|
||||
raise HomeAssistantError(node.value)
|
||||
|
@ -16,6 +16,7 @@ from homeassistant.const import (
|
||||
CONF_TIME_ZONE, CONF_ELEVATION, CONF_CUSTOMIZE, __version__,
|
||||
CONF_UNIT_SYSTEM_METRIC, CONF_UNIT_SYSTEM_IMPERIAL, CONF_TEMPERATURE_UNIT)
|
||||
from homeassistant.util import location as location_util, dt as dt_util
|
||||
from homeassistant.util.yaml import SECRET_YAML
|
||||
from homeassistant.util.async import run_coroutine_threadsafe
|
||||
from homeassistant.helpers.entity import Entity
|
||||
from homeassistant.components.config.group import (
|
||||
@ -32,6 +33,7 @@ from tests.common import (
|
||||
|
||||
CONFIG_DIR = get_test_config_dir()
|
||||
YAML_PATH = os.path.join(CONFIG_DIR, config_util.YAML_CONFIG_FILE)
|
||||
SECRET_PATH = os.path.join(CONFIG_DIR, SECRET_YAML)
|
||||
VERSION_PATH = os.path.join(CONFIG_DIR, config_util.VERSION_FILE)
|
||||
GROUP_PATH = os.path.join(CONFIG_DIR, GROUP_CONFIG_PATH)
|
||||
AUTOMATIONS_PATH = os.path.join(CONFIG_DIR, AUTOMATIONS_CONFIG_PATH)
|
||||
@ -62,6 +64,9 @@ class TestConfig(unittest.TestCase):
|
||||
if os.path.isfile(YAML_PATH):
|
||||
os.remove(YAML_PATH)
|
||||
|
||||
if os.path.isfile(SECRET_PATH):
|
||||
os.remove(SECRET_PATH)
|
||||
|
||||
if os.path.isfile(VERSION_PATH):
|
||||
os.remove(VERSION_PATH)
|
||||
|
||||
@ -85,6 +90,7 @@ class TestConfig(unittest.TestCase):
|
||||
config_util.create_default_config(CONFIG_DIR, False)
|
||||
|
||||
assert os.path.isfile(YAML_PATH)
|
||||
assert os.path.isfile(SECRET_PATH)
|
||||
assert os.path.isfile(VERSION_PATH)
|
||||
assert os.path.isfile(GROUP_PATH)
|
||||
assert os.path.isfile(AUTOMATIONS_PATH)
|
||||
|
@ -302,7 +302,7 @@ class TestSecrets(unittest.TestCase):
|
||||
config_dir = get_test_config_dir()
|
||||
yaml.clear_secret_cache()
|
||||
self._yaml_path = os.path.join(config_dir, YAML_CONFIG_FILE)
|
||||
self._secret_path = os.path.join(config_dir, yaml._SECRET_YAML)
|
||||
self._secret_path = os.path.join(config_dir, yaml.SECRET_YAML)
|
||||
self._sub_folder_path = os.path.join(config_dir, 'subFolder')
|
||||
self._unrelated_path = os.path.join(config_dir, 'unrelated')
|
||||
|
||||
@ -351,7 +351,7 @@ class TestSecrets(unittest.TestCase):
|
||||
def test_secret_overrides_parent(self):
|
||||
"""Test loading current directory secret overrides the parent."""
|
||||
expected = {'api_password': 'override'}
|
||||
load_yaml(os.path.join(self._sub_folder_path, yaml._SECRET_YAML),
|
||||
load_yaml(os.path.join(self._sub_folder_path, yaml.SECRET_YAML),
|
||||
'http_pw: override')
|
||||
self._yaml = load_yaml(os.path.join(self._sub_folder_path, 'sub.yaml'),
|
||||
'http:\n'
|
||||
@ -365,7 +365,7 @@ class TestSecrets(unittest.TestCase):
|
||||
|
||||
def test_secrets_from_unrelated_fails(self):
|
||||
"""Test loading secrets from unrelated folder fails."""
|
||||
load_yaml(os.path.join(self._unrelated_path, yaml._SECRET_YAML),
|
||||
load_yaml(os.path.join(self._unrelated_path, yaml.SECRET_YAML),
|
||||
'test: failure')
|
||||
with self.assertRaises(HomeAssistantError):
|
||||
load_yaml(os.path.join(self._sub_folder_path, 'sub.yaml'),
|
||||
|
Loading…
x
Reference in New Issue
Block a user