Skip to content

Commit bffc3e8

Browse files
committed
Support unix socket-authenticated WebSocket connections
1 parent de46fe5 commit bffc3e8

File tree

2 files changed

+30
-13
lines changed

2 files changed

+30
-13
lines changed

supervisor/homeassistant/api.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -193,10 +193,13 @@ async def make_request(
193193
if content_type is not None:
194194
headers[hdrs.CONTENT_TYPE] = content_type
195195

196+
use_unix = self.use_unix_socket
197+
196198
for _ in (1, 2):
197199
try:
198-
await self.ensure_access_token()
199-
headers[hdrs.AUTHORIZATION] = f"Bearer {self.access_token}"
200+
if not use_unix:
201+
await self.ensure_access_token()
202+
headers[hdrs.AUTHORIZATION] = f"Bearer {self.access_token}"
200203
async with self._session.request(
201204
method,
202205
url,
@@ -207,8 +210,8 @@ async def make_request(
207210
params=params,
208211
ssl=False,
209212
) as resp:
210-
# Access token expired
211-
if resp.status == 401:
213+
# Access token expired (only relevant for TCP)
214+
if resp.status == 401 and not use_unix:
212215
self.access_token = None
213216
continue
214217
yield resp

supervisor/homeassistant/websocket.py

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -140,16 +140,28 @@ async def _receive_json(self) -> None:
140140

141141
@classmethod
142142
async def connect_with_auth(
143-
cls, session: aiohttp.ClientSession, url: str, token: str
143+
cls,
144+
session: aiohttp.ClientSession,
145+
url: str,
146+
token: str | None,
144147
) -> WSClient:
145-
"""Create an authenticated websocket client."""
148+
"""Create an authenticated websocket client.
149+
150+
When token is None (Unix socket), Core sends auth_ok immediately
151+
without requiring an auth exchange.
152+
"""
146153
try:
147154
client = await session.ws_connect(url, ssl=False)
148155
except aiohttp.client_exceptions.ClientConnectorError:
149156
raise HomeAssistantWSConnectionError("Can't connect") from None
150157

151-
hello_message = await client.receive_json()
158+
first_message = await client.receive_json()
159+
160+
if first_message[ATTR_TYPE] == "auth_ok":
161+
# Unix socket: Core already authenticated us
162+
return cls(AwesomeVersion(first_message["ha_version"]), client)
152163

164+
# TCP: auth_required → send token → auth_ok
153165
await client.send_json(
154166
{ATTR_TYPE: WSType.AUTH, ATTR_ACCESS_TOKEN: token}, dumps=json_dumps
155167
)
@@ -159,7 +171,7 @@ async def connect_with_auth(
159171
if auth_ok_message[ATTR_TYPE] != "auth_ok":
160172
raise HomeAssistantAPIError("AUTH NOT OK")
161173

162-
return cls(AwesomeVersion(hello_message["ha_version"]), client)
174+
return cls(AwesomeVersion(first_message["ha_version"]), client)
163175

164176

165177
class HomeAssistantWebSocket(CoreSysAttributes):
@@ -186,12 +198,14 @@ async def _get_ws_client(self) -> WSClient:
186198
if self._client is not None and self._client.connected:
187199
return self._client
188200

189-
with suppress(asyncio.TimeoutError, aiohttp.ClientError):
190-
await self.sys_homeassistant.api.ensure_access_token()
201+
api = self.sys_homeassistant.api
202+
if not api.use_unix_socket:
203+
with suppress(asyncio.TimeoutError, aiohttp.ClientError):
204+
await api.ensure_access_token()
191205
client = await WSClient.connect_with_auth(
192-
self.sys_homeassistant.api._session,
193-
self.sys_homeassistant.api._ws_url,
194-
cast(str, self.sys_homeassistant.api.access_token),
206+
api._session,
207+
api._ws_url,
208+
None if api.use_unix_socket else cast(str, api.access_token),
195209
)
196210

197211
self.sys_create_task(client.start_listener())

0 commit comments

Comments
 (0)