From 95988131f60aae199766bfa3c14dd20a2d0cb9de Mon Sep 17 00:00:00 2001 From: maciej-or Date: Tue, 5 Nov 2024 21:31:11 +0100 Subject: [PATCH] verify SSL option for self-signed certs --- .../hikvision_next/config_flow.py | 17 +++++------ .../hikvision_next/hikvision_device.py | 28 ++++++++++++------- .../hikvision_next/translations/en.json | 1 + .../hikvision_next/translations/pl.json | 1 + tests/conftest.py | 5 ++-- 5 files changed, 30 insertions(+), 22 deletions(-) diff --git a/custom_components/hikvision_next/config_flow.py b/custom_components/hikvision_next/config_flow.py index f89d33c..2751419 100755 --- a/custom_components/hikvision_next/config_flow.py +++ b/custom_components/hikvision_next/config_flow.py @@ -12,12 +12,11 @@ from homeassistant.components.network import async_get_source_ip from homeassistant.config_entries import ConfigEntry, ConfigFlow -from homeassistant.const import CONF_HOST, CONF_PASSWORD, CONF_USERNAME +from homeassistant.const import CONF_HOST, CONF_PASSWORD, CONF_USERNAME, CONF_VERIFY_SSL from homeassistant.data_entry_flow import FlowResult -from homeassistant.helpers.httpx_client import get_async_client from .const import CONF_ALARM_SERVER_HOST, CONF_SET_ALARM_SERVER, DOMAIN -from .isapi import ISAPIClient +from .hikvision_device import HikvisionDevice _LOGGER = logging.getLogger(__name__) @@ -37,6 +36,7 @@ async def get_schema(self, user_input: dict[str, Any]): vol.Required(CONF_HOST, default=user_input.get(CONF_HOST, "http://")): str, vol.Required(CONF_USERNAME, default=user_input.get(CONF_USERNAME, "")): str, vol.Required(CONF_PASSWORD, default=user_input.get(CONF_PASSWORD, "")): str, + vol.Required(CONF_VERIFY_SSL, default=True): bool, vol.Required( CONF_SET_ALARM_SERVER, default=user_input.get(CONF_SET_ALARM_SERVER, True), @@ -56,23 +56,20 @@ async def async_step_user(self, user_input: dict[str, Any] | None = None) -> Flo if user_input is not None: try: host = user_input[CONF_HOST].rstrip("/") - username = user_input[CONF_USERNAME] - password = user_input[CONF_PASSWORD] user_input_validated = { **user_input, CONF_HOST: host, } - session = get_async_client(self.hass) - isapi = ISAPIClient(host, username, password, session) - await isapi.get_device_info() + device = HikvisionDevice(self.hass, data=user_input_validated) + await device.get_device_info() if self._reauth_entry: self.hass.config_entries.async_update_entry(self._reauth_entry, data=user_input_validated) self.hass.async_create_task(self.hass.config_entries.async_reload(self._reauth_entry.entry_id)) return self.async_abort(reason="reauth_successful") - await self.async_set_unique_id(isapi.device_info.serial_no) + await self.async_set_unique_id(device.device_info.serial_no) self._abort_if_unique_id_configured() except HTTPStatusError as error: @@ -88,7 +85,7 @@ async def async_step_user(self, user_input: dict[str, Any] | None = None) -> Flo _LOGGER.error("Unexpected %s %s", {type(ex).__name__}, ex) errors["base"] = f"Unexpected {type(ex).__name__}: {ex}" else: - return self.async_create_entry(title=isapi.device_info.name, data=user_input_validated) + return self.async_create_entry(title=device.device_info.name, data=user_input_validated) schema = await self.get_schema(user_input or {}) return self.async_show_form(step_id="user", data_schema=schema, errors=errors) diff --git a/custom_components/hikvision_next/hikvision_device.py b/custom_components/hikvision_next/hikvision_device.py index fe96d49..c11a406 100644 --- a/custom_components/hikvision_next/hikvision_device.py +++ b/custom_components/hikvision_next/hikvision_device.py @@ -3,11 +3,12 @@ import asyncio from http import HTTPStatus import logging +from typing import Any import httpx from homeassistant.config_entries import ConfigEntry -from homeassistant.const import CONF_HOST, CONF_PASSWORD, CONF_USERNAME +from homeassistant.const import CONF_HOST, CONF_PASSWORD, CONF_USERNAME, CONF_VERIFY_SSL from homeassistant.core import HomeAssistant from homeassistant.exceptions import HomeAssistantError from homeassistant.helpers import device_registry as dr @@ -15,7 +16,6 @@ from homeassistant.helpers.httpx_client import get_async_client from homeassistant.util import slugify -from .isapi.const import CONNECTION_TYPE_DIRECT, EVENT_IO from .const import ( ALARM_SERVER_PATH, CONF_ALARM_SERVER_HOST, @@ -26,7 +26,8 @@ SECONDARY_COORDINATOR, ) from .coordinator import EventsCoordinator, SecondaryCoordinator -from .isapi import EventInfo, ISAPIClient, IPCamera +from .isapi import EventInfo, IPCamera, ISAPIClient +from .isapi.const import CONNECTION_TYPE_DIRECT, EVENT_IO _LOGGER = logging.getLogger(__name__) @@ -34,18 +35,25 @@ class HikvisionDevice(ISAPIClient): """Hikvision device for Home Assistant integration.""" - def __init__(self, hass: HomeAssistant, entry: ConfigEntry) -> None: + def __init__( + self, + hass: HomeAssistant, + entry: ConfigEntry | None = None, + data: dict[str, Any] | None = None, + ) -> None: """Initialize device.""" + config = entry.data if entry else data self.hass = hass - self.control_alarm_server_host = entry.data[CONF_SET_ALARM_SERVER] - self.alarm_server_host = entry.data[CONF_ALARM_SERVER_HOST] + self.control_alarm_server_host = config[CONF_SET_ALARM_SERVER] + self.alarm_server_host = config[CONF_ALARM_SERVER_HOST] # init ISAPI client - host = entry.data[CONF_HOST] - username = entry.data[CONF_USERNAME] - password = entry.data[CONF_PASSWORD] - session = get_async_client(hass) + host = config[CONF_HOST] + username = config[CONF_USERNAME] + password = config[CONF_PASSWORD] + varify_ssl = config.get(CONF_VERIFY_SSL, True) + session = get_async_client(hass, varify_ssl) super().__init__(host, username, password, session) self.events_info: list[EventInfo] = [] diff --git a/custom_components/hikvision_next/translations/en.json b/custom_components/hikvision_next/translations/en.json index 3917540..6925dd9 100644 --- a/custom_components/hikvision_next/translations/en.json +++ b/custom_components/hikvision_next/translations/en.json @@ -10,6 +10,7 @@ "host": "URL", "password": "Password", "username": "Username", + "verify_ssl": "Verify Hikvision device SSL certificate", "set_alarm_server": "Set notifications host using following address:", "alarm_server": "Home Assistant address accessible by Hikvison device" } diff --git a/custom_components/hikvision_next/translations/pl.json b/custom_components/hikvision_next/translations/pl.json index 8e115bf..b47cf92 100644 --- a/custom_components/hikvision_next/translations/pl.json +++ b/custom_components/hikvision_next/translations/pl.json @@ -10,6 +10,7 @@ "host": "URL", "password": "Hasło", "username": "Nazwa użytkownika", + "verify_ssl": "Zweryfikuj certyfikat SSL urządzenia Hikvision", "set_alarm_server": "Ustaw host powiadomień używając następującego adresu:", "alarm_server": "Adres Home Assistant dostępny dla urządzenia Hikvision" } diff --git a/tests/conftest.py b/tests/conftest.py index bad5d01..6c36748 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -5,7 +5,7 @@ import respx import xmltodict from custom_components.hikvision_next.const import DOMAIN, CONF_SET_ALARM_SERVER, CONF_ALARM_SERVER_HOST -from homeassistant.const import CONF_HOST, CONF_PASSWORD, CONF_USERNAME +from homeassistant.const import CONF_HOST, CONF_PASSWORD, CONF_USERNAME, CONF_VERIFY_SSL from pytest_homeassistant_custom_component.common import MockConfigEntry from custom_components.hikvision_next.isapi import ISAPIClient from homeassistant.core import HomeAssistant @@ -17,9 +17,10 @@ CONF_USERNAME: "u1", CONF_PASSWORD: "***", } -TEST_CONFIG = {**TEST_CLIENT, CONF_SET_ALARM_SERVER: False, CONF_ALARM_SERVER_HOST: ""} +TEST_CONFIG = {**TEST_CLIENT, CONF_VERIFY_SSL: True, CONF_SET_ALARM_SERVER: False, CONF_ALARM_SERVER_HOST: ""} TEST_CONFIG_WITH_ALARM_SERVER = { **TEST_CLIENT, + CONF_VERIFY_SSL: True, CONF_SET_ALARM_SERVER: True, CONF_ALARM_SERVER_HOST: "http://1.0.0.11:8123", }