diff --git a/esphome/dashboard/settings.py b/esphome/dashboard/settings.py index aa994ae4877..3b22180b1db 100644 --- a/esphome/dashboard/settings.py +++ b/esphome/dashboard/settings.py @@ -85,7 +85,9 @@ class DashboardSettings: if not self.using_auth: return True # Compare in constant running time (to prevent timing attacks) - username_matches = hmac.compare_digest(username, self.username) + username_matches = hmac.compare_digest( + username.encode("utf-8"), self.username.encode("utf-8") + ) password_matches = hmac.compare_digest( self.password_hash, password_hash(password) ) diff --git a/tests/dashboard/test_settings.py b/tests/dashboard/test_settings.py index 89f1b9a4247..55776ac7c4d 100644 --- a/tests/dashboard/test_settings.py +++ b/tests/dashboard/test_settings.py @@ -258,6 +258,18 @@ def test_check_password_no_auth(dashboard_settings: DashboardSettings) -> None: assert dashboard_settings.check_password("anyone", "anything") is True +def test_check_password_non_ascii_username( + dashboard_settings: DashboardSettings, +) -> None: + """Test check_password handles non-ASCII usernames without TypeError.""" + dashboard_settings.username = "\u00e9l\u00e8ve" + dashboard_settings.using_password = True + dashboard_settings.password_hash = password_hash("pass") + assert dashboard_settings.check_password("\u00e9l\u00e8ve", "pass") is True + assert dashboard_settings.check_password("\u00e9l\u00e8ve", "wrong") is False + assert dashboard_settings.check_password("other", "pass") is False + + def test_check_password_ha_addon_no_password( dashboard_settings: DashboardSettings, monkeypatch: pytest.MonkeyPatch,