mirror of
https://github.com/home-assistant/core.git
synced 2025-04-27 02:37:50 +00:00
Add ssl_cipher_list option to rest (#91078)
This commit is contained in:
parent
59dc0ea2e0
commit
323d16cc21
@ -43,7 +43,9 @@ from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
|
|||||||
|
|
||||||
from .const import (
|
from .const import (
|
||||||
CONF_ENCODING,
|
CONF_ENCODING,
|
||||||
|
CONF_SSL_CIPHER_LIST,
|
||||||
COORDINATOR,
|
COORDINATOR,
|
||||||
|
DEFAULT_SSL_CIPHER_LIST,
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
PLATFORM_IDX,
|
PLATFORM_IDX,
|
||||||
REST,
|
REST,
|
||||||
@ -185,6 +187,7 @@ def create_rest_data_from_config(hass: HomeAssistant, config: ConfigType) -> Res
|
|||||||
method: str = config[CONF_METHOD]
|
method: str = config[CONF_METHOD]
|
||||||
payload: str | None = config.get(CONF_PAYLOAD)
|
payload: str | None = config.get(CONF_PAYLOAD)
|
||||||
verify_ssl: bool = config[CONF_VERIFY_SSL]
|
verify_ssl: bool = config[CONF_VERIFY_SSL]
|
||||||
|
ssl_cipher_list: str = config.get(CONF_SSL_CIPHER_LIST, DEFAULT_SSL_CIPHER_LIST)
|
||||||
username: str | None = config.get(CONF_USERNAME)
|
username: str | None = config.get(CONF_USERNAME)
|
||||||
password: str | None = config.get(CONF_PASSWORD)
|
password: str | None = config.get(CONF_PASSWORD)
|
||||||
headers: dict[str, str] | None = config.get(CONF_HEADERS)
|
headers: dict[str, str] | None = config.get(CONF_HEADERS)
|
||||||
@ -218,5 +221,6 @@ def create_rest_data_from_config(hass: HomeAssistant, config: ConfigType) -> Res
|
|||||||
params,
|
params,
|
||||||
payload,
|
payload,
|
||||||
verify_ssl,
|
verify_ssl,
|
||||||
|
ssl_cipher_list,
|
||||||
timeout,
|
timeout,
|
||||||
)
|
)
|
||||||
|
@ -1,12 +1,16 @@
|
|||||||
"""The rest component constants."""
|
"""The rest component constants."""
|
||||||
|
|
||||||
|
from homeassistant.util.ssl import SSLCipherList
|
||||||
|
|
||||||
DOMAIN = "rest"
|
DOMAIN = "rest"
|
||||||
|
|
||||||
DEFAULT_METHOD = "GET"
|
DEFAULT_METHOD = "GET"
|
||||||
DEFAULT_VERIFY_SSL = True
|
DEFAULT_VERIFY_SSL = True
|
||||||
|
DEFAULT_SSL_CIPHER_LIST = SSLCipherList.PYTHON_DEFAULT
|
||||||
DEFAULT_FORCE_UPDATE = False
|
DEFAULT_FORCE_UPDATE = False
|
||||||
DEFAULT_ENCODING = "UTF-8"
|
DEFAULT_ENCODING = "UTF-8"
|
||||||
CONF_ENCODING = "encoding"
|
CONF_ENCODING = "encoding"
|
||||||
|
CONF_SSL_CIPHER_LIST = "ssl_cipher_list"
|
||||||
|
|
||||||
DEFAULT_BINARY_SENSOR_NAME = "REST Binary Sensor"
|
DEFAULT_BINARY_SENSOR_NAME = "REST Binary Sensor"
|
||||||
DEFAULT_SENSOR_NAME = "REST Sensor"
|
DEFAULT_SENSOR_NAME = "REST Sensor"
|
||||||
|
@ -9,6 +9,7 @@ import httpx
|
|||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.helpers import template
|
from homeassistant.helpers import template
|
||||||
from homeassistant.helpers.httpx_client import create_async_httpx_client
|
from homeassistant.helpers.httpx_client import create_async_httpx_client
|
||||||
|
from homeassistant.util.ssl import SSLCipherList
|
||||||
|
|
||||||
DEFAULT_TIMEOUT = 10
|
DEFAULT_TIMEOUT = 10
|
||||||
|
|
||||||
@ -29,6 +30,7 @@ class RestData:
|
|||||||
params: dict[str, str] | None,
|
params: dict[str, str] | None,
|
||||||
data: str | None,
|
data: str | None,
|
||||||
verify_ssl: bool,
|
verify_ssl: bool,
|
||||||
|
ssl_cipher_list: str,
|
||||||
timeout: int = DEFAULT_TIMEOUT,
|
timeout: int = DEFAULT_TIMEOUT,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Initialize the data object."""
|
"""Initialize the data object."""
|
||||||
@ -42,6 +44,7 @@ class RestData:
|
|||||||
self._request_data = data
|
self._request_data = data
|
||||||
self._timeout = timeout
|
self._timeout = timeout
|
||||||
self._verify_ssl = verify_ssl
|
self._verify_ssl = verify_ssl
|
||||||
|
self._ssl_cipher_list = SSLCipherList(ssl_cipher_list)
|
||||||
self._async_client: httpx.AsyncClient | None = None
|
self._async_client: httpx.AsyncClient | None = None
|
||||||
self.data: str | None = None
|
self.data: str | None = None
|
||||||
self.last_exception: Exception | None = None
|
self.last_exception: Exception | None = None
|
||||||
@ -55,7 +58,10 @@ class RestData:
|
|||||||
"""Get the latest data from REST service with provided method."""
|
"""Get the latest data from REST service with provided method."""
|
||||||
if not self._async_client:
|
if not self._async_client:
|
||||||
self._async_client = create_async_httpx_client(
|
self._async_client = create_async_httpx_client(
|
||||||
self._hass, verify_ssl=self._verify_ssl, default_encoding=self._encoding
|
self._hass,
|
||||||
|
verify_ssl=self._verify_ssl,
|
||||||
|
default_encoding=self._encoding,
|
||||||
|
ssl_cipher_list=self._ssl_cipher_list,
|
||||||
)
|
)
|
||||||
|
|
||||||
rendered_headers = template.render_complex(self._headers, parse_result=False)
|
rendered_headers = template.render_complex(self._headers, parse_result=False)
|
||||||
|
@ -31,14 +31,17 @@ from homeassistant.helpers.template_entity import (
|
|||||||
TEMPLATE_ENTITY_BASE_SCHEMA,
|
TEMPLATE_ENTITY_BASE_SCHEMA,
|
||||||
TEMPLATE_SENSOR_BASE_SCHEMA,
|
TEMPLATE_SENSOR_BASE_SCHEMA,
|
||||||
)
|
)
|
||||||
|
from homeassistant.util.ssl import SSLCipherList
|
||||||
|
|
||||||
from .const import (
|
from .const import (
|
||||||
CONF_ENCODING,
|
CONF_ENCODING,
|
||||||
CONF_JSON_ATTRS,
|
CONF_JSON_ATTRS,
|
||||||
CONF_JSON_ATTRS_PATH,
|
CONF_JSON_ATTRS_PATH,
|
||||||
|
CONF_SSL_CIPHER_LIST,
|
||||||
DEFAULT_ENCODING,
|
DEFAULT_ENCODING,
|
||||||
DEFAULT_FORCE_UPDATE,
|
DEFAULT_FORCE_UPDATE,
|
||||||
DEFAULT_METHOD,
|
DEFAULT_METHOD,
|
||||||
|
DEFAULT_SSL_CIPHER_LIST,
|
||||||
DEFAULT_VERIFY_SSL,
|
DEFAULT_VERIFY_SSL,
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
METHODS,
|
METHODS,
|
||||||
@ -58,6 +61,10 @@ RESOURCE_SCHEMA = {
|
|||||||
vol.Optional(CONF_PASSWORD): cv.string,
|
vol.Optional(CONF_PASSWORD): cv.string,
|
||||||
vol.Optional(CONF_PAYLOAD): cv.string,
|
vol.Optional(CONF_PAYLOAD): cv.string,
|
||||||
vol.Optional(CONF_VERIFY_SSL, default=DEFAULT_VERIFY_SSL): cv.boolean,
|
vol.Optional(CONF_VERIFY_SSL, default=DEFAULT_VERIFY_SSL): cv.boolean,
|
||||||
|
vol.Optional(
|
||||||
|
CONF_SSL_CIPHER_LIST,
|
||||||
|
default=DEFAULT_SSL_CIPHER_LIST,
|
||||||
|
): vol.In([e.value for e in SSLCipherList]),
|
||||||
vol.Optional(CONF_TIMEOUT, default=DEFAULT_TIMEOUT): cv.positive_int,
|
vol.Optional(CONF_TIMEOUT, default=DEFAULT_TIMEOUT): cv.positive_int,
|
||||||
vol.Optional(CONF_ENCODING, default=DEFAULT_ENCODING): cv.string,
|
vol.Optional(CONF_ENCODING, default=DEFAULT_ENCODING): cv.string,
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
import asyncio
|
import asyncio
|
||||||
from http import HTTPStatus
|
from http import HTTPStatus
|
||||||
import ssl
|
import ssl
|
||||||
from unittest.mock import MagicMock, patch
|
from unittest.mock import AsyncMock, MagicMock, patch
|
||||||
|
|
||||||
import httpx
|
import httpx
|
||||||
import pytest
|
import pytest
|
||||||
@ -30,6 +30,7 @@ from homeassistant.const import (
|
|||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.helpers import entity_registry as er
|
from homeassistant.helpers import entity_registry as er
|
||||||
from homeassistant.setup import async_setup_component
|
from homeassistant.setup import async_setup_component
|
||||||
|
from homeassistant.util.ssl import SSLCipherList
|
||||||
|
|
||||||
from tests.common import get_fixture_path
|
from tests.common import get_fixture_path
|
||||||
|
|
||||||
@ -157,6 +158,44 @@ async def test_setup_encoding(hass: HomeAssistant) -> None:
|
|||||||
assert hass.states.get("sensor.mysensor").state == "tack själv"
|
assert hass.states.get("sensor.mysensor").state == "tack själv"
|
||||||
|
|
||||||
|
|
||||||
|
@respx.mock
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
("ssl_cipher_list", "ssl_cipher_list_expected"),
|
||||||
|
(
|
||||||
|
("python_default", SSLCipherList.PYTHON_DEFAULT),
|
||||||
|
("intermediate", SSLCipherList.INTERMEDIATE),
|
||||||
|
("modern", SSLCipherList.MODERN),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
async def test_setup_ssl_ciphers(
|
||||||
|
hass: HomeAssistant, ssl_cipher_list: str, ssl_cipher_list_expected: SSLCipherList
|
||||||
|
) -> None:
|
||||||
|
"""Test setup with minimum configuration."""
|
||||||
|
with patch(
|
||||||
|
"homeassistant.components.rest.data.create_async_httpx_client",
|
||||||
|
return_value=MagicMock(request=AsyncMock(return_value=respx.MockResponse())),
|
||||||
|
) as httpx:
|
||||||
|
assert await async_setup_component(
|
||||||
|
hass,
|
||||||
|
SENSOR_DOMAIN,
|
||||||
|
{
|
||||||
|
SENSOR_DOMAIN: {
|
||||||
|
"platform": DOMAIN,
|
||||||
|
"resource": "http://localhost",
|
||||||
|
"method": "GET",
|
||||||
|
"ssl_cipher_list": ssl_cipher_list,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
httpx.assert_called_once_with(
|
||||||
|
hass,
|
||||||
|
verify_ssl=True,
|
||||||
|
default_encoding="UTF-8",
|
||||||
|
ssl_cipher_list=ssl_cipher_list_expected,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@respx.mock
|
@respx.mock
|
||||||
async def test_manual_update(hass: HomeAssistant) -> None:
|
async def test_manual_update(hass: HomeAssistant) -> None:
|
||||||
"""Test setup with minimum configuration."""
|
"""Test setup with minimum configuration."""
|
||||||
|
Loading…
x
Reference in New Issue
Block a user