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:
Paulus Schoutsen 2017-10-05 09:10:29 -07:00 committed by GitHub
parent 8db4641455
commit 75f902f57e
4 changed files with 32 additions and 12 deletions

View File

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

View File

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

View File

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

View File

@ -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'),