Skip to content

Commit 2ea20ee

Browse files
authored
Fix UTF-8 encoding for REST basic authentication (home-assistant#148225)
1 parent 008e2a3 commit 2ea20ee

File tree

3 files changed

+37
-1
lines changed

3 files changed

+37
-1
lines changed

homeassistant/components/rest/data.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ def __init__(
4949
# Convert auth tuple to aiohttp.BasicAuth if needed
5050
if isinstance(auth, tuple) and len(auth) == 2:
5151
self._auth: aiohttp.BasicAuth | aiohttp.DigestAuthMiddleware | None = (
52-
aiohttp.BasicAuth(auth[0], auth[1])
52+
aiohttp.BasicAuth(auth[0], auth[1], encoding="utf-8")
5353
)
5454
else:
5555
self._auth = auth

tests/components/rest/test_binary_sensor.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -667,3 +667,36 @@ async def test_availability_blocks_value_template(
667667
await hass.async_block_till_done()
668668

669669
assert error in caplog.text
670+
671+
672+
async def test_setup_get_basic_auth_utf8(
673+
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker
674+
) -> None:
675+
"""Test setup with basic auth using UTF-8 characters including Unicode char \u2018."""
676+
# Use a password with the Unicode character \u2018 (left single quotation mark)
677+
aioclient_mock.get("http://localhost", status=HTTPStatus.OK, json={"key": "on"})
678+
assert await async_setup_component(
679+
hass,
680+
BINARY_SENSOR_DOMAIN,
681+
{
682+
BINARY_SENSOR_DOMAIN: {
683+
"platform": DOMAIN,
684+
"resource": "http://localhost",
685+
"method": "GET",
686+
"value_template": "{{ value_json.key }}",
687+
"name": "foo",
688+
"verify_ssl": "true",
689+
"timeout": 30,
690+
"authentication": "basic",
691+
"username": "test_user",
692+
"password": "test\u2018password", # Password with Unicode char
693+
"headers": {"Accept": CONTENT_TYPE_JSON},
694+
}
695+
},
696+
)
697+
698+
await hass.async_block_till_done()
699+
assert len(hass.states.async_all(BINARY_SENSOR_DOMAIN)) == 1
700+
701+
state = hass.states.get("binary_sensor.foo")
702+
assert state.state == STATE_ON

tests/test_util/aiohttp.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,9 @@ async def match_request(
156156

157157
for response in self._mocks:
158158
if response.match_request(method, url, params):
159+
# If auth is provided, try to encode it to trigger any encoding errors
160+
if auth is not None:
161+
auth.encode()
159162
self.mock_calls.append((method, url, data, headers))
160163
if response.side_effect:
161164
response = await response.side_effect(method, url, data)

0 commit comments

Comments
 (0)