1
0
mirror of https://github.com/home-assistant/supervisor.git synced 2026-04-02 08:12:47 +01:00

Support unix socket-authenticated WebSocket connections

This commit is contained in:
Stefan Agner
2026-03-11 17:52:37 +01:00
parent 1c43af968a
commit f116cbbfc3
2 changed files with 30 additions and 13 deletions

View File

@@ -193,10 +193,13 @@ class HomeAssistantAPI(CoreSysAttributes):
if content_type is not None:
headers[hdrs.CONTENT_TYPE] = content_type
use_unix = self.use_unix_socket
for _ in (1, 2):
try:
await self.ensure_access_token()
headers[hdrs.AUTHORIZATION] = f"Bearer {self.access_token}"
if not use_unix:
await self.ensure_access_token()
headers[hdrs.AUTHORIZATION] = f"Bearer {self.access_token}"
async with self._session.request(
method,
url,
@@ -207,8 +210,8 @@ class HomeAssistantAPI(CoreSysAttributes):
params=params,
ssl=False,
) as resp:
# Access token expired
if resp.status == 401:
# Access token expired (only relevant for TCP)
if resp.status == 401 and not use_unix:
self.access_token = None
continue
yield resp

View File

@@ -140,16 +140,28 @@ class WSClient:
@classmethod
async def connect_with_auth(
cls, session: aiohttp.ClientSession, url: str, token: str
cls,
session: aiohttp.ClientSession,
url: str,
token: str | None,
) -> WSClient:
"""Create an authenticated websocket client."""
"""Create an authenticated websocket client.
When token is None (Unix socket), Core sends auth_ok immediately
without requiring an auth exchange.
"""
try:
client = await session.ws_connect(url, ssl=False)
except aiohttp.client_exceptions.ClientConnectorError:
raise HomeAssistantWSConnectionError("Can't connect") from None
hello_message = await client.receive_json()
first_message = await client.receive_json()
if first_message[ATTR_TYPE] == "auth_ok":
# Unix socket: Core already authenticated us
return cls(AwesomeVersion(first_message["ha_version"]), client)
# TCP: auth_required → send token → auth_ok
await client.send_json(
{ATTR_TYPE: WSType.AUTH, ATTR_ACCESS_TOKEN: token}, dumps=json_dumps
)
@@ -159,7 +171,7 @@ class WSClient:
if auth_ok_message[ATTR_TYPE] != "auth_ok":
raise HomeAssistantAPIError("AUTH NOT OK")
return cls(AwesomeVersion(hello_message["ha_version"]), client)
return cls(AwesomeVersion(first_message["ha_version"]), client)
class HomeAssistantWebSocket(CoreSysAttributes):
@@ -186,12 +198,14 @@ class HomeAssistantWebSocket(CoreSysAttributes):
if self._client is not None and self._client.connected:
return self._client
with suppress(asyncio.TimeoutError, aiohttp.ClientError):
await self.sys_homeassistant.api.ensure_access_token()
api = self.sys_homeassistant.api
if not api.use_unix_socket:
with suppress(asyncio.TimeoutError, aiohttp.ClientError):
await api.ensure_access_token()
client = await WSClient.connect_with_auth(
self.sys_homeassistant.api._session,
self.sys_homeassistant.api._ws_url,
cast(str, self.sys_homeassistant.api.access_token),
api._session,
api._ws_url,
None if api.use_unix_socket else cast(str, api.access_token),
)
self.sys_create_task(client.start_listener())