From cfd081e53924f563e391891f0664df6082d61842 Mon Sep 17 00:00:00 2001 From: Francois Thibault Date: Tue, 17 Jun 2025 07:24:26 -0400 Subject: [PATCH 1/4] Disable session cookie quoting to work with aiohttp v3.12.12. Fix issue #684 --- pyhilo/oauth2.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/pyhilo/oauth2.py b/pyhilo/oauth2.py index 04f8b6b..47379b8 100644 --- a/pyhilo/oauth2.py +++ b/pyhilo/oauth2.py @@ -5,6 +5,8 @@ from homeassistant.core import HomeAssistant from homeassistant.helpers.config_entry_oauth2_flow import LocalOAuth2Implementation +from homeassistant.helpers.aiohttp_client import async_create_clientsession +from aiohttp import CookieJar from pyhilo.const import AUTH_AUTHORIZE, AUTH_CLIENT_ID, AUTH_TOKEN, DOMAIN from pyhilo.oauth2helper import OAuth2Helper @@ -26,6 +28,7 @@ def __init__( AUTH_TOKEN, ) + self.session = async_create_clientsession(self.hass, cookie_jar=CookieJar(quote_cookie=False)) self.oauth_helper = OAuth2Helper() # ... Override AbstractOAuth2Implementation details @@ -49,3 +52,21 @@ async def async_resolve_external_data(self, external_data: Any) -> dict: ) ), ) + + async def _token_request(self, data: dict) -> dict: + """Make a token request.""" + data["client_id"] = self.client_id + + if self.client_secret: + data["client_secret"] = self.client_secret + + resp = await self.session.post(self.token_url, data=data) + if resp.status >= 400: + try: + error_response = await resp.json() + except (ClientError, JSONDecodeError): + error_response = {} + error_code = error_response.get("error", "unknown") + error_description = error_response.get("error_description", "unknown error") + resp.raise_for_status() + return cast(dict, await resp.json()) From 16959ac537778263e380e218361b98d058445f43 Mon Sep 17 00:00:00 2001 From: Francois Thibault Date: Tue, 17 Jun 2025 13:42:27 -0400 Subject: [PATCH 2/4] Remove unnecessary code --- pyhilo/oauth2.py | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/pyhilo/oauth2.py b/pyhilo/oauth2.py index 47379b8..e81968d 100644 --- a/pyhilo/oauth2.py +++ b/pyhilo/oauth2.py @@ -7,6 +7,7 @@ from homeassistant.helpers.aiohttp_client import async_create_clientsession from aiohttp import CookieJar + from pyhilo.const import AUTH_AUTHORIZE, AUTH_CLIENT_ID, AUTH_TOKEN, DOMAIN from pyhilo.oauth2helper import OAuth2Helper @@ -61,12 +62,5 @@ async def _token_request(self, data: dict) -> dict: data["client_secret"] = self.client_secret resp = await self.session.post(self.token_url, data=data) - if resp.status >= 400: - try: - error_response = await resp.json() - except (ClientError, JSONDecodeError): - error_response = {} - error_code = error_response.get("error", "unknown") - error_description = error_response.get("error_description", "unknown error") resp.raise_for_status() return cast(dict, await resp.json()) From 96727f7c1a4ca0fcb00bea13032935417fe2cf4b Mon Sep 17 00:00:00 2001 From: Francois Thibault Date: Wed, 18 Jun 2025 07:31:12 -0400 Subject: [PATCH 3/4] removed oauth2 entirely as its are now moved in hilo plugin --- pyhilo/__init__.py | 2 -- pyhilo/oauth2.py | 66 ---------------------------------------------- 2 files changed, 68 deletions(-) delete mode 100644 pyhilo/oauth2.py diff --git a/pyhilo/__init__.py b/pyhilo/__init__.py index 7320aa2..c09325e 100644 --- a/pyhilo/__init__.py +++ b/pyhilo/__init__.py @@ -6,7 +6,6 @@ from pyhilo.devices import Devices from pyhilo.event import Event from pyhilo.exceptions import HiloError, InvalidCredentialsError, WebsocketError -from pyhilo.oauth2 import AuthCodeWithPKCEImplementation from pyhilo.util import from_utc_timestamp, time_diff from pyhilo.websocket import WebsocketEvent @@ -18,7 +17,6 @@ "HiloError", "InvalidCredentialsError", "WebsocketError", - "AuthCodeWithPKCEImplementation", "from_utc_timestamp", "time_diff", "WebsocketEvent", diff --git a/pyhilo/oauth2.py b/pyhilo/oauth2.py deleted file mode 100644 index e81968d..0000000 --- a/pyhilo/oauth2.py +++ /dev/null @@ -1,66 +0,0 @@ -"""Custom OAuth2 implementation.""" - -from typing import Any, cast - -from homeassistant.core import HomeAssistant -from homeassistant.helpers.config_entry_oauth2_flow import LocalOAuth2Implementation - -from homeassistant.helpers.aiohttp_client import async_create_clientsession -from aiohttp import CookieJar - -from pyhilo.const import AUTH_AUTHORIZE, AUTH_CLIENT_ID, AUTH_TOKEN, DOMAIN -from pyhilo.oauth2helper import OAuth2Helper - - -class AuthCodeWithPKCEImplementation(LocalOAuth2Implementation): # type: ignore[misc] - """Custom OAuth2 implementation.""" - - def __init__( - self, - hass: HomeAssistant, - ) -> None: - """Initialize AuthCodeWithPKCEImplementation.""" - super().__init__( - hass, - DOMAIN, - AUTH_CLIENT_ID, - "", - AUTH_AUTHORIZE, - AUTH_TOKEN, - ) - - self.session = async_create_clientsession(self.hass, cookie_jar=CookieJar(quote_cookie=False)) - self.oauth_helper = OAuth2Helper() - - # ... Override AbstractOAuth2Implementation details - @property - def name(self) -> str: - """Name of the implementation.""" - return "Hilo" - - @property - def extra_authorize_data(self) -> dict: - """Extra data that needs to be appended to the authorize url.""" - return self.oauth_helper.get_authorize_parameters() - - async def async_resolve_external_data(self, external_data: Any) -> dict: - """Resolve the authorization code to tokens.""" - return cast( - dict, - await self._token_request( - self.oauth_helper.get_token_request_parameters( - external_data["code"], external_data["state"]["redirect_uri"] - ) - ), - ) - - async def _token_request(self, data: dict) -> dict: - """Make a token request.""" - data["client_id"] = self.client_id - - if self.client_secret: - data["client_secret"] = self.client_secret - - resp = await self.session.post(self.token_url, data=data) - resp.raise_for_status() - return cast(dict, await resp.json()) From 2250caa4916c6f8318cd2ecd18cee1b9fe19861a Mon Sep 17 00:00:00 2001 From: Francois Thibault Date: Wed, 18 Jun 2025 09:58:02 -0400 Subject: [PATCH 4/4] Linting --- pyhilo/devices.py | 4 ++-- pyhilo/graphql.py | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/pyhilo/devices.py b/pyhilo/devices.py index f9257d8..e558646 100644 --- a/pyhilo/devices.py +++ b/pyhilo/devices.py @@ -38,7 +38,7 @@ def attributes_list(self) -> list[Union[int, dict[int, list[str]]]]: ] def parse_values_received(self, values: list[dict[str, Any]]) -> list[HiloDevice]: - """Places value received in a dict while removing null attributes, + """Places value received in a dict while removing null attributes, this returns values to be mapped to devices. """ readings = [] @@ -110,7 +110,7 @@ async def update(self) -> None: async def update_devicelist_from_signalr( self, values: list[dict[str, Any]] ) -> list[HiloDevice]: - #ic-dev21 not sure if this is dead code? + # ic-dev21 not sure if this is dead code? new_devices = [] for raw_device in values: LOG.debug(f"Generating device {raw_device}") diff --git a/pyhilo/graphql.py b/pyhilo/graphql.py index 7344e01..8a8dace 100644 --- a/pyhilo/graphql.py +++ b/pyhilo/graphql.py @@ -574,7 +574,9 @@ async def subscribe_to_device_updated( await asyncio.sleep(5) try: await self.call_get_location_query(location_hilo_id) - LOG.debug("subscribe_to_device_updated, call_get_location_query success") + LOG.debug( + "subscribe_to_device_updated, call_get_location_query success" + ) except Exception as e2: LOG.error(