diff --git a/homeassistant/auth/models.py b/homeassistant/auth/models.py index 6889d17a25f..08f2f375b41 100644 --- a/homeassistant/auth/models.py +++ b/homeassistant/auth/models.py @@ -1,5 +1,6 @@ """Auth models.""" from datetime import datetime, timedelta +import secrets from typing import Dict, List, NamedTuple, Optional import uuid @@ -9,7 +10,6 @@ from homeassistant.util import dt as dt_util from . import permissions as perm_mdl from .const import GROUP_ID_ADMIN -from .util import generate_secret TOKEN_TYPE_NORMAL = "normal" TOKEN_TYPE_SYSTEM = "system" @@ -96,8 +96,8 @@ class RefreshToken: ) id = attr.ib(type=str, factory=lambda: uuid.uuid4().hex) created_at = attr.ib(type=datetime, factory=dt_util.utcnow) - token = attr.ib(type=str, factory=lambda: generate_secret(64)) - jwt_key = attr.ib(type=str, factory=lambda: generate_secret(64)) + token = attr.ib(type=str, factory=lambda: secrets.token_hex(64)) + jwt_key = attr.ib(type=str, factory=lambda: secrets.token_hex(64)) last_used_at = attr.ib(type=Optional[datetime], default=None) last_used_ip = attr.ib(type=Optional[str], default=None) diff --git a/homeassistant/auth/util.py b/homeassistant/auth/util.py deleted file mode 100644 index 83834fa7683..00000000000 --- a/homeassistant/auth/util.py +++ /dev/null @@ -1,13 +0,0 @@ -"""Auth utils.""" -import binascii -import os - - -def generate_secret(entropy: int = 32) -> str: - """Generate a secret. - - Backport of secrets.token_hex from Python 3.6 - - Event loop friendly. - """ - return binascii.hexlify(os.urandom(entropy)).decode("ascii") diff --git a/homeassistant/components/http/auth.py b/homeassistant/components/http/auth.py index 3866e770de0..58814b77e2d 100644 --- a/homeassistant/components/http/auth.py +++ b/homeassistant/components/http/auth.py @@ -1,11 +1,11 @@ """Authentication for HTTP component.""" import logging +import secrets from aiohttp import hdrs from aiohttp.web import middleware import jwt -from homeassistant.auth.util import generate_secret from homeassistant.core import callback from homeassistant.util import dt as dt_util @@ -26,7 +26,7 @@ def async_sign_path(hass, refresh_token_id, path, expiration): secret = hass.data.get(DATA_SIGN_SECRET) if secret is None: - secret = hass.data[DATA_SIGN_SECRET] = generate_secret() + secret = hass.data[DATA_SIGN_SECRET] = secrets.token_hex() now = dt_util.utcnow() return "{}?{}={}".format( diff --git a/homeassistant/components/mobile_app/http_api.py b/homeassistant/components/mobile_app/http_api.py index ede18528f81..9581a374384 100644 --- a/homeassistant/components/mobile_app/http_api.py +++ b/homeassistant/components/mobile_app/http_api.py @@ -1,11 +1,11 @@ """Provides an HTTP API for mobile_app.""" +import secrets from typing import Dict import uuid from aiohttp.web import Request, Response from nacl.secret import SecretBox -from homeassistant.auth.util import generate_secret from homeassistant.components.http import HomeAssistantView from homeassistant.components.http.data_validator import RequestDataValidator from homeassistant.const import CONF_WEBHOOK_ID, HTTP_CREATED @@ -34,7 +34,7 @@ class RegistrationsView(HomeAssistantView): """Handle the POST request for registration.""" hass = request.app["hass"] - webhook_id = generate_secret() + webhook_id = secrets.token_hex() if hass.components.cloud.async_active_subscription(): data[ @@ -46,7 +46,7 @@ class RegistrationsView(HomeAssistantView): data[CONF_WEBHOOK_ID] = webhook_id if data[ATTR_SUPPORTS_ENCRYPTION] and supports_encryption(): - data[CONF_SECRET] = generate_secret(SecretBox.KEY_SIZE) + data[CONF_SECRET] = secrets.token_hex(SecretBox.KEY_SIZE) data[CONF_USER_ID] = request["hass_user"].id diff --git a/homeassistant/components/owntracks/config_flow.py b/homeassistant/components/owntracks/config_flow.py index 82f89de6363..0aba24217cc 100644 --- a/homeassistant/components/owntracks/config_flow.py +++ b/homeassistant/components/owntracks/config_flow.py @@ -1,6 +1,7 @@ """Config flow for OwnTracks.""" +import secrets + from homeassistant import config_entries -from homeassistant.auth.util import generate_secret from homeassistant.const import CONF_WEBHOOK_ID from .const import DOMAIN # noqa pylint: disable=unused-import @@ -25,7 +26,7 @@ class OwnTracksFlow(config_entries.ConfigFlow, domain=DOMAIN): webhook_id, webhook_url, cloudhook = await self._get_webhook_id() - secret = generate_secret(16) + secret = secrets.token_hex(16) if supports_encryption(): secret_desc = f"The encryption key is {secret} (on Android under preferences -> advanced)" @@ -53,7 +54,7 @@ class OwnTracksFlow(config_entries.ConfigFlow, domain=DOMAIN): if self._async_current_entries(): return self.async_abort(reason="one_instance_allowed") webhook_id, _webhook_url, cloudhook = await self._get_webhook_id() - secret = generate_secret(16) + secret = secrets.token_hex(16) return self.async_create_entry( title="OwnTracks", data={ diff --git a/homeassistant/components/rachio/__init__.py b/homeassistant/components/rachio/__init__.py index 4d67175ecd5..1b24f4e0071 100644 --- a/homeassistant/components/rachio/__init__.py +++ b/homeassistant/components/rachio/__init__.py @@ -1,13 +1,13 @@ """Integration with the Rachio Iro sprinkler system controller.""" import asyncio import logging +import secrets from typing import Optional from aiohttp import web from rachiopy import Rachio import voluptuous as vol -from homeassistant.auth.util import generate_secret from homeassistant.components.http import HomeAssistantView from homeassistant.const import CONF_API_KEY, EVENT_HOMEASSISTANT_STOP, URL_API from homeassistant.helpers import config_validation as cv, discovery @@ -115,7 +115,7 @@ def setup(hass, config) -> bool: # Get the URL of this server custom_url = config[DOMAIN].get(CONF_CUSTOM_URL) hass_url = hass.config.api.base_url if custom_url is None else custom_url - rachio.webhook_auth = generate_secret() + rachio.webhook_auth = secrets.token_hex() rachio.webhook_url = hass_url + WEBHOOK_PATH # Get the API user diff --git a/homeassistant/components/smartthings/smartapp.py b/homeassistant/components/smartthings/smartapp.py index 9b67df21491..74feb93eec4 100644 --- a/homeassistant/components/smartthings/smartapp.py +++ b/homeassistant/components/smartthings/smartapp.py @@ -2,6 +2,7 @@ import asyncio import functools import logging +import secrets from urllib.parse import urlparse from uuid import uuid4 @@ -208,7 +209,7 @@ async def setup_smartapp_endpoint(hass: HomeAssistantType): # Create config config = { CONF_INSTANCE_ID: str(uuid4()), - CONF_WEBHOOK_ID: webhook.generate_secret(), + CONF_WEBHOOK_ID: secrets.token_hex(), CONF_CLOUDHOOK_URL: None, } await store.async_save(config) diff --git a/homeassistant/components/stream/__init__.py b/homeassistant/components/stream/__init__.py index 2bfd37a2641..d88f90a83f8 100644 --- a/homeassistant/components/stream/__init__.py +++ b/homeassistant/components/stream/__init__.py @@ -1,10 +1,10 @@ """Provide functionality to stream video source.""" import logging +import secrets import threading import voluptuous as vol -from homeassistant.auth.util import generate_secret from homeassistant.const import CONF_FILENAME, EVENT_HOMEASSISTANT_STOP from homeassistant.core import callback from homeassistant.exceptions import HomeAssistantError @@ -72,7 +72,7 @@ def request_stream(hass, stream_source, *, fmt="hls", keepalive=False, options=N stream.add_provider(fmt) if not stream.access_token: - stream.access_token = generate_secret() + stream.access_token = secrets.token_hex() stream.start() return hass.data[DOMAIN][ATTR_ENDPOINTS][fmt].format(stream.access_token) except Exception: diff --git a/homeassistant/components/webhook/__init__.py b/homeassistant/components/webhook/__init__.py index d51771d0b16..217baf42f3a 100644 --- a/homeassistant/components/webhook/__init__.py +++ b/homeassistant/components/webhook/__init__.py @@ -1,10 +1,10 @@ """Webhooks for Home Assistant.""" import logging +import secrets from aiohttp.web import Request, Response import voluptuous as vol -from homeassistant.auth.util import generate_secret from homeassistant.components import websocket_api from homeassistant.components.http.view import HomeAssistantView from homeassistant.core import callback @@ -46,7 +46,7 @@ def async_unregister(hass, webhook_id): @callback def async_generate_id(): """Generate a webhook_id.""" - return generate_secret(entropy=32) + return secrets.token_hex(32) @callback diff --git a/homeassistant/helpers/config_entry_oauth2_flow.py b/homeassistant/helpers/config_entry_oauth2_flow.py index 4ea82f5f047..2fdfea8673f 100644 --- a/homeassistant/helpers/config_entry_oauth2_flow.py +++ b/homeassistant/helpers/config_entry_oauth2_flow.py @@ -8,6 +8,7 @@ This module exists of the following parts: from abc import ABC, ABCMeta, abstractmethod import asyncio import logging +import secrets import time from typing import Any, Awaitable, Callable, Dict, Optional, cast @@ -18,7 +19,6 @@ import voluptuous as vol from yarl import URL from homeassistant import config_entries -from homeassistant.auth.util import generate_secret from homeassistant.components.http import HomeAssistantView from homeassistant.core import HomeAssistant, callback @@ -441,7 +441,7 @@ def _encode_jwt(hass: HomeAssistant, data: dict) -> str: secret = hass.data.get(DATA_JWT_SECRET) if secret is None: - secret = hass.data[DATA_JWT_SECRET] = generate_secret() + secret = hass.data[DATA_JWT_SECRET] = secrets.token_hex() return jwt.encode(data, secret, algorithm="HS256").decode() diff --git a/tests/components/smartthings/conftest.py b/tests/components/smartthings/conftest.py index b3b172e7606..0dc71ea72b9 100644 --- a/tests/components/smartthings/conftest.py +++ b/tests/components/smartthings/conftest.py @@ -1,4 +1,5 @@ """Test configuration and mocks for the SmartThings component.""" +import secrets from uuid import uuid4 from asynctest import Mock, patch @@ -160,7 +161,7 @@ def installed_apps_fixture(installed_app, locations, app): @pytest.fixture(name="config_file") def config_file_fixture(): """Fixture representing the local config file contents.""" - return {CONF_INSTANCE_ID: str(uuid4()), CONF_WEBHOOK_ID: webhook.generate_secret()} + return {CONF_INSTANCE_ID: str(uuid4()), CONF_WEBHOOK_ID: secrets.token_hex()} @pytest.fixture(name="smartthings_mock")