mirror of
https://github.com/home-assistant/supervisor.git
synced 2026-04-17 23:33:35 +01:00
Support unix socket-authenticated WebSocket connections
This commit is contained in:
@@ -193,10 +193,13 @@ class HomeAssistantAPI(CoreSysAttributes):
|
|||||||
if content_type is not None:
|
if content_type is not None:
|
||||||
headers[hdrs.CONTENT_TYPE] = content_type
|
headers[hdrs.CONTENT_TYPE] = content_type
|
||||||
|
|
||||||
|
use_unix = self.use_unix_socket
|
||||||
|
|
||||||
for _ in (1, 2):
|
for _ in (1, 2):
|
||||||
try:
|
try:
|
||||||
await self.ensure_access_token()
|
if not use_unix:
|
||||||
headers[hdrs.AUTHORIZATION] = f"Bearer {self.access_token}"
|
await self.ensure_access_token()
|
||||||
|
headers[hdrs.AUTHORIZATION] = f"Bearer {self.access_token}"
|
||||||
async with self._session.request(
|
async with self._session.request(
|
||||||
method,
|
method,
|
||||||
url,
|
url,
|
||||||
@@ -207,8 +210,8 @@ class HomeAssistantAPI(CoreSysAttributes):
|
|||||||
params=params,
|
params=params,
|
||||||
ssl=False,
|
ssl=False,
|
||||||
) as resp:
|
) as resp:
|
||||||
# Access token expired
|
# Access token expired (only relevant for TCP)
|
||||||
if resp.status == 401:
|
if resp.status == 401 and not use_unix:
|
||||||
self.access_token = None
|
self.access_token = None
|
||||||
continue
|
continue
|
||||||
yield resp
|
yield resp
|
||||||
|
|||||||
@@ -140,16 +140,28 @@ class WSClient:
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def connect_with_auth(
|
async def connect_with_auth(
|
||||||
cls, session: aiohttp.ClientSession, url: str, token: str
|
cls,
|
||||||
|
session: aiohttp.ClientSession,
|
||||||
|
url: str,
|
||||||
|
token: str | None,
|
||||||
) -> WSClient:
|
) -> 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:
|
try:
|
||||||
client = await session.ws_connect(url, ssl=False)
|
client = await session.ws_connect(url, ssl=False)
|
||||||
except aiohttp.client_exceptions.ClientConnectorError:
|
except aiohttp.client_exceptions.ClientConnectorError:
|
||||||
raise HomeAssistantWSConnectionError("Can't connect") from None
|
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(
|
await client.send_json(
|
||||||
{ATTR_TYPE: WSType.AUTH, ATTR_ACCESS_TOKEN: token}, dumps=json_dumps
|
{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":
|
if auth_ok_message[ATTR_TYPE] != "auth_ok":
|
||||||
raise HomeAssistantAPIError("AUTH NOT 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):
|
class HomeAssistantWebSocket(CoreSysAttributes):
|
||||||
@@ -186,12 +198,14 @@ class HomeAssistantWebSocket(CoreSysAttributes):
|
|||||||
if self._client is not None and self._client.connected:
|
if self._client is not None and self._client.connected:
|
||||||
return self._client
|
return self._client
|
||||||
|
|
||||||
with suppress(asyncio.TimeoutError, aiohttp.ClientError):
|
api = self.sys_homeassistant.api
|
||||||
await self.sys_homeassistant.api.ensure_access_token()
|
if not api.use_unix_socket:
|
||||||
|
with suppress(asyncio.TimeoutError, aiohttp.ClientError):
|
||||||
|
await api.ensure_access_token()
|
||||||
client = await WSClient.connect_with_auth(
|
client = await WSClient.connect_with_auth(
|
||||||
self.sys_homeassistant.api._session,
|
api._session,
|
||||||
self.sys_homeassistant.api._ws_url,
|
api._ws_url,
|
||||||
cast(str, self.sys_homeassistant.api.access_token),
|
None if api.use_unix_socket else cast(str, api.access_token),
|
||||||
)
|
)
|
||||||
|
|
||||||
self.sys_create_task(client.start_listener())
|
self.sys_create_task(client.start_listener())
|
||||||
|
|||||||
Reference in New Issue
Block a user